zturner created this revision. zturner added reviewers: aleksandr.urakov, labath, lemo. Herald added subscribers: erik.pilkington, mgorny.
Previously we were not able to accurately represent tag record types with clang record decls. The primary reason for this is that for type information PDB only contains fully instantiated type names. It does not contain rich information about namespaces, declaration contexts (e.g. parent classes, function scopes for local classes, etc), template parameters, or anything else. All you have is a big long string that is a fully instantiated type name. What it does give you, however, is the mangled name of this type. So we can extract all of the relevant information (minus the distinction between outer class and outer namespace) from the mangled name. This patch is the start of this effort. It uses LLVM's demangler to demangle the name, and treat each component as one component of a namespace chain. Obviously this is not true in the general case, as something like `Foo<int>::Bar(double)::`1'::LocalClass<7>::NestedClass` will get treated as if it were in a series of namespaces. However, it's a good start, and clang doesn't actually care for most uses. So we can improve on this incrementally with subsequent patches to make this more accurate. https://reviews.llvm.org/D54053 Files: lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.cpp lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.h lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -175,7 +175,8 @@ lldb::TypeSP CreateProcedureType(PdbSymUid type_uid, const llvm::codeview::ProcedureRecord &pr); lldb::TypeSP - CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size, + CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, + llvm::StringRef unique_name, size_t size, clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance); Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -51,6 +51,7 @@ #include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h" +#include "MangledAST.h" #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -731,27 +732,11 @@ } lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( - PdbSymUid type_uid, llvm::StringRef name, size_t size, - clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) { + PdbSymUid type_uid, llvm::StringRef name, llvm::StringRef unique_name, + size_t size, clang::TagTypeKind ttk, + clang::MSInheritanceAttr::Spelling inheritance) { - // Ignore unnamed-tag UDTs. - name = DropNameScope(name); - if (name.empty()) - return nullptr; - - clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl(); - - lldb::AccessType access = - (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; - - ClangASTMetadata metadata; - metadata.SetUserID(type_uid.toOpaqueId()); - metadata.SetIsDynamicCXXType(false); - - CompilerType ct = - m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk, - lldb::eLanguageTypeC_plus_plus, &metadata); - lldbassert(ct.IsValid()); + CompilerType ct = CreateClangDeclFromMangledName(*m_clang, unique_name); clang::CXXRecordDecl *record_decl = m_clang->GetAsCXXRecordDecl(ct.GetOpaqueQualType()); @@ -771,7 +756,7 @@ // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. Declaration decl; return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(), - ConstString(name), size, nullptr, + ct.GetTypeName(), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::eResolveStateForward); } @@ -782,14 +767,15 @@ clang::MSInheritanceAttr::Spelling inheritance = GetMSInheritance(m_index->tpi().typeCollection(), cr); - return CreateClassStructUnion(type_uid, cr.getName(), cr.getSize(), ttk, - inheritance); + return CreateClassStructUnion(type_uid, cr.getName(), cr.getUniqueName(), + cr.getSize(), ttk, inheritance); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid, const UnionRecord &ur) { return CreateClassStructUnion( - type_uid, ur.getName(), ur.getSize(), clang::TTK_Union, + type_uid, ur.getName(), ur.getUniqueName(), ur.getSize(), + clang::TTK_Union, clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance); } Index: lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.h =================================================================== --- /dev/null +++ lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.h @@ -0,0 +1,30 @@ +//===-- MangledAST.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H + +namespace clang { +class TagDecl; +} // namespace clang + +namespace llvm { +class StringRef; +} + +namespace lldb_private { +class ClangASTContext; +class CompilerType; +namespace npdb { +CompilerType CreateClangDeclFromMangledName(ClangASTContext &clang, + llvm::StringRef mangled); +} // namespace npdb +} // namespace lldb_private + +#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H Index: lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.cpp @@ -0,0 +1,90 @@ +//===-- MangledAST.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MangledAST.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/MicrosoftDemangle.h" +#include "llvm/Demangle/MicrosoftDemangleNodes.h" +#include "llvm/Demangle/StringView.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::ms_demangle; + +static std::string render(const Node &node) { + OutputStream OS; + initializeOutputStream(nullptr, nullptr, OS, 1024); + node.output(OS, OF_Default); + OS << '\0'; + return {OS.getBuffer()}; +} + +static clang::TagTypeKind TranslateTagKind(TagKind tk) { + switch (tk) { + case TagKind::Class: + return clang::TagTypeKind::TTK_Class; + case TagKind::Enum: + return clang::TagTypeKind::TTK_Enum; + case TagKind::Struct: + return clang::TagTypeKind::TTK_Struct; + case TagKind::Union: + return clang::TagTypeKind::TTK_Union; + } + llvm_unreachable("Unreachable!"); +} + +static clang::DeclContext *CreateDeclContext(ClangASTContext &clang, + llvm::ArrayRef<Node *> scope) { + clang::DeclContext *decl_context = clang.GetTranslationUnitDecl(); + if (scope.empty()) + return decl_context; + + clang::DeclContext *top_level_decl = decl_context; + // For now we're just going to pretend that each component of the scope is a + // namespace. This isn't actually true, as they could be functions, nested + // classes with template parameters, or many other things. But it's a nice + // simplifying assumption that lets us make incremental progress while keeping + // things simple. + for (Node *ns : scope) { + std::string name = render(*ns); + decl_context = + clang.GetUniqueNamespaceDeclaration(name.c_str(), decl_context); + } + return decl_context; +} + +CompilerType +lldb_private::npdb::CreateClangDeclFromMangledName(ClangASTContext &clang, + llvm::StringRef mangled) { + StringView sv(mangled.data(), mangled.size()); + Demangler demangler; + TagTypeNode *ttn = demangler.parseTagUniqueName(sv); + if (!ttn) + return CompilerType{}; + + NodeArrayNode &name_components = *ttn->QualifiedName->Components; + llvm::ArrayRef<Node *> components(name_components.Nodes, + name_components.Count); + + lldb::AccessType access = + (ttn->Tag == TagKind::Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; + + std::string name = render(*components.back()); + + llvm::ArrayRef<Node *> scope = components.drop_back(); + clang::TagTypeKind ttk = TranslateTagKind(ttn->Tag); + clang::DeclContext *decl_context = CreateDeclContext(clang, scope); + return clang.CreateRecordType(decl_context, access, name.c_str(), ttk, + lldb::eLanguageTypeC_plus_plus, nullptr); +} Index: lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN CompileUnitIndex.cpp + MangledAST.cpp PdbIndex.cpp PdbUtil.cpp SymbolFileNativePDB.cpp Index: lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp =================================================================== --- lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp +++ lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp @@ -81,31 +81,23 @@ // classes nested in namespaces and inner classes -// FIXME: LLDB with native pdb plugin doesn't currently resolve nested names -// correctly, because it requires creating clang::NamespaceDecl or -// clang::RecordDecl for the outer namespace or classes. PDB doesn't contain -// sufficient information to distinguish namespace scopes from nested class -// scopes, so the best we can hope for is a heuristic reconstruction of the -// clang AST based on demangling the type's unique name. However, this is -// as-yet unimplemented in the native PDB plugin, so for now all of these will -// all just look like `S` when LLDB prints them. auto e = &three<A::B::S*, B::A::S*, A::C::S&>; -// CHECK: (S *(*)(S *, S &)) e = {{.*}} +// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}} auto f = &three<A::C::S&, A::B::S*, B::A::S*>; -// CHECK: (S &(*)(S *, S *)) f = {{.*}} +// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}} auto g = &three<B::A::S*, A::C::S&, A::B::S*>; -// CHECK: (S *(*)(S &, S *)) g = {{.*}} +// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}} // parameter types that are themselves template instantiations. auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>; // Note the awkward space in TC<TC<int> >. This is because this is how template // instantiations are emitted by the compiler, as the fully instantiated name. // Only via reconstruction of the AST through the mangled type name (see above // comment) can we hope to do better than this). -// CHECK: (TC<void> (*)(TC<int>, TC<TC<int> >, S>)) h = {{.*}} +// CHECK: (TC<void> (*)(TC<int>, TC<struct TC<int>>, TC<struct A::B::S>)) h = {{.*}} auto i = &nullary<A::B::S>; -// CHECK: (S (*)()) i = {{.*}} +// CHECK: (A::B::S (*)()) i = {{.*}} // Make sure we can handle types that don't have complete debug info.
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits