This revision was automatically updated to reflect the committed changes.
Closed by commit rLLDB345047: [NativePDB] Add basic support for tag types to 
the native pdb plugin. (authored by zturner, committed by ).
Herald added subscribers: teemperor, abidh.

Changed prior to commit:
  https://reviews.llvm.org/D53511?vs=170447&id=170683#toc

Repository:
  rLLDB LLDB

https://reviews.llvm.org/D53511

Files:
  lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
  lit/SymbolFile/NativePDB/tag-types.cpp
  source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
  source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
  source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
  source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h

Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -10,6 +10,7 @@
 #ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 #define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 
+#include "lldb/Symbol/ClangASTImporter.h"
 #include "lldb/Symbol/SymbolFile.h"
 
 #include "llvm/ADT/DenseMap.h"
@@ -144,22 +145,63 @@
   llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
   const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
 
+  ClangASTContext &GetASTContext() { return *m_clang; }
+  ClangASTImporter &GetASTImporter() { return *m_importer; }
+
 private:
+  void AddBaseClassesToLayout(CompilerType &derived_ct,
+                              ClangASTImporter::LayoutInfo &layout,
+                              const llvm::codeview::ClassRecord &record);
+  void AddMembersToLayout(ClangASTImporter::LayoutInfo &layout,
+                          const llvm::codeview::TagRecord &record);
+  void AddMethodsToLayout(ClangASTImporter::LayoutInfo &layout,
+                          const llvm::codeview::TagRecord &record);
+
+  size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches,
+                         TypeMap &types);
+
+  lldb::TypeSP CreateModifierType(PdbSymUid type_uid,
+                                  const llvm::codeview::ModifierRecord &mr);
+  lldb::TypeSP CreatePointerType(PdbSymUid type_uid,
+                                 const llvm::codeview::PointerRecord &pr);
+  lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::ClassRecord &cr);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::EnumRecord &er);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::UnionRecord &ur);
+  lldb::TypeSP
+  CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
+                         clang::TagTypeKind ttk,
+                         clang::MSInheritanceAttr::Spelling inheritance);
+
   lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid,
                                        const SymbolContext &sc);
   lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci);
+  lldb::TypeSP GetOrCreateType(PdbSymUid type_uid);
+  lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti);
 
   lldb::FunctionSP CreateFunction(PdbSymUid func_uid, const SymbolContext &sc);
   lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci);
+  lldb::TypeSP CreateType(PdbSymUid type_uid);
+  lldb::TypeSP CreateAndCacheType(PdbSymUid type_uid);
 
   llvm::BumpPtrAllocator m_allocator;
 
   lldb::addr_t m_obj_load_address = 0;
 
   std::unique_ptr<PdbIndex> m_index;
+  std::unique_ptr<ClangASTImporter> m_importer;
+  ClangASTContext *m_clang = nullptr;
+
+  llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status;
+
+  llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl;
 
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
   llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
+  llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
 };
 
 } // namespace npdb
