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

Reply via email to