This revision was automatically updated to reflect the committed changes.
Closed by commit rL346429: [NativePDB] Higher fidelity reconstruction of AST 
from Debug Info. (authored by zturner, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D54216?vs=172989&id=173198#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D54216

Files:
  lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
  lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
  lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
  lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
  lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
  lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h

Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
===================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -429,6 +429,10 @@
     return (Options & ClassOptions::ForwardReference) != ClassOptions::None;
   }
 
+  bool containsNestedClass() const {
+    return (Options & ClassOptions::ContainsNestedClass) != ClassOptions::None;
+  }
+
   bool isScoped() const {
     return (Options & ClassOptions::Scoped) != ClassOptions::None;
   }
Index: lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
@@ -0,0 +1,131 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test various interesting cases for AST reconstruction.
+// RUN: clang-cl /Z7 /GS- /GR- /c /Fo%t.obj -- %s
+// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
+// RUN:     %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck %s
+
+// Test trivial versions of each tag type.
+class TrivialC {};
+struct TrivialS {};
+union TrivialU {};
+enum TrivialE {TE_A};
+
+// Test reconstruction of DeclContext hierarchies.
+namespace A {
+  namespace B {
+    template<typename T>
+    struct C {
+      T ABCMember;
+    };
+
+    // Let's try a template specialization with a different implementation
+    template<>
+    struct C<void> {
+      void *ABCSpecializationMember;
+    };
+  }
+
+  // Let's make sure we can distinguish classes and namespaces.  Also let's try
+  // a non-type template parameter.
+  template<int N>
+  struct C {
+    class D {
+      int ACDMember = 0;
+      C<N - 1> *CPtr = nullptr;
+    };
+  };
+
+  struct D {
+    // Let's make a nested class with the same name as another nested class
+    // elsewhere, and confirm that they appear in the right DeclContexts in
+    // the AST.
+    struct E {
+      int ADDMember;
+    };
+  };
+}
+
+
+// Let's try an anonymous namespace.
+namespace {
+  template<typename T>
+  struct Anonymous {
+    int AnonymousMember;
+    // And a nested class within an anonymous namespace
+    struct D {
+      int AnonymousDMember;
+    };
+  };
+}
+
+TrivialC TC;
+TrivialS TS;
+TrivialU TU;
+TrivialE TE;
+
+A::B::C<int> ABCInt;
+A::B::C<float> ABCFloat;
+A::B::C<void> ABCVoid;
+
+A::C<0> AC0;
+A::C<-1> ACNeg1;
+
+A::C<0>::D AC0D;
+A::C<-1>::D ACNeg1D;
+A::D AD;
+A::D::E ADE;
+
+// FIXME: Anonymous namespaces aren't working correctly.
+Anonymous<int> AnonInt;
+Anonymous<A::B::C<void>> AnonABCVoid;
+Anonymous<A::B::C<int>>::D AnonABCVoidD;
+
+// FIXME: Enum size isn't being correctly determined.
+// FIXME: Can't read memory for variable values.
+
+// CHECK: (TrivialC) TC = {}
+// CHECK: (TrivialS) TS = {}
+// CHECK: (TrivialU) TU = {}
+// CHECK: (TrivialE) TE = <Unable to determine byte size.>
+// CHECK: (A::B::C<int>) ABCInt = (ABCMember = <read memory from {{.*}} failed>)
+// CHECK: (A::B::C<float>) ABCFloat = (ABCMember = <read memory from {{.*}} failed>)
+// CHECK: (A::B::C<void>) ABCVoid = (ABCSpecializationMember = <read memory from {{.*}} failed>)
+// CHECK: (A::C<0>) AC0 = {}
+// CHECK: (A::C<-1>) ACNeg1 = {}
+// CHECK: (A::C<0>::D) AC0D = (ACDMember = <read memory from {{.*}} failed>, CPtr = <read memory from {{.*}} failed>)
+// CHECK: (A::C<-1>::D) ACNeg1D = (ACDMember = <read memory from {{.*}} failed>, CPtr = <read memory from {{.*}} failed>)
+// CHECK: (A::D) AD = {}
+// CHECK: (A::D::E) ADE = (ADDMember = <read memory from {{.*}} failed>)
+// CHECK: Dumping clang ast for 1 modules.
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class TrivialC definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TrivialS definition
+// CHECK: |-CXXRecordDecl {{.*}} union TrivialU definition
+// CHECK: |-EnumDecl {{.*}} TrivialE
+// CHECK: |-NamespaceDecl {{.*}} A
+// CHECK: | |-NamespaceDecl {{.*}} B
+// CHECK: | | |-CXXRecordDecl {{.*}} struct C<int> definition
+// CHECK: | | | `-FieldDecl {{.*}} ABCMember 'int'
+// CHECK: | | |-CXXRecordDecl {{.*}} struct C<float> definition
+// CHECK: | | | `-FieldDecl {{.*}} ABCMember 'float'
+// CHECK: | | `-CXXRecordDecl {{.*}} struct C<void> definition
+// CHECK: | |   `-FieldDecl {{.*}} ABCSpecializationMember 'void *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<0> definition
+// CHECK: | | `-CXXRecordDecl {{.*}} class D definition
+// CHECK: | |   |-FieldDecl {{.*}} ACDMember 'int'
+// CHECK: | |   `-FieldDecl {{.*}} CPtr 'A::C<-1> *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<-1> definition
+// CHECK: | | `-CXXRecordDecl {{.*}} class D definition
+// CHECK: | |   |-FieldDecl {{.*}} ACDMember 'int'
+// CHECK: | |   `-FieldDecl {{.*}} CPtr 'A::C<-2> *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<-2>
+// CHECK: | `-CXXRecordDecl {{.*}} struct D definition
+// CHECK: |   `-CXXRecordDecl {{.*}} struct E definition
+// CHECK: |     `-FieldDecl {{.*}} ADDMember 'int'
+
+int main(int argc, char **argv) {
+  return 0;
+}
\ No newline at end of file
Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
@@ -2,7 +2,7 @@
 // REQUIRES: lld
 
 // Test that we can display function signatures with class types.
-// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: clang-cl /Z7 /GS- /GR- /c -fstandalone-debug -Xclang -fkeep-static-consts /Fo%t.obj -- %s
 // RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
 // RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
 // RUN:     %p/Inputs/function-types-classes.lldbinit | FileCheck %s
@@ -66,6 +66,13 @@
   };
 };
 
+// clang (incorrectly) doesn't emit debug information for outer classes
+// unless they are instantiated.  They should also be emitted if there
+// is an inner class which is instantiated.
+A::C ForceInstantiateAC;
+B ForceInstantiateB;
+B::A ForceInstantiateBA;
+
 template<typename T>
 struct TC {};
 
@@ -81,38 +88,45 @@
 
 // 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.
 struct Incomplete;
 auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
 // CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}}
 
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class C definition
+// CHECK: |-CXXRecordDecl {{.*}} union U definition
+// CHECK: |-EnumDecl {{.*}} E
+// CHECK: |-CXXRecordDecl {{.*}} struct S definition
+// CHECK: |-CXXRecordDecl {{.*}} struct B
+// CHECK: | |-CXXRecordDecl {{.*}} struct A
+// CHECK: | | |-CXXRecordDecl {{.*}} struct S
+// CHECK: |-NamespaceDecl {{.*}} A
+// CHECK: | |-CXXRecordDecl {{.*}} struct C
+// CHECK: | | |-CXXRecordDecl {{.*}} struct S
+// CHECK: | `-NamespaceDecl {{.*}} B
+// CHECK: |   `-CXXRecordDecl {{.*}} struct S definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<int> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct TC<int>> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct A::B::S> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<void> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct Incomplete
+
 int main(int argc, char **argv) {
   return 0;
 }
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
@@ -9,4 +9,6 @@
 target variable i
 target variable incomplete
 
+target modules dump ast
+
 quit
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
@@ -11,4 +11,6 @@
 target variable -T PointersInstance
 target variable -T ReferencesInstance
 
+target modules dump ast
+
 quit
\ No newline at end of file
Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
@@ -0,0 +1,20 @@
+target variable TC
+target variable TS
+target variable TU
+target variable TE
+
+target variable ABCInt
+target variable ABCFloat
+target variable ABCVoid
+
+target variable AC0
+target variable ACNeg1
+
+target variable AC0D
+target variable ACNeg1D
+target variable AD
+target variable ADE
+
+target modules dump ast
+
+quit
Index: lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
===================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
+++ lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
@@ -270,6 +270,94 @@
 // CHECK-NEXT:   (long long &) m = {{.*}}
 // CHECK-NEXT: }
 