Index: source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -0,0 +1,188 @@
+#include "UdtRecordCompleter.h"
+
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+#include "SymbolFileNativePDB.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+
+using Error = llvm::Error;
+
+UdtRecordCompleter::UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
+                                       clang::TagDecl &tag_decl,
+                                       SymbolFileNativePDB &symbol_file)
+    : m_uid(uid), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
+      m_symbol_file(symbol_file) {
+  TpiStream &tpi = symbol_file.m_index->tpi();
+  TypeIndex ti(uid.asTypeSym().index);
+  CVType cvt = tpi.getType(ti);
+  switch (cvt.kind()) {
+  case LF_ENUM:
+    lldbassert(uid.tag() == PDB_SymType::Enum);
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
+    break;
+  case LF_UNION:
+    lldbassert(uid.tag() == PDB_SymType::UDT);
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
+    break;
+  case LF_CLASS:
+  case LF_STRUCTURE:
+    lldbassert(uid.tag() == PDB_SymType::UDT);
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
+    break;
+  default:
+    llvm_unreachable("unreachable!");
+  }
+}
+
+lldb::opaque_compiler_type_t UdtRecordCompleter::AddBaseClassForTypeIndex(
+    llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) {
+  TypeSP base_type = m_symbol_file.GetOrCreateType(ti);
+  CompilerType base_ct = base_type->GetFullCompilerType();
+
+  CVType udt_cvt = m_symbol_file.m_index->tpi().getType(ti);
+
+  lldb::opaque_compiler_type_t base_qt = base_ct.GetOpaqueQualType();
+  clang::CXXBaseSpecifier *base_spec =
+      m_symbol_file.GetASTContext().CreateBaseClassSpecifier(
+          base_qt, TranslateMemberAccess(access), false,
+          udt_cvt.kind() == LF_CLASS);
+
+  m_bases.push_back(base_spec);
+  return base_qt;
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           BaseClassRecord &base) {
+  lldb::opaque_compiler_type_t base_qt =
+      AddBaseClassForTypeIndex(base.Type, base.getAccess());
+
+  auto decl = m_symbol_file.GetASTContext().GetAsCXXRecordDecl(base_qt);
+  lldbassert(decl);
+
+  auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
+  m_layout.base_offsets.insert(std::make_pair(decl, offset));
+
+  return llvm::Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           VirtualBaseClassRecord &base) {
+  AddBaseClassForTypeIndex(base.BaseType, base.getAccess());
+
+  // FIXME: Handle virtual base offsets.
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           ListContinuationRecord &cont) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           VFPtrRecord &vfptr) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(
+    CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
+  TypeSP member_type = m_symbol_file.GetOrCreateType(static_data_member.Type);
+  CompilerType complete_member_type = member_type->GetFullCompilerType();
+
+  lldb::AccessType access =
+      TranslateMemberAccess(static_data_member.getAccess());
+  ClangASTContext::AddVariableToRecordType(
+      m_derived_ct, static_data_member.Name.str().c_str(), complete_member_type,
+      access);
+
+  // FIXME: Add a PdbSymUid namespace for field list members and update
+  // the m_uid_to_decl map with this decl.
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           NestedTypeRecord &nested) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           DataMemberRecord &data_member) {
+
+  TypeSP member_type = m_symbol_file.GetOrCreateType(data_member.Type);
+  CompilerType complete_member_type = member_type->GetFullCompilerType();
+
+  lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
+
+  clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
+      m_derived_ct, data_member.Name.str().c_str(), complete_member_type,
+      access, 0);
+  // FIXME: Add a PdbSymUid namespace for field list members and update
+  // the m_uid_to_decl map with this decl.
+
+  uint64_t offset = data_member.FieldOffset * 8;
+  m_layout.field_offsets.insert(std::make_pair(decl, offset));
+
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           OneMethodRecord &one_method) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           OverloadedMethodRecord &overloaded) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           EnumeratorRecord &enumerator) {
+  ClangASTContext &clang = m_symbol_file.GetASTContext();
+
+  Declaration decl;
+  llvm::StringRef name = DropNameScope(enumerator.getName());
+  lldbassert(m_uid.tag() == PDB_SymType::Enum);
+  TypeSP underlying_type =
+      m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType());
+
+  lldb::opaque_compiler_type_t enum_qt = m_derived_ct.GetOpaqueQualType();
+
+  CompilerType enumerator_type = clang.GetEnumerationIntegerType(enum_qt);
+  uint64_t byte_size = underlying_type->GetByteSize();
+  clang.AddEnumerationValueToEnumerationType(
+      m_derived_ct.GetOpaqueQualType(), enumerator_type, decl,
+      name.str().c_str(), enumerator.Value.getSExtValue(),
+      byte_size * 8);
+  return Error::success();
+}
+
+void UdtRecordCompleter::complete() {
+  ClangASTContext &clang = m_symbol_file.GetASTContext();
+  clang.SetBaseClassesForClassType(m_derived_ct.GetOpaqueQualType(),
+                                   m_bases.data(), m_bases.size());
+  ClangASTContext::DeleteBaseClassSpecifiers(m_bases.data(), m_bases.size());
+
+  clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
+  ClangASTContext::BuildIndirectFields(m_derived_ct);
+  ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
+
+  if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
+    m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout);
+  }
+}
\ No newline at end of file
Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -9,24 +9,36 @@
 
 #include "SymbolFileNativePDB.h"
 
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Symbol/SymbolVendor.h"
 
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
 #include "llvm/DebugInfo/CodeView/RecordName.h"
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Allocator.h"
@@ -36,10 +48,11 @@
 
 #include "PdbSymUid.h"
 #include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
 
 using namespace lldb;
 using namespace lldb_private;
-using namespace lldb_private::npdb;
+using namespace npdb;
 using namespace llvm::codeview;
 using namespace llvm::pdb;
 
@@ -139,6 +152,265 @@
   return false;
 }
 
