LLDB mainline
AppleObjCTypeEncodingParser.cpp
Go to the documentation of this file.
1//===-- AppleObjCTypeEncodingParser.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
14#include "lldb/Target/Process.h"
15#include "lldb/Target/Target.h"
17
18#include "clang/Basic/TargetInfo.h"
19
20#include <vector>
21
22using namespace lldb_private;
23
25 ObjCLanguageRuntime &runtime)
26 : ObjCLanguageRuntime::EncodingToType(), m_runtime(runtime) {
28 return;
29
30 m_scratch_ast_ctx_sp = std::make_shared<TypeSystemClang>(
31 "AppleObjCTypeEncodingParser ASTContext",
33}
34
36 StreamString buffer;
37 while (type.HasAtLeast(1) && type.Peek() != '=')
38 buffer.Printf("%c", type.Next());
39 return std::string(buffer.GetString());
40}
41
43 StreamString buffer;
44 while (type.HasAtLeast(1) && type.Peek() != '"')
45 buffer.Printf("%c", type.Next());
46 StringLexer::Character next = type.Next();
48 assert(next == '"');
49 return std::string(buffer.GetString());
50}
51
53 uint32_t total = 0;
54 while (type.HasAtLeast(1) && isdigit(type.Peek()))
55 total = 10 * total + (type.Next() - '0');
56 return total;
57}
58
59// as an extension to the published grammar recent runtimes emit structs like
60// this:
61// "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}"
62
64 : type(clang::QualType()) {}
65
68 StringLexer &type,
69 bool for_expression) {
70 StructElement retval;
71 if (type.NextIf('"'))
72 retval.name = ReadQuotedString(type);
73 if (!type.NextIf('"'))
74 return retval;
75 uint32_t bitfield_size = 0;
76 retval.type = BuildType(ast_ctx, type, for_expression, &bitfield_size);
77 retval.bitfield = bitfield_size;
78 return retval;
79}
80
82 TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
83 return BuildAggregate(ast_ctx, type, for_expression, _C_STRUCT_B, _C_STRUCT_E,
84 llvm::to_underlying(clang::TagTypeKind::Struct));
85}
86
88 TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
89 return BuildAggregate(ast_ctx, type, for_expression, _C_UNION_B, _C_UNION_E,
90 llvm::to_underlying(clang::TagTypeKind::Union));
91}
92
94 TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression,
95 char opener, char closer, uint32_t kind) {
96 if (!type.NextIf(opener))
97 return clang::QualType();
98 std::string name(ReadStructName(type));
99
100 // We do not handle templated classes/structs at the moment. If the name has
101 // a < in it, we are going to abandon this. We're still obliged to parse it,
102 // so we just set a flag that means "Don't actually build anything."
103
104 const bool is_templated = name.find('<') != std::string::npos;
105
106 if (!type.NextIf('='))
107 return clang::QualType();
108 bool in_union = true;
109 std::vector<StructElement> elements;
110 while (in_union && type.HasAtLeast(1)) {
111 if (type.NextIf(closer)) {
112 in_union = false;
113 break;
114 } else {
115 auto element = ReadStructElement(ast_ctx, type, for_expression);
116 if (element.type.isNull())
117 break;
118 else
119 elements.push_back(element);
120 }
121 }
122 if (in_union)
123 return clang::QualType();
124
125 if (is_templated)
126 return clang::QualType(); // This is where we bail out. Sorry!
127
128 CompilerType union_type(ast_ctx.CreateRecordType(
129 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, name, kind,
131 if (union_type) {
133
134 unsigned int count = 0;
135 for (auto element : elements) {
136 if (element.name.empty()) {
137 StreamString elem_name;
138 elem_name.Printf("__unnamed_%u", count);
139 element.name = std::string(elem_name.GetString());
140 }
142 union_type, element.name.c_str(), ast_ctx.GetType(element.type),
143 lldb::eAccessPublic, element.bitfield);
144 ++count;
145 }
147 }
148 return ClangUtil::GetQualType(union_type);
149}
150
152 TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
153 if (!type.NextIf(_C_ARY_B))
154 return clang::QualType();
155 uint32_t size = ReadNumber(type);
156 clang::QualType element_type(BuildType(ast_ctx, type, for_expression));
157 if (!type.NextIf(_C_ARY_E))
158 return clang::QualType();
159 CompilerType array_type(ast_ctx.CreateArrayType(
160 CompilerType(ast_ctx.weak_from_this(), element_type.getAsOpaquePtr()),
161 size, false));
162 return ClangUtil::GetQualType(array_type);
163}
164
165// the runtime can emit these in the form of @"SomeType", giving more specifics
166// this would be interesting for expression parser interop, but since we
167// actually try to avoid exposing the ivar info to the expression evaluator,
168// consume but ignore the type info and always return an 'id'; if anything,
169// dynamic typing will resolve things for us anyway
171 TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression) {
172 if (!type.NextIf(_C_ID))
173 return clang::QualType();
174
175 clang::ASTContext &ast_ctx = clang_ast_ctx.getASTContext();
176
177 std::string name;
178
179 if (type.NextIf('"')) {
180 // We have to be careful here. We're used to seeing
181 // @"NSString"
182 // but in records it is possible that the string following an @ is the name
183 // of the next field and @ means "id". This is the case if anything
184 // unquoted except for "}", the end of the type, or another name follows
185 // the quoted string.
186 //
187 // E.g.
188 // - @"NSString"@ means "id, followed by a field named NSString of type id"
189 // - @"NSString"} means "a pointer to NSString and the end of the struct" -
190 // @"NSString""nextField" means "a pointer to NSString and a field named
191 // nextField" - @"NSString" followed by the end of the string means "a
192 // pointer to NSString"
193 //
194 // As a result, the rule is: If we see @ followed by a quoted string, we
195 // peek. - If we see }, ), ], the end of the string, or a quote ("), the
196 // quoted string is a class name. - If we see anything else, the quoted
197 // string is a field name and we push it back onto type.
198
199 name = ReadQuotedString(type);
200
201 if (type.HasAtLeast(1)) {
202 switch (type.Peek()) {
203 default:
204 // roll back
205 type.PutBack(name.length() +
206 2); // undo our consumption of the string and of the quotes
207 name.clear();
208 break;
209 case _C_STRUCT_E:
210 case _C_UNION_E:
211 case _C_ARY_E:
212 case '"':
213 // the quoted string is a class name – see the rule
214 break;
215 }
216 } else {
217 // the quoted string is a class name – see the rule
218 }
219 }
220
221 if (for_expression && !name.empty()) {
222 size_t less_than_pos = name.find('<');
223
224 if (less_than_pos != std::string::npos) {
225 if (less_than_pos == 0)
226 return ast_ctx.getObjCIdType();
227 else
228 name.erase(less_than_pos);
229 }
230
231 DeclVendor *decl_vendor = m_runtime.GetDeclVendor();
232 if (!decl_vendor)
233 return clang::QualType();
234
235 auto types = decl_vendor->FindTypes(ConstString(name), /*max_matches*/ 1);
236
237 // The user can forward-declare something that has no definition. The runtime
238 // doesn't prohibit this at all. This is a rare and very weird case. We keep
239 // this assert in debug builds so we catch other weird cases.
240 lldbassert(!types.empty());
241 if (types.empty())
242 return ast_ctx.getObjCIdType();
243
244 return ClangUtil::GetQualType(types.front().GetPointerType());
245 } else {
246 // We're going to resolve this dynamically anyway, so just smile and wave.
247 return ast_ctx.getObjCIdType();
248 }
249}
250
251clang::QualType
253 StringLexer &type, bool for_expression,
254 uint32_t *bitfield_bit_size) {
255 if (!type.HasAtLeast(1))
256 return clang::QualType();
257
258 clang::ASTContext &ast_ctx = clang_ast_ctx.getASTContext();
259
260 switch (type.Peek()) {
261 default:
262 break;
263 case _C_STRUCT_B:
264 return BuildStruct(clang_ast_ctx, type, for_expression);
265 case _C_ARY_B:
266 return BuildArray(clang_ast_ctx, type, for_expression);
267 case _C_UNION_B:
268 return BuildUnion(clang_ast_ctx, type, for_expression);
269 case _C_ID:
270 return BuildObjCObjectPointerType(clang_ast_ctx, type, for_expression);
271 }
272
273 switch (type.Next()) {
274 default:
275 type.PutBack(1);
276 return clang::QualType();
277 case _C_CHR:
278 return ast_ctx.CharTy;
279 case _C_INT:
280 return ast_ctx.IntTy;
281 case _C_SHT:
282 return ast_ctx.ShortTy;
283 case _C_LNG:
284 return ast_ctx.getIntTypeForBitwidth(32, true);
285 // this used to be done like this:
286 // return clang_ast_ctx->GetIntTypeFromBitSize(32, true).GetQualType();
287 // which uses one of the constants if one is available, but we don't think
288 // all this work is necessary.
289 case _C_LNG_LNG:
290 return ast_ctx.LongLongTy;
291 case _C_UCHR:
292 return ast_ctx.UnsignedCharTy;
293 case _C_UINT:
294 return ast_ctx.UnsignedIntTy;
295 case _C_USHT:
296 return ast_ctx.UnsignedShortTy;
297 case _C_ULNG:
298 return ast_ctx.getIntTypeForBitwidth(32, false);
299 // see note for _C_LNG
300 case _C_ULNG_LNG:
301 return ast_ctx.UnsignedLongLongTy;
302 case _C_FLT:
303 return ast_ctx.FloatTy;
304 case _C_DBL:
305 return ast_ctx.DoubleTy;
306 case _C_BOOL:
307 return ast_ctx.BoolTy;
308 case _C_VOID:
309 return ast_ctx.VoidTy;
310 case _C_CHARPTR:
311 return ast_ctx.getPointerType(ast_ctx.CharTy);
312 case _C_CLASS:
313 return ast_ctx.getObjCClassType();
314 case _C_SEL:
315 return ast_ctx.getObjCSelType();
316 case _C_BFLD: {
317 uint32_t size = ReadNumber(type);
318 if (bitfield_bit_size) {
319 *bitfield_bit_size = size;
320 return ast_ctx.UnsignedIntTy; // FIXME: the spec is fairly vague here.
321 } else
322 return clang::QualType();
323 }
324 case _C_CONST: {
325 clang::QualType target_type =
326 BuildType(clang_ast_ctx, type, for_expression);
327 if (target_type.isNull())
328 return clang::QualType();
329 else if (target_type == ast_ctx.UnknownAnyTy)
330 return ast_ctx.UnknownAnyTy;
331 else
332 return ast_ctx.getConstType(target_type);
333 }
334 case _C_PTR: {
335 if (!for_expression && type.NextIf(_C_UNDEF)) {
336 // if we are not supporting the concept of unknownAny, but what is being
337 // created here is an unknownAny*, then we can just get away with a void*
338 // this is theoretically wrong (in the same sense as 'theoretically
339 // nothing exists') but is way better than outright failure in many
340 // practical cases
341 return ast_ctx.VoidPtrTy;
342 } else {
343 clang::QualType target_type =
344 BuildType(clang_ast_ctx, type, for_expression);
345 if (target_type.isNull())
346 return clang::QualType();
347 else if (target_type == ast_ctx.UnknownAnyTy)
348 return ast_ctx.UnknownAnyTy;
349 else
350 return ast_ctx.getPointerType(target_type);
351 }
352 }
353 case _C_UNDEF:
354 return for_expression ? ast_ctx.UnknownAnyTy : clang::QualType();
355 }
356}
357
359 const char *name,
360 bool for_expression) {
361 if (name && name[0]) {
362 StringLexer lexer(name);
363 clang::QualType qual_type = BuildType(ast_ctx, lexer, for_expression);
364 return ast_ctx.GetType(qual_type);
365 }
366 return CompilerType();
367}
#define lldbassert(x)
Definition: LLDBAssert.h:15
#define _C_ARY_B
Definition: ObjCConstants.h:35
#define _C_CONST
Definition: ObjCConstants.h:42
#define _C_ID
Definition: ObjCConstants.h:13
#define _C_USHT
Definition: ObjCConstants.h:19
#define _C_STRUCT_B
Definition: ObjCConstants.h:39
#define _C_ULNG
Definition: ObjCConstants.h:23
#define _C_BOOL
Definition: ObjCConstants.h:29
#define _C_CHARPTR
Definition: ObjCConstants.h:33
#define _C_STRUCT_E
Definition: ObjCConstants.h:40
#define _C_INT
Definition: ObjCConstants.h:20
#define _C_DBL
Definition: ObjCConstants.h:27
#define _C_UNION_E
Definition: ObjCConstants.h:38
#define _C_UNION_B
Definition: ObjCConstants.h:37
#define _C_BFLD
Definition: ObjCConstants.h:28
#define _C_UINT
Definition: ObjCConstants.h:21
#define _C_CHR
Definition: ObjCConstants.h:16
#define _C_ULNG_LNG
Definition: ObjCConstants.h:25
#define _C_VOID
Definition: ObjCConstants.h:30
#define _C_ARY_E
Definition: ObjCConstants.h:36
#define _C_CLASS
Definition: ObjCConstants.h:14
#define _C_UCHR
Definition: ObjCConstants.h:17
#define _C_LNG
Definition: ObjCConstants.h:22
#define _C_LNG_LNG
Definition: ObjCConstants.h:24
#define _C_FLT
Definition: ObjCConstants.h:26
#define _C_PTR
Definition: ObjCConstants.h:32
#define _C_SHT
Definition: ObjCConstants.h:18
#define _C_SEL
Definition: ObjCConstants.h:15
#define _C_UNDEF
Definition: ObjCConstants.h:31
clang::QualType BuildType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size=nullptr)
clang::QualType BuildObjCObjectPointerType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression)
CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression) override
clang::QualType BuildAggregate(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, char opener, char closer, uint32_t kind)
StructElement ReadStructElement(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
clang::QualType BuildArray(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
clang::QualType BuildStruct(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
clang::QualType BuildUnion(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:450
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
A uniqued constant string class.
Definition: ConstString.h:40
std::vector< CompilerType > FindTypes(ConstString name, uint32_t max_matches)
Look up the types that the DeclVendor currently knows about matching a given name.
Definition: DeclVendor.cpp:18
virtual DeclVendor * GetDeclVendor()
std::shared_ptr< TypeSystemClang > m_scratch_ast_ctx_sp
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1277
Process * GetProcess()
Definition: Runtime.h:22
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
std::string::value_type Character
Definition: StringLexer.h:23
bool NextIf(Character c)
Definition: StringLexer.cpp:21
const ArchSpec & GetArchitecture() const
Definition: Target.h:1014
A TypeSystem implementation based on Clang.
static clang::FieldDecl * AddFieldToRecordType(const CompilerType &type, llvm::StringRef name, const CompilerType &field_type, lldb::AccessType access, uint32_t bitfield_bit_size)
CompilerType GetType(clang::QualType qt)
Creates a CompilerType from the given QualType with the current TypeSystemClang instance as the Compi...
clang::ASTContext & getASTContext()
Returns the clang::ASTContext instance managed by this TypeSystemClang.
static bool CompleteTagDeclarationDefinition(const CompilerType &type)
CompilerType CreateArrayType(const CompilerType &element_type, size_t element_count, bool is_vector)
static bool StartTagDeclarationDefinition(const CompilerType &type)
CompilerType CreateRecordType(clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, lldb::AccessType access_type, llvm::StringRef name, int kind, lldb::LanguageType language, ClangASTMetadata *metadata=nullptr, bool exports_symbols=false)
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:140
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
@ eLanguageTypeC
Non-standardized C, such as K&R.
static clang::QualType GetQualType(const CompilerType &ct)
Definition: ClangUtil.cpp:36