[PDB] Better support for enumerating pointer types.

There were several issues with the previous implementation.

1) There were no tests.
2) We didn't support creating PDBSymbolTypePointer records for
   builtin types since those aren't described by LF_POINTER
   records.
3) We didn't support a wide enough variety of builtin types even
   ignoring pointers.

This patch fixes all of these issues.  In order to add tests,
it's helpful to be able to ignore the symbol index id hierarchy
because it makes the golden output from the DIA version not match
our output, so I've extended the dumper to disable dumping of id
fields.

llvm-svn: 342493
diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
index 0b4b127..46b7ab0 100644
--- a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
@@ -150,6 +150,17 @@
     dumpSymbolField(OS, Name, static_cast<PrintType>(Value), Indent);
 }
 
+void DumpDIAIdValue(llvm::raw_ostream &OS, int Indent, StringRef Name,
+                    IDiaSymbol *Symbol,
+                    HRESULT (__stdcall IDiaSymbol::*Method)(DWORD *),
+                    const IPDBSession &Session, PdbSymbolIdField FieldId,
+                    PdbSymbolIdField ShowFlags, PdbSymbolIdField RecurseFlags) {
+  DWORD Value;
+  if (S_OK == (Symbol->*Method)(&Value))
+    dumpSymbolIdField(OS, Name, Value, Indent, Session, FieldId, ShowFlags,
+                      RecurseFlags);
+}
+
 template <typename ArgType>
 void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name,
                   IDiaSymbol *Symbol,
@@ -199,6 +210,12 @@
                            CComPtr<IDiaSymbol> DiaSymbol)
     : Session(PDBSession), Symbol(DiaSymbol) {}
 