+static clang::MSInheritanceAttr::Spelling
+GetMSInheritance(LazyRandomTypeCollection &tpi, const ClassRecord &record) {
+  if (record.DerivationList == TypeIndex::None())
+    return clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+
+  CVType bases = tpi.getType(record.DerivationList);
+  ArgListRecord base_list;
+  cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(bases, base_list));
+  if (base_list.ArgIndices.empty())
+    return clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+
+  int base_count = 0;
+  for (TypeIndex ti : base_list.ArgIndices) {
+    CVType base = tpi.getType(ti);
+    if (base.kind() == LF_VBCLASS || base.kind() == LF_IVBCLASS)
+      return clang::MSInheritanceAttr::Spelling::Keyword_virtual_inheritance;
+    ++base_count;
+  }
+
+  if (base_count > 1)
+    return clang::MSInheritanceAttr::Keyword_multiple_inheritance;
+  return clang::MSInheritanceAttr::Keyword_single_inheritance;
+}
+
+static lldb::BasicType GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Boolean8:
+    return lldb::eBasicTypeBool;
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+    return lldb::eBasicTypeUnsignedChar;
+  case SimpleTypeKind::NarrowCharacter:
+    return lldb::eBasicTypeChar;
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return lldb::eBasicTypeSignedChar;
+  case SimpleTypeKind::Character16:
+    return lldb::eBasicTypeChar16;
+  case SimpleTypeKind::Character32:
+    return lldb::eBasicTypeChar32;
+  case SimpleTypeKind::Complex80:
+    return lldb::eBasicTypeLongDoubleComplex;
+  case SimpleTypeKind::Complex64:
+    return lldb::eBasicTypeDoubleComplex;
+  case SimpleTypeKind::Complex32:
+    return lldb::eBasicTypeFloatComplex;
+  case SimpleTypeKind::Float128:
+  case SimpleTypeKind::Float80:
+    return lldb::eBasicTypeLongDouble;
+  case SimpleTypeKind::Float64:
+    return lldb::eBasicTypeDouble;
+  case SimpleTypeKind::Float32:
+    return lldb::eBasicTypeFloat;
+  case SimpleTypeKind::Float16:
+    return lldb::eBasicTypeHalf;
+  case SimpleTypeKind::Int128:
+    return lldb::eBasicTypeInt128;
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return lldb::eBasicTypeLongLong;
+  case SimpleTypeKind::Int32:
+    return lldb::eBasicTypeInt;
+  case SimpleTypeKind::Int16:
+  case SimpleTypeKind::Int16Short:
+    return lldb::eBasicTypeShort;
+  case SimpleTypeKind::UInt128:
+    return lldb::eBasicTypeUnsignedInt128;
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+    return lldb::eBasicTypeUnsignedLongLong;
+  case SimpleTypeKind::HResult:
+  case SimpleTypeKind::UInt32:
+    return lldb::eBasicTypeUnsignedInt;
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+    return lldb::eBasicTypeUnsignedShort;
+  case SimpleTypeKind::Int32Long:
+    return lldb::eBasicTypeLong;
+  case SimpleTypeKind::UInt32Long:
+    return lldb::eBasicTypeUnsignedLong;
+  case SimpleTypeKind::Void:
+    return lldb::eBasicTypeVoid;
+  case SimpleTypeKind::WideCharacter:
+    return lldb::eBasicTypeWChar;
+  default:
+    return lldb::eBasicTypeInvalid;
+  }
+}
+
+static size_t GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Int128:
+  case SimpleTypeKind::UInt128:
+  case SimpleTypeKind::Float128:
+    return 16;
+  case SimpleTypeKind::Complex80:
+  case SimpleTypeKind::Float80:
+    return 10;
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Complex64:
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+  case SimpleTypeKind::Float64:
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return 8;
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Character32:
+  case SimpleTypeKind::Complex32:
+  case SimpleTypeKind::Float32:
+  case SimpleTypeKind::Int32:
+  case SimpleTypeKind::Int32Long:
+  case SimpleTypeKind::UInt32Long:
+  case SimpleTypeKind::HResult:
+  case SimpleTypeKind::UInt32:
+    return 4;
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Character16:
+  case SimpleTypeKind::Float16:
+  case SimpleTypeKind::Int16:
+  case SimpleTypeKind::Int16Short:
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+  case SimpleTypeKind::WideCharacter:
+    return 2;
+  case SimpleTypeKind::Boolean8:
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+  case SimpleTypeKind::NarrowCharacter:
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return 1;
+  case SimpleTypeKind::Void:
+  default:
+    return 0;
+  }
+}
+
+static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Boolean8:
+    return "bool";
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+    return "unsigned char";
+  case SimpleTypeKind::NarrowCharacter:
+    return "char";
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return "signed chr";
+  case SimpleTypeKind::Character16:
+    return "char16_t";
+  case SimpleTypeKind::Character32:
+    return "char32_t";
+  case SimpleTypeKind::Complex80:
+  case SimpleTypeKind::Complex64:
+  case SimpleTypeKind::Complex32:
+    return "complex";
+  case SimpleTypeKind::Float128:
+  case SimpleTypeKind::Float80:
+    return "long double";
+  case SimpleTypeKind::Float64:
+    return "double";
+  case SimpleTypeKind::Float32:
+    return "float";
+  case SimpleTypeKind::Float16:
+    return "single";
+  case SimpleTypeKind::Int128:
+    return "__int128";
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return "__int64";
+  case SimpleTypeKind::Int32:
+    return "int";
+  case SimpleTypeKind::Int16:
+    return "short";
+  case SimpleTypeKind::UInt128:
+    return "unsigned __int128";
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+    return "unsigned __int64";
+  case SimpleTypeKind::HResult:
+    return "HRESULT";
+  case SimpleTypeKind::UInt32:
+    return "unsigned";
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+    return "unsigned short";
+  case SimpleTypeKind::Int32Long:
+    return "long";
+  case SimpleTypeKind::UInt32Long:
+    return "unsigned long";
+  case SimpleTypeKind::Void:
+    return "void";
+  case SimpleTypeKind::WideCharacter:
+    return "wchar_t";
+  default:
+    return "";
+  }
+}
+
+static bool IsClassRecord(TypeLeafKind kind) {
+  switch (kind) {
+  case LF_STRUCTURE:
+  case LF_CLASS:
+  case LF_INTERFACE:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static PDB_SymType GetPdbSymType(TpiStream &tpi, TypeIndex ti) {
+  if (ti.isSimple()) {
+    if (ti.getSimpleMode() == SimpleTypeMode::Direct)
+      return PDB_SymType::BuiltinType;
+    return PDB_SymType::PointerType;
+  }
+
+  CVType cvt = tpi.getType(ti);
+  TypeLeafKind kind = cvt.kind();
+  if (kind != LF_MODIFIER)
+    return CVTypeToPDBType(kind);
+
+  // If this is an LF_MODIFIER, look through it to get the kind that it
+  // modifies.  Note that it's not possible to have an LF_MODIFIER that
+  // modifies another LF_MODIFIER, although this would handle that anyway.
+  ModifierRecord mr;
+  llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mr));
+  return GetPdbSymType(tpi, mr.ModifiedType);
+}
+
+static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
+  switch (cr.Kind) {
+  case TypeRecordKind::Class:
+    return clang::TTK_Class;
+  case TypeRecordKind::Struct:
+    return clang::TTK_Struct;
+  case TypeRecordKind::Union:
+    return clang::TTK_Union;
+  case TypeRecordKind::Interface:
+    return clang::TTK_Interface;
+  case TypeRecordKind::Enum:
+    return clang::TTK_Enum;
+  default:
+    lldbassert(false && "Invalid tag record kind!");
+    return clang::TTK_Struct;
+  }
+}
+
 void SymbolFileNativePDB::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                 GetPluginDescriptionStatic(), CreateInstance,