+// CHECK: Dumping clang ast for 1 modules.
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class ClassWithPadding definition
+// CHECK: | |-FieldDecl {{.*}} a 'char'
+// CHECK: | |-FieldDecl {{.*}} b 'short'
+// CHECK: | |-FieldDecl {{.*}} c 'char [2]'
+// CHECK: | |-FieldDecl {{.*}} d 'int'
+// CHECK: | |-FieldDecl {{.*}} e 'char'
+// CHECK: | |-FieldDecl {{.*}} f 'int'
+// CHECK: | |-FieldDecl {{.*}} g 'long long'
+// CHECK: | |-FieldDecl {{.*}} h 'char [3]'
+// CHECK: | |-FieldDecl {{.*}} i 'long long'
+// CHECK: | |-FieldDecl {{.*}} j 'char [2]'
+// CHECK: | |-FieldDecl {{.*}} k 'long long'
+// CHECK: | |-FieldDecl {{.*}} l 'char'
+// CHECK: | `-FieldDecl {{.*}} m 'long long'
+// CHECK: |-CXXRecordDecl {{.*}} class ClassNoPadding definition
+// CHECK: | |-FieldDecl {{.*}} a 'unsigned char'
+// CHECK: | |-FieldDecl {{.*}} b 'char'
+// CHECK: | |-FieldDecl {{.*}} c 'bool'
+// CHECK: | |-FieldDecl {{.*}} d 'bool'
+// CHECK: | |-FieldDecl {{.*}} e 'short'
+// CHECK: | |-FieldDecl {{.*}} f 'unsigned short'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned int'
+// CHECK: | |-FieldDecl {{.*}} h 'int'
+// CHECK: | |-FieldDecl {{.*}} i 'unsigned long'
+// CHECK: | |-FieldDecl {{.*}} j 'long'
+// CHECK: | |-FieldDecl {{.*}} k 'float'
+// CHECK: | |-FieldDecl {{.*}} l 'EnumType'
+// CHECK: | |-FieldDecl {{.*}} m 'double'
+// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long'
+// CHECK: | |-FieldDecl {{.*}} o 'long long'
+// CHECK: | `-FieldDecl {{.*}} p 'int [5]'
+// CHECK: |-EnumDecl {{.*}} EnumType
+// CHECK: | |-EnumConstantDecl {{.*}} A 'unsigned int'
+// CHECK: | `-EnumConstantDecl {{.*}} B 'unsigned int'
+// CHECK: |-CXXRecordDecl {{.*}} struct DerivedClass definition
+// CHECK: | |-public 'BaseClass<int>'
+// CHECK: | `-FieldDecl {{.*}} DerivedMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<int> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct EBO definition
+// CHECK: | |-public 'EmptyBase'
+// CHECK: | `-FieldDecl {{.*}} Member 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct EmptyBase definition
+// CHECK: |-CXXRecordDecl {{.*}} struct PaddedBases definition
+// CHECK: | |-public 'BaseClass<char>'
+// CHECK: | |-public 'BaseClass<short>'
+// CHECK: | |-public 'BaseClass<int>'
+// CHECK: | `-FieldDecl {{.*}} DerivedMember 'long long'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<char> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<short> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct <unnamed-type-UnnamedClassInstance> definition
+// CHECK: | |-FieldDecl {{.*}} x 'int'
+// CHECK: | `-FieldDecl {{.*}} EBOC 'EBO'
+// CHECK: |-CXXRecordDecl {{.*}} struct Pointers definition
+// CHECK: | |-FieldDecl {{.*}} a 'void *'
+// CHECK: | |-FieldDecl {{.*}} b 'char *'
+// CHECK: | |-FieldDecl {{.*}} c 'bool *'
+// CHECK: | |-FieldDecl {{.*}} e 'short *'
+// CHECK: | |-FieldDecl {{.*}} f 'unsigned short *'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned int *'
+// CHECK: | |-FieldDecl {{.*}} h 'int *'
+// CHECK: | |-FieldDecl {{.*}} i 'unsigned long *'
+// CHECK: | |-FieldDecl {{.*}} j 'long *'
+// CHECK: | |-FieldDecl {{.*}} k 'float *'
+// CHECK: | |-FieldDecl {{.*}} l 'EnumType *'
+// CHECK: | |-FieldDecl {{.*}} m 'double *'
+// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long *'
+// CHECK: | `-FieldDecl {{.*}} o 'long long *'
+// CHECK: |-CXXRecordDecl {{.*}} struct References definition
+// CHECK: | |-FieldDecl {{.*}} a 'char &'
+// CHECK: | |-FieldDecl {{.*}} b 'bool &'
+// CHECK: | |-FieldDecl {{.*}} c 'short &'
+// CHECK: | |-FieldDecl {{.*}} d 'unsigned short &'
+// CHECK: | |-FieldDecl {{.*}} e 'unsigned int &'
+// CHECK: | |-FieldDecl {{.*}} f 'int &'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned long &'
+// CHECK: | |-FieldDecl {{.*}} h 'long &'
+// CHECK: | |-FieldDecl {{.*}} i 'float &'
+// CHECK: | |-FieldDecl {{.*}} j 'EnumType &'
+// CHECK: | |-FieldDecl {{.*}} k 'double &'
+// CHECK: | |-FieldDecl {{.*}} l 'unsigned long long &'
+// CHECK: | `-FieldDecl {{.*}} m 'long long &'
+// CHECK: `-<undeserialized declarations>
+
 int main(int argc, char **argv) {
   return 0;
 }
