]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / LanguageRuntime / ObjC / AppleObjCRuntime / AppleObjCTypeEncodingParser.cpp
1 //===-- AppleObjCTypeEncodingParser.cpp -------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "AppleObjCTypeEncodingParser.h"
11
12 #include "lldb/Symbol/ClangASTContext.h"
13 #include "lldb/Symbol/ClangUtil.h"
14 #include "lldb/Symbol/CompilerType.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/StringLexer.h"
18
19 #include <vector>
20
21 using namespace lldb_private;
22 using namespace lldb_utility;
23
24 AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser(
25     ObjCLanguageRuntime &runtime)
26     : ObjCLanguageRuntime::EncodingToType(), m_runtime(runtime) {
27   if (!m_scratch_ast_ctx_ap)
28     m_scratch_ast_ctx_ap.reset(new ClangASTContext(runtime.GetProcess()
29                                                        ->GetTarget()
30                                                        .GetArchitecture()
31                                                        .GetTriple()
32                                                        .str()
33                                                        .c_str()));
34 }
35
36 std::string
37 AppleObjCTypeEncodingParser::ReadStructName(lldb_utility::StringLexer &type) {
38   StreamString buffer;
39   while (type.HasAtLeast(1) && type.Peek() != '=')
40     buffer.Printf("%c", type.Next());
41   return buffer.GetString();
42 }
43
44 std::string
45 AppleObjCTypeEncodingParser::ReadQuotedString(lldb_utility::StringLexer &type) {
46   StreamString buffer;
47   while (type.HasAtLeast(1) && type.Peek() != '"')
48     buffer.Printf("%c", type.Next());
49   StringLexer::Character next = type.Next();
50   UNUSED_IF_ASSERT_DISABLED(next);
51   assert(next == '"');
52   return buffer.GetString();
53 }
54
55 uint32_t
56 AppleObjCTypeEncodingParser::ReadNumber(lldb_utility::StringLexer &type) {
57   uint32_t total = 0;
58   while (type.HasAtLeast(1) && isdigit(type.Peek()))
59     total = 10 * total + (type.Next() - '0');
60   return total;
61 }
62
63 // as an extension to the published grammar recent runtimes emit structs like
64 // this:
65 // "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}"
66
67 AppleObjCTypeEncodingParser::StructElement::StructElement()
68     : name(""), type(clang::QualType()), bitfield(0) {}
69
70 AppleObjCTypeEncodingParser::StructElement
71 AppleObjCTypeEncodingParser::ReadStructElement(clang::ASTContext &ast_ctx,
72                                                lldb_utility::StringLexer &type,
73                                                bool for_expression) {
74   StructElement retval;
75   if (type.NextIf('"'))
76     retval.name = ReadQuotedString(type);
77   if (!type.NextIf('"'))
78     return retval;
79   uint32_t bitfield_size = 0;
80   retval.type = BuildType(ast_ctx, type, for_expression, &bitfield_size);
81   retval.bitfield = bitfield_size;
82   return retval;
83 }
84
85 clang::QualType
86 AppleObjCTypeEncodingParser::BuildStruct(clang::ASTContext &ast_ctx,
87                                          lldb_utility::StringLexer &type,
88                                          bool for_expression) {
89   return BuildAggregate(ast_ctx, type, for_expression, '{', '}',
90                         clang::TTK_Struct);
91 }
92
93 clang::QualType
94 AppleObjCTypeEncodingParser::BuildUnion(clang::ASTContext &ast_ctx,
95                                         lldb_utility::StringLexer &type,
96                                         bool for_expression) {
97   return BuildAggregate(ast_ctx, type, for_expression, '(', ')',
98                         clang::TTK_Union);
99 }
100
101 clang::QualType AppleObjCTypeEncodingParser::BuildAggregate(
102     clang::ASTContext &ast_ctx, lldb_utility::StringLexer &type,
103     bool for_expression, char opener, char closer, uint32_t kind) {
104   if (!type.NextIf(opener))
105     return clang::QualType();
106   std::string name(ReadStructName(type));
107
108   // We do not handle templated classes/structs at the moment. If the name has
109   // a < in it, we are going to abandon this. We're still obliged to parse it,
110   // so we just set a flag that means "Don't actually build anything."
111
112   const bool is_templated = name.find('<') != std::string::npos;
113
114   if (!type.NextIf('='))
115     return clang::QualType();
116   bool in_union = true;
117   std::vector<StructElement> elements;
118   while (in_union && type.HasAtLeast(1)) {
119     if (type.NextIf(closer)) {
120       in_union = false;
121       break;
122     } else {
123       auto element = ReadStructElement(ast_ctx, type, for_expression);
124       if (element.type.isNull())
125         break;
126       else
127         elements.push_back(element);
128     }
129   }
130   if (in_union)
131     return clang::QualType();
132
133   if (is_templated)
134     return clang::QualType(); // This is where we bail out.  Sorry!
135
136   ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx);
137   if (!lldb_ctx)
138     return clang::QualType();
139   CompilerType union_type(lldb_ctx->CreateRecordType(
140       nullptr, lldb::eAccessPublic, name.c_str(), kind, lldb::eLanguageTypeC));
141   if (union_type) {
142     ClangASTContext::StartTagDeclarationDefinition(union_type);
143
144     unsigned int count = 0;
145     for (auto element : elements) {
146       if (element.name.empty()) {
147         StreamString elem_name;
148         elem_name.Printf("__unnamed_%u", count);
149         element.name = elem_name.GetString();
150       }
151       ClangASTContext::AddFieldToRecordType(
152           union_type, element.name.c_str(),
153           CompilerType(&ast_ctx, element.type), lldb::eAccessPublic,
154           element.bitfield);
155       ++count;
156     }
157     ClangASTContext::CompleteTagDeclarationDefinition(union_type);
158   }
159   return ClangUtil::GetQualType(union_type);
160 }
161
162 clang::QualType
163 AppleObjCTypeEncodingParser::BuildArray(clang::ASTContext &ast_ctx,
164                                         lldb_utility::StringLexer &type,
165                                         bool for_expression) {
166   if (!type.NextIf('['))
167     return clang::QualType();
168   uint32_t size = ReadNumber(type);
169   clang::QualType element_type(BuildType(ast_ctx, type, for_expression));
170   if (!type.NextIf(']'))
171     return clang::QualType();
172   ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx);
173   if (!lldb_ctx)
174     return clang::QualType();
175   CompilerType array_type(lldb_ctx->CreateArrayType(
176       CompilerType(&ast_ctx, element_type), size, false));
177   return ClangUtil::GetQualType(array_type);
178 }
179
180 // the runtime can emit these in the form of @"SomeType", giving more specifics
181 // this would be interesting for expression parser interop, but since we
182 // actually try to avoid exposing the ivar info to the expression evaluator,
183 // consume but ignore the type info and always return an 'id'; if anything,
184 // dynamic typing will resolve things for us anyway
185 clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType(
186     clang::ASTContext &ast_ctx, lldb_utility::StringLexer &type,
187     bool for_expression) {
188   if (!type.NextIf('@'))
189     return clang::QualType();
190
191   std::string name;
192
193   if (type.NextIf('"')) {
194     // We have to be careful here.  We're used to seeing
195     //   @"NSString"
196     // but in records it is possible that the string following an @ is the name
197     // of the next field and @ means "id". This is the case if anything
198     // unquoted except for "}", the end of the type, or another name follows
199     // the quoted string.
200     //
201     // E.g.
202     // - @"NSString"@ means "id, followed by a field named NSString of type id"
203     // - @"NSString"} means "a pointer to NSString and the end of the struct" -
204     // @"NSString""nextField" means "a pointer to NSString and a field named
205     // nextField" - @"NSString" followed by the end of the string means "a
206     // pointer to NSString"
207     //
208     // As a result, the rule is: If we see @ followed by a quoted string, we
209     // peek. - If we see }, ), ], the end of the string, or a quote ("), the
210     // quoted string is a class name. - If we see anything else, the quoted
211     // string is a field name and we push it back onto type.
212
213     name = ReadQuotedString(type);
214
215     if (type.HasAtLeast(1)) {
216       switch (type.Peek()) {
217       default:
218         // roll back
219         type.PutBack(name.length() +
220                      2); // undo our consumption of the string and of the quotes
221         name.clear();
222         break;
223       case '}':
224       case ')':
225       case ']':
226       case '"':
227         // the quoted string is a class name – see the rule
228         break;
229       }
230     } else {
231       // the quoted string is a class name – see the rule
232     }
233   }
234
235   if (for_expression && !name.empty()) {
236     size_t less_than_pos = name.find('<');
237
238     if (less_than_pos != std::string::npos) {
239       if (less_than_pos == 0)
240         return ast_ctx.getObjCIdType();
241       else
242         name.erase(less_than_pos);
243     }
244
245     DeclVendor *decl_vendor = m_runtime.GetDeclVendor();
246     if (!decl_vendor)
247       return clang::QualType();
248
249     const bool append = false;
250     const uint32_t max_matches = 1;
251     std::vector<clang::NamedDecl *> decls;
252
253     uint32_t num_types =
254         decl_vendor->FindDecls(ConstString(name), append, max_matches, decls);
255
256 // The user can forward-declare something that has no definition.  The runtime
257 // doesn't prohibit this at all. This is a rare and very weird case.  We keep
258 // this assert in debug builds so we catch other weird cases.
259 #ifdef LLDB_CONFIGURATION_DEBUG
260     assert(num_types);
261 #else
262     if (!num_types)
263       return ast_ctx.getObjCIdType();
264 #endif
265
266     return ClangUtil::GetQualType(
267         ClangASTContext::GetTypeForDecl(decls[0]).GetPointerType());
268   } else {
269     // We're going to resolve this dynamically anyway, so just smile and wave.
270     return ast_ctx.getObjCIdType();
271   }
272 }
273
274 clang::QualType
275 AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx,
276                                        StringLexer &type, bool for_expression,
277                                        uint32_t *bitfield_bit_size) {
278   if (!type.HasAtLeast(1))
279     return clang::QualType();
280
281   switch (type.Peek()) {
282   default:
283     break;
284   case '{':
285     return BuildStruct(ast_ctx, type, for_expression);
286   case '[':
287     return BuildArray(ast_ctx, type, for_expression);
288   case '(':
289     return BuildUnion(ast_ctx, type, for_expression);
290   case '@':
291     return BuildObjCObjectPointerType(ast_ctx, type, for_expression);
292   }
293
294   switch (type.Next()) {
295   default:
296     type.PutBack(1);
297     return clang::QualType();
298   case 'c':
299     return ast_ctx.CharTy;
300   case 'i':
301     return ast_ctx.IntTy;
302   case 's':
303     return ast_ctx.ShortTy;
304   case 'l':
305     return ast_ctx.getIntTypeForBitwidth(32, true);
306   // this used to be done like this:
307   //   ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx);
308   //   if (!lldb_ctx)
309   //      return clang::QualType();
310   //   return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType();
311   // which uses one of the constants if one is available, but we don't think
312   // all this work is necessary.
313   case 'q':
314     return ast_ctx.LongLongTy;
315   case 'C':
316     return ast_ctx.UnsignedCharTy;
317   case 'I':
318     return ast_ctx.UnsignedIntTy;
319   case 'S':
320     return ast_ctx.UnsignedShortTy;
321   case 'L':
322     return ast_ctx.getIntTypeForBitwidth(32, false);
323   // see note for 'l'
324   case 'Q':
325     return ast_ctx.UnsignedLongLongTy;
326   case 'f':
327     return ast_ctx.FloatTy;
328   case 'd':
329     return ast_ctx.DoubleTy;
330   case 'B':
331     return ast_ctx.BoolTy;
332   case 'v':
333     return ast_ctx.VoidTy;
334   case '*':
335     return ast_ctx.getPointerType(ast_ctx.CharTy);
336   case '#':
337     return ast_ctx.getObjCClassType();
338   case ':':
339     return ast_ctx.getObjCSelType();
340   case 'b': {
341     uint32_t size = ReadNumber(type);
342     if (bitfield_bit_size) {
343       *bitfield_bit_size = size;
344       return ast_ctx.UnsignedIntTy; // FIXME: the spec is fairly vague here.
345     } else
346       return clang::QualType();
347   }
348   case 'r': {
349     clang::QualType target_type = BuildType(ast_ctx, type, for_expression);
350     if (target_type.isNull())
351       return clang::QualType();
352     else if (target_type == ast_ctx.UnknownAnyTy)
353       return ast_ctx.UnknownAnyTy;
354     else
355       return ast_ctx.getConstType(target_type);
356   }
357   case '^': {
358     if (!for_expression && type.NextIf('?')) {
359       // if we are not supporting the concept of unknownAny, but what is being
360       // created here is an unknownAny*, then we can just get away with a void*
361       // this is theoretically wrong (in the same sense as 'theoretically
362       // nothing exists') but is way better than outright failure in many
363       // practical cases
364       return ast_ctx.VoidPtrTy;
365     } else {
366       clang::QualType target_type = BuildType(ast_ctx, type, for_expression);
367       if (target_type.isNull())
368         return clang::QualType();
369       else if (target_type == ast_ctx.UnknownAnyTy)
370         return ast_ctx.UnknownAnyTy;
371       else
372         return ast_ctx.getPointerType(target_type);
373     }
374   }
375   case '?':
376     return for_expression ? ast_ctx.UnknownAnyTy : clang::QualType();
377   }
378 }
379
380 CompilerType AppleObjCTypeEncodingParser::RealizeType(
381     clang::ASTContext &ast_ctx, const char *name, bool for_expression) {
382   if (name && name[0]) {
383     StringLexer lexer(name);
384     clang::QualType qual_type = BuildType(ast_ctx, lexer, for_expression);
385     return CompilerType(&ast_ctx, qual_type);
386   }
387   return CompilerType();
388 }