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 
22 using namespace lldb_private;
23 
25  ObjCLanguageRuntime &runtime)
26  : ObjCLanguageRuntime::EncodingToType(), m_runtime(runtime) {
28  m_scratch_ast_ctx_up = std::make_unique<TypeSystemClang>(
29  "AppleObjCTypeEncodingParser ASTContext",
31 }
32 
34  StreamString buffer;
35  while (type.HasAtLeast(1) && type.Peek() != '=')
36  buffer.Printf("%c", type.Next());
37  return std::string(buffer.GetString());
38 }
39 
41  StreamString buffer;
42  while (type.HasAtLeast(1) && type.Peek() != '"')
43  buffer.Printf("%c", type.Next());
44  StringLexer::Character next = type.Next();
46  assert(next == '"');
47  return std::string(buffer.GetString());
48 }
49 
51  uint32_t total = 0;
52  while (type.HasAtLeast(1) && isdigit(type.Peek()))
53  total = 10 * total + (type.Next() - '0');
54  return total;
55 }
56 
57 // as an extension to the published grammar recent runtimes emit structs like
58 // this:
59 // "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}"
60 
62  : name(""), type(clang::QualType()) {}
63 
66  StringLexer &type,
67  bool for_expression) {
68  StructElement retval;
69  if (type.NextIf('"'))
70  retval.name = ReadQuotedString(type);
71  if (!type.NextIf('"'))
72  return retval;
73  uint32_t bitfield_size = 0;
74  retval.type = BuildType(ast_ctx, type, for_expression, &bitfield_size);
75  retval.bitfield = bitfield_size;
76  return retval;
77 }
78 
80  TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
81  return BuildAggregate(ast_ctx, type, for_expression, _C_STRUCT_B, _C_STRUCT_E,
82  clang::TTK_Struct);
83 }
84 
86  TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
87  return BuildAggregate(ast_ctx, type, for_expression, _C_UNION_B, _C_UNION_E,
88  clang::TTK_Union);
89 }
90 
92  TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression,
93  char opener, char closer, uint32_t kind) {
94  if (!type.NextIf(opener))
95  return clang::QualType();
96  std::string name(ReadStructName(type));
97 
98  // We do not handle templated classes/structs at the moment. If the name has
99  // a < in it, we are going to abandon this. We're still obliged to parse it,
100  // so we just set a flag that means "Don't actually build anything."
101 
102  const bool is_templated = name.find('<') != std::string::npos;
103 
104  if (!type.NextIf('='))
105  return clang::QualType();
106  bool in_union = true;
107  std::vector<StructElement> elements;
108  while (in_union && type.HasAtLeast(1)) {
109  if (type.NextIf(closer)) {
110  in_union = false;
111  break;
112  } else {
113  auto element = ReadStructElement(ast_ctx, type, for_expression);
114  if (element.type.isNull())
115  break;
116  else
117  elements.push_back(element);
118  }
119  }
120  if (in_union)
121  return clang::QualType();
122 
123  if (is_templated)
124  return clang::QualType(); // This is where we bail out. Sorry!
125 
126  CompilerType union_type(ast_ctx.CreateRecordType(
127  nullptr, OptionalClangModuleID(), lldb::eAccessPublic, name, kind,
129  if (union_type) {
131 
132  unsigned int count = 0;
133  for (auto element : elements) {
134  if (element.name.empty()) {
135  StreamString elem_name;
136  elem_name.Printf("__unnamed_%u", count);
137  element.name = std::string(elem_name.GetString());
138  }
140  union_type, element.name.c_str(), ast_ctx.GetType(element.type),
141  lldb::eAccessPublic, element.bitfield);
142  ++count;
143  }
145  }
146  return ClangUtil::GetQualType(union_type);
147 }
148 
150  TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression) {
151  if (!type.NextIf(_C_ARY_B))
152  return clang::QualType();
153  uint32_t size = ReadNumber(type);
154  clang::QualType element_type(BuildType(ast_ctx, type, for_expression));
155  if (!type.NextIf(_C_ARY_E))
156  return clang::QualType();
157  CompilerType array_type(ast_ctx.CreateArrayType(
158  CompilerType(&ast_ctx, element_type.getAsOpaquePtr()), size, false));
159  return ClangUtil::GetQualType(array_type);
160 }
161 
162 // the runtime can emit these in the form of @"SomeType", giving more specifics
163 // this would be interesting for expression parser interop, but since we
164 // actually try to avoid exposing the ivar info to the expression evaluator,
165 // consume but ignore the type info and always return an 'id'; if anything,
166 // dynamic typing will resolve things for us anyway
168  TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression) {
169  if (!type.NextIf(_C_ID))
170  return clang::QualType();
171 
172  clang::ASTContext &ast_ctx = clang_ast_ctx.getASTContext();
173 
174  std::string name;
175 
176  if (type.NextIf('"')) {
177  // We have to be careful here. We're used to seeing
178  // @"NSString"
179  // but in records it is possible that the string following an @ is the name
180  // of the next field and @ means "id". This is the case if anything
181  // unquoted except for "}", the end of the type, or another name follows
182  // the quoted string.
183  //
184  // E.g.
185  // - @"NSString"@ means "id, followed by a field named NSString of type id"
186  // - @"NSString"} means "a pointer to NSString and the end of the struct" -
187  // @"NSString""nextField" means "a pointer to NSString and a field named
188  // nextField" - @"NSString" followed by the end of the string means "a
189  // pointer to NSString"
190  //
191  // As a result, the rule is: If we see @ followed by a quoted string, we
192  // peek. - If we see }, ), ], the end of the string, or a quote ("), the
193  // quoted string is a class name. - If we see anything else, the quoted
194  // string is a field name and we push it back onto type.
195 
196  name = ReadQuotedString(type);
197 
198  if (type.HasAtLeast(1)) {
199  switch (type.Peek()) {
200  default:
201  // roll back
202  type.PutBack(name.length() +
203  2); // undo our consumption of the string and of the quotes
204  name.clear();
205  break;
206  case _C_STRUCT_E:
207  case _C_UNION_E:
208  case _C_ARY_E:
209  case '"':
210  // the quoted string is a class name – see the rule
211  break;
212  }
213  } else {
214  // the quoted string is a class name – see the rule
215  }
216  }
217 
218  if (for_expression && !name.empty()) {
219  size_t less_than_pos = name.find('<');
220 
221  if (less_than_pos != std::string::npos) {
222  if (less_than_pos == 0)
223  return ast_ctx.getObjCIdType();
224  else
225  name.erase(less_than_pos);
226  }
227 
228  DeclVendor *decl_vendor = m_runtime.GetDeclVendor();
229  if (!decl_vendor)
230  return clang::QualType();
231 
232  auto types = decl_vendor->FindTypes(ConstString(name), /*max_matches*/ 1);
233 
234 // The user can forward-declare something that has no definition. The runtime
235 // doesn't prohibit this at all. This is a rare and very weird case. We keep
236 // this assert in debug builds so we catch other weird cases.
237 #ifdef LLDB_CONFIGURATION_DEBUG
238  assert(!types.empty());
239 #else
240  if (types.empty())
241  return ast_ctx.getObjCIdType();
242 #endif
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 
251 clang::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 }
lldb_private::AppleObjCTypeEncodingParser::StructElement::StructElement
StructElement()
Definition: AppleObjCTypeEncodingParser.cpp:61
UNUSED_IF_ASSERT_DISABLED
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:137
lldb_private::DeclVendor::FindTypes
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
lldb_private::TypeSystemClang::getASTContext
clang::ASTContext & getASTContext()
Returns the clang::ASTContext instance managed by this TypeSystemClang.
Definition: TypeSystemClang.cpp:692
_C_BFLD
#define _C_BFLD
Definition: ObjCConstants.h:28
lldb_private::StringLexer::Next
Character Next()
Definition: StringLexer.cpp:58
lldb_private::ObjCLanguageRuntime
Definition: ObjCLanguageRuntime.h:34
_C_BOOL
#define _C_BOOL
Definition: ObjCConstants.h:29
_C_ID
#define _C_ID
Definition: ObjCConstants.h:13
lldb_private::AppleObjCTypeEncodingParser::StructElement
Definition: AppleObjCTypeEncodingParser.h:29
_C_USHT
#define _C_USHT
Definition: ObjCConstants.h:19
lldb_private::ObjCLanguageRuntime::EncodingToType::m_scratch_ast_ctx_up
std::unique_ptr< TypeSystemClang > m_scratch_ast_ctx_up
Definition: ObjCLanguageRuntime.h:160
lldb_private::AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser
AppleObjCTypeEncodingParser(ObjCLanguageRuntime &runtime)
Definition: AppleObjCTypeEncodingParser.cpp:24
_C_STRUCT_B
#define _C_STRUCT_B
Definition: ObjCConstants.h:39
lldb_private::Process::GetTarget
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1214
lldb_private::AppleObjCTypeEncodingParser::BuildStruct
clang::QualType BuildStruct(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
Definition: AppleObjCTypeEncodingParser.cpp:79
_C_CONST
#define _C_CONST
Definition: ObjCConstants.h:42
lldb_private::AppleObjCTypeEncodingParser::ReadNumber
uint32_t ReadNumber(StringLexer &type)
Definition: AppleObjCTypeEncodingParser.cpp:50
lldb_private::AppleObjCTypeEncodingParser::BuildArray
clang::QualType BuildArray(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
Definition: AppleObjCTypeEncodingParser.cpp:149
_C_UNDEF
#define _C_UNDEF
Definition: ObjCConstants.h:31
lldb_private::ArchSpec::GetTriple
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:444
lldb_private::TypeSystemClang::CreateArrayType
CompilerType CreateArrayType(const CompilerType &element_type, size_t element_count, bool is_vector)
Definition: TypeSystemClang.cpp:2237
lldb_private::StreamString::GetString
llvm::StringRef GetString() const
Definition: StreamString.cpp:51
Process.h
ClangUtil.h
_C_UINT
#define _C_UINT
Definition: ObjCConstants.h:21
Target.h
lldb_private::StringLexer::PutBack
void PutBack(Size s)
Definition: StringLexer.cpp:68
lldb_private::AppleObjCTypeEncodingParser::ReadStructName
std::string ReadStructName(StringLexer &type)
Definition: AppleObjCTypeEncodingParser.cpp:33
_C_CLASS
#define _C_CLASS
Definition: ObjCConstants.h:14
lldb_private::ClangUtil::GetQualType
static clang::QualType GetQualType(const CompilerType &ct)
Definition: ClangUtil.cpp:36
lldb_private::AppleObjCTypeEncodingParser::BuildType
clang::QualType BuildType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size=nullptr)
Definition: AppleObjCTypeEncodingParser.cpp:252
_C_ARY_E
#define _C_ARY_E
Definition: ObjCConstants.h:36
TypeSystemClang.h
_C_DBL
#define _C_DBL
Definition: ObjCConstants.h:27
lldb_private::TypeSystemClang::AddFieldToRecordType
static clang::FieldDecl * AddFieldToRecordType(const CompilerType &type, llvm::StringRef name, const CompilerType &field_type, lldb::AccessType access, uint32_t bitfield_bit_size)
Definition: TypeSystemClang.cpp:7231
_C_VOID
#define _C_VOID
Definition: ObjCConstants.h:30
lldb_private::AppleObjCTypeEncodingParser::BuildObjCObjectPointerType
clang::QualType BuildObjCObjectPointerType(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression)
Definition: AppleObjCTypeEncodingParser.cpp:167
lldb_private::StringLexer::HasAtLeast
bool HasAtLeast(Size s)
Definition: StringLexer.cpp:64
_C_LNG_LNG
#define _C_LNG_LNG
Definition: ObjCConstants.h:24
lldb_private::ConstString
Definition: ConstString.h:40
_C_LNG
#define _C_LNG
Definition: ObjCConstants.h:22
lldb_private::StreamString
Definition: StreamString.h:23
lldb_private::StringLexer::NextIf
bool NextIf(Character c)
Definition: StringLexer.cpp:21
_C_UNION_B
#define _C_UNION_B
Definition: ObjCConstants.h:37
lldb_private::AppleObjCTypeEncodingParser::RealizeType
CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, bool for_expression) override
Definition: AppleObjCTypeEncodingParser.cpp:358
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:39
lldb_private::LanguageRuntime::GetDeclVendor
virtual DeclVendor * GetDeclVendor()
Definition: LanguageRuntime.h:129
CompilerType.h
lldb_private::AppleObjCTypeEncodingParser::m_runtime
ObjCLanguageRuntime & m_runtime
Definition: AppleObjCTypeEncodingParser.h:68
StringLexer.h
lldb_private::TypeSystemClang::GetType
CompilerType GetType(clang::QualType qt)
Creates a CompilerType form the given QualType with the current TypeSystemClang instance as the Compi...
Definition: TypeSystemClang.h:233
_C_UCHR
#define _C_UCHR
Definition: ObjCConstants.h:17
lldb::eAccessPublic
@ eAccessPublic
Definition: lldb-enumerations.h:509
lldb_private::Target::GetArchitecture
const ArchSpec & GetArchitecture() const
Definition: Target.h:970
lldb_private::StringLexer::Character
std::string::value_type Character
Definition: StringLexer.h:23
_C_ARY_B
#define _C_ARY_B
Definition: ObjCConstants.h:35
lldb_private::OptionalClangModuleID
A Clang module ID.
Definition: TypeSystemClang.h:57
uint32_t
lldb_private::DeclVendor
Definition: DeclVendor.h:20
AppleObjCTypeEncodingParser.h
lldb_private::Runtime::GetProcess
Process * GetProcess()
Definition: Runtime.h:22
_C_STRUCT_E
#define _C_STRUCT_E
Definition: ObjCConstants.h:40
lldb_private::AppleObjCTypeEncodingParser::BuildAggregate
clang::QualType BuildAggregate(TypeSystemClang &clang_ast_ctx, StringLexer &type, bool for_expression, char opener, char closer, uint32_t kind)
Definition: AppleObjCTypeEncodingParser.cpp:91
lldb_private::AppleObjCTypeEncodingParser::StructElement::type
clang::QualType type
Definition: AppleObjCTypeEncodingParser.h:31
lldb_private::TypeSystemClang::CreateRecordType
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)
Definition: TypeSystemClang.cpp:1282
clang
Definition: ASTResultSynthesizer.h:15
lldb_private::CompilerType
Generic representation of a type in a programming language.
Definition: CompilerType.h:33
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb_private::AppleObjCTypeEncodingParser::StructElement::name
std::string name
Definition: AppleObjCTypeEncodingParser.h:30
_C_SHT
#define _C_SHT
Definition: ObjCConstants.h:18
lldb_private::TypeSystemClang::StartTagDeclarationDefinition
static bool StartTagDeclarationDefinition(const CompilerType &type)
Definition: TypeSystemClang.cpp:8165
lldb::eLanguageTypeC
@ eLanguageTypeC
Non-standardized C, such as K&R.
Definition: lldb-enumerations.h:439
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::TypeSystemClang
A TypeSystem implementation based on Clang.
Definition: TypeSystemClang.h:106
_C_SEL
#define _C_SEL
Definition: ObjCConstants.h:15
lldb_private::AppleObjCTypeEncodingParser::ReadQuotedString
std::string ReadQuotedString(StringLexer &type)
Definition: AppleObjCTypeEncodingParser.cpp:40
lldb_private::AppleObjCTypeEncodingParser::BuildUnion
clang::QualType BuildUnion(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
Definition: AppleObjCTypeEncodingParser.cpp:85
_C_ULNG_LNG
#define _C_ULNG_LNG
Definition: ObjCConstants.h:25
lldb_private::AppleObjCTypeEncodingParser::ReadStructElement
StructElement ReadStructElement(TypeSystemClang &ast_ctx, StringLexer &type, bool for_expression)
Definition: AppleObjCTypeEncodingParser.cpp:65
_C_CHARPTR
#define _C_CHARPTR
Definition: ObjCConstants.h:33
_C_CHR
#define _C_CHR
Definition: ObjCConstants.h:16
_C_UNION_E
#define _C_UNION_E
Definition: ObjCConstants.h:38
_C_INT
#define _C_INT
Definition: ObjCConstants.h:20
_C_FLT
#define _C_FLT
Definition: ObjCConstants.h:26
_C_ULNG
#define _C_ULNG
Definition: ObjCConstants.h:23
lldb_private::TypeSystemClang::CompleteTagDeclarationDefinition
static bool CompleteTagDeclarationDefinition(const CompilerType &type)
Definition: TypeSystemClang.cpp:8190
_C_PTR
#define _C_PTR
Definition: ObjCConstants.h:32
lldb_private::StringLexer::Peek
Character Peek()
Definition: StringLexer.cpp:19
lldb_private::AppleObjCTypeEncodingParser::StructElement::bitfield
uint32_t bitfield
Definition: AppleObjCTypeEncodingParser.h:32
lldb_private::StringLexer
Definition: StringLexer.h:18