[llvm-pdbutil] Add the ability to dump the dependency tree for a type

Previously we had the -type-index option which would dump the record of
a single, but we had no way to follow the dependency graph backwards and
also dump all dependent types.

Having this option makes test-writing better, because we can limit the
test to only those records that are of importance for the thing we're
trying to test, which allows us to use things like CHECK-NEXT to reduce
fragility.

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

llvm-svn: 306852
diff --git a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
index f76635f..3a956c9 100644
--- a/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -37,6 +37,7 @@
 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
@@ -116,12 +117,14 @@
       return EC;
   }
 
-  if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) {
+  if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
+      opts::dump::DumpTypeExtras) {
     if (auto EC = dumpTpiStream(StreamTPI))
       return EC;
   }
 
-  if (opts::dump::DumpIds || opts::dump::DumpIdExtras) {
+  if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
+      opts::dump::DumpIdExtras) {
     if (auto EC = dumpTpiStream(StreamIPI))
       return EC;
   }
@@ -620,6 +623,76 @@
   return Error::success();
 }
 
+static void buildDepSet(LazyRandomTypeCollection &Types,
+                        ArrayRef<TypeIndex> Indices,
+                        std::map<TypeIndex, CVType> &DepSet) {
+  SmallVector<TypeIndex, 4> DepList;
+  for (const auto &I : Indices) {
+    TypeIndex TI(I);
+    if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
+      continue;
+
+    CVType Type = Types.getType(TI);
+    DepSet[TI] = Type;
+    codeview::discoverTypeIndices(Type, DepList);
+    buildDepSet(Types, DepList, DepSet);
+  }
+}
+
+static void dumpFullTypeStream(LinePrinter &Printer,
+                               LazyRandomTypeCollection &Types,
+                               TpiStream &Stream, bool Bytes, bool Extras) {
+  Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
+  uint32_t Width =
+      NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+                           Stream.getHashValues());
+
+  if (auto EC = codeview::visitTypeStream(Types, V)) {
+    Printer.formatLine("An error occurred dumping type records: {0}",
+                       toString(std::move(EC)));
+  }
+}
+
+static void dumpPartialTypeStream(LinePrinter &Printer,
+                                  LazyRandomTypeCollection &Types,
+                                  TpiStream &Stream, ArrayRef<TypeIndex> TiList,
+                                  bool Bytes, bool Extras, bool Deps) {
+  uint32_t Width =
+      NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+                           Stream.getHashValues());
+
+  if (opts::dump::DumpTypeDependents) {
+    // If we need to dump all dependents, then iterate each index and find
+    // all dependents, adding them to a map ordered by TypeIndex.
+    std::map<TypeIndex, CVType> DepSet;
+    buildDepSet(Types, TiList, DepSet);
+
+    Printer.formatLine(
+        "Showing {0:N} records and their dependents ({1:N} records total)",
+        TiList.size(), DepSet.size());
+
+    for (auto &Dep : DepSet) {
+      if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
+        Printer.formatLine("An error occurred dumping type record {0}: {1}",
+                           Dep.first, toString(std::move(EC)));
+    }
+  } else {
+    Printer.formatLine("Showing {0:N} records.", TiList.size());
+
+    for (const auto &I : TiList) {
+      TypeIndex TI(I);
+      CVType Type = Types.getType(TI);
+      if (auto EC = codeview::visitTypeRecord(Type, TI, V))
+        Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
+                           toString(std::move(EC)));
+    }
+  }
+}
+
 Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
 
@@ -659,27 +732,13 @@
 
   auto &Types = Err(initializeTypes(StreamIdx));
 
-  if (DumpTypes) {
-    P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
-    uint32_t Width =
-        NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
-
-    MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
-                             Stream.getHashValues());
-
-    if (Indices.empty()) {
-      if (auto EC = codeview::visitTypeStream(Types, V)) {
-        P.formatLine("An error occurred dumping type records: {0}",
-                     toString(std::move(EC)));
-      }
-    } else {
-      for (const auto &I : Indices) {
-        TypeIndex TI(I);
-        CVType Type = Types.getType(TI);
-        if (auto EC = codeview::visitTypeRecord(Type, TI, V))
-          P.formatLine("An error occurred dumping type record {0}: {1}", TI,
-                       toString(std::move(EC)));
-      }
+  if (DumpTypes || !Indices.empty()) {
+    if (Indices.empty())
+      dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
+    else {
+      std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
+      dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
+                            opts::dump::DumpTypeDependents);
     }
   }
 
diff --git a/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
index 296a6c1..4c52289 100644
--- a/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
+++ b/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -37,8 +37,6 @@
 
   Error dumpFileSummary();
   Error dumpStreamSummary();
-  Error dumpBlockRanges();
-  Error dumpStreamBytes();
   Error dumpStringTable();
   Error dumpLines();
   Error dumpInlineeLines();
diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index 22d3a45..1af53e3 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -377,7 +377,7 @@
 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
                                                MemberFunctionRecord &MF) {
   P.formatLine("return type = {0}, # args = {1}, param list = {2}",
-               MF.ParameterCount, MF.ArgumentList, MF.ReturnType);
+               MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
   P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
                MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
   P.formatLine("calling conv = {0}, options = {1}",
diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
index 4a176fb..ad11ad4 100644
--- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -419,6 +419,13 @@
     cl::desc("only dump ids with the specified hexadecimal type index"),
     cl::cat(TypeOptions), cl::sub(DumpSubcommand));
 
+cl::opt<bool> DumpTypeDependents(
+    "dependents",
+    cl::desc("In conjunection with -type-index and -id-index, dumps the entire "
+             "dependency graph for the specified index instead of "
+             "just the single record with the specified index"),
+    cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
 // SYMBOL OPTIONS
 cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
                           cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
diff --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
index 837d8eb..9ee5866 100644
--- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -135,6 +135,7 @@
 extern llvm::cl::opt<bool> DumpTypeData;
 extern llvm::cl::opt<bool> DumpTypeExtras;
 extern llvm::cl::list<uint32_t> DumpTypeIndex;
+extern llvm::cl::opt<bool> DumpTypeDependents;
 
 extern llvm::cl::opt<bool> DumpIds;
 extern llvm::cl::opt<bool> DumpIdData;