[llvm-objcopy] [COFF] Implmement --strip-unneeded and -x/--discard-all for symbols
[llvm-complete.git] / tools / llvm-pdbutil / MinimalTypeDumper.cpp
blob3f10e8ab8a1e6a8a669cf737c16191586aa904eb
1 //===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
10 #include "MinimalTypeDumper.h"
12 #include "FormatUtil.h"
13 #include "LinePrinter.h"
15 #include "llvm-pdbutil.h"
16 #include "llvm/DebugInfo/CodeView/CVRecord.h"
17 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
18 #include "llvm/DebugInfo/CodeView/CodeView.h"
19 #include "llvm/DebugInfo/CodeView/Formatters.h"
20 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
21 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
22 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
23 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24 #include "llvm/Support/FormatVariadic.h"
25 #include "llvm/Support/MathExtras.h"
27 using namespace llvm;
28 using namespace llvm::codeview;
29 using namespace llvm::pdb;
31 static std::string formatClassOptions(uint32_t IndentLevel,
32 ClassOptions Options, TpiStream *Stream,
33 TypeIndex CurrentTypeIndex) {
34 std::vector<std::string> Opts;
36 if (Stream && Stream->supportsTypeLookup() &&
37 !opts::dump::DontResolveForwardRefs &&
38 ((Options & ClassOptions::ForwardReference) != ClassOptions::None)) {
39 // If we're able to resolve forward references, do that.
40 Expected<TypeIndex> ETI =
41 Stream->findFullDeclForForwardRef(CurrentTypeIndex);
42 if (!ETI) {
43 consumeError(ETI.takeError());
44 PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref (??\?)");
45 } else {
46 const char *Direction = (*ETI == CurrentTypeIndex)
47 ? "="
48 : ((*ETI < CurrentTypeIndex) ? "<-" : "->");
49 std::string Formatted =
50 formatv("forward ref ({0} {1})", Direction, *ETI).str();
51 PUSH_FLAG(ClassOptions, ForwardReference, Options, std::move(Formatted));
53 } else {
54 PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
57 PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
58 "has ctor / dtor");
59 PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
60 "contains nested class");
61 PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
62 "conversion operator");
63 PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
64 PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
65 PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
66 PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
67 "overloaded operator");
68 PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
69 "overloaded operator=");
70 PUSH_FLAG(ClassOptions, Packed, Options, "packed");
71 PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
72 PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
74 return typesetItemList(Opts, 4, IndentLevel, " | ");
77 static std::string pointerOptions(PointerOptions Options) {
78 std::vector<std::string> Opts;
79 PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
80 PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
81 PUSH_FLAG(PointerOptions, Const, Options, "const");
82 PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
83 PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
84 PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
85 if (Opts.empty())
86 return "None";
87 return join(Opts, " | ");
90 static std::string modifierOptions(ModifierOptions Options) {
91 std::vector<std::string> Opts;
92 PUSH_FLAG(ModifierOptions, Const, Options, "const");
93 PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
94 PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
95 if (Opts.empty())
96 return "None";
97 return join(Opts, " | ");
100 static std::string formatCallingConvention(CallingConvention Convention) {
101 switch (Convention) {
102 RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
103 RETURN_CASE(CallingConvention, AM33Call, "am33call");
104 RETURN_CASE(CallingConvention, ArmCall, "armcall");
105 RETURN_CASE(CallingConvention, ClrCall, "clrcall");
106 RETURN_CASE(CallingConvention, FarC, "far cdecl");
107 RETURN_CASE(CallingConvention, FarFast, "far fastcall");
108 RETURN_CASE(CallingConvention, FarPascal, "far pascal");
109 RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
110 RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
111 RETURN_CASE(CallingConvention, Generic, "generic");
112 RETURN_CASE(CallingConvention, Inline, "inline");
113 RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
114 RETURN_CASE(CallingConvention, MipsCall, "mipscall");
115 RETURN_CASE(CallingConvention, NearC, "cdecl");
116 RETURN_CASE(CallingConvention, NearFast, "fastcall");
117 RETURN_CASE(CallingConvention, NearPascal, "pascal");
118 RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
119 RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
120 RETURN_CASE(CallingConvention, NearVector, "vectorcall");
121 RETURN_CASE(CallingConvention, PpcCall, "ppccall");
122 RETURN_CASE(CallingConvention, SHCall, "shcall");
123 RETURN_CASE(CallingConvention, SH5Call, "sh5call");
124 RETURN_CASE(CallingConvention, ThisCall, "thiscall");
125 RETURN_CASE(CallingConvention, TriCall, "tricall");
127 return formatUnknownEnum(Convention);
130 static std::string formatPointerMode(PointerMode Mode) {
131 switch (Mode) {
132 RETURN_CASE(PointerMode, LValueReference, "ref");
133 RETURN_CASE(PointerMode, Pointer, "pointer");
134 RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
135 RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
136 RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
138 return formatUnknownEnum(Mode);
141 static std::string memberAccess(MemberAccess Access) {
142 switch (Access) {
143 RETURN_CASE(MemberAccess, None, "");
144 RETURN_CASE(MemberAccess, Private, "private");
145 RETURN_CASE(MemberAccess, Protected, "protected");
146 RETURN_CASE(MemberAccess, Public, "public");
148 return formatUnknownEnum(Access);
151 static std::string methodKind(MethodKind Kind) {
152 switch (Kind) {
153 RETURN_CASE(MethodKind, Vanilla, "");
154 RETURN_CASE(MethodKind, Virtual, "virtual");
155 RETURN_CASE(MethodKind, Static, "static");
156 RETURN_CASE(MethodKind, Friend, "friend");
157 RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
158 RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
159 RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
161 return formatUnknownEnum(Kind);
164 static std::string pointerKind(PointerKind Kind) {
165 switch (Kind) {
166 RETURN_CASE(PointerKind, Near16, "ptr16");
167 RETURN_CASE(PointerKind, Far16, "far ptr16");
168 RETURN_CASE(PointerKind, Huge16, "huge ptr16");
169 RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
170 RETURN_CASE(PointerKind, BasedOnValue, "value based");
171 RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
172 RETURN_CASE(PointerKind, BasedOnAddress, "address based");
173 RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
174 RETURN_CASE(PointerKind, BasedOnType, "type based");
175 RETURN_CASE(PointerKind, BasedOnSelf, "self based");
176 RETURN_CASE(PointerKind, Near32, "ptr32");
177 RETURN_CASE(PointerKind, Far32, "far ptr32");
178 RETURN_CASE(PointerKind, Near64, "ptr64");
180 return formatUnknownEnum(Kind);
183 static std::string memberAttributes(const MemberAttributes &Attrs) {
184 std::vector<std::string> Opts;
185 std::string Access = memberAccess(Attrs.getAccess());
186 std::string Kind = methodKind(Attrs.getMethodKind());
187 if (!Access.empty())
188 Opts.push_back(Access);
189 if (!Kind.empty())
190 Opts.push_back(Kind);
191 MethodOptions Flags = Attrs.getFlags();
192 PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
193 PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
194 PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
195 PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
196 PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
197 return join(Opts, " ");
200 static std::string formatPointerAttrs(const PointerRecord &Record) {
201 PointerMode Mode = Record.getMode();
202 PointerOptions Opts = Record.getOptions();
203 PointerKind Kind = Record.getPointerKind();
204 return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
205 pointerOptions(Opts), pointerKind(Kind));
208 static std::string formatFunctionOptions(FunctionOptions Options) {
209 std::vector<std::string> Opts;
211 PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
212 PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
213 "constructor with virtual bases");
214 PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
215 if (Opts.empty())
216 return "None";
217 return join(Opts, " | ");
220 Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
221 CurrentTypeIndex = Index;
222 // formatLine puts the newline at the beginning, so we use formatLine here
223 // to start a new line, and then individual visit methods use format to
224 // append to the existing line.
225 if (!Hashes) {
226 P.formatLine("{0} | {1} [size = {2}]",
227 fmt_align(Index, AlignStyle::Right, Width),
228 formatTypeLeafKind(Record.Type), Record.length());
229 } else {
230 std::string H;
231 if (Index.toArrayIndex() >= HashValues.size()) {
232 H = "(not present)";
233 } else {
234 uint32_t Hash = HashValues[Index.toArrayIndex()];
235 Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
236 if (!MaybeHash)
237 return MaybeHash.takeError();
238 uint32_t OurHash = *MaybeHash;
239 OurHash %= NumHashBuckets;
240 if (Hash == OurHash)
241 H = "0x" + utohexstr(Hash);
242 else
243 H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
245 P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
246 fmt_align(Index, AlignStyle::Right, Width),
247 formatTypeLeafKind(Record.Type), Record.length(), H);
249 P.Indent(Width + 3);
250 return Error::success();
252 Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
253 P.Unindent(Width + 3);
254 if (RecordBytes) {
255 AutoIndent Indent(P, 9);
256 P.formatBinary("Bytes", Record.RecordData, 0);
258 return Error::success();
261 Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
262 P.formatLine("- {0}", formatTypeLeafKind(Record.Kind));
263 return Error::success();
266 Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
267 if (RecordBytes) {
268 AutoIndent Indent(P, 2);
269 P.formatBinary("Bytes", Record.Data, 0);
271 return Error::success();
274 StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
275 if (TI.isNoneType())
276 return "";
277 return Types.getTypeName(TI);
280 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
281 FieldListRecord &FieldList) {
282 if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
283 return EC;
285 return Error::success();
288 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
289 StringIdRecord &String) {
290 P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
291 return Error::success();
294 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
295 ArgListRecord &Args) {
296 auto Indices = Args.getIndices();
297 if (Indices.empty())
298 return Error::success();
300 auto Max = std::max_element(Indices.begin(), Indices.end());
301 uint32_t W = NumDigits(Max->getIndex()) + 2;
303 for (auto I : Indices)
304 P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
305 getTypeName(I));
306 return Error::success();
309 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
310 StringListRecord &Strings) {
311 auto Indices = Strings.getIndices();
312 if (Indices.empty())
313 return Error::success();
315 auto Max = std::max_element(Indices.begin(), Indices.end());
316 uint32_t W = NumDigits(Max->getIndex()) + 2;
318 for (auto I : Indices)
319 P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
320 getTypeName(I));
321 return Error::success();
324 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
325 ClassRecord &Class) {
326 P.format(" `{0}`", Class.Name);
327 if (Class.hasUniqueName())
328 P.formatLine("unique name: `{0}`", Class.UniqueName);
329 P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
330 Class.VTableShape, Class.DerivationList, Class.FieldList);
331 P.formatLine("options: {0}, sizeof {1}",
332 formatClassOptions(P.getIndentLevel(), Class.Options, Stream,
333 CurrentTypeIndex),
334 Class.Size);
335 return Error::success();
338 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
339 UnionRecord &Union) {
340 P.format(" `{0}`", Union.Name);
341 if (Union.hasUniqueName())
342 P.formatLine("unique name: `{0}`", Union.UniqueName);
343 P.formatLine("field list: {0}", Union.FieldList);
344 P.formatLine("options: {0}, sizeof {1}",
345 formatClassOptions(P.getIndentLevel(), Union.Options, Stream,
346 CurrentTypeIndex),
347 Union.Size);
348 return Error::success();
351 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
352 P.format(" `{0}`", Enum.Name);
353 if (Enum.hasUniqueName())
354 P.formatLine("unique name: `{0}`", Enum.UniqueName);
355 P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
356 Enum.UnderlyingType);
357 P.formatLine("options: {0}",
358 formatClassOptions(P.getIndentLevel(), Enum.Options, Stream,
359 CurrentTypeIndex));
360 return Error::success();
363 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
364 if (AT.Name.empty()) {
365 P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
366 AT.IndexType, AT.ElementType);
367 } else {
368 P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
369 AT.Name, AT.Size, AT.IndexType, AT.ElementType);
371 return Error::success();
374 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
375 VFTableRecord &VFT) {
376 P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
377 VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
378 P.formatLine("method names: ");
379 if (!VFT.MethodNames.empty()) {
380 std::string Sep =
381 formatv("\n{0}",
382 fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
383 .str();
384 P.print(join(VFT.MethodNames, Sep));
386 return Error::success();
389 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
390 MemberFuncIdRecord &Id) {
391 P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
392 Id.FunctionType, Id.ClassType);
393 return Error::success();
396 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
397 ProcedureRecord &Proc) {
398 P.formatLine("return type = {0}, # args = {1}, param list = {2}",
399 Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
400 P.formatLine("calling conv = {0}, options = {1}",
401 formatCallingConvention(Proc.CallConv),
402 formatFunctionOptions(Proc.Options));
403 return Error::success();
406 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
407 MemberFunctionRecord &MF) {
408 P.formatLine("return type = {0}, # args = {1}, param list = {2}",
409 MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
410 P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
411 MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
412 P.formatLine("calling conv = {0}, options = {1}",
413 formatCallingConvention(MF.CallConv),
414 formatFunctionOptions(MF.Options));
415 return Error::success();
418 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
419 FuncIdRecord &Func) {
420 P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
421 Func.FunctionType, Func.ParentScope);
422 return Error::success();
425 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
426 TypeServer2Record &TS) {
427 P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
428 return Error::success();
431 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
432 PointerRecord &Ptr) {
433 P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
434 formatPointerAttrs(Ptr));
435 return Error::success();
438 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
439 ModifierRecord &Mod) {
440 P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
441 modifierOptions(Mod.Modifiers));
442 return Error::success();
445 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
446 VFTableShapeRecord &Shape) {
447 return Error::success();
450 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
451 UdtModSourceLineRecord &U) {
452 P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
453 U.SourceFile.getIndex(), U.LineNumber);
454 return Error::success();
457 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
458 UdtSourceLineRecord &U) {
459 P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
460 U.SourceFile.getIndex(), U.LineNumber);
461 return Error::success();
464 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
465 BitFieldRecord &BF) {
466 P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
467 BF.BitOffset, BF.BitSize);
468 return Error::success();
471 Error MinimalTypeDumpVisitor::visitKnownRecord(
472 CVType &CVR, MethodOverloadListRecord &Overloads) {
473 for (auto &M : Overloads.Methods)
474 P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
475 M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
476 return Error::success();
479 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
480 BuildInfoRecord &BI) {
481 auto Indices = BI.ArgIndices;
482 if (Indices.empty())
483 return Error::success();
485 auto Max = std::max_element(Indices.begin(), Indices.end());
486 uint32_t W = NumDigits(Max->getIndex()) + 2;
488 for (auto I : Indices)
489 P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
490 getTypeName(I));
491 return Error::success();
494 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
495 std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
496 P.format(" type = {0}", Type);
497 return Error::success();
500 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
501 PrecompRecord &Precomp) {
502 P.format(" start index = {0:X+}, types count = {1:X+}, signature = {2:X+},"
503 " precomp path = {3}",
504 Precomp.StartTypeIndex, Precomp.TypesCount, Precomp.Signature,
505 Precomp.PrecompFilePath);
506 return Error::success();
509 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
510 EndPrecompRecord &EP) {
511 P.format(" signature = {0:X+}", EP.Signature);
512 return Error::success();
515 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
516 NestedTypeRecord &Nested) {
517 P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
518 return Error::success();
521 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
522 OneMethodRecord &Method) {
523 P.format(" [name = `{0}`]", Method.Name);
524 AutoIndent Indent(P);
525 P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
526 Method.VFTableOffset, memberAttributes(Method.Attrs));
527 return Error::success();
530 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
531 OverloadedMethodRecord &Method) {
532 P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
533 Method.Name, Method.NumOverloads, Method.MethodList);
534 return Error::success();
537 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
538 DataMemberRecord &Field) {
539 P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
540 Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
541 return Error::success();
544 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
545 StaticDataMemberRecord &Field) {
546 P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
547 memberAttributes(Field.Attrs));
548 return Error::success();
551 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
552 EnumeratorRecord &Enum) {
553 P.format(" [{0} = {1}]", Enum.Name,
554 Enum.Value.toString(10, Enum.Value.isSigned()));
555 return Error::success();
558 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
559 BaseClassRecord &Base) {
560 AutoIndent Indent(P);
561 P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
562 memberAttributes(Base.Attrs));
563 return Error::success();
566 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
567 VirtualBaseClassRecord &Base) {
568 AutoIndent Indent(P);
569 P.formatLine(
570 "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
571 Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
572 P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
573 return Error::success();
576 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
577 ListContinuationRecord &Cont) {
578 P.format(" continuation = {0}", Cont.ContinuationIndex);
579 return Error::success();
582 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
583 VFPtrRecord &VFP) {
584 P.format(" type = {0}", VFP.Type);
585 return Error::success();