+#define RAW_ID_METHOD_DUMP(Stream, Method, Session, FieldId, ShowFlags,        \
+                           RecurseFlags)                                       \
+  DumpDIAIdValue(Stream, Indent, StringRef{#Method}, Symbol,                   \
+                 &IDiaSymbol::get_##Method, Session, FieldId, ShowFlags,       \
+                 RecurseFlags);
+
 #define RAW_METHOD_DUMP(Stream, Method)                                        \
   DumpDIAValue(Stream, Indent, StringRef{#Method}, Symbol,                     \
                &IDiaSymbol::get_##Method);
@@ -207,9 +224,12 @@
   DumpDIAValueAs<Type>(Stream, Indent, StringRef{#Method}, Symbol,             \
                        &IDiaSymbol::get_##Method);
 
-void DIARawSymbol::dump(raw_ostream &OS, int Indent) const {
-  RAW_METHOD_DUMP(OS, symIndexId);
-  RAW_METHOD_DUMP(OS, symTag);
+void DIARawSymbol::dump(raw_ostream &OS, int Indent,
+                        PdbSymbolIdField ShowIdFields,
+                        PdbSymbolIdField RecurseIdFields) const {
+  RAW_ID_METHOD_DUMP(OS, symIndexId, Session, PdbSymbolIdField::SymIndexId,
+                     ShowIdFields, RecurseIdFields);
+  RAW_METHOD_DUMP_AS(OS, symTag, PDB_SymType);
 
   RAW_METHOD_DUMP(OS, access);
   RAW_METHOD_DUMP(OS, addressOffset);
@@ -226,7 +246,8 @@
   RAW_METHOD_DUMP(OS, baseType);
   RAW_METHOD_DUMP(OS, bitPosition);
   RAW_METHOD_DUMP(OS, callingConvention);
-  RAW_METHOD_DUMP(OS, classParentId);
+  RAW_ID_METHOD_DUMP(OS, classParentId, Session, PdbSymbolIdField::ClassParent,
+                     ShowIdFields, RecurseIdFields);
   RAW_METHOD_DUMP(OS, compilerName);
   RAW_METHOD_DUMP(OS, count);
   RAW_METHOD_DUMP(OS, countLiveRanges);
@@ -234,7 +255,9 @@
   RAW_METHOD_DUMP(OS, frontEndMinor);
   RAW_METHOD_DUMP(OS, frontEndBuild);
   RAW_METHOD_DUMP(OS, frontEndQFE);
-  RAW_METHOD_DUMP(OS, lexicalParentId);
+  RAW_ID_METHOD_DUMP(OS, lexicalParentId, Session,
+                     PdbSymbolIdField::LexicalParent, ShowIdFields,
+                     RecurseIdFields);
   RAW_METHOD_DUMP(OS, libraryName);
   RAW_METHOD_DUMP(OS, liveRangeStartAddressOffset);
   RAW_METHOD_DUMP(OS, liveRangeStartAddressSection);
@@ -272,10 +295,13 @@
   RAW_METHOD_DUMP(OS, textureSlot);
   RAW_METHOD_DUMP(OS, timeStamp);
   RAW_METHOD_DUMP(OS, token);
-  RAW_METHOD_DUMP(OS, typeId);
+  RAW_ID_METHOD_DUMP(OS, typeId, Session, PdbSymbolIdField::Type, ShowIdFields,
+                     RecurseIdFields);
   RAW_METHOD_DUMP(OS, uavSlot);
   RAW_METHOD_DUMP(OS, undecoratedName);
-  RAW_METHOD_DUMP(OS, unmodifiedTypeId);
+  RAW_ID_METHOD_DUMP(OS, unmodifiedTypeId, Session,
+                     PdbSymbolIdField::UnmodifiedType, ShowIdFields,
+                     RecurseIdFields);
   RAW_METHOD_DUMP(OS, upperBoundId);
   RAW_METHOD_DUMP(OS, virtualBaseDispIndex);
   RAW_METHOD_DUMP(OS, virtualBaseOffset);
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
index 64ddf75..efa70b0 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
 
 #include "llvm/ADT/STLExtras.h"
 
@@ -23,10 +24,14 @@
   return PDB_SymType::Compiland;
 }
 
-void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent) const {
-  NativeRawSymbol::dump(OS, Indent);
+void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent,
+                                 PdbSymbolIdField ShowIdFields,
+                                 PdbSymbolIdField RecurseIdFields) const {
+  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
 
-  dumpSymbolField(OS, "lexicalParentId", 0, Indent);
+  dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+                    PdbSymbolIdField::LexicalParent, ShowIdFields,
+                    RecurseIdFields);
   dumpSymbolField(OS, "libraryName", getLibraryName(), Indent);
   dumpSymbolField(OS, "name", getName(), Indent);
   dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(),
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
index e36d534..1a8c75d 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
@@ -9,6 +9,7 @@
 
 #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
 #include "llvm/Support/FormatVariadic.h"
 
@@ -19,9 +20,13 @@
                                  SymIndexId SymbolId)
     : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {}
 
-void NativeRawSymbol::dump(raw_ostream &OS, int Indent) const {
-  dumpSymbolField(OS, "symIndexId", SymbolId, Indent);
-  dumpSymbolField(OS, "symTag", static_cast<uint32_t>(Tag), Indent);
+void NativeRawSymbol::dump(raw_ostream &OS, int Indent,
+                           PdbSymbolIdField ShowIdFields,
+                           PdbSymbolIdField RecurseIdFields) const {
+  dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session,
+                    PdbSymbolIdField::SymIndexId, ShowIdFields,
+                    RecurseIdFields);
+  dumpSymbolField(OS, "symTag", Tag, Indent);
 }
 
 std::unique_ptr<IPDBEnumSymbols>
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
index 18b13b0..6ebb8ca 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
@@ -25,12 +25,19 @@
 
 NativeSymbolEnumerator::~NativeSymbolEnumerator() {}
 
-void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent) const {
-  NativeRawSymbol::dump(OS, Indent);
-  dumpSymbolField(OS, "classParentId", getClassParentId(), Indent);
-  dumpSymbolField(OS, "lexicalParentId", getLexicalParentId(), Indent);
+void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent,
+                                  PdbSymbolIdField ShowIdFields,
+                                  PdbSymbolIdField RecurseIdFields) const {
+  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+  dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session,
+                    PdbSymbolIdField::ClassParent, ShowIdFields,
+                    RecurseIdFields);
+  dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent,
+                    Session, PdbSymbolIdField::LexicalParent, ShowIdFields,
+                    RecurseIdFields);
   dumpSymbolField(OS, "name", getName(), Indent);
-  dumpSymbolField(OS, "typeId", getTypeId(), Indent);
+  dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+                    PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
   dumpSymbolField(OS, "dataKind", getDataKind(), Indent);
   dumpSymbolField(OS, "locationType", getLocationType(), Indent);
   dumpSymbolField(OS, "constType", isConstType(), Indent);
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
index a9197b7..824d9bd 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
@@ -21,8 +21,9 @@
 
 NativeTypeBuiltin::~NativeTypeBuiltin() {}
 
-void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent) const {
-}
+void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent,
+                             PdbSymbolIdField ShowIdFields,
+                             PdbSymbolIdField RecurseIdFields) const {}
 
 PDB_SymType NativeTypeBuiltin::getSymTag() const {
   return PDB_SymType::BuiltinType;
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp
index e833b6d..0994be4 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp
@@ -130,16 +130,23 @@
 
 NativeTypeEnum::~NativeTypeEnum() {}
 
-void NativeTypeEnum::dump(raw_ostream &OS, int Indent) const {
-  NativeRawSymbol::dump(OS, Indent);
+void NativeTypeEnum::dump(raw_ostream &OS, int Indent,
+                          PdbSymbolIdField ShowIdFields,
+                          PdbSymbolIdField RecurseIdFields) const {
+  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
 
   dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()),
                   Indent);
-  dumpSymbolField(OS, "lexicalParentId", 0, Indent);
+  dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+                    PdbSymbolIdField::LexicalParent, ShowIdFields,
+                    RecurseIdFields);
   dumpSymbolField(OS, "name", getName(), Indent);
