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