Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -18,6 +18,7 @@ #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -1001,6 +1002,20 @@ importer.CompleteTagDecl(rd); } +/// Recreate a module with its parents in \p to_source and return its id. +static ModuleID RemapModule(ModuleID from_id, + ClangExternalASTSourceCallbacks &from_source, + ClangExternalASTSourceCallbacks &to_source) { + if (!from_id.HasValue()) + return {}; + clang::Module *module = from_source.getModule(*from_id.get()); + ModuleID parent = RemapModule(from_source.GetIDForModule(module->Parent), + from_source, to_source); + TypeSystemClang &to_ts = to_source.GetTypeSystem(); + return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, + module->IsExplicit); +} + void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, clang::Decl *to) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1010,6 +1025,19 @@ if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end()) return clang::ASTImporter::Imported(from, to); + // Transfer module ownership information. + auto *from_source = llvm::dyn_cast_or_null( + getFromContext().getExternalSource()); + // Can also be a ClangASTSourceProxy. + auto *to_source = llvm::dyn_cast_or_null( + getToContext().getExternalSource()); + if (from_source && to_source) { + ModuleID from_id(from->getOwningModuleID()); + ModuleID to_id = RemapModule(from_id, *from_source, *to_source); + TypeSystemClang &to_ts = to_source->GetTypeSystem(); + to_ts.SetOwningModule(to, to_id); + } + lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); if (metadata) Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -14,8 +14,6 @@ namespace lldb_private { -class TypeSystemClang; - class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { /// LLVM RTTI support. static char ID; @@ -51,8 +49,8 @@ llvm::Optional getSourceDescriptor(unsigned ID) override; clang::Module *getModule(unsigned ID) override; - unsigned RegisterModule(clang::Module *module); - unsigned GetIDForModule(clang::Module *module); + ModuleID RegisterModule(clang::Module *module); + ModuleID GetIDForModule(clang::Module *module); /// \} private: TypeSystemClang &m_ast; Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -46,11 +46,11 @@ } } -unsigned ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { +ModuleID ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { m_modules.push_back(module); unsigned id = m_modules.size(); m_ids.insert({module, id}); - return id; + return ModuleID(id); } llvm::Optional @@ -66,6 +66,6 @@ return nullptr; } -unsigned ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { - return m_ids[module]; +ModuleID ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { + return ModuleID(m_ids[module]); } Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -78,6 +78,8 @@ DIEToDeclContextMap; typedef std::multimap DeclContextToDIEMap; + typedef llvm::DenseMap + DIEToModuleMap; typedef llvm::DenseMap DIEToDeclMap; typedef llvm::DenseMap DeclToDIEMap; @@ -87,6 +89,7 @@ DeclToDIEMap m_decl_to_die; DIEToDeclContextMap m_die_to_decl_ctx; DeclContextToDIEMap m_decl_ctx_to_die; + DIEToModuleMap m_die_to_module; std::unique_ptr m_clang_ast_importer_up; /// @} @@ -140,6 +143,7 @@ clang::DeclContext *GetClangDeclContextContainingDIE(const DWARFDIE &die, DWARFDIE *decl_ctx_die); + lldb_private::ModuleID GetOwningModuleID(const DWARFDIE &die); bool CopyUniqueClassMethodTypes(const DWARFDIE &src_class_die, const DWARFDIE &dst_class_die, Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -210,14 +210,15 @@ TypeSP type_sp(new Type( die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningModuleID(die)))); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type); - if (tag_decl) + if (tag_decl) { LinkDeclContextToDIE(tag_decl, die); - else { + } else { clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); @@ -706,7 +707,7 @@ type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state); + clang_type, resolve_state, TypePayloadClang(GetOwningModuleID(die))); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; @@ -788,7 +789,8 @@ clang_type = m_ast.CreateEnumerationType( attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), - ModuleID(), attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); + GetOwningModuleID(die), attrs.decl, enumerator_clang_type, + attrs.is_scoped_enum); } else { enumerator_clang_type = m_ast.GetEnumerationIntegerType(clang_type); } @@ -798,7 +800,8 @@ type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); + clang_type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningModuleID(die))); if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { if (die.HasChildren()) { @@ -1171,7 +1174,8 @@ function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - ModuleID(), attrs.name.GetCString(), clang_type, attrs.storage, + GetOwningModuleID(die), + attrs.name.GetCString(), clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { @@ -1180,12 +1184,13 @@ template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - ModuleID(), attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + GetOwningModuleID(die), attrs.name.GetCString(), clang_type, + attrs.storage, attrs.is_inline); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, ModuleID(), template_function_decl, - attrs.name.GetCString(), template_param_infos); + containing_decl_ctx, GetOwningModuleID(die), + template_function_decl, attrs.name.GetCString(), + template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( function_decl, func_template_decl, template_param_infos); } @@ -1583,7 +1588,7 @@ if (ParseTemplateParameterInfos(die, template_param_infos)) { clang::ClassTemplateDecl *class_template_decl = m_ast.ParseClassTemplateDecl( - decl_ctx, ModuleID(), attrs.accessibility, + decl_ctx, GetOwningModuleID(die), attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, template_param_infos); if (!class_template_decl) { if (log) { @@ -1599,8 +1604,8 @@ clang::ClassTemplateSpecializationDecl *class_specialization_decl = m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, ModuleID(), class_template_decl, tag_decl_kind, - template_param_infos); + decl_ctx, GetOwningModuleID(die), class_template_decl, + tag_decl_kind, template_param_infos); clang_type = m_ast.CreateClassTemplateSpecializationType( class_specialization_decl); clang_type_was_created = true; @@ -1613,9 +1618,9 @@ if (!clang_type_was_created) { clang_type_was_created = true; clang_type = m_ast.CreateRecordType( - decl_ctx, ModuleID(), attrs.accessibility, attrs.name.GetCString(), - tag_decl_kind, attrs.class_language, &metadata, - attrs.exports_symbols); + decl_ctx, GetOwningModuleID(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, attrs.class_language, + &metadata, attrs.exports_symbols); } } @@ -1627,7 +1632,7 @@ die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Forward, - TypePayloadClang(attrs.is_complete_objc_class)); + TypePayloadClang(ModuleID(), attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our @@ -3062,7 +3067,7 @@ clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration( - containing_decl_ctx, ModuleID(), name, + containing_decl_ctx, GetOwningModuleID(die), name, type->GetForwardCompilerType(), storage); assert(param_var_decl); function_param_decls.push_back(param_var_decl); @@ -3261,7 +3266,7 @@ TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); decl = m_ast.CreateVariableDeclaration( - decl_context, ModuleID(), name, + decl_context, GetOwningModuleID(die), name, ClangUtil::GetQualType(type->GetForwardCompilerType())); } break; @@ -3357,6 +3362,31 @@ return nullptr; } +ModuleID DWARFASTParserClang::GetOwningModuleID(const DWARFDIE &die) { + if (!die.IsValid()) + return {}; + + for (DWARFDIE parent = die.GetParent(); parent.IsValid(); + parent = parent.GetParent()) { + const dw_tag_t tag = parent.Tag(); + if (tag == DW_TAG_module) { + DWARFDIE module_die = parent; + auto it = m_die_to_module.find(module_die.GetDIE()); + if (it != m_die_to_module.end()) + return it->second; + const char *name = module_die.GetAttributeValueAsString(DW_AT_name, 0); + if (!name) + return {}; + + ModuleID id = + m_ast.GetOrCreateClangModule(name, GetOwningModuleID(module_die)); + m_die_to_module.insert({module_die.GetDIE(), id}); + return id; + } + } + return {}; +} + static bool IsSubroutine(const DWARFDIE &die) { switch (die.Tag()) { case DW_TAG_subprogram: @@ -3429,7 +3459,7 @@ DWARFDIE decl_context_die; clang::DeclContext *decl_context = GetClangDeclContextContainingDIE(die, &decl_context_die); - decl = m_ast.CreateBlockDeclaration(decl_context, ModuleID()); + decl = m_ast.CreateBlockDeclaration(decl_context, GetOwningModuleID(die)); if (decl) LinkDeclContextToDIE((clang::DeclContext *)decl, die); Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -75,7 +75,8 @@ uint32_t m_payload; public: TypePayloadClang() = default; - explicit TypePayloadClang(bool is_complete_objc_class, ModuleID owning_module); + explicit TypePayloadClang(ModuleID owning_module, + bool is_complete_objc_class = false); explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} operator uint32_t() { return m_payload; } @@ -314,8 +315,8 @@ static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes); - /// Synthesize a clang::Module and return its ID or 0. - unsigned GetOrCreateClangModule(llvm::StringRef name, unsigned parent, + /// Synthesize a clang::Module and return its ID or a default-constructed ID. + ModuleID GetOrCreateClangModule(llvm::StringRef name, ModuleID parent, bool is_framework = false, bool is_explicit = false); Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -319,8 +319,8 @@ return *g_map_ptr; } -TypePayloadClang::TypePayloadClang(bool is_complete_objc_class, - ModuleID owning_module) +TypePayloadClang::TypePayloadClang(ModuleID owning_module, + bool is_complete_objc_class) : m_payload(owning_module.id) { SetIsCompleteObjCClass(is_complete_objc_class); } @@ -1225,8 +1225,8 @@ decl->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); } -unsigned TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name, - unsigned parent, +ModuleID TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name, + ModuleID parent, bool is_framework, bool is_explicit) { // Get the external AST source which holds the modules. @@ -1234,7 +1234,7 @@ getASTContext().getExternalSource()); assert(ast_source && "external ast source was lost"); if (!ast_source) - return 0; + return {}; // Lazily initialize the module map. if (!m_header_search_up) { @@ -1250,7 +1250,7 @@ // Get or create the module context. bool created; clang::Module *module; - auto parent_desc = ast_source->getSourceDescriptor(parent); + auto parent_desc = ast_source->getSourceDescriptor(parent.id); std::tie(module, created) = m_module_map_up->findOrCreateModule( name, parent_desc ? parent_desc->getModuleOrNull() : nullptr, is_framework, is_explicit); Index: lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h @@ -0,0 +1,30 @@ +#include "B.h" // -*- ObjC -*- + +typedef int Typedef; + +struct TopLevelStruct { + int a; +}; + +typedef struct Struct_s { + int a; +} Struct; + +struct Nested { + StructB fromb; +}; + +typedef enum Enum_e { + a = 0 +} Enum; + +@interface SomeClass {} +@end + +template struct Template { T field; }; +extern template struct Template; + +namespace Namespace { +template struct InNamespace { T field; }; +extern template struct InNamespace; +} Index: lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h @@ -0,0 +1,8 @@ +typedef struct { + int b; +} StructB; + +namespace Namespace { +template struct AlsoInNamespace { T field; }; + extern template struct AlsoInNamespace; +} Index: lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap @@ -0,0 +1,6 @@ +module A { + header "A.h" + module B { + header "B.h" + } +} Index: lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg =================================================================== --- lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg +++ lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg @@ -1 +1 @@ -config.suffixes = ['.cpp', '.m', '.s', '.test', '.ll'] +config.suffixes = ['.cpp', '.m', '.mm', '.s', '.test', '.ll'] Index: lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm @@ -0,0 +1,41 @@ +// RUN: %clang --target=x86_64-apple-macosx -g -gmodules \ +// RUN: -fmodules -fmodules-cache-path=%t.cache \ +// RUN: -c -o %t.o %s -I%S/Inputs +// RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s +// Verify that the owning module information from DWARF is preserved in the AST. + +@import A; + +Typedef t1; +// CHECK-DAG: TypedefDecl {{.*}} imported in A Typedef + +TopLevelStruct s1; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct TopLevelStruct +// CHECK-DAG: -FieldDecl {{.*}} in A a 'int' + +Struct s2; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct + +StructB s3; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A.B struct +// CHECK-DAG: -FieldDecl {{.*}} in A.B b 'int' + +Nested s4; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct Nested +// CHECK-DAG: -FieldDecl {{.*}} in A fromb 'StructB' + +Enum e1; +// CHECK-DAG: EnumDecl {{.*}} imported in A {{.*}} Enum_e +// FIXME: : -EnumConstantDecl {{.*}} imported in A a + +SomeClass *obj1; +// CHECK-DAG: ObjCInterfaceDecl {{.*}} imported in A SomeClass + +Template t2; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} imported in A struct Template + +Namespace::InNamespace t3; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} imported in A struct InNamespace + +Namespace::AlsoInNamespace t4; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} imported in A.B struct AlsoInNamespace