-  dumpSymbolField(OS, "typeId", getTypeId(), Indent);
+  dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+                    PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
   if (Modifiers.hasValue())
-    dumpSymbolField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent);
+    dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
+                      Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
+                      RecurseIdFields);
   dumpSymbolField(OS, "length", getLength(), Indent);
   dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
   dumpSymbolField(OS, "constType", isConstType(), Indent);
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
index f41d0a2..4545f7e 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
@@ -18,6 +18,13 @@
 using namespace llvm::pdb;
 
 NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id,
+                                     codeview::TypeIndex TI)
+    : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) {
+  assert(TI.isSimple());
+  assert(TI.getSimpleMode() != SimpleTypeMode::Direct);
+}
+
+NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id,
                                      codeview::TypeIndex TI,
                                      codeview::PointerRecord Record)
     : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI),
@@ -25,11 +32,16 @@
 
 NativeTypePointer::~NativeTypePointer() {}
 
-void NativeTypePointer::dump(raw_ostream &OS, int Indent) const {
-  NativeRawSymbol::dump(OS, Indent);
+void NativeTypePointer::dump(raw_ostream &OS, int Indent,
+                             PdbSymbolIdField ShowIdFields,
+                             PdbSymbolIdField RecurseIdFields) const {
+  NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
 
-  dumpSymbolField(OS, "lexicalParentId", 0, Indent);
-  dumpSymbolField(OS, "typeId", getTypeId(), Indent);
+  dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+                    PdbSymbolIdField::LexicalParent, ShowIdFields,
+                    RecurseIdFields);
+  dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+                    PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
   dumpSymbolField(OS, "length", getLength(), Indent);
   dumpSymbolField(OS, "constType", isConstType(), Indent);
   dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent);
@@ -42,45 +54,82 @@
   dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
 }
 
-uint64_t NativeTypePointer::getLength() const { return Record.getSize(); }
+uint64_t NativeTypePointer::getLength() const {
+  if (Record)
+    return Record->getSize();
+
+  switch (TI.getSimpleMode()) {
+  case SimpleTypeMode::NearPointer:
+  case SimpleTypeMode::FarPointer:
+  case SimpleTypeMode::HugePointer:
+    return 2;
+  case SimpleTypeMode::NearPointer32:
+  case SimpleTypeMode::FarPointer32:
+    return 4;
+  case SimpleTypeMode::NearPointer64:
+    return 8;
+  case SimpleTypeMode::NearPointer128:
+    return 16;
+  default:
+    assert(false && "invalid simple type mode!");
+  }
+  return 0;
+}
 
 SymIndexId NativeTypePointer::getTypeId() const {
   // This is the pointee SymIndexId.
-  return Session.getSymbolCache().findSymbolByTypeIndex(Record.ReferentType);
+  TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect();
+
+  return Session.getSymbolCache().findSymbolByTypeIndex(Referent);
 }
 
 bool NativeTypePointer::isReference() const {
-  return Record.getMode() == PointerMode::LValueReference ||
-         isRValueReference();
+  if (!Record)
+    return false;
+  return Record->getMode() == PointerMode::LValueReference;
 }
 
 bool NativeTypePointer::isRValueReference() const {
-  return Record.getMode() == PointerMode::RValueReference;
+  if (!Record)
+    return false;
+  return Record->getMode() == PointerMode::RValueReference;
 }
 
 bool NativeTypePointer::isPointerToDataMember() const {
-  return Record.getMode() == PointerMode::PointerToDataMember;
+  if (!Record)
+    return false;
+  return Record->getMode() == PointerMode::PointerToDataMember;
 }
 
 bool NativeTypePointer::isPointerToMemberFunction() const {
-  return Record.getMode() == PointerMode::PointerToMemberFunction;
+  if (!Record)
+    return false;
+  return Record->getMode() == PointerMode::PointerToMemberFunction;
 }
 
 bool NativeTypePointer::isConstType() const {
-  return (Record.getOptions() & PointerOptions::Const) != PointerOptions::None;
+  if (!Record)
+    return false;
+  return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None;
 }
 
 bool NativeTypePointer::isRestrictedType() const {
-  return (Record.getOptions() & PointerOptions::Restrict) !=
+  if (!Record)
+    return false;
+  return (Record->getOptions() & PointerOptions::Restrict) !=
          PointerOptions::None;
 }
 
 bool NativeTypePointer::isVolatileType() const {
-  return (Record.getOptions() & PointerOptions::Volatile) !=
+  if (!Record)
+    return false;
+  return (Record->getOptions() & PointerOptions::Volatile) !=
          PointerOptions::None;
 }
 
 bool NativeTypePointer::isUnalignedType() const {
-  return (Record.getOptions() & PointerOptions::Unaligned) !=
+  if (!Record)
+    return false;
+  return (Record->getOptions() & PointerOptions::Unaligned) !=
          PointerOptions::None;
 }
diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
index a4b1ecf..a661227 100644
--- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
@@ -65,18 +65,20 @@
 
 SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
                                          ModifierOptions Mods) {
-  // FIXME:  We will eventually need to handle pointers to other simple types,
-  // which are still simple types in the world of CodeView TypeIndexes.
-  if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
-    return 0;
+  if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) {
+    SymIndexId Id = Cache.size();
+    Cache.emplace_back(
+        llvm::make_unique<NativeTypePointer>(Session, Id, Index));
+    return Id;
+  }
 
+  SymIndexId Id = Cache.size();
   const auto Kind = Index.getSimpleKind();
   const auto It = std::find_if(
       std::begin(BuiltinTypes), std::end(BuiltinTypes),
       [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; });
   if (It == std::end(BuiltinTypes))
     return 0;
-  SymIndexId Id = Cache.size();
   Cache.emplace_back(llvm::make_unique<NativeTypeBuiltin>(Session, Id, Mods,
                                                           It->Type, It->Size));
   TypeIndexToSymbolId[Index] = Id;
@@ -175,12 +177,16 @@
   assert(SymbolId < Cache.size());
 
   // Id 0 is reserved.
-  if (SymbolId == 0)
+  if (SymbolId == 0 || SymbolId >= Cache.size())
     return nullptr;
 
-  // If the caller has a SymbolId, it'd better be in our SymbolCache.
-  return SymbolId < Cache.size() ? PDBSymbol::create(Session, *Cache[SymbolId])
-                                 : nullptr;
+  // Make sure to handle the case where we've inserted a placeholder symbol
+  // for types we don't yet suppport.
+  NativeRawSymbol *NRS = Cache[SymbolId].get();
+  if (!NRS)
+    return nullptr;
+
+  return PDBSymbol::create(Session, *NRS);
 }
 
 NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const {
diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp
index 22ce972..d492eda 100644
--- a/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp
+++ b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp
@@ -115,13 +115,15 @@
   return SymbolPtr;
 }
 
-void PDBSymbol::defaultDump(raw_ostream &OS, int Indent) const {
-  RawSymbol->dump(OS, Indent);
+void PDBSymbol::defaultDump(raw_ostream &OS, int Indent,
+                            PdbSymbolIdField ShowFlags,
+                            PdbSymbolIdField RecurseFlags) const {
+  RawSymbol->dump(OS, Indent, ShowFlags, RecurseFlags);
 }
 
 void PDBSymbol::dumpProperties() const {
   outs() << "\n";
-  defaultDump(outs(), 0);
+  defaultDump(outs(), 0, PdbSymbolIdField::All, PdbSymbolIdField::None);
   outs().flush();
 }
 
@@ -180,3 +182,34 @@
 std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const {
   return Session.getSymbolById(Id);
 }
+
+void llvm::pdb::dumpSymbolIdField(raw_ostream &OS, StringRef Name,
+                                  SymIndexId Value, int Indent,
+                                  const IPDBSession &Session,
+                                  PdbSymbolIdField FieldId,
+                                  PdbSymbolIdField ShowFlags,
+                                  PdbSymbolIdField RecurseFlags) {
+  if ((FieldId & ShowFlags) == PdbSymbolIdField::None)
+    return;
+
+  OS << "\n";
+  OS.indent(Indent);
+  OS << Name << ": " << Value;
+  // Don't recurse unless the user requested it.
+  if ((FieldId & RecurseFlags) == PdbSymbolIdField::None)
+    return;
+  // And obviously don't recurse on the symbol itself.
+  if (FieldId == PdbSymbolIdField::SymIndexId)
+    return;
+
+  auto Child = Session.getSymbolById(Value);
+
+  // It could have been a placeholder symbol for a type we don't yet support,
+  // so just exit in that case.
+  if (!Child)
+    return;
+
+  // Don't recurse more than once, so pass PdbSymbolIdField::None) for the
+  // recurse flags.
+  Child->defaultDump(OS, Indent + 2, ShowFlags, PdbSymbolIdField::None);
+}