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