\ No newline at end of file
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -13,14 +13,57 @@
 #include "lldb/lldb-enumerations.h"
 
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 
 #include <tuple>
 #include <utility>
 
 namespace lldb_private {
 namespace npdb {
 
+struct CVTagRecord {
+  enum Kind { Class, Struct, Union, Enum };
+
+  static CVTagRecord create(llvm::codeview::CVType type);
+
+  Kind kind() const { return m_kind; }
+
+  const llvm::codeview::TagRecord &asTag() const {
+    if (m_kind == Struct || m_kind == Class)
+      return cvclass;
+    if (m_kind == Enum)
+      return cvenum;
+    return cvunion;
+  }
+
+  const llvm::codeview::ClassRecord &asClass() const {
+    assert(m_kind == Struct || m_kind == Class);
+    return cvclass;
+  }
+
+  const llvm::codeview::EnumRecord &asEnum() const {
+    assert(m_kind == Enum);
+    return cvenum;
+  }
+
+  const llvm::codeview::UnionRecord &asUnion() const {
+    assert(m_kind == Union);
+    return cvunion;
+  }
+
+private:
+  CVTagRecord(llvm::codeview::ClassRecord &&c);
+  CVTagRecord(llvm::codeview::UnionRecord &&u);
+  CVTagRecord(llvm::codeview::EnumRecord &&e);
+  Kind m_kind;
+  union {
+    llvm::codeview::ClassRecord cvclass;
+    llvm::codeview::EnumRecord cvenum;
+    llvm::codeview::UnionRecord cvunion;
+  };
+};
+
 struct SegmentOffset {
   SegmentOffset() = default;
   SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {}
@@ -56,6 +99,7 @@
 }
 
 bool IsForwardRefUdt(llvm::codeview::CVType cvt);
+bool IsTagRecord(llvm::codeview::CVType cvt);
 
 lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
 llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -162,6 +162,11 @@
   void DumpClangAST(Stream &s) override;
 
 private:
+  std::pair<clang::DeclContext *, std::string>
+  CreateDeclInfoForType(const llvm::codeview::TagRecord &record,
+                        llvm::codeview::TypeIndex ti);
+
+  void PreprocessTpiStream();
   size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches,
                          TypeMap &types);
 
@@ -180,10 +185,9 @@
                                const llvm::codeview::ArrayRecord &ar);
   lldb::TypeSP CreateProcedureType(PdbSymUid type_uid,
                                    const llvm::codeview::ProcedureRecord &pr);
-  lldb::TypeSP
-  CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
-                         clang::TagTypeKind ttk,
-                         clang::MSInheritanceAttr::Spelling inheritance);
+  lldb::TypeSP CreateClassStructUnion(
+      PdbSymUid type_uid, const llvm::codeview::TagRecord &record, size_t size,
+      clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance);
 
   lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid,
                                        const SymbolContext &sc);
