1 //===-- AppleObjCDeclVendor.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "AppleObjCDeclVendor.h"
11 #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
12 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
13 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/LLDBLog.h"
18 #include "lldb/Utility/Log.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/DeclObjC.h"
22 #include "clang/AST/ExternalASTSource.h"
24 using namespace lldb_private
;
26 class lldb_private::AppleObjCExternalASTSource
27 : public clang::ExternalASTSource
{
29 AppleObjCExternalASTSource(AppleObjCDeclVendor
&decl_vendor
)
30 : m_decl_vendor(decl_vendor
) {}
32 bool FindExternalVisibleDeclsByName(const clang::DeclContext
*decl_ctx
,
33 clang::DeclarationName name
) override
{
36 LLDBLog::Expressions
)); // FIXME - a more appropriate log channel?
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
));
48 const clang::ObjCInterfaceDecl
*interface_decl
=
49 llvm::dyn_cast
<clang::ObjCInterfaceDecl
>(decl_ctx
);
54 clang::ObjCInterfaceDecl
*non_const_interface_decl
=
55 const_cast<clang::ObjCInterfaceDecl
*>(interface_decl
);
57 if (!m_decl_vendor
.FinishDecl(non_const_interface_decl
))
60 clang::DeclContext::lookup_result result
=
61 non_const_interface_decl
->lookup(name
);
63 return (!result
.empty());
66 SetNoExternalVisibleDeclsForName(decl_ctx
, name
);
70 void CompleteType(clang::TagDecl
*tag_decl
) override
{
73 LLDBLog::Expressions
)); // FIXME - a more appropriate log channel?
76 "AppleObjCExternalASTSource::CompleteType on "
77 "(ASTContext*)%p Completing (TagDecl*)%p named %s",
78 static_cast<void *>(&tag_decl
->getASTContext()),
79 static_cast<void *>(tag_decl
), tag_decl
->getName().str().c_str());
81 LLDB_LOG(log
, " AOEAS::CT Before:\n{1}", ClangUtil::DumpDecl(tag_decl
));
83 LLDB_LOG(log
, " AOEAS::CT After:{1}", ClangUtil::DumpDecl(tag_decl
));
86 void CompleteType(clang::ObjCInterfaceDecl
*interface_decl
) override
{
89 LLDBLog::Expressions
)); // FIXME - a more appropriate log channel?
93 "AppleObjCExternalASTSource::CompleteType on "
94 "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
95 static_cast<void *>(&interface_decl
->getASTContext()),
96 static_cast<void *>(interface_decl
),
97 interface_decl
->getName().str().c_str());
99 LLDB_LOGF(log
, " AOEAS::CT Before:");
100 LLDB_LOG(log
, " [CT] {0}", ClangUtil::DumpDecl(interface_decl
));
103 m_decl_vendor
.FinishDecl(interface_decl
);
106 LLDB_LOGF(log
, " [CT] After:");
107 LLDB_LOG(log
, " [CT] {0}", ClangUtil::DumpDecl(interface_decl
));
111 bool layoutRecordType(
112 const clang::RecordDecl
*Record
, uint64_t &Size
, uint64_t &Alignment
,
113 llvm::DenseMap
<const clang::FieldDecl
*, uint64_t> &FieldOffsets
,
114 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
116 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
>
117 &VirtualBaseOffsets
) override
{
121 void StartTranslationUnit(clang::ASTConsumer
*Consumer
) override
{
122 clang::TranslationUnitDecl
*translation_unit_decl
=
123 m_decl_vendor
.m_ast_ctx
->getASTContext().getTranslationUnitDecl();
124 translation_unit_decl
->setHasExternalVisibleStorage();
125 translation_unit_decl
->setHasExternalLexicalStorage();
129 AppleObjCDeclVendor
&m_decl_vendor
;
132 AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime
&runtime
)
133 : ClangDeclVendor(eAppleObjCDeclVendor
), m_runtime(runtime
),
134 m_type_realizer_sp(m_runtime
.GetEncodingToType()) {
135 m_ast_ctx
= std::make_shared
<TypeSystemClang
>(
136 "AppleObjCDeclVendor AST",
137 runtime
.GetProcess()->GetTarget().GetArchitecture().GetTriple());
138 m_external_source
= new AppleObjCExternalASTSource(*this);
139 llvm::IntrusiveRefCntPtr
<clang::ExternalASTSource
> external_source_owning_ptr(
141 m_ast_ctx
->getASTContext().setExternalSource(external_source_owning_ptr
);
144 clang::ObjCInterfaceDecl
*
145 AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa
) {
146 ISAToInterfaceMap::const_iterator iter
= m_isa_to_interface
.find(isa
);
148 if (iter
!= m_isa_to_interface
.end())
151 clang::ASTContext
&ast_ctx
= m_ast_ctx
->getASTContext();
153 ObjCLanguageRuntime::ClassDescriptorSP descriptor
=
154 m_runtime
.GetClassDescriptorFromISA(isa
);
159 ConstString
name(descriptor
->GetClassName());
161 clang::IdentifierInfo
&identifier_info
=
162 ast_ctx
.Idents
.get(name
.GetStringRef());
164 clang::ObjCInterfaceDecl
*new_iface_decl
= clang::ObjCInterfaceDecl::Create(
165 ast_ctx
, ast_ctx
.getTranslationUnitDecl(), clang::SourceLocation(),
166 &identifier_info
, nullptr, nullptr);
168 ClangASTMetadata meta_data
;
169 meta_data
.SetISAPtr(isa
);
170 m_ast_ctx
->SetMetadata(new_iface_decl
, meta_data
);
172 new_iface_decl
->setHasExternalVisibleStorage();
173 new_iface_decl
->setHasExternalLexicalStorage();
175 ast_ctx
.getTranslationUnitDecl()->addDecl(new_iface_decl
);
177 m_isa_to_interface
[isa
] = new_iface_decl
;
179 return new_iface_decl
;
182 class ObjCRuntimeMethodType
{
184 ObjCRuntimeMethodType(const char *types
) {
185 const char *cursor
= types
;
186 enum ParserState
{ Start
= 0, InType
, InPos
} state
= Start
;
187 const char *type
= nullptr;
190 uint32_t stepsLeft
= 256;
193 if (--stepsLeft
== 0) {
240 m_type_vector
.push_back(std::string(type
, (cursor
- type
)));
298 clang::ObjCMethodDecl
*
299 BuildMethod(TypeSystemClang
&clang_ast_ctxt
,
300 clang::ObjCInterfaceDecl
*interface_decl
, const char *name
,
302 ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp
) {
303 if (!m_is_valid
|| m_type_vector
.size() < 3)
306 clang::ASTContext
&ast_ctx(interface_decl
->getASTContext());
308 const bool isInstance
= instance
;
309 const bool isVariadic
= false;
310 const bool isPropertyAccessor
= false;
311 const bool isSynthesizedAccessorStub
= false;
312 const bool isImplicitlyDeclared
= true;
313 const bool isDefined
= false;
314 const clang::ObjCImplementationControl impControl
=
315 clang::ObjCImplementationControl::None
;
316 const bool HasRelatedResultType
= false;
317 const bool for_expression
= true;
319 std::vector
<const clang::IdentifierInfo
*> selector_components
;
321 const char *name_cursor
= name
;
322 bool is_zero_argument
= true;
324 while (*name_cursor
!= '\0') {
325 const char *colon_loc
= strchr(name_cursor
, ':');
327 selector_components
.push_back(
328 &ast_ctx
.Idents
.get(llvm::StringRef(name_cursor
)));
331 is_zero_argument
= false;
332 selector_components
.push_back(&ast_ctx
.Idents
.get(
333 llvm::StringRef(name_cursor
, colon_loc
- name_cursor
)));
334 name_cursor
= colon_loc
+ 1;
338 const clang::IdentifierInfo
**identifier_infos
= selector_components
.data();
339 if (!identifier_infos
) {
343 clang::Selector sel
= ast_ctx
.Selectors
.getSelector(
344 is_zero_argument
? 0 : selector_components
.size(),
347 clang::QualType ret_type
=
348 ClangUtil::GetQualType(type_realizer_sp
->RealizeType(
349 clang_ast_ctxt
, m_type_vector
[0].c_str(), for_expression
));
351 if (ret_type
.isNull())
354 clang::ObjCMethodDecl
*ret
= clang::ObjCMethodDecl::Create(
355 ast_ctx
, clang::SourceLocation(), clang::SourceLocation(), sel
,
356 ret_type
, nullptr, interface_decl
, isInstance
, isVariadic
,
357 isPropertyAccessor
, isSynthesizedAccessorStub
, isImplicitlyDeclared
,
358 isDefined
, impControl
, HasRelatedResultType
);
360 std::vector
<clang::ParmVarDecl
*> parm_vars
;
362 for (size_t ai
= 3, ae
= m_type_vector
.size(); ai
!= ae
; ++ai
) {
363 const bool for_expression
= true;
364 clang::QualType arg_type
=
365 ClangUtil::GetQualType(type_realizer_sp
->RealizeType(
366 clang_ast_ctxt
, m_type_vector
[ai
].c_str(), for_expression
));
368 if (arg_type
.isNull())
369 return nullptr; // well, we just wasted a bunch of time. Wish we could
370 // delete the stuff we'd just made!
372 parm_vars
.push_back(clang::ParmVarDecl::Create(
373 ast_ctx
, ret
, clang::SourceLocation(), clang::SourceLocation(),
374 nullptr, arg_type
, nullptr, clang::SC_None
, nullptr));
377 ret
->setMethodParams(ast_ctx
,
378 llvm::ArrayRef
<clang::ParmVarDecl
*>(parm_vars
),
379 llvm::ArrayRef
<clang::SourceLocation
>());
384 explicit operator bool() { return m_is_valid
; }
386 size_t GetNumTypes() { return m_type_vector
.size(); }
388 const char *GetTypeAtIndex(size_t idx
) { return m_type_vector
[idx
].c_str(); }
391 typedef std::vector
<std::string
> TypeVector
;
393 TypeVector m_type_vector
;
394 bool m_is_valid
= false;
397 bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl
*interface_decl
) {
399 GetLog(LLDBLog::Expressions
)); // FIXME - a more appropriate log channel?
401 ObjCLanguageRuntime::ObjCISA objc_isa
= 0;
402 if (std::optional
<ClangASTMetadata
> metadata
=
403 m_ast_ctx
->GetMetadata(interface_decl
))
404 objc_isa
= metadata
->GetISAPtr();
409 if (!interface_decl
->hasExternalVisibleStorage())
412 interface_decl
->startDefinition();
414 interface_decl
->setHasExternalVisibleStorage(false);
415 interface_decl
->setHasExternalLexicalStorage(false);
417 ObjCLanguageRuntime::ClassDescriptorSP descriptor
=
418 m_runtime
.GetClassDescriptorFromISA(objc_isa
);
423 auto superclass_func
= [interface_decl
,
424 this](ObjCLanguageRuntime::ObjCISA isa
) {
425 clang::ObjCInterfaceDecl
*superclass_decl
= GetDeclForISA(isa
);
427 if (!superclass_decl
)
430 FinishDecl(superclass_decl
);
431 clang::ASTContext
&context
= m_ast_ctx
->getASTContext();
432 interface_decl
->setSuperClass(context
.getTrivialTypeSourceInfo(
433 context
.getObjCInterfaceType(superclass_decl
)));
436 auto instance_method_func
=
437 [log
, interface_decl
, this](const char *name
, const char *types
) -> bool {
439 return false; // skip this one
441 ObjCRuntimeMethodType
method_type(types
);
443 clang::ObjCMethodDecl
*method_decl
= method_type
.BuildMethod(
444 *m_ast_ctx
, interface_decl
, name
, true, m_type_realizer_sp
);
446 LLDB_LOGF(log
, "[ AOTV::FD] Instance method [%s] [%s]", name
, types
);
449 interface_decl
->addDecl(method_decl
);
454 auto class_method_func
= [log
, interface_decl
,
455 this](const char *name
, const char *types
) -> bool {
457 return false; // skip this one
459 ObjCRuntimeMethodType
method_type(types
);
461 clang::ObjCMethodDecl
*method_decl
= method_type
.BuildMethod(
462 *m_ast_ctx
, interface_decl
, name
, false, m_type_realizer_sp
);
464 LLDB_LOGF(log
, "[ AOTV::FD] Class method [%s] [%s]", name
, types
);
467 interface_decl
->addDecl(method_decl
);
472 auto ivar_func
= [log
, interface_decl
,
473 this](const char *name
, const char *type
,
474 lldb::addr_t offset_ptr
, uint64_t size
) -> bool {
478 const bool for_expression
= false;
481 "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64
,
482 name
, type
, offset_ptr
);
484 CompilerType ivar_type
= m_runtime
.GetEncodingToType()->RealizeType(
485 *m_ast_ctx
, type
, for_expression
);
487 if (ivar_type
.IsValid()) {
488 clang::TypeSourceInfo
*const type_source_info
= nullptr;
489 const bool is_synthesized
= false;
490 clang::ObjCIvarDecl
*ivar_decl
= clang::ObjCIvarDecl::Create(
491 m_ast_ctx
->getASTContext(), interface_decl
, clang::SourceLocation(),
492 clang::SourceLocation(), &m_ast_ctx
->getASTContext().Idents
.get(name
),
493 ClangUtil::GetQualType(ivar_type
),
494 type_source_info
, // TypeSourceInfo *
495 clang::ObjCIvarDecl::Public
, nullptr, is_synthesized
);
498 interface_decl
->addDecl(ivar_decl
);
506 "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "
508 descriptor
->GetClassName().AsCString());
510 if (!descriptor
->Describe(superclass_func
, instance_method_func
,
511 class_method_func
, ivar_func
))
517 "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");
519 LLDB_LOG(log
, " [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl
));
525 uint32_t AppleObjCDeclVendor::FindDecls(ConstString name
, bool append
,
526 uint32_t max_matches
,
527 std::vector
<CompilerDecl
> &decls
) {
530 GetLog(LLDBLog::Expressions
)); // FIXME - a more appropriate log channel?
532 LLDB_LOGF(log
, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )",
533 (const char *)name
.AsCString(), append
? "true" : "false",
542 // See if the type is already in our ASTContext.
544 clang::ASTContext
&ast_ctx
= m_ast_ctx
->getASTContext();
546 clang::IdentifierInfo
&identifier_info
=
547 ast_ctx
.Idents
.get(name
.GetStringRef());
548 clang::DeclarationName decl_name
=
549 ast_ctx
.DeclarationNames
.getIdentifier(&identifier_info
);
551 clang::DeclContext::lookup_result lookup_result
=
552 ast_ctx
.getTranslationUnitDecl()->lookup(decl_name
);
554 if (!lookup_result
.empty()) {
555 if (clang::ObjCInterfaceDecl
*result_iface_decl
=
556 llvm::dyn_cast
<clang::ObjCInterfaceDecl
>(*lookup_result
.begin())) {
558 clang::QualType result_iface_type
=
559 ast_ctx
.getObjCInterfaceType(result_iface_decl
);
561 uint64_t isa_value
= LLDB_INVALID_ADDRESS
;
562 if (std::optional
<ClangASTMetadata
> metadata
=
563 m_ast_ctx
->GetMetadata(result_iface_decl
))
564 isa_value
= metadata
->GetISAPtr();
567 "AOCTV::FT Found %s (isa 0x%" PRIx64
") in the ASTContext",
568 result_iface_type
.getAsString().data(), isa_value
);
571 decls
.push_back(m_ast_ctx
->GetCompilerDecl(result_iface_decl
));
575 LLDB_LOGF(log
, "AOCTV::FT There's something in the ASTContext, but "
576 "it's not something we know about");
580 LLDB_LOGF(log
, "AOCTV::FT Couldn't find %s in the ASTContext",
584 // It's not. If it exists, we have to put it into our ASTContext.
586 ObjCLanguageRuntime::ObjCISA isa
= m_runtime
.GetISA(name
);
589 LLDB_LOGF(log
, "AOCTV::FT Couldn't find the isa");
594 clang::ObjCInterfaceDecl
*iface_decl
= GetDeclForISA(isa
);
598 "AOCTV::FT Couldn't get the Objective-C interface for "
606 clang::QualType new_iface_type
= ast_ctx
.getObjCInterfaceType(iface_decl
);
608 LLDB_LOG(log
, "AOCTV::FT Created {0} (isa 0x{1:x})",
609 new_iface_type
.getAsString(), (uint64_t)isa
);
612 decls
.push_back(m_ast_ctx
->GetCompilerDecl(iface_decl
));