Index: lldb/trunk/include/lldb/Symbol/ClangASTContext.h =================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h @@ -214,19 +214,24 @@ static CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl); template - CompilerType GetTypeForIdentifier(const ConstString &type_name) { + CompilerType + GetTypeForIdentifier(const ConstString &type_name, + clang::DeclContext *decl_context = nullptr) { CompilerType compiler_type; if (type_name.GetLength()) { clang::ASTContext *ast = getASTContext(); if (ast) { + if (!decl_context) + decl_context = ast->getTranslationUnitDecl(); + clang::IdentifierInfo &myIdent = ast->Idents.get(type_name.GetCString()); clang::DeclarationName myName = ast->DeclarationNames.getIdentifier(&myIdent); clang::DeclContext::lookup_result result = - ast->getTranslationUnitDecl()->lookup(myName); + decl_context->lookup(myName); if (!result.empty()) { clang::NamedDecl *named_decl = result[0]; @@ -881,7 +886,7 @@ //---------------------------------------------------------------------- // Modifying Enumeration types //---------------------------------------------------------------------- - bool AddEnumerationValueToEnumerationType( + clang::EnumConstantDecl *AddEnumerationValueToEnumerationType( lldb::opaque_compiler_type_t type, const CompilerType &enumerator_qual_type, const Declaration &decl, const char *name, int64_t enum_value, uint32_t enum_value_bit_size); @@ -937,6 +942,8 @@ static clang::TagDecl *GetAsTagDecl(const CompilerType &type); + static clang::TypedefNameDecl *GetAsTypedefDecl(const CompilerType &type); + clang::CXXRecordDecl *GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type); static clang::ObjCInterfaceDecl * Index: lldb/trunk/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp =================================================================== --- lldb/trunk/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp +++ lldb/trunk/lit/SymbolFile/PDB/Inputs/AstRestoreTest.cpp @@ -0,0 +1,47 @@ +namespace N0 { +namespace N1 { + +namespace { +enum Enum { Enum_0 = 1, Enum_1 = 2, Enum_2 = 4, Enum_3 = 8 }; +} + +Enum Global = Enum_3; + +struct Base { + Enum m_e = Enum_1; +}; + +class Class : public Base { +public: + Class(Enum e) : m_ce(e) {} + + static int StaticFunc(const Class &c) { + return c.PrivateFunc(c.m_inner) + Global + ClassStatic; + } + + const Enum m_ce; + + static int ClassStatic; + +private: + struct Inner { + char x; + short y; + int z; + }; + + int PrivateFunc(const Inner &i) const { return i.z; } + + Inner m_inner{}; +}; +int Class::ClassStatic = 7; + +void foo() { Class::StaticFunc(Class(Enum_0)); } + +} // namespace N1 +} // namespace N0 + +int main() { + N0::N1::foo(); + return 0; +} Index: lldb/trunk/lit/SymbolFile/PDB/ast-restore.test =================================================================== --- lldb/trunk/lit/SymbolFile/PDB/ast-restore.test +++ lldb/trunk/lit/SymbolFile/PDB/ast-restore.test @@ -0,0 +1,77 @@ +REQUIRES: windows +RUN: cl /Zi /GS- /c %S/Inputs/AstRestoreTest.cpp /Fo%t.obj +RUN: link /debug:full /nodefaultlib /entry:main %t.obj /out:%t.exe +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=ENUM %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=GLOBAL %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=BASE %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=CLASS %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=INNER %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=FOO %s +RUN: lldb-test symbols -dump-ast %t.exe | FileCheck --check-prefix=MAIN %s + +ENUM: Module: {{.*}} +ENUM: namespace N0 { +ENUM: namespace N1 { +ENUM: namespace { +ENUM: enum Enum { +ENUM: Enum_0, +ENUM: Enum_1, +ENUM: Enum_2, +ENUM: Enum_3 +ENUM: }; +ENUM: } +ENUM: } +ENUM: } + +GLOBAL: Module: {{.*}} +GLOBAL: namespace N0 { +GLOBAL: namespace N1 { +GLOBAL: N0::N1::(anonymous namespace)::Enum Global; +GLOBAL: } +GLOBAL: } + +BASE: Module: {{.*}} +BASE: namespace N0 { +BASE: namespace N1 { +BASE: struct Base { +BASE: N0::N1::(anonymous namespace)::Enum m_e; +BASE: }; +BASE: } +BASE: } + +CLASS: Module: {{.*}} +CLASS: namespace N0 { +CLASS: namespace N1 { +CLASS: class Class : public N0::N1::Base { +CLASS-DAG: const N0::N1::(anonymous namespace)::Enum m_ce; +CLASS-DAG: static int ClassStatic; +CLASS-DAG: N0::N1::Class::Inner m_inner; +CLASS-DAG: {{(inline )?}}Class(N0::N1::(anonymous namespace)::Enum); +CLASS-DAG: static {{(inline )?}}int StaticFunc(const N0::N1::Class &); +CLASS-DAG: {{(inline )?}}int PrivateFunc(const N0::N1::Class::Inner &); +CLASS: }; +CLASS: } +CLASS: } + +INNER: Module: {{.*}} +INNER: namespace N0 { +INNER: namespace N1 { +INNER: class Class : public N0::N1::Base { +INNER: struct Inner { +INNER: signed char x; +INNER: short y; +INNER: int z; +INNER: }; +INNER: }; +INNER: } +INNER: } + +FOO: Module: {{.*}} +FOO: namespace N0 { +FOO: namespace N1 { +FOO: void foo(); +FOO: } +FOO: } + +MAIN: Module: {{.*}} +MAIN: int main(); Index: lldb/trunk/lit/SymbolFile/PDB/class-layout.test =================================================================== --- lldb/trunk/lit/SymbolFile/PDB/class-layout.test +++ lldb/trunk/lit/SymbolFile/PDB/class-layout.test @@ -61,30 +61,30 @@ UNNAMED-STRUCT: int a; UNNAMED-STRUCT:} -BASE: name = "MemberTest::Base", size = 4, decl = ClassLayoutTest.cpp:59 -BASE-SAME: class MemberTest::Base { +BASE: name = "Base", size = 4, decl = ClassLayoutTest.cpp:59 +BASE-SAME: class Base { BASE: int a; -BASE: void {{.*}}Base(); -BASE: {{.*}}~Base(); -BASE: int {{.*}}Get(); +BASE: Base(); +BASE: ~Base(); +BASE: int Get(); BASE:} -FRIEND: name = "MemberTest::Friend", size = 1, decl = ClassLayoutTest.cpp:70 -FRIEND-SAME: class MemberTest::Friend { +FRIEND: name = "Friend", size = 1, decl = ClassLayoutTest.cpp:70 +FRIEND-SAME: class Friend { FRIEND: int f(); FRIEND: } -CLASS: name = "MemberTest::Class", size = 88, decl = ClassLayoutTest.cpp:74 -CLASS-SAME: class MemberTest::Class : public MemberTest::Base { +CLASS: name = "Class", size = 88, decl = ClassLayoutTest.cpp:74 +CLASS-SAME: class Class : public MemberTest::Base { CLASS: static int m_static; CLASS: int m_public; CLASS: Struct m_struct; CLASS: Union m_union; CLASS: int m_private; CLASS: int m_protected; -CLASS: void Class(); -CLASS: void Class(int); -CLASS: ~MemberTest::Class(); +CLASS: Class(); +CLASS: Class(int); +CLASS: ~Class(); CLASS: static int {{.*}}StaticMemberFunc(int, ...); CLASS: int Get(); CLASS: int f(MemberTest::Friend); Index: lldb/trunk/lit/SymbolFile/PDB/func-symbols.test =================================================================== --- lldb/trunk/lit/SymbolFile/PDB/func-symbols.test +++ lldb/trunk/lit/SymbolFile/PDB/func-symbols.test @@ -14,11 +14,11 @@ CHECK-ONE-DAG: [[TY1:.*]]: Type{[[UID1:.*]]} , name = "Func_arg_void", decl = FuncSymbolsTestMain.cpp:4, compiler_type = {{.*}} void (void) CHECK-ONE-DAG: [[TY2:.*]]: Type{[[UID2:.*]]} , name = "Func_arg_none", decl = FuncSymbolsTestMain.cpp:5, compiler_type = {{.*}} void (void) CHECK-ONE-DAG: [[TY3:.*]]: Type{[[UID3:.*]]} , name = "Func_varargs", decl = FuncSymbolsTestMain.cpp:6, compiler_type = {{.*}} void (...) -CHECK-ONE-DAG: [[TY4:.*]]: Type{[[UID4:.*]]} , name = "NS::Func", decl = FuncSymbolsTestMain.cpp:28, compiler_type = {{.*}} void (signed char, int) +CHECK-ONE-DAG: [[TY4:.*]]: Type{[[UID4:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:28, compiler_type = {{.*}} void (signed char, int) CHECK-ONE-DAG: [[TY5:.*]]: Type{[[UID5:.*]]} , name = "main", decl = FuncSymbolsTestMain.cpp:44, compiler_type = {{.*}} int (void) -CHECK-ONE-DAG: [[TY6:.*]]: Type{[[UID6:.*]]} , name = "`anonymous namespace'::Func", decl = FuncSymbolsTestMain.cpp:24, compiler_type = {{.*}} void (int, const long, volatile _Bool, ...) +CHECK-ONE-DAG: [[TY6:.*]]: Type{[[UID6:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:24, compiler_type = {{.*}} void (int, const long, volatile _Bool, ...) CHECK-ONE-DAG: [[TY7:.*]]: Type{[[UID7:.*]]} , name = "StaticFunction", decl = FuncSymbolsTestMain.cpp:35, compiler_type = {{.*}} long (int) -CHECK-ONE-DAG: [[TY8:.*]]: Type{[[UID8:.*]]} , name = "MemberTest::A::Func", decl = FuncSymbolsTestMain.cpp:12, compiler_type = {{.*}} int (int, ...) +CHECK-ONE-DAG: [[TY8:.*]]: Type{[[UID8:.*]]} , name = "Func", decl = FuncSymbolsTestMain.cpp:12, compiler_type = {{.*}} int (int, ...) CHECK-ONE-DAG: [[TY9:.*]]: Type{[[UID9:.*]]} , name = "TemplateFunc<1,int>", decl = FuncSymbolsTestMain.cpp:18, compiler_type = {{.*}} void (int) CHECK-ONE-DAG: [[TY10:.*]]: Type{[[UID10:.*]]} , name = "TemplateFunc<1,int,int,int>", decl = FuncSymbolsTestMain.cpp:18, compiler_type = {{.*}} void (int, int, int) CHECK-ONE-DAG: [[TY11:.*]]: Type{[[UID11:.*]]} , name = "InlinedFunction", decl = FuncSymbolsTestMain.cpp:40, compiler_type = {{.*}} void (long) @@ -39,7 +39,7 @@ ; We expect new types observed in another compile unit CHECK-TWO-DAG: [[TY30:.*]]: Type{[[UID30:.*]]} , name = "FunctionCall", decl = FuncSymbols.cpp:13, compiler_type = {{.*}} void (void) -CHECK-TWO-DAG: [[TY31:.*]]: Type{[[UID31:.*]]} , name = "`anonymous namespace'::StaticFunction", decl = FuncSymbols.cpp:4, compiler_type = {{.*}} long (int) +CHECK-TWO-DAG: [[TY31:.*]]: Type{[[UID31:.*]]} , name = "StaticFunction", decl = FuncSymbols.cpp:4, compiler_type = {{.*}} long (int) CHECK-TWO-DAG: [[TY32:.*]]: Type{[[UID32:.*]]} , name = "InlinedFunction", decl = FuncSymbols.cpp:10, compiler_type = {{.*}} int (long) CHECK-TWO: {{.*}}: CompileUnit{{.*}}, language = "c++", file = '{{.*}}\FuncSymbols.cpp' Index: lldb/trunk/lit/SymbolFile/PDB/pointers.test =================================================================== --- lldb/trunk/lit/SymbolFile/PDB/pointers.test +++ lldb/trunk/lit/SymbolFile/PDB/pointers.test @@ -10,11 +10,11 @@ CHECK: Module [[MOD:.*]] CHECK: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\PointerTypeTest.cpp' -MAIN-ST-F: name = "main::ST::f" +MAIN-ST-F: name = "f" MAIN-ST-F-SAME: decl = PointerTypeTest.cpp:8 MAIN-ST-F-SAME: compiler_type = {{.*}} int (int) -MAIN-ST: name = "main::ST", size = 4, decl = PointerTypeTest.cpp:6, compiler_type = {{.*}} struct main::ST { +MAIN-ST: name = "ST", size = 4, decl = PointerTypeTest.cpp:6, compiler_type = {{.*}} struct ST { MAIN-ST-NEXT: int a; MAIN-ST-NEXT: int {{.*}}f(int); MAIN-ST-NEXT:} @@ -26,13 +26,13 @@ MAIN: Variable{{.*}}, name = "p_int" MAIN-SAME: (int *), scope = local MAIN: Variable{{.*}}, name = "p_member_field" -MAIN-SAME: (int main::ST::*), scope = local +MAIN-SAME: (int ST::*), scope = local MAIN: Variable{{.*}}, name = "p_member_method" -MAIN-SAME: (int (main::ST::*)(int)), scope = local +MAIN-SAME: (int (ST::*)(int)), scope = local F: Function{[[FID2:.*]]}, demangled = {{.*}}f(int) F-NEXT: Block{[[FID2]]} F: Variable{{.*}}, name = "this" -F-SAME: (main::ST *), scope = parameter, location = {{.*}}, artificial +F-SAME: (ST *), scope = parameter, location = {{.*}}, artificial F: Variable{{.*}}, name = "x" F-SAME: (int), scope = parameter, decl = PointerTypeTest.cpp:8 Index: lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -14,6 +14,8 @@ #include "lldb/Symbol/ClangASTImporter.h" +class SymbolFilePDB; + namespace clang { class CharUnits; class CXXRecordDecl; @@ -47,13 +49,32 @@ lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type); bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type); + clang::Decl *GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol); + + clang::DeclContext * + GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol); + clang::DeclContext * + GetDeclContextContainingSymbol(const llvm::pdb::PDBSymbol &symbol); + + void ParseDeclsForDeclContext(const clang::DeclContext *decl_context); + + clang::NamespaceDecl *FindNamespaceDecl(const clang::DeclContext *parent, + llvm::StringRef name); + lldb_private::ClangASTImporter &GetClangASTImporter() { return m_ast_importer; } + static std::string PDBNameDropScope(const std::string &name); + private: - typedef llvm::DenseMap - ClangTypeToUidMap; + typedef llvm::DenseMap + CXXRecordDeclToUidMap; + typedef llvm::DenseMap UidToDeclMap; + typedef llvm::DenseMap> + ParentToNamespacesMap; + typedef llvm::DenseMap + DeclContextToUidMap; typedef llvm::pdb::ConcreteSymbolEnumerator PDBDataSymbolEnumerator; typedef llvm::pdb::ConcreteSymbolEnumerator @@ -62,29 +83,31 @@ PDBFuncSymbolEnumerator; bool AddEnumValue(lldb_private::CompilerType enum_type, - const llvm::pdb::PDBSymbolData &data) const; + const llvm::pdb::PDBSymbolData &data); bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file, lldb_private::CompilerType &compiler_type, llvm::pdb::PDBSymbolTypeUDT &udt); - void AddRecordMembers( - lldb_private::SymbolFile &symbol_file, - lldb_private::CompilerType &record_type, - PDBDataSymbolEnumerator &members_enum, - lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; - void AddRecordBases( - lldb_private::SymbolFile &symbol_file, - lldb_private::CompilerType &record_type, - int record_kind, - PDBBaseClassSymbolEnumerator &bases_enum, - lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; - void AddRecordMethods( - lldb_private::SymbolFile &symbol_file, - lldb_private::CompilerType &record_type, - PDBFuncSymbolEnumerator &methods_enum) const; + void + AddRecordMembers(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBDataSymbolEnumerator &members_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info); + void + AddRecordBases(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, int record_kind, + PDBBaseClassSymbolEnumerator &bases_enum, + lldb_private::ClangASTImporter::LayoutInfo &layout_info) const; + void AddRecordMethods(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum); lldb_private::ClangASTContext &m_ast; lldb_private::ClangASTImporter m_ast_importer; - ClangTypeToUidMap m_forward_decl_clang_type_to_uid; + + CXXRecordDeclToUidMap m_forward_decl_to_uid; + UidToDeclMap m_uid_to_decl; + ParentToNamespacesMap m_parent_to_namespaces; + DeclContextToUidMap m_decl_context_to_uid; }; #endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H Index: lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ lldb/trunk/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -21,6 +21,7 @@ #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeMap.h" #include "lldb/Symbol/TypeSystem.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" @@ -244,8 +245,8 @@ return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind()); } -clang::MSInheritanceAttr::Spelling GetMSInheritance( - const PDBSymbolTypeUDT &udt) { +clang::MSInheritanceAttr::Spelling +GetMSInheritance(const PDBSymbolTypeUDT &udt) { int base_count = 0; bool has_virtual = false; @@ -263,6 +264,46 @@ return clang::MSInheritanceAttr::Keyword_multiple_inheritance; return clang::MSInheritanceAttr::Keyword_single_inheritance; } + +std::unique_ptr +GetClassOrFunctionParent(const llvm::pdb::PDBSymbol &symbol) { + const IPDBSession &session = symbol.getSession(); + const IPDBRawSymbol &raw = symbol.getRawSymbol(); + + auto class_parent_id = raw.getClassParentId(); + if (auto class_parent = session.getSymbolById(class_parent_id)) + return class_parent; + + auto lexical_parent_id = raw.getLexicalParentId(); + auto lexical_parent = session.getSymbolById(lexical_parent_id); + if (!lexical_parent) + return nullptr; + + auto lexical_parent_tag = lexical_parent->getSymTag(); + if (lexical_parent_tag == PDB_SymType::Function) + return lexical_parent; + if (lexical_parent_tag == PDB_SymType::Exe) + return nullptr; + + return GetClassOrFunctionParent(*lexical_parent); +} + +clang::NamedDecl * +GetDeclFromContextByName(const clang::ASTContext &ast, + const clang::DeclContext &decl_context, + llvm::StringRef name) { + clang::IdentifierInfo &ident = ast.Idents.get(name); + clang::DeclarationName decl_name = ast.DeclarationNames.getIdentifier(&ident); + clang::DeclContext::lookup_result result = decl_context.lookup(decl_name); + if (result.empty()) + return nullptr; + + return result[0]; +} + +bool IsAnonymousNamespaceName(const std::string &name) { + return name == "`anonymous namespace'" | name == "`anonymous-namespace'"; +} } // namespace PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} @@ -272,13 +313,7 @@ // DebugInfoASTParser interface lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { - // PDB doesn't maintain enough information to robustly rebuild the entire - // tree, and this is most problematic when it comes to figure out the right - // DeclContext to put a type in. So for now, everything goes in the - // translation unit decl as a fully qualified type. - clang::DeclContext *tu_decl_ctx = m_ast.GetTranslationUnitDecl(); Declaration decl; - switch (type.getSymTag()) { case PDB_SymType::BaseClass: { auto symbol_file = m_ast.GetSymbolFile(); @@ -304,21 +339,66 @@ return nullptr; // Ignore unnamed-tag UDTs. - if (udt->getName().empty()) + auto name = PDBNameDropScope(udt->getName()); + if (name.empty()) return nullptr; - auto access = GetAccessibilityForUdt(*udt); + auto decl_context = GetDeclContextContainingSymbol(type); - auto tag_type_kind = TranslateUdtKind(udt->getUdtKind()); + // Check if such an UDT already exists in the current context. + // This may occur with const or volatile types. There are separate type + // symbols in PDB for types with const or volatile modifiers, but we need + // to create only one declaration for them all. + Type::ResolveStateTag type_resolve_state_tag; + CompilerType clang_type = m_ast.GetTypeForIdentifier( + ConstString(name), decl_context); + if (!clang_type.IsValid()) { + auto access = GetAccessibilityForUdt(*udt); + + auto tag_type_kind = TranslateUdtKind(udt->getUdtKind()); + + ClangASTMetadata metadata; + metadata.SetUserID(type.getSymIndexId()); + metadata.SetIsDynamicCXXType(false); + + clang_type = m_ast.CreateRecordType( + decl_context, access, name.c_str(), tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); + assert(clang_type.IsValid()); + + auto record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + assert(record_decl); + m_uid_to_decl[type.getSymIndexId()] = record_decl; + + auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit( + *m_ast.getASTContext(), GetMSInheritance(*udt)); + record_decl->addAttr(inheritance_attr); + + ClangASTContext::StartTagDeclarationDefinition(clang_type); + + auto children = udt->findAllChildren(); + if (!children || children->getChildCount() == 0) { + // PDB does not have symbol of forwarder. We assume we get an udt w/o + // any fields. Just complete it at this point. + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + + ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + false); - ClangASTMetadata metadata; - metadata.SetUserID(type.getSymIndexId()); - metadata.SetIsDynamicCXXType(false); - - CompilerType clang_type = m_ast.CreateRecordType( - tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, - lldb::eLanguageTypeC_plus_plus, &metadata); - assert(clang_type.IsValid()); + type_resolve_state_tag = Type::eResolveStateFull; + } else { + // Add the type to the forward declarations. It will help us to avoid + // an endless recursion in CompleteTypeFromUdt function. + m_forward_decl_to_uid[record_decl] = type.getSymIndexId(); + + ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), + true); + + type_resolve_state_tag = Type::eResolveStateForward; + } + } else + type_resolve_state_tag = Type::eResolveStateForward; if (udt->isConstType()) clang_type = clang_type.AddConstModifier(); @@ -326,83 +406,73 @@ if (udt->isVolatileType()) clang_type = clang_type.AddVolatileModifier(); - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - assert(record_decl); - auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit( - *m_ast.getASTContext(), GetMSInheritance(*udt)); - record_decl->addAttr(inheritance_attr); - - ClangASTContext::StartTagDeclarationDefinition(clang_type); - - Type::ResolveStateTag type_resolve_state_tag; - auto children = udt->findAllChildren(); - if (!children || children->getChildCount() == 0) { - // PDB does not have symbol of forwarder. We assume we get an udt w/o any - // fields. Just complete it at this point. - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false); - - type_resolve_state_tag = Type::eResolveStateFull; - } else { - // Add the type to the forward declarations. It will help us to avoid - // an endless recursion in CompleteTypeFromUdt function. - auto clang_type_removed_fast_quals = - ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(); - m_forward_decl_clang_type_to_uid[clang_type_removed_fast_quals] = - type.getSymIndexId(); - - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); - - type_resolve_state_tag = Type::eResolveStateForward; - } - GetDeclarationForSymbol(type, decl); return std::make_shared( - type.getSymIndexId(), m_ast.GetSymbolFile(), - ConstString(udt->getName()), udt->getLength(), nullptr, - LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, + type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), + udt->getLength(), nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, clang_type, type_resolve_state_tag); } break; case PDB_SymType::Enum: { auto enum_type = llvm::dyn_cast(&type); assert(enum_type); - auto underlying_type_up = enum_type->getUnderlyingType(); - if (!underlying_type_up) - return nullptr; - lldb::Encoding encoding = - TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); - // FIXME: Type of underlying builtin is always `Int`. We correct it with - // the very first enumerator's encoding if any. - auto first_child = enum_type->findOneChild(); - if (first_child) { - encoding = TranslateEnumEncoding(first_child->getValue().Type); - } - std::string name = enum_type->getName(); + + std::string name = PDBNameDropScope(enum_type->getName()); + auto decl_context = GetDeclContextContainingSymbol(type); uint64_t bytes = enum_type->getLength(); - CompilerType builtin_type; - if (bytes > 0) - builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( - m_ast, *underlying_type_up, encoding, bytes * 8); - else - builtin_type = m_ast.GetBasicType(eBasicTypeInt); - // FIXME: PDB does not have information about scoped enumeration (Enum - // Class). Set it false for now. - bool isScoped = false; - - CompilerType ast_enum = m_ast.CreateEnumerationType( - name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped); - auto enum_values = enum_type->findAllChildren(); - if (enum_values) { - while (auto enum_value = enum_values->getNext()) { - if (enum_value->getDataKind() != PDB_DataKind::Constant) - continue; - AddEnumValue(ast_enum, *enum_value); + + // Check if such an enum already exists in the current context + CompilerType ast_enum = m_ast.GetTypeForIdentifier( + ConstString(name), decl_context); + if (!ast_enum.IsValid()) { + auto underlying_type_up = enum_type->getUnderlyingType(); + if (!underlying_type_up) + return nullptr; + + lldb::Encoding encoding = + TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); + // FIXME: Type of underlying builtin is always `Int`. We correct it with + // the very first enumerator's encoding if any. + auto first_child = enum_type->findOneChild(); + if (first_child) + encoding = TranslateEnumEncoding(first_child->getValue().Type); + + CompilerType builtin_type; + if (bytes > 0) + builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( + m_ast, *underlying_type_up, encoding, bytes * 8); + else + builtin_type = m_ast.GetBasicType(eBasicTypeInt); + + // FIXME: PDB does not have information about scoped enumeration (Enum + // Class). Set it false for now. + bool isScoped = false; + + ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl, + builtin_type, isScoped); + + auto enum_decl = ClangASTContext::GetAsEnumDecl(ast_enum); + assert(enum_decl); + m_uid_to_decl[type.getSymIndexId()] = enum_decl; + + auto enum_values = enum_type->findAllChildren(); + if (enum_values) { + while (auto enum_value = enum_values->getNext()) { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } } + + if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) + ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); } - if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) - ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); + + if (enum_type->isConstType()) + ast_enum = ast_enum.AddConstModifier(); + + if (enum_type->isVolatileType()) + ast_enum = ast_enum.AddVolatileModifier(); GetDeclarationForSymbol(type, decl); return std::make_shared( @@ -413,23 +483,42 @@ case PDB_SymType::Typedef: { auto type_def = llvm::dyn_cast(&type); assert(type_def); + lldb_private::Type *target_type = m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); if (!target_type) return nullptr; - std::string name = type_def->getName(); - uint64_t bytes = type_def->getLength(); - CompilerType target_ast_type = target_type->GetFullCompilerType(); - CompilerDeclContext target_decl_ctx = - m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); + + std::string name = PDBNameDropScope(type_def->getName()); + auto decl_ctx = GetDeclContextContainingSymbol(type); + + // Check if such a typedef already exists in the current context CompilerType ast_typedef = - m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); - if (!ast_typedef) - return nullptr; + m_ast.GetTypeForIdentifier(ConstString(name), + decl_ctx); + if (!ast_typedef.IsValid()) { + CompilerType target_ast_type = target_type->GetFullCompilerType(); + + ast_typedef = m_ast.CreateTypedefType( + target_ast_type, name.c_str(), CompilerDeclContext(&m_ast, decl_ctx)); + if (!ast_typedef) + return nullptr; + auto typedef_decl = ClangASTContext::GetAsTypedefDecl(ast_typedef); + assert(typedef_decl); + m_uid_to_decl[type.getSymIndexId()] = typedef_decl; + } + + if (type_def->isConstType()) + ast_typedef = ast_typedef.AddConstModifier(); + + if (type_def->isVolatileType()) + ast_typedef = ast_typedef.AddVolatileModifier(); + + GetDeclarationForSymbol(type, decl); return std::make_shared( type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), - bytes, nullptr, target_type->GetID(), + type_def->getLength(), nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef, lldb_private::Type::eResolveStateFull); } break; @@ -446,7 +535,7 @@ return nullptr; func_sig = sig.release(); // Function type is named. - name = pdb_func->getName(); + name = PDBNameDropScope(pdb_func->getName()); } else if (auto pdb_func_sig = llvm::dyn_cast(&type)) { func_sig = const_cast(pdb_func_sig); @@ -623,11 +712,10 @@ // Remove the type from the forward declarations to avoid // an endless recursion for types like a linked list. - CompilerType compiler_type_no_qualifiers = - ClangUtil::RemoveFastQualifiers(compiler_type); - auto uid_it = m_forward_decl_clang_type_to_uid.find( - compiler_type_no_qualifiers.GetOpaqueQualType()); - if (uid_it == m_forward_decl_clang_type_to_uid.end()) + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType()); + auto uid_it = m_forward_decl_to_uid.find(record_decl); + if (uid_it == m_forward_decl_to_uid.end()) return true; auto symbol_file = static_cast(m_ast.GetSymbolFile()); @@ -639,7 +727,7 @@ if (!symbol) return false; - m_forward_decl_clang_type_to_uid.erase(uid_it); + m_forward_decl_to_uid.erase(uid_it); ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), false); @@ -657,11 +745,265 @@ } } +clang::Decl * +PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { + auto it = m_uid_to_decl.find(symbol.getSymIndexId()); + if (it != m_uid_to_decl.end()) + return it->second; + + auto symbol_file = static_cast(m_ast.GetSymbolFile()); + if (!symbol_file) + return nullptr; + + // First of all, check if the symbol is a member of a class. Resolve the full + // class type and return the declaration from the cache if so. + auto tag = symbol.getSymTag(); + if (tag == PDB_SymType::Data || tag == PDB_SymType::Function) { + const IPDBSession &session = symbol.getSession(); + const IPDBRawSymbol &raw = symbol.getRawSymbol(); + + auto class_parent_id = raw.getClassParentId(); + if (session.getSymbolById(class_parent_id)) { + auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_id); + if (!class_parent_type) + return nullptr; + + class_parent_type->GetFullCompilerType(); + + return m_uid_to_decl.lookup(symbol.getSymIndexId()); + } + } + + // If we are here, then the symbol is not belonging to a class and is not + // contained in the cache. So create a declaration for it. + switch (symbol.getSymTag()) { + case PDB_SymType::Data: { + auto data = llvm::dyn_cast(&symbol); + assert(data); + + auto decl_context = GetDeclContextContainingSymbol(symbol); + assert(decl_context); + + // May be the current context is a class really, but we haven't found + // any class parent. This happens e.g. in the case of class static + // variables - they has two symbols, one is a child of the class when + // another is a child of the exe. So always complete the parent and use + // an existing declaration if possible. + if (auto parent_decl = llvm::dyn_cast_or_null(decl_context)) + m_ast.GetCompleteDecl(parent_decl); + + auto name = PDBNameDropScope(data->getName()); + + // Check if the current context already contains the symbol with the name. + clang::Decl *decl = + GetDeclFromContextByName(*m_ast.getASTContext(), *decl_context, name); + if (!decl) { + auto type = symbol_file->ResolveTypeUID(data->getTypeId()); + if (!type) + return nullptr; + + decl = m_ast.CreateVariableDeclaration( + decl_context, name.c_str(), + ClangUtil::GetQualType(type->GetLayoutCompilerType())); + } + + m_uid_to_decl[data->getSymIndexId()] = decl; + + return decl; + } + case PDB_SymType::Function: { + auto func = llvm::dyn_cast(&symbol); + assert(func); + + auto decl_context = GetDeclContextContainingSymbol(symbol); + assert(decl_context); + + auto name = PDBNameDropScope(func->getName()); + + auto type = symbol_file->ResolveTypeUID(func->getSymIndexId()); + if (!type) + return nullptr; + + auto storage = func->isStatic() ? clang::StorageClass::SC_Static + : clang::StorageClass::SC_None; + + auto decl = m_ast.CreateFunctionDeclaration( + decl_context, name.c_str(), type->GetForwardCompilerType(), storage, + func->hasInlineAttribute()); + + m_uid_to_decl[func->getSymIndexId()] = decl; + + return decl; + } + default: { + // It's not a variable and not a function, check if it's a type + auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId()); + if (!type) + return nullptr; + + return m_uid_to_decl.lookup(symbol.getSymIndexId()); + } + } +} + +clang::DeclContext * +PDBASTParser::GetDeclContextForSymbol(const llvm::pdb::PDBSymbol &symbol) { + if (symbol.getSymTag() == PDB_SymType::Function) { + clang::DeclContext *result = + llvm::dyn_cast_or_null(GetDeclForSymbol(symbol)); + + if (result) + m_decl_context_to_uid[result] = symbol.getSymIndexId(); + + return result; + } + + auto symbol_file = static_cast(m_ast.GetSymbolFile()); + if (!symbol_file) + return nullptr; + + auto type = symbol_file->ResolveTypeUID(symbol.getSymIndexId()); + if (!type) + return nullptr; + + clang::DeclContext *result = + m_ast.GetDeclContextForType(type->GetForwardCompilerType()); + + if (result) + m_decl_context_to_uid[result] = symbol.getSymIndexId(); + + return result; +} + +clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol( + const llvm::pdb::PDBSymbol &symbol) { + auto parent = GetClassOrFunctionParent(symbol); + while (parent) { + if (auto parent_context = GetDeclContextForSymbol(*parent)) + return parent_context; + + parent = GetClassOrFunctionParent(*parent); + } + + // We can't find any class or function parent of the symbol. So analyze + // the full symbol name. The symbol may be belonging to a namespace + // or function (or even to a class if it's e.g. a static variable symbol). + // We do not use CPlusPlusNameParser because it fails on things like + // `anonymous namespace'. + + // TODO: Make clang to emit full names for variables in namespaces + // (as MSVC does) + + auto context = symbol.getRawSymbol().getName(); + auto context_size = context.rfind("::"); + if (context_size == std::string::npos) + context_size = 0; + context = context.substr(0, context_size); + + // Check if there is a symbol with the name of the context. + + auto symbol_file = static_cast(m_ast.GetSymbolFile()); + if (!symbol_file) + return m_ast.GetTranslationUnitDecl(); + + auto global = symbol_file->GetPDBSession().getGlobalScope(); + if (!global) + return m_ast.GetTranslationUnitDecl(); + + TypeMap types; + if (auto children_enum = + global->findChildren(PDB_SymType::None, context, NS_CaseSensitive)) + while (auto child = children_enum->getNext()) + if (auto child_context = GetDeclContextForSymbol(*child)) + return child_context; + + // Split context and retrieve nested namespaces + auto curr_context = m_ast.GetTranslationUnitDecl(); + auto from = 0; + while (from < context_size) { + auto to = context.find("::", from); + if (to == std::string::npos) + to = context_size; + + auto namespace_name = context.substr(from, to - from); + auto namespace_name_c_str = IsAnonymousNamespaceName(namespace_name) + ? nullptr + : namespace_name.c_str(); + auto namespace_decl = + m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, curr_context); + + m_parent_to_namespaces[curr_context].insert(namespace_decl); + + curr_context = namespace_decl; + from = to + 2; + } + + return curr_context; +} + +void PDBASTParser::ParseDeclsForDeclContext( + const clang::DeclContext *decl_context) { + auto symbol_file = static_cast(m_ast.GetSymbolFile()); + if (!symbol_file) + return; + + IPDBSession &session = symbol_file->GetPDBSession(); + auto symbol_up = + session.getSymbolById(m_decl_context_to_uid.lookup(decl_context)); + auto global_up = session.getGlobalScope(); + + PDBSymbol *symbol; + if (symbol_up) + symbol = symbol_up.get(); + else if (global_up) + symbol = global_up.get(); + else + return; + + if (auto children = symbol->findAllChildren()) + while (auto child = children->getNext()) + GetDeclForSymbol(*child); +} + +clang::NamespaceDecl * +PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent, + llvm::StringRef name) { + if (!parent) + parent = m_ast.GetTranslationUnitDecl(); + + auto it = m_parent_to_namespaces.find(parent); + if (it == m_parent_to_namespaces.end()) + return nullptr; + + for (auto namespace_decl : it->second) + if (namespace_decl->getName().equals(name)) + return namespace_decl; + + for (auto namespace_decl : it->second) + if (namespace_decl->isAnonymousNamespace()) + return FindNamespaceDecl(namespace_decl, name); + + return nullptr; +} + +std::string PDBASTParser::PDBNameDropScope(const std::string &name) { + // Not all PDB names can be parsed with CPlusPlusNameParser. + // E.g. it fails on names containing `anonymous namespace'. + // So we simply drop everything before '::' + + auto offset = name.rfind("::"); + if (offset == std::string::npos) + return name; + assert(offset + 2 <= name.size()); + + return name.substr(offset + 2); +} + bool PDBASTParser::AddEnumValue(CompilerType enum_type, - const PDBSymbolData &enum_value) const { + const PDBSymbolData &enum_value) { Declaration decl; Variant v = enum_value.getValue(); - std::string name = enum_value.getName(); + std::string name = PDBNameDropScope(enum_value.getName()); int64_t raw_value; switch (v.Type) { case PDB_VariantType::Int8: @@ -695,9 +1037,15 @@ m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); uint32_t byte_size = m_ast.getASTContext()->getTypeSize( ClangUtil::GetQualType(underlying_type)); - return m_ast.AddEnumerationValueToEnumerationType( + auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType( enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(), raw_value, byte_size * 8); + if (!enum_constant_decl) + return false; + + m_uid_to_decl[enum_value.getSymIndexId()] = enum_constant_decl; + + return true; } bool PDBASTParser::CompleteTypeFromUDT( @@ -744,10 +1092,10 @@ lldb_private::SymbolFile &symbol_file, lldb_private::CompilerType &record_type, PDBDataSymbolEnumerator &members_enum, - lldb_private::ClangASTImporter::LayoutInfo &layout_info) const { + lldb_private::ClangASTImporter::LayoutInfo &layout_info) { while (auto member = members_enum.getNext()) { if (member->isCompilerGenerated()) - continue; + continue; auto member_name = member->getName(); @@ -781,6 +1129,8 @@ if (!decl) continue; + m_uid_to_decl[member->getSymIndexId()] = decl; + auto offset = member->getOffset() * 8; if (location_type == PDB_LocType::BitField) offset += member->getBitPosition(); @@ -789,10 +1139,16 @@ break; } - case PDB_DataKind::StaticMember: - ClangASTContext::AddVariableToRecordType(record_type, member_name.c_str(), - member_comp_type, access); + case PDB_DataKind::StaticMember: { + auto decl = ClangASTContext::AddVariableToRecordType( + record_type, member_name.c_str(), member_comp_type, access); + if (!decl) + continue; + + m_uid_to_decl[member->getSymIndexId()] = decl; + break; + } default: llvm_unreachable("unsupported PDB data kind"); } @@ -829,12 +1185,12 @@ base_comp_type.GetOpaqueQualType(), access, is_virtual, record_kind == clang::TTK_Class); if (!base_class_spec) - continue; + continue; base_classes.push_back(base_class_spec); if (is_virtual) - continue; + continue; auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType()); if (!decl) @@ -852,15 +1208,16 @@ } } -void PDBASTParser::AddRecordMethods( - lldb_private::SymbolFile &symbol_file, - lldb_private::CompilerType &record_type, - PDBFuncSymbolEnumerator &methods_enum) const { +void PDBASTParser::AddRecordMethods(lldb_private::SymbolFile &symbol_file, + lldb_private::CompilerType &record_type, + PDBFuncSymbolEnumerator &methods_enum) { while (auto method = methods_enum.getNext()) { + auto name = PDBNameDropScope(method->getName().c_str()); + auto method_type = symbol_file.ResolveTypeUID(method->getSymIndexId()); // MSVC specific __vecDelDtor. if (!method_type) - break; + continue; auto method_comp_type = method_type->GetFullCompilerType(); if (!method_comp_type.GetCompleteType()) { @@ -873,13 +1230,17 @@ } // TODO: get mangled name for the method. - m_ast.AddMethodToCXXRecordType( - record_type.GetOpaqueQualType(), method->getName().c_str(), + auto decl = m_ast.AddMethodToCXXRecordType( + record_type.GetOpaqueQualType(), name.c_str(), /*mangled_name*/ nullptr, method_comp_type, TranslateMemberAccess(method->getAccess()), method->isVirtual(), method->isStatic(), method->hasInlineAttribute(), /*is_explicit*/ false, // FIXME: Need this field in CodeView. /*is_attr_used*/ false, /*is_artificial*/ method->isCompilerGenerated()); + if (!decl) + continue; + + m_uid_to_decl[method->getSymIndexId()] = decl; } } Index: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -179,8 +179,9 @@ const llvm::pdb::PDBSymbolCompiland &pdb_compiland, llvm::DenseMap &index_map) const; - void FindTypesByName(const std::string &name, uint32_t max_matches, - lldb_private::TypeMap &types); + void FindTypesByName(const std::string &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, lldb_private::TypeMap &types); std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data); Index: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -551,8 +551,7 @@ llvm::dyn_cast_or_null(type_system); if (!clang_type_system) return nullptr; - PDBASTParser *pdb = - llvm::dyn_cast(clang_type_system->GetPDBParser()); + PDBASTParser *pdb = clang_type_system->GetPDBParser(); if (!pdb) return nullptr; @@ -579,8 +578,7 @@ if (!clang_ast_ctx) return false; - PDBASTParser *pdb = - llvm::dyn_cast(clang_ast_ctx->GetPDBParser()); + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); if (!pdb) return false; @@ -588,24 +586,83 @@ } lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) { - return lldb_private::CompilerDecl(); + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDecl(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDecl(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDecl(); + + auto decl = pdb->GetDeclForSymbol(*symbol); + if (!decl) + return CompilerDecl(); + + return CompilerDecl(clang_ast_ctx, decl); } lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) { - // PDB always uses the translation unit decl context for everything. We can - // improve this later but it's not easy because PDB doesn't provide a high - // enough level of type fidelity in this area. - return *m_tu_decl_ctx_up; + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDeclContext(); + + auto decl_context = pdb->GetDeclContextForSymbol(*symbol); + if (!decl_context) + return GetDeclContextContainingUID(uid); + + return CompilerDeclContext(clang_ast_ctx, decl_context); } lldb_private::CompilerDeclContext SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { - return *m_tu_decl_ctx_up; + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + auto symbol = m_session_up->getSymbolById(uid); + if (!symbol) + return CompilerDeclContext(); + + auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol); + assert(decl_context); + + return CompilerDeclContext(clang_ast_ctx, decl_context); } void SymbolFilePDB::ParseDeclsForContext( - lldb_private::CompilerDeclContext decl_ctx) {} + lldb_private::CompilerDeclContext decl_ctx) { + ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null( + GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return; + + PDBASTParser *pdb = clang_ast_ctx->GetPDBParser(); + if (!pdb) + return; + + pdb->ParseDeclsForDeclContext( + static_cast(decl_ctx.GetOpaqueDeclContext())); +} uint32_t SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, @@ -876,7 +933,7 @@ if (scope == eValueTypeVariableLocal) { if (sc.function) { context_scope = sc.function->GetBlock(true).FindBlockByID( - pdb_data.getClassParentId()); + pdb_data.getLexicalParentId()); if (context_scope == nullptr) context_scope = sc.function; } @@ -973,14 +1030,14 @@ const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) { + if (!parent_decl_ctx) + parent_decl_ctx = m_tu_decl_ctx_up.get(); if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return 0; if (name.IsEmpty()) return 0; - auto results = - m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(), - PDB_NameSearchFlags::NS_CaseSensitive); + auto results = m_global_scope_up->findAllChildren(); if (!results) return 0; @@ -1000,6 +1057,15 @@ if (sc.comp_unit == nullptr) continue; + if (!name.GetStringRef().equals( + PDBASTParser::PDBNameDropScope(pdb_data->getName()))) + continue; + + auto actual_parent_decl_ctx = + GetDeclContextContainingUID(result->getSymIndexId()); + if (actual_parent_decl_ctx != *parent_decl_ctx) + continue; + ParseVariables(sc, *pdb_data, &variables); matches = variables.GetSize() - old_size; } @@ -1275,7 +1341,7 @@ std::string name_str = name.AsCString(); // There is an assumption 'name' is not a regex - FindTypesByName(name_str, max_matches, types); + FindTypesByName(name_str, parent_decl_ctx, max_matches, types); return types.GetSize(); } @@ -1335,14 +1401,16 @@ } } -void SymbolFilePDB::FindTypesByName(const std::string &name, - uint32_t max_matches, - lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypesByName( + const std::string &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, + uint32_t max_matches, lldb_private::TypeMap &types) { + if (!parent_decl_ctx) + parent_decl_ctx = m_tu_decl_ctx_up.get(); std::unique_ptr results; if (name.empty()) return; - results = m_global_scope_up->findChildren(PDB_SymType::None, name, - PDB_NameSearchFlags::NS_Default); + results = m_global_scope_up->findAllChildren(PDB_SymType::None); if (!results) return; @@ -1351,6 +1419,11 @@ while (auto result = results->getNext()) { if (max_matches > 0 && matches >= max_matches) break; + + if (PDBASTParser::PDBNameDropScope(result->getRawSymbol().getName()) != + name) + continue; + switch (result->getSymTag()) { case PDB_SymType::Enum: case PDB_SymType::UDT: @@ -1367,6 +1440,11 @@ if (!ResolveTypeUID(result->getSymIndexId())) continue; + auto actual_parent_decl_ctx = + GetDeclContextContainingUID(result->getSymIndexId()); + if (actual_parent_decl_ctx != *parent_decl_ctx) + continue; + auto iter = m_types.find(result->getSymIndexId()); if (iter == m_types.end()) continue; @@ -1477,7 +1555,27 @@ const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) { - return lldb_private::CompilerDeclContext(); + auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + auto clang_type_system = llvm::dyn_cast_or_null(type_system); + if (!clang_type_system) + return CompilerDeclContext(); + + PDBASTParser *pdb = clang_type_system->GetPDBParser(); + if (!pdb) + return CompilerDeclContext(); + + clang::DeclContext *decl_context = nullptr; + if (parent_decl_ctx) + decl_context = static_cast( + parent_decl_ctx->GetOpaqueDeclContext()); + + auto namespace_decl = + pdb->FindNamespaceDecl(decl_context, name.GetStringRef()); + if (!namespace_decl) + return CompilerDeclContext(); + + return CompilerDeclContext(type_system, + static_cast(namespace_decl)); } lldb_private::ConstString SymbolFilePDB::GetPluginName() { Index: lldb/trunk/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp +++ lldb/trunk/source/Symbol/ClangASTContext.cpp @@ -2212,6 +2212,9 @@ false); // IsFixed if (enum_decl) { + if (decl_ctx) + decl_ctx->addDecl(enum_decl); + // TODO: check if we should be setting the promotion type too? enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type)); @@ -4739,6 +4742,8 @@ decl->setAccess(clang::AS_public); // TODO respect proper access specifier + decl_ctx->addDecl(decl); + // Get a uniqued clang::QualType for the typedef decl type return CompilerType(clang_ast, clang_ast->getTypedefType(decl)); } @@ -7746,6 +7751,15 @@ return qual_type->getAsTagDecl(); } +clang::TypedefNameDecl * +ClangASTContext::GetAsTypedefDecl(const CompilerType &type) { + const clang::TypedefType *typedef_type = + llvm::dyn_cast(ClangUtil::GetQualType(type)); + if (typedef_type) + return typedef_type->getDecl(); + return nullptr; +} + clang::CXXRecordDecl * ClangASTContext::GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type) { return GetCanonicalQualType(type)->getAsCXXRecordDecl(); @@ -8831,7 +8845,7 @@ return false; } -bool ClangASTContext::AddEnumerationValueToEnumerationType( +clang::EnumConstantDecl *ClangASTContext::AddEnumerationValueToEnumerationType( lldb::opaque_compiler_type_t type, const CompilerType &enumerator_clang_type, const Declaration &decl, const char *name, int64_t enum_value, uint32_t enum_value_bit_size) { @@ -8863,12 +8877,12 @@ VerifyDecl(enumerator_decl); #endif - return true; + return enumerator_decl; } } } } - return false; + return nullptr; } CompilerType Index: lldb/trunk/tools/lldb-test/lldb-test.cpp =================================================================== --- lldb/trunk/tools/lldb-test/lldb-test.cpp +++ lldb/trunk/tools/lldb-test/lldb-test.cpp @@ -148,6 +148,10 @@ return Result; } +static cl::opt DumpAST("dump-ast", + cl::desc("Dump AST restored from symbols."), + cl::sub(SymbolsSubcommand)); + static cl::opt Verify("verify", cl::desc("Verify symbol information."), cl::sub(SymbolsSubcommand)); @@ -165,6 +169,7 @@ static Error findTypes(lldb_private::Module &Module); static Error findVariables(lldb_private::Module &Module); static Error dumpModule(lldb_private::Module &Module); +static Error dumpAST(lldb_private::Module &Module); static Error verify(lldb_private::Module &Module); static Expected getAction(); @@ -509,6 +514,34 @@ return Error::success(); } +Error opts::symbols::dumpAST(lldb_private::Module &Module) { + SymbolVendor &plugin = *Module.GetSymbolVendor(); + + auto symfile = plugin.GetSymbolFile(); + if (!symfile) + return make_string_error("Module has no symbol file."); + + auto clang_ast_ctx = llvm::dyn_cast_or_null( + symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus)); + if (!clang_ast_ctx) + return make_string_error("Can't retrieve Clang AST context."); + + auto ast_ctx = clang_ast_ctx->getASTContext(); + if (!ast_ctx) + return make_string_error("Can't retrieve AST context."); + + auto tu = ast_ctx->getTranslationUnitDecl(); + if (!tu) + return make_string_error("Can't retrieve translation unit declaration."); + + symfile->ParseDeclsForContext(CompilerDeclContext( + clang_ast_ctx, static_cast(tu))); + + tu->print(outs()); + + return Error::success(); +} + Error opts::symbols::verify(lldb_private::Module &Module) { SymbolVendor &plugin = *Module.GetSymbolVendor(); @@ -562,6 +595,10 @@ } Expected opts::symbols::getAction() { + if (Verify && DumpAST) + return make_string_error( + "Cannot both verify symbol information and dump AST."); + if (Verify) { if (Find != FindType::None) return make_string_error( @@ -574,6 +611,18 @@ return verify; } + if (DumpAST) { + if (Find != FindType::None) + return make_string_error( + "Cannot both search and dump AST."); + if (Regex || !Context.empty() || !Name.empty() || !File.empty() || + Line != 0) + return make_string_error( + "-regex, -context, -name, -file and -line options are not " + "applicable for dumping AST."); + return dumpAST; + } + if (Regex && !Context.empty()) return make_string_error( "Cannot search using both regular expressions and context."); @@ -632,6 +681,8 @@ "using line numbers."); return findVariables; } + + llvm_unreachable("Unsupported symbol action."); } int opts::symbols::dumpSymbols(Debugger &Dbg) {