@@ -209,6 +213,8 @@
   llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status;
 
   llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl;
+  llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
+      m_parent_types;
 
   llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars;
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -21,6 +21,38 @@
 using namespace llvm::codeview;
 using namespace llvm::pdb;
 
+CVTagRecord CVTagRecord::create(CVType type) {
+  assert(IsTagRecord(type) && "type is not a tag record!");
+  switch (type.kind()) {
+  case LF_CLASS:
+  case LF_STRUCTURE:
+  case LF_INTERFACE: {
+    ClassRecord cr;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
+    return CVTagRecord(std::move(cr));
+  }
+  case LF_UNION: {
+    UnionRecord ur;
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
+    return CVTagRecord(std::move(ur));
+  }
+  case LF_ENUM: {
+    EnumRecord er;
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
+    return CVTagRecord(std::move(er));
+  }
+  default:
+    llvm_unreachable("Unreachable!");
+  }
+}
+
+CVTagRecord::CVTagRecord(ClassRecord &&c)
+    : cvclass(std::move(c)),
+      m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
+CVTagRecord::CVTagRecord(UnionRecord &&u)
+    : cvunion(std::move(u)), m_kind(Union) {}
+CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
+
 PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
   switch (kind) {
   case S_COMPILE3:
@@ -94,6 +126,8 @@
     return PDB_SymType::Enum;
   case LF_PROCEDURE:
     return PDB_SymType::FunctionSig;
+  case LF_BITFIELD:
+    return PDB_SymType::BuiltinType;
   default:
     lldbassert(false && "Invalid type record kind!");
   }
@@ -306,6 +340,18 @@
   }
 }
 
+bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
+  switch (cvt.kind()) {
+  case LF_CLASS:
+  case LF_STRUCTURE:
+  case LF_UNION:
+  case LF_ENUM:
+    return true;
+  default:
+    return false;
+  }
+}
+
 lldb::AccessType
 lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
   switch (access) {
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -13,13 +13,16 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
 
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/StreamBuffer.h"
+#include "lldb/Core/StreamFile.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ClangASTImporter.h"
 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -43,14 +46,14 @@
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
-
 #include "PdbSymUid.h"
 #include "PdbUtil.h"
 #include "UdtRecordCompleter.h"
@@ -527,9 +530,60 @@
   TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
   m_clang = llvm::dyn_cast_or_null<ClangASTContext>(ts);
   m_importer = llvm::make_unique<ClangASTImporter>();
+
+  PreprocessTpiStream();
   lldbassert(m_clang);
 }
 
+void SymbolFileNativePDB::PreprocessTpiStream() {
+  LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+  for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+    CVType type = types.getType(*ti);
+    if (!IsTagRecord(type))
+      continue;
+
+    CVTagRecord tag = CVTagRecord::create(type);
+    // We're looking for LF_NESTTYPE records in the field list, so ignore
+    // forward references (no field list), and anything without a nested class
+    // (since there won't be any LF_NESTTYPE records).
+    if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass())
+      continue;
+
+    struct ProcessTpiStream : public TypeVisitorCallbacks {
+      ProcessTpiStream(PdbIndex &index, TypeIndex parent,
+                       llvm::DenseMap<TypeIndex, TypeIndex> &parents)
+          : index(index), parents(parents), parent(parent) {}
+
+      PdbIndex &index;
+      llvm::DenseMap<TypeIndex, TypeIndex> &parents;
+      TypeIndex parent;
+
+      llvm::Error visitKnownMember(CVMemberRecord &CVR,
+                                   NestedTypeRecord &Record) override {
+        parents[Record.Type] = parent;
+        CVType child = index.tpi().getType(Record.Type);
+        if (!IsForwardRefUdt(child))
+          return llvm::ErrorSuccess();
+        llvm::Expected<TypeIndex> full_decl =
+            index.tpi().findFullDeclForForwardRef(Record.Type);
+        if (!full_decl) {
+          llvm::consumeError(full_decl.takeError());
+          return llvm::ErrorSuccess();
+        }
+        parents[*full_decl] = parent;
+        return llvm::ErrorSuccess();
+      }
+    };
+
+    CVType field_list = m_index->tpi().getType(tag.asTag().FieldList);
+    ProcessTpiStream process(*m_index, *ti, m_parent_types);
+    llvm::Error error = visitMemberRecordStream(field_list.data(), process);
+    if (error)
+      llvm::consumeError(std::move(error));
+  }
+}
+
 uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
   const DbiModuleList &modules = m_index->dbi().modules();
   uint32_t count = modules.getModuleCount();