@@ -216,6 +488,11 @@
   m_obj_load_address = m_obj_file->GetFileOffset();
   m_index->SetLoadAddress(m_obj_load_address);
   m_index->ParseSectionContribs();
+
+  TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  m_clang = llvm::dyn_cast_or_null<ClangASTContext>(ts);
+  m_importer = llvm::make_unique<ClangASTImporter>();
+  lldbassert(m_clang);
 }
 
 uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
@@ -295,6 +572,329 @@
   return cu_sp;
 }
 
+lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbSymUid type_uid,
+                                                     const ModifierRecord &mr) {
+  TpiStream &stream = m_index->tpi();
+
+  TypeSP t = GetOrCreateType(mr.ModifiedType);
+  CompilerType ct = t->GetForwardCompilerType();
+  if ((mr.Modifiers & ModifierOptions::Const) != ModifierOptions::None)
+    ct = ct.AddConstModifier();
+  if ((mr.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None)
+    ct = ct.AddVolatileModifier();
+  std::string name;
+  if (mr.ModifiedType.isSimple())
+    name = GetSimpleTypeName(mr.ModifiedType.getSimpleKind());
+  else
+    name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+  Declaration decl;
+  return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(name), t->GetByteSize(), nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreatePointerType(
+    PdbSymUid type_uid, const llvm::codeview::PointerRecord &pr) {
+  TypeSP pointee = GetOrCreateType(pr.ReferentType);
+  CompilerType pointee_ct = pointee->GetForwardCompilerType();
+  lldbassert(pointee_ct);
+  Declaration decl;
+
+  if (pr.isPointerToMember()) {
+    MemberPointerInfo mpi = pr.getMemberInfo();
+    TypeSP class_type = GetOrCreateType(mpi.ContainingType);
+
+    CompilerType ct = ClangASTContext::CreateMemberPointerType(
+        class_type->GetLayoutCompilerType(), pointee_ct);
+
+    return std::make_shared<Type>(
+        type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(),
+        pr.getSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+        Type::eResolveStateFull);
+  }
+
+  CompilerType pointer_ct = pointee_ct;
+  if (pr.getMode() == PointerMode::LValueReference)
+    pointer_ct = pointer_ct.GetLValueReferenceType();
+  else if (pr.getMode() == PointerMode::RValueReference)
+    pointer_ct = pointer_ct.GetRValueReferenceType();
+  else
+    pointer_ct = pointer_ct.GetPointerType();
+
+  if ((pr.getOptions() & PointerOptions::Const) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddConstModifier();
+
+  if ((pr.getOptions() & PointerOptions::Volatile) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddVolatileModifier();
+
+  if ((pr.getOptions() & PointerOptions::Restrict) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddRestrictModifier();
+
+  return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(), pr.getSize(), nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                pointer_ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) {
+  if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+    PdbSymUid uid =
+        PdbSymUid::makeTypeSymId(PDB_SymType::PointerType, ti, false);
+    TypeSP direct_sp = GetOrCreateType(ti.makeDirect());
+    CompilerType ct = direct_sp->GetFullCompilerType();
+    ct = ct.GetPointerType();
+    uint32_t pointer_size = 4;
+    switch (ti.getSimpleMode()) {
+    case SimpleTypeMode::FarPointer32:
+    case SimpleTypeMode::NearPointer32:
+      pointer_size = 4;
+      break;
+    case SimpleTypeMode::NearPointer64:
+      pointer_size = 8;
+      break;
+    default:
+      // 128-bit and 16-bit pointers unsupported.
+      return nullptr;
+    }
+    Declaration decl;
+    return std::make_shared<Type>(uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                  ConstString(), pointer_size, nullptr,
+                                  LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                  ct, Type::eResolveStateFull);
+  }
+
+  PdbSymUid uid = PdbSymUid::makeTypeSymId(PDB_SymType::BuiltinType, ti, false);
+  if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+    return nullptr;
+
+  lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind());
+  lldbassert(bt != lldb::eBasicTypeInvalid);
+  CompilerType ct = m_clang->GetBasicType(bt);
+  size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
+
+  llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
+
+  Declaration decl;
+  return std::make_shared<Type>(uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(type_name), size, nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion(
+    PdbSymUid type_uid, llvm::StringRef name, size_t size,
+    clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) {
+
+  // Some UDT with trival ctor has zero length. Just ignore.
+  if (size == 0)
+    return nullptr;
+
+  // 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());
+
+  clang::CXXRecordDecl *record_decl =
+      m_clang->GetAsCXXRecordDecl(ct.GetOpaqueQualType());
+  lldbassert(record_decl);
+
+  clang::MSInheritanceAttr *attr = clang::MSInheritanceAttr::CreateImplicit(
+      *m_clang->getASTContext(), inheritance);
+  record_decl->addAttr(attr);
+
+  ClangASTContext::StartTagDeclarationDefinition(ct);
+
+  // Even if it's possible, don't complete it at this point. Just mark it
+  // forward resolved, and if/when LLDB needs the full definition, it can
+  // ask us.
+  ClangASTContext::SetHasExternalStorage(ct.GetOpaqueQualType(), true);
+
+  // 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,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateForward);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
+                                                const ClassRecord &cr) {
+  clang::TagTypeKind ttk = TranslateUdtKind(cr);
+
+  clang::MSInheritanceAttr::Spelling inheritance =
+      GetMSInheritance(m_index->tpi().typeCollection(), cr);
+  return CreateClassStructUnion(type_uid, cr.getName(), 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,
+      clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
+                                                const EnumRecord &er) {
+  llvm::StringRef name = DropNameScope(er.getName());
+
+  clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+
+  Declaration decl;
+  TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
+  CompilerType enum_ct = m_clang->CreateEnumerationType(
+      name.str().c_str(), decl_context, decl,
+      underlying_type->GetFullCompilerType(), er.isScoped());
+
+  ClangASTContext::StartTagDeclarationDefinition(enum_ct);
+
+  // We're just going to forward resolve this for now.  We'll complete
+  // it only if the user requests.
+  return std::make_shared<lldb_private::Type>(
+      type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(name),
+      underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID,
+      lldb_private::Type::eEncodingIsUID, decl, enum_ct,
+      lldb_private::Type::eResolveStateForward);
+}
+
+TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
+  const PdbTypeSymId &tsid = type_uid.asTypeSym();
+  TypeIndex index(tsid.index);
+
+  if (index.getIndex() < TypeIndex::FirstNonSimpleIndex)
+    return CreateSimpleType(index);
+
+  TpiStream &stream = tsid.is_ipi ? m_index->ipi() : m_index->tpi();
+  CVType cvt = stream.getType(index);
+
+  if (cvt.kind() == LF_MODIFIER) {
+    ModifierRecord modifier;
+    llvm::cantFail(
+        TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+    return CreateModifierType(type_uid, modifier);
+  }
+
+  if (cvt.kind() == LF_POINTER) {
+    PointerRecord pointer;
+    llvm::cantFail(
+        TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+    return CreatePointerType(type_uid, pointer);
+  }
+
+  if (IsClassRecord(cvt.kind())) {
+    ClassRecord cr;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+    return CreateTagType(type_uid, cr);
+  }
+
+  if (cvt.kind() == LF_ENUM) {
+    EnumRecord er;
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+    return CreateTagType(type_uid, er);
+  }
+
+  if (cvt.kind() == LF_UNION) {
+    UnionRecord ur;
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+    return CreateTagType(type_uid, ur);
+  }
+
+  return nullptr;
+}
+
+TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbSymUid type_uid) {
+  // If they search for a UDT which is a forward ref, try and resolve the full
+  // decl and just map the forward ref uid to the full decl record.
+  llvm::Optional<PdbSymUid> full_decl_uid;
+  if (type_uid.tag() == PDB_SymType::UDT ||
+      type_uid.tag() == PDB_SymType::Enum) {
+    const PdbTypeSymId &type_id = type_uid.asTypeSym();
+    TypeIndex ti(type_id.index);
+    lldbassert(!ti.isSimple());
+    CVType cvt = m_index->tpi().getType(ti);
+
+    if (IsForwardRefUdt(cvt)) {
+      auto expected_full_ti = m_index->tpi().findFullDeclForForwardRef(ti);
+      if (!expected_full_ti)
+        llvm::consumeError(expected_full_ti.takeError());
+      else {
+        full_decl_uid = PdbSymUid::makeTypeSymId(
+            type_uid.tag(), *expected_full_ti, type_id.is_ipi);
+
+        // It's possible that a lookup would occur for the full decl causing it
+        // to be cached, then a second lookup would occur for the forward decl.
+        // We don't want to create a second full decl, so make sure the full
+        // decl hasn't already been cached.
+        auto full_iter = m_types.find(full_decl_uid->toOpaqueId());
+        if (full_iter != m_types.end()) {
+          TypeSP result = full_iter->second;
+          // Map the forward decl to the TypeSP for the full decl so we can take
+          // the fast path next time.
+          m_types[type_uid.toOpaqueId()] = result;
+          return result;
+        }
+      }
+    }
+  }
+
+  PdbSymUid best_uid = full_decl_uid ? *full_decl_uid : type_uid;
+  TypeSP result = CreateType(best_uid);
+  m_types[best_uid.toOpaqueId()] = result;
+  // If we had both a forward decl and a full decl, make both point to the new
+  // type.
+  if (full_decl_uid)
+    m_types[type_uid.toOpaqueId()] = result;
+
+  const PdbTypeSymId &type_id = best_uid.asTypeSym();
+  if (best_uid.tag() == PDB_SymType::UDT ||
+      best_uid.tag() == PDB_SymType::Enum) {
+    clang::TagDecl *record_decl =
+        m_clang->GetAsTagDecl(result->GetForwardCompilerType());
+    lldbassert(record_decl);
+
+    TypeIndex ti(type_id.index);
+    CVType cvt = m_index->tpi().getType(ti);
+    m_uid_to_decl[best_uid.toOpaqueId()] = record_decl;
+    m_decl_to_status[record_decl] =
+        DeclStatus(best_uid.toOpaqueId(), Type::eResolveStateForward);
+  }
+  return result;
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateType(PdbSymUid type_uid) {
+  lldbassert(PdbSymUid::isTypeSym(type_uid.tag()));
+  // We can't use try_emplace / overwrite here because the process of creating
+  // a type could create nested types, which could invalidate iterators.  So
+  // we have to do a 2-phase lookup / insert.
+  auto iter = m_types.find(type_uid.toOpaqueId());
+  if (iter != m_types.end())
+    return iter->second;
+
+  return CreateAndCacheType(type_uid);
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::GetOrCreateType(llvm::codeview::TypeIndex ti) {
+  PDB_SymType pdbst = GetPdbSymType(m_index->tpi(), ti);
+  PdbSymUid tuid = PdbSymUid::makeTypeSymId(pdbst, ti, false);
+  return GetOrCreateType(tuid);
+}
+
 FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbSymUid func_uid,
                                                     const SymbolContext &sc) {
   lldbassert(func_uid.tag() == PDB_SymType::Function);
@@ -595,22 +1195,116 @@
     const CompilerDeclContext *parent_decl_ctx, bool append,
     uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files,
     TypeMap &types) {
-  return 0;
+  if (!append)
+    types.Clear();
+  if (!name)
+    return 0;
+
+  searched_symbol_files.clear();
+  searched_symbol_files.insert(this);
+
+  // There is an assumption 'name' is not a regex
+  size_t match_count = FindTypesByName(name.GetStringRef(), max_matches, types);
+
+  return match_count;
 }
 
 size_t
 SymbolFileNativePDB::FindTypes(const std::vector<CompilerContext> &context,
                                bool append, TypeMap &types) {
   return 0;
 }
 
+size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
+                                            uint32_t max_matches,
+                                            TypeMap &types) {
+
+  size_t match_count = 0;
+  std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);
+  if (max_matches > 0 && max_matches < matches.size())
+    matches.resize(max_matches);
+
+  for (TypeIndex ti : matches) {
+    TypeSP type = GetOrCreateType(ti);
+    if (!type)
+      continue;
+
+    types.Insert(type);
+    ++match_count;
+  }
+  return match_count;
+}
+
 size_t SymbolFileNativePDB::ParseTypes(const SymbolContext &sc) { return 0; }
 
 Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
-  return nullptr;
+  auto iter = m_types.find(type_uid);
+  // lldb should not be passing us non-sensical type uids.  the only way it
+  // could have a type uid in the first place is if we handed it out, in which
+  // case we should know about the type.  So this is not a get-or-create type
+  // operation, it is strictly a get, and the type is guaranteed to exist.
+  //
+  // However, since the implementation is not yet complete, we don't currently
+  // support all possible use cases.  For example, we currently create all
+  // functions with indices of 0 for the signature type simply because this is
+  // not yet implemented.  At the time the function object is created we should
+  // be creating an lldb::TypeSP for this, adding it to the m_types, and
+  // returning a valid Type object for it and putting it in this map.  Once all
+  // cases like this are handled, we can promote this to an assert.
+  if (iter == m_types.end())
+    return nullptr;
+  return &*iter->second;
 }
 
 bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
+  // If this is not in our map, it's an error.
+  clang::TagDecl *tag_decl = m_clang->GetAsTagDecl(compiler_type);
+  lldbassert(tag_decl);
+  auto status_iter = m_decl_to_status.find(tag_decl);
+  lldbassert(status_iter != m_decl_to_status.end());
+
+  // If it's already complete, just return.
+  DeclStatus &status = status_iter->second;
+  if (status.status == Type::eResolveStateFull)
+    return true;
+
+  PdbSymUid uid = PdbSymUid::fromOpaqueId(status.uid);
+  lldbassert(uid.tag() == PDB_SymType::UDT || uid.tag() == PDB_SymType::Enum);
+
+  const PdbTypeSymId &type_id = uid.asTypeSym();
+
+  ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+                                         false);
+
+  // In CreateAndCacheType, we already go out of our way to resolve forward
+  // ref UDTs to full decls, and the uids we vend out always refer to full
+  // decls if a full decl exists in the debug info.  So if we don't have a full
+  // decl here, it means one doesn't exist in the debug info, and we can't
+  // complete the type.
+  CVType cvt = m_index->tpi().getType(TypeIndex(type_id.index));
+  if (IsForwardRefUdt(cvt))
+    return false;
+
+  auto types_iter = m_types.find(uid.toOpaqueId());
+  lldbassert(types_iter != m_types.end());
+
+  TypeIndex field_list_ti = GetFieldListIndex(cvt);
+  CVType field_list_cvt = m_index->tpi().getType(field_list_ti);
+  if (field_list_cvt.kind() != LF_FIELDLIST)
+    return false;
+
+  // Visit all members of this class, then perform any finalization necessary
+  // to complete the class.
+  UdtRecordCompleter completer(uid, compiler_type, *tag_decl, *this);
+  auto error =
+      llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
+  completer.complete();
+
+  status.status = Type::eResolveStateFull;
+  if (!error)
+    return true;
+
+  llvm::consumeError(std::move(error));
   return false;
 }
 
Index: source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
+++ source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Error.h"
 
@@ -51,6 +52,8 @@
   ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
   ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
 
+  result->m_tpi->buildHashMap();
+
   result->m_file = std::move(file);
 
   return std::move(result);
@@ -101,6 +104,9 @@
         : m_ctx(ctx), m_imap(imap) {}
 
     void visit(const SectionContrib &C) override {
+      if (C.Size == 0)
+        return;
+
       uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
       uint64_t end = va + C.Size;
       // IntervalMap's start and end represent a closed range, not a half-open
Index: source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
===================================================================
--- source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
+++ source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
@@ -3,6 +3,7 @@
   PdbIndex.cpp
   PdbUtil.cpp
   SymbolFileNativePDB.cpp
+  UdtRecordCompleter.cpp
 
   LINK_LIBS
     clangAST
Index: source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
===================================================================
--- source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
+++ source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -0,0 +1,68 @@
+//===-- SymbolFileNativePDB.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_UDTRECORDCOMPLETER_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+#include "PdbSymUid.h"
+
+namespace clang {
+class CXXBaseSpecifier;
+class TagDecl;
+} // namespace clang
+
+namespace lldb_private {
+class Type;
+class CompilerType;
+namespace npdb {
+class SymbolFileNativePDB;
+
+class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
+  union UdtTagRecord {
+    UdtTagRecord() {}
+    llvm::codeview::UnionRecord ur;
+    llvm::codeview::ClassRecord cr;
+    llvm::codeview::EnumRecord er;
+  } m_cvr;
+
+  PdbSymUid m_uid;
+  CompilerType &m_derived_ct;
+  clang::TagDecl &m_tag_decl;
+  SymbolFileNativePDB &m_symbol_file;
+  std::vector<clang::CXXBaseSpecifier *> m_bases;
+  ClangASTImporter::LayoutInfo m_layout;
+
+public:
+  UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
+                     clang::TagDecl &tag_decl,
+                     SymbolFileNativePDB &symbol_file);
+
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR,            \
+                               llvm::codeview::Name##Record &Record) override;
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+  void complete();
+
+private:
+  lldb::opaque_compiler_type_t
+  AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti,
+                           llvm::codeview::MemberAccess access);
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
Index: lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
===================================================================
--- lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
+++ lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
@@ -0,0 +1,8 @@
+type lookup -- Struct
+type lookup -- Class
+type lookup -- Union
+type lookup -- Derived
+type lookup -- Derived2
+type lookup -- EnumInt
+type lookup -- EnumShort
+type lookup -- InvalidType
Index: lit/SymbolFile/NativePDB/tag-types.cpp
===================================================================
--- lit/SymbolFile/NativePDB/tag-types.cpp
+++ lit/SymbolFile/NativePDB/tag-types.cpp
@@ -0,0 +1,236 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test that we can display tag types.
+// 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/tag-types.lldbinit | FileCheck %s
+
+// Test struct
+struct Struct {
+  // Test builtin types, which are represented by special CodeView type indices.
+  bool                B;
+  char                C;
+  signed char         SC;
+  unsigned char       UC;
+  char16_t            C16;
+  char32_t            C32;
+  wchar_t             WC;
+  short               S;
+  unsigned short      US;
+  int                 I;
+  unsigned int        UI;
+  long                L;
+  unsigned long       UL;
+  long long           LL;
+  unsigned long long  ULL;
+  float               F;
+  double              D;
+  long double         LD;
+};
+
+// Test class
+class Class {
+public:
+  // Test pointers to builtin types, which are represented by different special
+  // CodeView type indices.
+  bool                *PB;
+  char                *PC;
+  signed char         *PSC;
+  unsigned char       *PUC;
+  char16_t            *PC16;
+  char32_t            *PC32;
+  wchar_t             *PWC;
+  short               *PS;
+  unsigned short      *PUS;
+  int                 *PI;
+  unsigned int        *PUI;
+  long                *PL;
+  unsigned long       *PUL;
+  long long           *PLL;
+  unsigned long long  *PULL;
+  float               *PF;
+  double              *PD;
+  long double         *PLD;
+};
+
+// Test union
+union Union {
+  // Test modified types.
+  const bool                *PB;
+  const char                *PC;
+  const signed char         *PSC;
+  const unsigned char       *PUC;
+  const char16_t            *PC16;
+  const char32_t            *PC32;
+  const wchar_t             *PWC;
+  const short               *PS;
+  const unsigned short      *PUS;
+  const int                 *PI;
+  const unsigned int        *PUI;
+  const long                *PL;
+  const unsigned long       *PUL;
+  const long long           *PLL;
+  const unsigned long long  *PULL;
+  const float               *PF;
+  const double              *PD;
+  const long double         *PLD;
+};
+
+struct OneMember {
+  int N = 0;
+};
+
+
+// Test single inheritance.
+class Derived : public Class {
+public:
+  explicit Derived()
+    : Reference(*this), RefMember(Member), RValueRefMember((OneMember&&)Member) {}
+
+  // Test reference to self, to make sure we don't end up in an
+  // infinite cycle.
+  Derived &Reference;
+
+  // Test aggregate class member.
+  OneMember Member;
+
+  // And modified aggregate class member.
+  const OneMember ConstMember;
+  volatile OneMember VolatileMember;
+  const volatile OneMember CVMember;
+
+  // And all types of pointers to class members
+  OneMember *PtrMember;
+  OneMember &RefMember;
+  OneMember &&RValueRefMember;
+};
+
+// Test multiple inheritance, as well as protected and private inheritance.
+class Derived2 : protected Class, private Struct {
+public:
+  // Test static data members
+  static unsigned StaticDataMember;
+};
+
+unsigned Derived2::StaticDataMember = 0;
+
+// Test scoped enums and unscoped enums.
+enum class EnumInt {
+  A = 1,
+  B = 2
+};
+
+// Test explicit underlying types
+enum EnumShort : short {
+  ES_A = 2,
+  ES_B = 3
+};
+
+int main(int argc, char **argv) {
+  Struct S;
+  Class C;
+  Union U;
+  Derived D;
+  Derived2 D2;
+  EnumInt EI;
+  EnumShort ES;
+  
+  return 0;
+}
+
+// CHECK:      (lldb) target create "{{.*}}tag-types.cpp.tmp.exe"
+// CHECK-NEXT: Current executable set to '{{.*}}tag-types.cpp.tmp.exe' (x86_64).
+// CHECK-NEXT: (lldb) command source -s 0 '{{.*}}tag-types.lldbinit'
+// CHECK-NEXT: Executing commands in '{{.*}}tag-types.lldbinit'.
+// CHECK-NEXT: (lldb) type lookup -- Struct
+// CHECK-NEXT: struct Struct {
+// CHECK-NEXT:     bool B;
+// CHECK-NEXT:     char C;
+// CHECK-NEXT:     signed char SC;
+// CHECK-NEXT:     unsigned char UC;
+// CHECK-NEXT:     char16_t C16;
+// CHECK-NEXT:     char32_t C32;
+// CHECK-NEXT:     wchar_t WC;
+// CHECK-NEXT:     short S;
+// CHECK-NEXT:     unsigned short US;
+// CHECK-NEXT:     int I;
+// CHECK-NEXT:     unsigned int UI;
+// CHECK-NEXT:     long L;
+// CHECK-NEXT:     unsigned long UL;
+// CHECK-NEXT:     long long LL;
+// CHECK-NEXT:     unsigned long long ULL;
+// CHECK-NEXT:     float F;
+// CHECK-NEXT:     double D;
+// CHECK-NEXT:     double LD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Class
+// CHECK-NEXT: class Class {
+// CHECK-NEXT:     bool *PB;
+// CHECK-NEXT:     char *PC;
+// CHECK-NEXT:     signed char *PSC;
+// CHECK-NEXT:     unsigned char *PUC;
+// CHECK-NEXT:     char16_t *PC16;
+// CHECK-NEXT:     char32_t *PC32;
+// CHECK-NEXT:     wchar_t *PWC;
+// CHECK-NEXT:     short *PS;
+// CHECK-NEXT:     unsigned short *PUS;
+// CHECK-NEXT:     int *PI;
+// CHECK-NEXT:     unsigned int *PUI;
+// CHECK-NEXT:     long *PL;
+// CHECK-NEXT:     unsigned long *PUL;
+// CHECK-NEXT:     long long *PLL;
+// CHECK-NEXT:     unsigned long long *PULL;
+// CHECK-NEXT:     float *PF;
+// CHECK-NEXT:     double *PD;
+// CHECK-NEXT:     double *PLD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Union
+// CHECK-NEXT: union Union {
+// CHECK-NEXT:     const bool *PB;
+// CHECK-NEXT:     const char *PC;
+// CHECK-NEXT:     const signed char *PSC;
+// CHECK-NEXT:     const unsigned char *PUC;
+// CHECK-NEXT:     const char16_t *PC16;
+// CHECK-NEXT:     const char32_t *PC32;
+// CHECK-NEXT:     const wchar_t *PWC;
+// CHECK-NEXT:     const short *PS;
+// CHECK-NEXT:     const unsigned short *PUS;
+// CHECK-NEXT:     const int *PI;
+// CHECK-NEXT:     const unsigned int *PUI;
+// CHECK-NEXT:     const long *PL;
+// CHECK-NEXT:     const unsigned long *PUL;
+// CHECK-NEXT:     const long long *PLL;
+// CHECK-NEXT:     const unsigned long long *PULL;
+// CHECK-NEXT:     const float *PF;
+// CHECK-NEXT:     const double *PD;
+// CHECK-NEXT:     const double *PLD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Derived
+// CHECK-NEXT: class Derived : public Class {
+// CHECK-NEXT:     Derived &Reference;
+// CHECK-NEXT:     OneMember Member;
+// CHECK-NEXT:     const OneMember ConstMember;
+// CHECK-NEXT:     volatile OneMember VolatileMember;
+// CHECK-NEXT:     const volatile OneMember CVMember;
+// CHECK-NEXT:     OneMember *PtrMember;
+// CHECK-NEXT:     OneMember &RefMember;
+// CHECK-NEXT:     OneMember &&RValueRefMember;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Derived2
+// CHECK-NEXT: class Derived2 : protected Class, private Struct {
+// CHECK-NEXT:     static unsigned int StaticDataMember;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- EnumInt
+// CHECK-NEXT: enum EnumInt {
+// CHECK-NEXT:     A,
+// CHECK-NEXT:     B
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- EnumShort
+// CHECK-NEXT: enum EnumShort {
+// CHECK-NEXT:     ES_A,
+// CHECK-NEXT:     ES_B
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- InvalidType
+// CHECK-NEXT: no type was found matching 'InvalidType'
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to