LLDB mainline
AppleObjCDeclVendor.cpp
Go to the documentation of this file.
1//===-- AppleObjCDeclVendor.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/Core/Module.h"
15#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
18#include "lldb/Utility/Log.h"
19
20#include "clang/AST/ASTContext.h"
21#include "clang/AST/DeclObjC.h"
22#include "clang/AST/ExternalASTSource.h"
23
24using namespace lldb_private;
25
27 : public clang::ExternalASTSource {
28public:
31
33 const clang::DeclContext *decl_ctx, clang::DeclarationName name,
34 const clang::DeclContext *original_dc) override {
35
36 Log *log(GetLog(
37 LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
38
39 LLDB_LOGF(log,
40 "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName"
41 " on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
42 static_cast<void *>(&decl_ctx->getParentASTContext()),
43 name.getAsString().c_str(), decl_ctx->getDeclKindName(),
44 static_cast<const void *>(decl_ctx));
45
46 do {
47 const clang::ObjCInterfaceDecl *interface_decl =
48 llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
49
50 if (!interface_decl)
51 break;
52
53 clang::ObjCInterfaceDecl *non_const_interface_decl =
54 const_cast<clang::ObjCInterfaceDecl *>(interface_decl);
55
56 if (!m_decl_vendor.FinishDecl(non_const_interface_decl))
57 break;
58
59 clang::DeclContext::lookup_result result =
60 non_const_interface_decl->lookup(name);
61
62 return (!result.empty());
63 } while (false);
64
65 SetNoExternalVisibleDeclsForName(decl_ctx, name);
66 return false;
67 }
68
69 void CompleteType(clang::TagDecl *tag_decl) override {
70
71 Log *log(GetLog(
72 LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
73
74 LLDB_LOGF(log,
75 "AppleObjCExternalASTSource::CompleteType on "
76 "(ASTContext*)%p Completing (TagDecl*)%p named %s",
77 static_cast<void *>(&tag_decl->getASTContext()),
78 static_cast<void *>(tag_decl), tag_decl->getName().str().c_str());
79
80 LLDB_LOG(log, " AOEAS::CT Before:\n{0}", ClangUtil::DumpDecl(tag_decl));
81
82 LLDB_LOG(log, " AOEAS::CT After:{0}", ClangUtil::DumpDecl(tag_decl));
83 }
84
85 void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override {
86
87 Log *log(GetLog(
88 LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
89
90 LLDB_LOGF(log,
91 "AppleObjCExternalASTSource::CompleteType on "
92 "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
93 static_cast<void *>(&interface_decl->getASTContext()),
94 static_cast<void *>(interface_decl),
95 interface_decl->getName().str().c_str());
96
97 LLDB_LOGF(log, " AOEAS::CT Before:");
98 LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
99
100 m_decl_vendor.FinishDecl(interface_decl);
101
102 LLDB_LOGF(log, " [CT] After:");
103 LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
104 }
105
107 const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
108 llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
109 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
110 &BaseOffsets,
111 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
112 &VirtualBaseOffsets) override {
113 return false;
114 }
115
116 void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
117 clang::TranslationUnitDecl *translation_unit_decl =
118 m_decl_vendor.m_ast_ctx->getASTContext().getTranslationUnitDecl();
119 translation_unit_decl->setHasExternalVisibleStorage();
120 translation_unit_decl->setHasExternalLexicalStorage();
121 }
122
123private:
125};
126
129 m_type_realizer_sp(m_runtime.GetEncodingToType()) {
130 m_ast_ctx = std::make_shared<TypeSystemClang>(
131 "AppleObjCDeclVendor AST",
133 auto external_source_owning_ptr =
134 llvm::makeIntrusiveRefCnt<AppleObjCExternalASTSource>(*this);
135 m_external_source = external_source_owning_ptr.get();
136 m_ast_ctx->getASTContext().setExternalSource(external_source_owning_ptr);
137}
138
139clang::ObjCInterfaceDecl *
141 ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
142
143 if (iter != m_isa_to_interface.end())
144 return iter->second;
145
146 clang::ASTContext &ast_ctx = m_ast_ctx->getASTContext();
147
149 m_runtime.GetClassDescriptorFromISA(isa);
150
151 if (!descriptor)
152 return nullptr;
153
154 ConstString name(descriptor->GetClassName());
155
156 clang::IdentifierInfo &identifier_info =
157 ast_ctx.Idents.get(name.GetStringRef());
158
159 clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(
160 ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(),
161 &identifier_info, nullptr, nullptr);
162
163 ClangASTMetadata meta_data;
164 meta_data.SetISAPtr(isa);
165 m_ast_ctx->SetMetadata(new_iface_decl, meta_data);
166
167 new_iface_decl->setHasExternalVisibleStorage();
168 new_iface_decl->setHasExternalLexicalStorage();
169
170 ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);
171
172 m_isa_to_interface[isa] = new_iface_decl;
173
174 return new_iface_decl;
175}
176
178public:
179 ObjCRuntimeMethodType(const char *types) {
180 const char *cursor = types;
181 enum ParserState { Start = 0, InType, InPos } state = Start;
182 const char *type = nullptr;
183 int brace_depth = 0;
184
185 uint32_t stepsLeft = 256;
186
187 while (true) {
188 if (--stepsLeft == 0) {
189 m_is_valid = false;
190 return;
191 }
192
193 switch (state) {
194 case Start: {
195 switch (*cursor) {
196 default:
197 state = InType;
198 type = cursor;
199 break;
200 case '\0':
201 m_is_valid = true;
202 return;
203 case '0':
204 case '1':
205 case '2':
206 case '3':
207 case '4':
208 case '5':
209 case '6':
210 case '7':
211 case '8':
212 case '9':
213 m_is_valid = false;
214 return;
215 }
216 } break;
217 case InType: {
218 switch (*cursor) {
219 default:
220 ++cursor;
221 break;
222 case '0':
223 case '1':
224 case '2':
225 case '3':
226 case '4':
227 case '5':
228 case '6':
229 case '7':
230 case '8':
231 case '9':
232 if (!brace_depth) {
233 state = InPos;
234 if (type) {
235 m_type_vector.push_back(std::string(type, (cursor - type)));
236 } else {
237 m_is_valid = false;
238 return;
239 }
240 type = nullptr;
241 } else {
242 ++cursor;
243 }
244 break;
245 case '[':
246 case '{':
247 case '(':
248 ++brace_depth;
249 ++cursor;
250 break;
251 case ']':
252 case '}':
253 case ')':
254 if (!brace_depth) {
255 m_is_valid = false;
256 return;
257 }
258 --brace_depth;
259 ++cursor;
260 break;
261 case '\0':
262 m_is_valid = false;
263 return;
264 }
265 } break;
266 case InPos: {
267 switch (*cursor) {
268 default:
269 state = InType;
270 type = cursor;
271 break;
272 case '0':
273 case '1':
274 case '2':
275 case '3':
276 case '4':
277 case '5':
278 case '6':
279 case '7':
280 case '8':
281 case '9':
282 ++cursor;
283 break;
284 case '\0':
285 m_is_valid = true;
286 return;
287 }
288 } break;
289 }
290 }
291 }
292
293 clang::ObjCMethodDecl *
295 clang::ObjCInterfaceDecl *interface_decl, const char *name,
296 bool instance,
297 ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) {
298 if (!m_is_valid || m_type_vector.size() < 3)
299 return nullptr;
300
301 clang::ASTContext &ast_ctx(interface_decl->getASTContext());
302
303 const bool isInstance = instance;
304 const bool isVariadic = false;
305 const bool isPropertyAccessor = false;
306 const bool isSynthesizedAccessorStub = false;
307 const bool isImplicitlyDeclared = true;
308 const bool isDefined = false;
309 const clang::ObjCImplementationControl impControl =
310 clang::ObjCImplementationControl::None;
311 const bool HasRelatedResultType = false;
312 const bool for_expression = true;
313
314 std::vector<const clang::IdentifierInfo *> selector_components;
315
316 const char *name_cursor = name;
317 bool is_zero_argument = true;
318
319 while (*name_cursor != '\0') {
320 const char *colon_loc = strchr(name_cursor, ':');
321 if (!colon_loc) {
322 selector_components.push_back(
323 &ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
324 break;
325 } else {
326 is_zero_argument = false;
327 selector_components.push_back(&ast_ctx.Idents.get(
328 llvm::StringRef(name_cursor, colon_loc - name_cursor)));
329 name_cursor = colon_loc + 1;
330 }
331 }
332
333 const clang::IdentifierInfo **identifier_infos = selector_components.data();
334 if (!identifier_infos) {
335 return nullptr;
336 }
337
338 clang::Selector sel = ast_ctx.Selectors.getSelector(
339 is_zero_argument ? 0 : selector_components.size(),
340 identifier_infos);
341
342 clang::QualType ret_type =
343 ClangUtil::GetQualType(type_realizer_sp->RealizeType(
344 clang_ast_ctxt, m_type_vector[0].c_str(), for_expression));
345
346 if (ret_type.isNull())
347 return nullptr;
348
349 clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(
350 ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel,
351 ret_type, nullptr, interface_decl, isInstance, isVariadic,
352 isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
353 isDefined, impControl, HasRelatedResultType);
354
355 std::vector<clang::ParmVarDecl *> parm_vars;
356
357 for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) {
358 const bool for_expression = true;
359 clang::QualType arg_type =
360 ClangUtil::GetQualType(type_realizer_sp->RealizeType(
361 clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression));
362
363 if (arg_type.isNull())
364 return nullptr; // well, we just wasted a bunch of time. Wish we could
365 // delete the stuff we'd just made!
366
367 parm_vars.push_back(clang::ParmVarDecl::Create(
368 ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(),
369 nullptr, arg_type, nullptr, clang::SC_None, nullptr));
370 }
371
372 ret->setMethodParams(ast_ctx,
373 llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),
374 llvm::ArrayRef<clang::SourceLocation>());
375
376 return ret;
377 }
378
379 explicit operator bool() { return m_is_valid; }
380
381 size_t GetNumTypes() { return m_type_vector.size(); }
382
383 const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); }
384
385private:
386 typedef std::vector<std::string> TypeVector;
387
389 bool m_is_valid = false;
390};
391
392bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
393 Log *log(
394 GetLog(LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
395
396 ObjCLanguageRuntime::ObjCISA objc_isa = 0;
397 if (std::optional<ClangASTMetadata> metadata =
398 m_ast_ctx->GetMetadata(interface_decl))
399 objc_isa = metadata->GetISAPtr();
400
401 if (!objc_isa)
402 return false;
403
404 if (!interface_decl->hasExternalVisibleStorage())
405 return true;
406
407 interface_decl->startDefinition();
408
409 interface_decl->setHasExternalVisibleStorage(false);
410 interface_decl->setHasExternalLexicalStorage(false);
411
413 m_runtime.GetClassDescriptorFromISA(objc_isa);
414
415 if (!descriptor)
416 return false;
417
418 auto superclass_func = [interface_decl,
420 clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
421
422 if (!superclass_decl)
423 return;
424
425 FinishDecl(superclass_decl);
426 clang::ASTContext &context = m_ast_ctx->getASTContext();
427 interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(
428 context.getObjCInterfaceType(superclass_decl)));
429 };
430
431 auto instance_method_func =
432 [log, interface_decl, this](const char *name, const char *types) -> bool {
433 if (!name || !types)
434 return false; // skip this one
435
436 ObjCRuntimeMethodType method_type(types);
437
438 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
439 *m_ast_ctx, interface_decl, name, true, m_type_realizer_sp);
440
441 LLDB_LOGF(log, "[ AOTV::FD] Instance method [%s] [%s]", name, types);
442
443 if (method_decl)
444 interface_decl->addDecl(method_decl);
445
446 return false;
447 };
448
449 auto class_method_func = [log, interface_decl,
450 this](const char *name, const char *types) -> bool {
451 if (!name || !types)
452 return false; // skip this one
453
454 ObjCRuntimeMethodType method_type(types);
455
456 clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
457 *m_ast_ctx, interface_decl, name, false, m_type_realizer_sp);
458
459 LLDB_LOGF(log, "[ AOTV::FD] Class method [%s] [%s]", name, types);
460
461 if (method_decl)
462 interface_decl->addDecl(method_decl);
463
464 return false;
465 };
466
467 auto ivar_func = [log, interface_decl,
468 this](const char *name, const char *type,
469 lldb::addr_t offset_ptr, uint64_t size) -> bool {
470 if (!name || !type)
471 return false;
472
473 const bool for_expression = false;
474
475 LLDB_LOGF(log,
476 "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64,
477 name, type, offset_ptr);
478
479 CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(
480 *m_ast_ctx, type, for_expression);
481
482 if (ivar_type.IsValid()) {
483 clang::TypeSourceInfo *const type_source_info = nullptr;
484 const bool is_synthesized = false;
485 clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create(
486 m_ast_ctx->getASTContext(), interface_decl, clang::SourceLocation(),
487 clang::SourceLocation(), &m_ast_ctx->getASTContext().Idents.get(name),
488 ClangUtil::GetQualType(ivar_type),
489 type_source_info, // TypeSourceInfo *
490 clang::ObjCIvarDecl::Public, nullptr, is_synthesized);
491
492 if (ivar_decl) {
493 interface_decl->addDecl(ivar_decl);
494 }
495 }
496
497 return false;
498 };
499
500 LLDB_LOGF(log,
501 "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "
502 "interface for %s",
503 descriptor->GetClassName().AsCString());
504
505 if (!descriptor->Describe(superclass_func, instance_method_func,
506 class_method_func, ivar_func))
507 return false;
508
509 LLDB_LOGF(log,
510 "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");
511
512 LLDB_LOG(log, " [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl));
513
514 return true;
515}
516
518 uint32_t max_matches,
519 std::vector<CompilerDecl> &decls) {
520
521 Log *log(
522 GetLog(LLDBLog::Expressions)); // FIXME - a more appropriate log channel?
523
524 LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )",
525 (const char *)name.AsCString(), append ? "true" : "false",
526 max_matches);
527
528 if (!append)
529 decls.clear();
530
531 // See if the type is already in our ASTContext.
532
533 clang::ASTContext &ast_ctx = m_ast_ctx->getASTContext();
534
535 clang::IdentifierInfo &identifier_info =
536 ast_ctx.Idents.get(name.GetStringRef());
537 clang::DeclarationName decl_name =
538 ast_ctx.DeclarationNames.getIdentifier(&identifier_info);
539
540 clang::DeclContext::lookup_result lookup_result =
541 ast_ctx.getTranslationUnitDecl()->lookup(decl_name);
542
543 if (!lookup_result.empty()) {
544 if (clang::ObjCInterfaceDecl *result_iface_decl =
545 llvm::dyn_cast<clang::ObjCInterfaceDecl>(*lookup_result.begin())) {
546 if (log) {
547 clang::QualType result_iface_type =
548 ast_ctx.getObjCInterfaceType(result_iface_decl);
549
550 uint64_t isa_value = LLDB_INVALID_ADDRESS;
551 if (std::optional<ClangASTMetadata> metadata =
552 m_ast_ctx->GetMetadata(result_iface_decl))
553 isa_value = metadata->GetISAPtr();
554
555 LLDB_LOGF(log,
556 "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext",
557 result_iface_type.getAsString().data(), isa_value);
558 }
559
560 decls.push_back(m_ast_ctx->GetCompilerDecl(result_iface_decl));
561 return 1;
562 }
563
564 LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but "
565 "it's not something we know about");
566 return 0;
567 }
568
569 LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext",
570 name.AsCString());
571
572 // It's not. If it exists, we have to put it into our ASTContext.
573
574 ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
575
576 if (!isa) {
577 LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa");
578
579 return 0;
580 }
581
582 clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
583
584 if (!iface_decl) {
585 LLDB_LOGF(log,
586 "AOCTV::FT Couldn't get the Objective-C interface for "
587 "isa 0x%" PRIx64,
588 (uint64_t)isa);
589
590 return 0;
591 }
592
593 if (log) {
594 clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl);
595
596 LLDB_LOG(log, "AOCTV::FT Created {0} (isa 0x{1:x})",
597 new_iface_type.getAsString(), (uint64_t)isa);
598 }
599
600 decls.push_back(m_ast_ctx->GetCompilerDecl(iface_decl));
601 return 1;
602}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
#define LLDB_LOGF(log,...)
Definition Log.h:383
ObjCRuntimeMethodType(const char *types)
const char * GetTypeAtIndex(size_t idx)
clang::ObjCMethodDecl * BuildMethod(TypeSystemClang &clang_ast_ctxt, clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp)
std::vector< std::string > TypeVector
ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp
uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector< CompilerDecl > &decls) override
Look up the set of Decls that the DeclVendor currently knows about matching a given name.
bool FinishDecl(clang::ObjCInterfaceDecl *decl)
AppleObjCExternalASTSource * m_external_source
std::shared_ptr< TypeSystemClang > m_ast_ctx
AppleObjCDeclVendor(ObjCLanguageRuntime &runtime)
clang::ObjCInterfaceDecl * GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
void CompleteType(clang::TagDecl *tag_decl) override
void StartTranslationUnit(clang::ASTConsumer *Consumer) override
AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName name, const clang::DeclContext *original_dc) override
bool layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap< const clang::FieldDecl *, uint64_t > &FieldOffsets, llvm::DenseMap< const clang::CXXRecordDecl *, clang::CharUnits > &BaseOffsets, llvm::DenseMap< const clang::CXXRecordDecl *, clang::CharUnits > &VirtualBaseOffsets) override
void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:457
void SetISAPtr(uint64_t isa_ptr)
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
DeclVendor(DeclVendorKind kind)
Definition DeclVendor.h:28
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
std::shared_ptr< EncodingToType > EncodingToTypeSP
Target & GetTarget()
Get the target object pointer for this module.
Definition Process.h:1250
Process * GetProcess()
Definition Runtime.h:22
const ArchSpec & GetArchitecture() const
Definition Target.h:1182
A TypeSystem implementation based on Clang.
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
uint64_t addr_t
Definition lldb-types.h:80
static clang::QualType GetQualType(const CompilerType &ct)
Definition ClangUtil.cpp:36
static std::string DumpDecl(const clang::Decl *d)
Returns a textual representation of the given Decl's AST.
Definition ClangUtil.cpp:68