@@ -730,16 +784,69 @@
                                 ct, Type::eResolveStateFull);
 }
 
+static std::string RenderDemanglerNode(llvm::ms_demangle::Node *n) {
+  OutputStream OS;
+  initializeOutputStream(nullptr, nullptr, OS, 1024);
+  n->output(OS, llvm::ms_demangle::OF_Default);
+  OS << '\0';
+  return {OS.getBuffer()};
+}
+
+std::pair<clang::DeclContext *, std::string>
+SymbolFileNativePDB::CreateDeclInfoForType(const TagRecord &record,
+                                           TypeIndex ti) {
+  llvm::ms_demangle::Demangler demangler;
+  StringView sv(record.UniqueName.begin(), record.UniqueName.size());
+  llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+  llvm::ms_demangle::IdentifierNode *idn =
+      ttn->QualifiedName->getUnqualifiedIdentifier();
+  std::string uname = RenderDemanglerNode(idn);
+
+  llvm::ms_demangle::NodeArrayNode *name_components =
+      ttn->QualifiedName->Components;
+  llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes,
+                                                   name_components->Count - 1);
+
+  clang::DeclContext *context = m_clang->GetTranslationUnitDecl();
+
+  // If this type doesn't have a parent type in the debug info, then the best we
+  // can do is to say that it's either a series of namespaces (if the scope is
+  // non-empty), or the translation unit (if the scope is empty).
+  auto parent_iter = m_parent_types.find(ti);
+  if (parent_iter == m_parent_types.end()) {
+    if (scopes.empty())
+      return {context, uname};
+
+    for (llvm::ms_demangle::Node *scope : scopes) {
+      auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope);
+      std::string str = RenderDemanglerNode(nii);
+      context = m_clang->GetUniqueNamespaceDeclaration(str.c_str(), context);
+    }
+    return {context, uname};
+  }
+
+  // Otherwise, all we need to do is get the parent type of this type and
+  // recurse into our lazy type creation / AST reconstruction logic to get an
+  // LLDB TypeSP for the parent.  This will cause the AST to automatically get
+  // the right DeclContext created for any parent.
+  TypeSP parent = GetOrCreateType(parent_iter->second);
+  if (!parent)
+    return {context, uname};
+  CompilerType parent_ct = parent->GetForwardCompilerType();
+  clang::QualType qt = ClangUtil::GetCanonicalQualType(parent_ct);
+  context = clang::TagDecl::castToDeclContext(qt->getAsTagDecl());
+  return {context, uname};
+}
+
 lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion(
-    PdbSymUid type_uid, llvm::StringRef name, size_t size,
+    PdbSymUid type_uid, const llvm::codeview::TagRecord &record, 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();
+  const PdbTypeSymId &tid = type_uid.asTypeSym();
+  TypeIndex ti(tid.index);
+  clang::DeclContext *decl_context = nullptr;
+  std::string uname;
+  std::tie(decl_context, uname) = CreateDeclInfoForType(record, ti);
 
   lldb::AccessType access =
       (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic;
@@ -749,8 +856,9 @@
   metadata.SetIsDynamicCXXType(false);
 
   CompilerType ct =
-      m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk,
+      m_clang->CreateRecordType(decl_context, access, uname.c_str(), ttk,
                                 lldb::eLanguageTypeC_plus_plus, &metadata);
+
   lldbassert(ct.IsValid());
 
   clang::CXXRecordDecl *record_decl =
@@ -771,7 +879,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,
+                                ConstString(uname), size, nullptr,
                                 LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
                                 ct, Type::eResolveStateForward);
 }
@@ -782,14 +890,13 @@
 
   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, 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, ur.getSize(), clang::TTK_Union,
       clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance);
 }
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to