Enable llvm-pdbutil to list enumerations using native PDB reader

This extends the native reader to enable llvm-pdbutil to list the enums in a
PDB and it includes a simple test. It does not yet list the values in the
enumerations, which requires an actual implementation of
NativeEnumSymbol::FindChildren.

To exercise this code, use a command like:

    llvm-pdbutil pretty -native -enums foo.pdb

Differential Revision: https://reviews.llvm.org/D35738

llvm-svn: 310144
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index 2658584..37eca01 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -44,6 +44,8 @@
   Native/NativeBuiltinSymbol.cpp
   Native/NativeCompilandSymbol.cpp
   Native/NativeEnumModules.cpp
+  Native/NativeEnumSymbol.cpp
+  Native/NativeEnumTypes.cpp
   Native/NativeExeSymbol.cpp
   Native/NativeRawSymbol.cpp
   Native/NamedStreamMap.cpp
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp
new file mode 100644
index 0000000..38d6591
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp
@@ -0,0 +1,108 @@
+//===- NativeEnumSymbol.cpp - info about enum type --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id,
+                                   const codeview::CVType &CVT)
+    : NativeRawSymbol(Session, Id), CV(CVT),
+      Record(codeview::TypeRecordKind::Enum) {
+  assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM);
+  cantFail(visitTypeRecord(CV, *this));
+}
+
+NativeEnumSymbol::~NativeEnumSymbol() {}
+
+std::unique_ptr<NativeRawSymbol> NativeEnumSymbol::clone() const {
+  return llvm::make_unique<NativeEnumSymbol>(Session, SymbolId, CV);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeEnumSymbol::findChildren(PDB_SymType Type) const {
+  switch (Type) {
+  case PDB_SymType::Data: {
+    // TODO(amccarth):  Provide an actual implementation.
+    return nullptr;
+  }
+  default:
+    return nullptr;
+  }
+}
+
+Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR,
+                                         codeview::EnumRecord &ER) {
+  Record = ER;
+  return Error::success();
+}
+
+Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM,
+                                         codeview::EnumeratorRecord &R) {
+  return Error::success();
+}
+
+PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; }
+
+uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; }
+
+uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; }
+
+bool NativeEnumSymbol::hasConstructor() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasConstructorOrDestructor);
+}
+
+bool NativeEnumSymbol::hasAssignmentOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasOverloadedAssignmentOperator);
+}
+
+bool NativeEnumSymbol::hasCastOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasConversionOperator);
+}
+
+uint64_t NativeEnumSymbol::getLength() const {
+  const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+  const auto UnderlyingType =
+      Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
+  return UnderlyingType ? UnderlyingType->getLength() : 0;
+}
+
+std::string NativeEnumSymbol::getName() const { return Record.getName(); }
+
+bool NativeEnumSymbol::isNested() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Nested);
+}
+
+bool NativeEnumSymbol::hasOverloadedOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasOverloadedOperator);
+}
+
+bool NativeEnumSymbol::isPacked() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Packed);
+}
+
+bool NativeEnumSymbol::isScoped() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Scoped);
+}
+
+uint32_t NativeEnumSymbol::getTypeId() const {
+  return Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
new file mode 100644
index 0000000..36a68a1
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
@@ -0,0 +1,59 @@
+//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+namespace llvm {
+namespace pdb {
+
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+                                 codeview::LazyRandomTypeCollection &Types,
+                                 codeview::TypeLeafKind Kind)
+    : Matches(), Index(0), Session(PDBSession), Kind(Kind) {
+  for (auto Index = Types.getFirst(); Index;
+       Index = Types.getNext(Index.getValue())) {
+    if (Types.getType(Index.getValue()).kind() == Kind)
+      Matches.push_back(Index.getValue());
+  }
+}
+
+NativeEnumTypes::NativeEnumTypes(
+    NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches,
+    codeview::TypeLeafKind Kind)
+    : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {}
+
+uint32_t NativeEnumTypes::getChildCount() const {
+  return static_cast<uint32_t>(Matches.size());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumTypes::getChildAtIndex(uint32_t Index) const {
+  if (Index < Matches.size())
+    return Session.createEnumSymbol(Matches[Index]);
+  return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
+  return getChildAtIndex(Index++);
+}
+
+void NativeEnumTypes::reset() { Index = 0; }
+
+NativeEnumTypes *NativeEnumTypes::clone() const {
+  return new NativeEnumTypes(Session, Matches, Kind);
+}
+
+} // namespace pdb
+} // namespace llvm
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
index 3241000..b29d589 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
@@ -13,7 +13,9 @@
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 
 namespace llvm {
 namespace pdb {
@@ -38,6 +40,8 @@
     consumeError(Dbi.takeError());
     break;
   }
+  case PDB_SymType::Enum:
+    return Session.createTypeEnumerator(codeview::LF_ENUM);
   default:
     break;
   }
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
index 76de0d8..d7be2d5 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -16,11 +16,15 @@
 #include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
 #include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h"
 #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
 #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/BinaryByteStream.h"
 #include "llvm/Support/Error.h"
@@ -28,6 +32,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 
 #include <algorithm>
+#include <cassert>
 #include <memory>
 #include <utility>
 
@@ -102,6 +107,25 @@
       *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
 }
 
+std::unique_ptr<PDBSymbolTypeEnum>
+NativeSession::createEnumSymbol(codeview::TypeIndex Index) {
+  const auto Id = findSymbolByTypeIndex(Index);
+  return llvm::make_unique<PDBSymbolTypeEnum>(
+      *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeSession::createTypeEnumerator(codeview::TypeLeafKind Kind) {
+  auto Tpi = Pdb->getPDBTpiStream();
+  if (!Tpi) {
+    consumeError(Tpi.takeError());
+    return nullptr;
+  }
+  auto &Types = Tpi->typeCollection();
+  return std::unique_ptr<IPDBEnumSymbols>(
+      new NativeEnumTypes(*this, Types, codeview::LF_ENUM));
+}
+
 SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) {
   // First see if it's already in our cache.
   const auto Entry = TypeIndexToSymbolId.find(Index);
@@ -129,9 +153,20 @@
     return Id;
   }
 
-  // TODO:  Look up PDB type by type index
-
-  return 0;
+  // We need to instantiate and cache the desired type symbol.
+  auto Tpi = Pdb->getPDBTpiStream();
+  if (!Tpi) {
+    consumeError(Tpi.takeError());
+    return 0;
+  }
+  auto &Types = Tpi->typeCollection();
+  const auto &I = Types.getType(Index);
+  const auto Id = static_cast<SymIndexId>(SymbolCache.size());
+  // TODO(amccarth):  Make this handle all types, not just LF_ENUMs.
+  assert(I.kind() == codeview::LF_ENUM);
+  SymbolCache.emplace_back(llvm::make_unique<NativeEnumSymbol>(*this, Id, I));
+  TypeIndexToSymbolId[Index] = Id;
+  return Id;
 }
 
 uint64_t NativeSession::getLoadAddress() const { return 0; }