[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / tools / llvm-pdbutil / PrettyTypeDumper.cpp
blob9547d4e4ed356e503a5390aa58183211e24cab4d
1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "PrettyTypeDumper.h"
11 #include "PrettyBuiltinDumper.h"
12 #include "PrettyClassDefinitionDumper.h"
13 #include "PrettyEnumDumper.h"
14 #include "PrettyFunctionDumper.h"
15 #include "PrettyTypedefDumper.h"
16 #include "llvm-pdbutil.h"
18 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
19 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
20 #include "llvm/DebugInfo/PDB/IPDBSession.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
25 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
26 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
27 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
28 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
29 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
30 #include "llvm/DebugInfo/PDB/UDTLayout.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/FormatVariadic.h"
34 using namespace llvm;
35 using namespace llvm::pdb;
37 using LayoutPtr = std::unique_ptr<ClassLayout>;
39 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
41 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
42 return S1->getName() < S2->getName();
45 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
46 return S1->getSize() < S2->getSize();
49 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
50 return S1->deepPaddingSize() < S2->deepPaddingSize();
53 static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
54 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
55 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
56 return Pct1 < Pct2;
59 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
60 return S1->immediatePadding() < S2->immediatePadding();
63 static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
64 const LayoutPtr &S2) {
65 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
66 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
67 return Pct1 < Pct2;
70 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
71 switch (Mode) {
72 case opts::pretty::ClassSortMode::Name:
73 return CompareNames;
74 case opts::pretty::ClassSortMode::Size:
75 return CompareSizes;
76 case opts::pretty::ClassSortMode::Padding:
77 return ComparePadding;
78 case opts::pretty::ClassSortMode::PaddingPct:
79 return ComparePaddingPct;
80 case opts::pretty::ClassSortMode::PaddingImmediate:
81 return ComparePaddingImmediate;
82 case opts::pretty::ClassSortMode::PaddingPctImmediate:
83 return ComparePaddingPctImmediate;
84 default:
85 return nullptr;
89 template <typename Enumerator>
90 static std::vector<std::unique_ptr<ClassLayout>>
91 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
92 uint32_t UnfilteredCount) {
93 std::vector<std::unique_ptr<ClassLayout>> Filtered;
95 Filtered.reserve(UnfilteredCount);
96 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
98 if (UnfilteredCount > 10000) {
99 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
100 errs().flush();
102 uint32_t Examined = 0;
103 uint32_t Discarded = 0;
104 while (auto Class = E.getNext()) {
105 ++Examined;
106 if (Examined % 10000 == 0) {
107 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
108 Examined, UnfilteredCount, Discarded);
109 errs().flush();
112 if (Class->getUnmodifiedTypeId() != 0) {
113 ++Discarded;
114 continue;
117 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
118 ++Discarded;
119 continue;
122 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
123 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
124 ++Discarded;
125 continue;
127 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
128 ++Discarded;
129 continue;
132 Filtered.push_back(std::move(Layout));
135 if (Comp)
136 llvm::sort(Filtered, Comp);
137 return Filtered;
140 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
142 template <typename T>
143 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
144 return false;
147 static bool isTypeExcluded(LinePrinter &Printer,
148 const PDBSymbolTypeEnum &Enum) {
149 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
150 return true;
151 // Dump member enums when dumping their class definition.
152 if (nullptr != Enum.getClassParent())
153 return true;
154 return false;
157 static bool isTypeExcluded(LinePrinter &Printer,
158 const PDBSymbolTypeTypedef &Typedef) {
159 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
162 template <typename SymbolT>
163 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
164 TypeDumper &TD, StringRef Label) {
165 if (auto Children = Exe.findAllChildren<SymbolT>()) {
166 Printer.NewLine();
167 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
168 Printer << ": (" << Children->getChildCount() << " items)";
169 Printer.Indent();
170 while (auto Child = Children->getNext()) {
171 if (isTypeExcluded(Printer, *Child))
172 continue;
174 Printer.NewLine();
175 Child->dump(TD);
177 Printer.Unindent();
181 static void printClassDecl(LinePrinter &Printer,
182 const PDBSymbolTypeUDT &Class) {
183 if (Class.getUnmodifiedTypeId() != 0) {
184 if (Class.isConstType())
185 WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
186 if (Class.isVolatileType())
187 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
188 if (Class.isUnalignedType())
189 WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
191 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
192 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
195 void TypeDumper::start(const PDBSymbolExe &Exe) {
196 if (opts::pretty::Enums)
197 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
199 if (opts::pretty::Funcsigs)
200 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
201 "Function Signatures");
203 if (opts::pretty::Typedefs)
204 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
206 if (opts::pretty::Arrays)
207 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
209 if (opts::pretty::Pointers)
210 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
212 if (opts::pretty::VTShapes)
213 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
214 "VFTable Shapes");
216 if (opts::pretty::Classes) {
217 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
218 uint32_t All = Classes->getChildCount();
220 Printer.NewLine();
221 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
223 bool Precompute = false;
224 Precompute =
225 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
227 // If we're using no sort mode, then we can start getting immediate output
228 // from the tool by just filtering as we go, rather than processing
229 // everything up front so that we can sort it. This makes the tool more
230 // responsive. So only precompute the filtered/sorted set of classes if
231 // necessary due to the specified options.
232 std::vector<LayoutPtr> Filtered;
233 uint32_t Shown = All;
234 if (Precompute) {
235 Filtered = filterAndSortClassDefs(Printer, *Classes, All);
237 Shown = Filtered.size();
240 Printer << ": (Showing " << Shown << " items";
241 if (Shown < All)
242 Printer << ", " << (All - Shown) << " filtered";
243 Printer << ")";
244 Printer.Indent();
246 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
247 // the DIA enumerator and filter on the fly.
248 if (Precompute) {
249 for (auto &Class : Filtered)
250 dumpClassLayout(*Class);
251 } else {
252 while (auto Class = Classes->getNext()) {
253 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
254 continue;
256 // No point duplicating a full class layout. Just print the modified
257 // declaration and continue.
258 if (Class->getUnmodifiedTypeId() != 0) {
259 Printer.NewLine();
260 printClassDecl(Printer, *Class);
261 continue;
264 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
265 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
266 continue;
268 dumpClassLayout(*Layout);
272 Printer.Unindent();
277 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
278 assert(opts::pretty::Enums);
280 EnumDumper Dumper(Printer);
281 Dumper.start(Symbol);
284 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
285 BuiltinDumper BD(Printer);
286 BD.start(Symbol);
289 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
290 printClassDecl(Printer, Symbol);
293 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
294 assert(opts::pretty::Typedefs);
296 TypedefDumper Dumper(Printer);
297 Dumper.start(Symbol);
300 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
301 auto ElementType = Symbol.getElementType();
303 ElementType->dump(*this);
304 Printer << "[";
305 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
306 Printer << "]";
309 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
310 FunctionDumper Dumper(Printer);
311 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
314 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
315 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
317 if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
318 FunctionDumper Dumper(Printer);
319 FunctionDumper::PointerType PT =
320 Symbol.isReference() ? FunctionDumper::PointerType::Reference
321 : FunctionDumper::PointerType::Pointer;
322 Dumper.start(*FS, nullptr, PT);
323 return;
326 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
327 printClassDecl(Printer, *UDT);
328 } else if (P) {
329 P->dump(*this);
332 if (auto Parent = Symbol.getClassParent()) {
333 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
334 if (UDT)
335 Printer << " " << UDT->getName() << "::";
338 if (Symbol.isReference())
339 Printer << "&";
340 else if (Symbol.isRValueReference())
341 Printer << "&&";
342 else
343 Printer << "*";
346 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
347 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
350 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
351 assert(opts::pretty::Classes);
353 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
354 WithColor(Printer, PDB_ColorItem::Keyword).get()
355 << Class.getClass().getUdtKind() << " ";
356 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
357 } else {
358 ClassDefinitionDumper Dumper(Printer);
359 Dumper.start(Class);