1 //===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MinimalTypeDumper.h"
11 #include "TypeReferenceTracker.h"
13 #include "llvm-pdbutil.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/DebugInfo/CodeView/CVRecord.h"
16 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
17 #include "llvm/DebugInfo/CodeView/CodeView.h"
18 #include "llvm/DebugInfo/CodeView/Formatters.h"
19 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
20 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
21 #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
22 #include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
23 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
24 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
25 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
26 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
27 #include "llvm/Object/COFF.h"
28 #include "llvm/Support/FormatVariadic.h"
29 #include "llvm/Support/MathExtras.h"
32 using namespace llvm::codeview
;
33 using namespace llvm::pdb
;
35 static std::string
formatClassOptions(uint32_t IndentLevel
,
36 ClassOptions Options
, TpiStream
*Stream
,
37 TypeIndex CurrentTypeIndex
) {
38 std::vector
<std::string
> Opts
;
40 if (Stream
&& Stream
->supportsTypeLookup() &&
41 !opts::dump::DontResolveForwardRefs
&&
42 ((Options
& ClassOptions::ForwardReference
) != ClassOptions::None
)) {
43 // If we're able to resolve forward references, do that.
44 Expected
<TypeIndex
> ETI
=
45 Stream
->findFullDeclForForwardRef(CurrentTypeIndex
);
47 consumeError(ETI
.takeError());
48 PUSH_FLAG(ClassOptions
, ForwardReference
, Options
, "forward ref (??\?)");
50 const char *Direction
= (*ETI
== CurrentTypeIndex
)
52 : ((*ETI
< CurrentTypeIndex
) ? "<-" : "->");
53 std::string Formatted
=
54 formatv("forward ref ({0} {1})", Direction
, *ETI
).str();
55 PUSH_FLAG(ClassOptions
, ForwardReference
, Options
, std::move(Formatted
));
58 PUSH_FLAG(ClassOptions
, ForwardReference
, Options
, "forward ref");
61 PUSH_FLAG(ClassOptions
, HasConstructorOrDestructor
, Options
,
63 PUSH_FLAG(ClassOptions
, ContainsNestedClass
, Options
,
64 "contains nested class");
65 PUSH_FLAG(ClassOptions
, HasConversionOperator
, Options
,
66 "conversion operator");
67 PUSH_FLAG(ClassOptions
, HasUniqueName
, Options
, "has unique name");
68 PUSH_FLAG(ClassOptions
, Intrinsic
, Options
, "intrin");
69 PUSH_FLAG(ClassOptions
, Nested
, Options
, "is nested");
70 PUSH_FLAG(ClassOptions
, HasOverloadedOperator
, Options
,
71 "overloaded operator");
72 PUSH_FLAG(ClassOptions
, HasOverloadedAssignmentOperator
, Options
,
73 "overloaded operator=");
74 PUSH_FLAG(ClassOptions
, Packed
, Options
, "packed");
75 PUSH_FLAG(ClassOptions
, Scoped
, Options
, "scoped");
76 PUSH_FLAG(ClassOptions
, Sealed
, Options
, "sealed");
78 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
81 static std::string
pointerOptions(PointerOptions Options
) {
82 std::vector
<std::string
> Opts
;
83 PUSH_FLAG(PointerOptions
, Flat32
, Options
, "flat32");
84 PUSH_FLAG(PointerOptions
, Volatile
, Options
, "volatile");
85 PUSH_FLAG(PointerOptions
, Const
, Options
, "const");
86 PUSH_FLAG(PointerOptions
, Unaligned
, Options
, "unaligned");
87 PUSH_FLAG(PointerOptions
, Restrict
, Options
, "restrict");
88 PUSH_FLAG(PointerOptions
, WinRTSmartPointer
, Options
, "winrt");
91 return join(Opts
, " | ");
94 static std::string
modifierOptions(ModifierOptions Options
) {
95 std::vector
<std::string
> Opts
;
96 PUSH_FLAG(ModifierOptions
, Const
, Options
, "const");
97 PUSH_FLAG(ModifierOptions
, Volatile
, Options
, "volatile");
98 PUSH_FLAG(ModifierOptions
, Unaligned
, Options
, "unaligned");
101 return join(Opts
, " | ");
104 static std::string
formatCallingConvention(CallingConvention Convention
) {
105 switch (Convention
) {
106 RETURN_CASE(CallingConvention
, AlphaCall
, "alphacall");
107 RETURN_CASE(CallingConvention
, AM33Call
, "am33call");
108 RETURN_CASE(CallingConvention
, ArmCall
, "armcall");
109 RETURN_CASE(CallingConvention
, ClrCall
, "clrcall");
110 RETURN_CASE(CallingConvention
, FarC
, "far cdecl");
111 RETURN_CASE(CallingConvention
, FarFast
, "far fastcall");
112 RETURN_CASE(CallingConvention
, FarPascal
, "far pascal");
113 RETURN_CASE(CallingConvention
, FarStdCall
, "far stdcall");
114 RETURN_CASE(CallingConvention
, FarSysCall
, "far syscall");
115 RETURN_CASE(CallingConvention
, Generic
, "generic");
116 RETURN_CASE(CallingConvention
, Inline
, "inline");
117 RETURN_CASE(CallingConvention
, M32RCall
, "m32rcall");
118 RETURN_CASE(CallingConvention
, MipsCall
, "mipscall");
119 RETURN_CASE(CallingConvention
, NearC
, "cdecl");
120 RETURN_CASE(CallingConvention
, NearFast
, "fastcall");
121 RETURN_CASE(CallingConvention
, NearPascal
, "pascal");
122 RETURN_CASE(CallingConvention
, NearStdCall
, "stdcall");
123 RETURN_CASE(CallingConvention
, NearSysCall
, "near syscall");
124 RETURN_CASE(CallingConvention
, NearVector
, "vectorcall");
125 RETURN_CASE(CallingConvention
, PpcCall
, "ppccall");
126 RETURN_CASE(CallingConvention
, SHCall
, "shcall");
127 RETURN_CASE(CallingConvention
, SH5Call
, "sh5call");
128 RETURN_CASE(CallingConvention
, ThisCall
, "thiscall");
129 RETURN_CASE(CallingConvention
, TriCall
, "tricall");
131 return formatUnknownEnum(Convention
);
134 static std::string
formatPointerMode(PointerMode Mode
) {
136 RETURN_CASE(PointerMode
, LValueReference
, "ref");
137 RETURN_CASE(PointerMode
, Pointer
, "pointer");
138 RETURN_CASE(PointerMode
, PointerToDataMember
, "data member pointer");
139 RETURN_CASE(PointerMode
, PointerToMemberFunction
, "member fn pointer");
140 RETURN_CASE(PointerMode
, RValueReference
, "rvalue ref");
142 return formatUnknownEnum(Mode
);
145 static std::string
memberAccess(MemberAccess Access
) {
147 RETURN_CASE(MemberAccess
, None
, "");
148 RETURN_CASE(MemberAccess
, Private
, "private");
149 RETURN_CASE(MemberAccess
, Protected
, "protected");
150 RETURN_CASE(MemberAccess
, Public
, "public");
152 return formatUnknownEnum(Access
);
155 static std::string
methodKind(MethodKind Kind
) {
157 RETURN_CASE(MethodKind
, Vanilla
, "");
158 RETURN_CASE(MethodKind
, Virtual
, "virtual");
159 RETURN_CASE(MethodKind
, Static
, "static");
160 RETURN_CASE(MethodKind
, Friend
, "friend");
161 RETURN_CASE(MethodKind
, IntroducingVirtual
, "intro virtual");
162 RETURN_CASE(MethodKind
, PureVirtual
, "pure virtual");
163 RETURN_CASE(MethodKind
, PureIntroducingVirtual
, "pure intro virtual");
165 return formatUnknownEnum(Kind
);
168 static std::string
pointerKind(PointerKind Kind
) {
170 RETURN_CASE(PointerKind
, Near16
, "ptr16");
171 RETURN_CASE(PointerKind
, Far16
, "far ptr16");
172 RETURN_CASE(PointerKind
, Huge16
, "huge ptr16");
173 RETURN_CASE(PointerKind
, BasedOnSegment
, "segment based");
174 RETURN_CASE(PointerKind
, BasedOnValue
, "value based");
175 RETURN_CASE(PointerKind
, BasedOnSegmentValue
, "segment value based");
176 RETURN_CASE(PointerKind
, BasedOnAddress
, "address based");
177 RETURN_CASE(PointerKind
, BasedOnSegmentAddress
, "segment address based");
178 RETURN_CASE(PointerKind
, BasedOnType
, "type based");
179 RETURN_CASE(PointerKind
, BasedOnSelf
, "self based");
180 RETURN_CASE(PointerKind
, Near32
, "ptr32");
181 RETURN_CASE(PointerKind
, Far32
, "far ptr32");
182 RETURN_CASE(PointerKind
, Near64
, "ptr64");
184 return formatUnknownEnum(Kind
);
187 static std::string
memberAttributes(const MemberAttributes
&Attrs
) {
188 std::vector
<std::string
> Opts
;
189 std::string Access
= memberAccess(Attrs
.getAccess());
190 std::string Kind
= methodKind(Attrs
.getMethodKind());
192 Opts
.push_back(Access
);
194 Opts
.push_back(Kind
);
195 MethodOptions Flags
= Attrs
.getFlags();
196 PUSH_FLAG(MethodOptions
, Pseudo
, Flags
, "pseudo");
197 PUSH_FLAG(MethodOptions
, NoInherit
, Flags
, "noinherit");
198 PUSH_FLAG(MethodOptions
, NoConstruct
, Flags
, "noconstruct");
199 PUSH_FLAG(MethodOptions
, CompilerGenerated
, Flags
, "compiler-generated");
200 PUSH_FLAG(MethodOptions
, Sealed
, Flags
, "sealed");
201 return join(Opts
, " ");
204 static std::string
formatPointerAttrs(const PointerRecord
&Record
) {
205 PointerMode Mode
= Record
.getMode();
206 PointerOptions Opts
= Record
.getOptions();
207 PointerKind Kind
= Record
.getPointerKind();
208 return std::string(formatv("mode = {0}, opts = {1}, kind = {2}",
209 formatPointerMode(Mode
), pointerOptions(Opts
),
213 static std::string
formatFunctionOptions(FunctionOptions Options
) {
214 std::vector
<std::string
> Opts
;
216 PUSH_FLAG(FunctionOptions
, CxxReturnUdt
, Options
, "returns cxx udt");
217 PUSH_FLAG(FunctionOptions
, ConstructorWithVirtualBases
, Options
,
218 "constructor with virtual bases");
219 PUSH_FLAG(FunctionOptions
, Constructor
, Options
, "constructor");
222 return join(Opts
, " | ");
225 Error
MinimalTypeDumpVisitor::visitTypeBegin(CVType
&Record
, TypeIndex Index
) {
226 CurrentTypeIndex
= Index
;
227 // formatLine puts the newline at the beginning, so we use formatLine here
228 // to start a new line, and then individual visit methods use format to
229 // append to the existing line.
230 P
.formatLine("{0} | {1} [size = {2}",
231 fmt_align(Index
, AlignStyle::Right
, Width
),
232 formatTypeLeafKind(Record
.kind()), Record
.length());
235 if (Index
.toArrayIndex() >= HashValues
.size()) {
238 uint32_t Hash
= HashValues
[Index
.toArrayIndex()];
239 Expected
<uint32_t> MaybeHash
= hashTypeRecord(Record
);
241 return MaybeHash
.takeError();
242 uint32_t OurHash
= *MaybeHash
;
243 OurHash
%= NumHashBuckets
;
245 H
= "0x" + utohexstr(Hash
);
247 H
= "0x" + utohexstr(Hash
) + ", our hash = 0x" + utohexstr(OurHash
);
249 P
.format(", hash = {0}", H
);
252 if (RefTracker
->isTypeReferenced(Index
))
253 P
.format(", referenced");
255 P
.format(", unreferenced");
259 return Error::success();
262 Error
MinimalTypeDumpVisitor::visitTypeEnd(CVType
&Record
) {
263 P
.Unindent(Width
+ 3);
265 AutoIndent
Indent(P
, 9);
266 P
.formatBinary("Bytes", Record
.RecordData
, 0);
268 return Error::success();
271 Error
MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord
&Record
) {
272 P
.formatLine("- {0}", formatTypeLeafKind(Record
.Kind
));
273 return Error::success();
276 Error
MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord
&Record
) {
278 AutoIndent
Indent(P
, 2);
279 P
.formatBinary("Bytes", Record
.Data
, 0);
281 return Error::success();
284 StringRef
MinimalTypeDumpVisitor::getTypeName(TypeIndex TI
) const {
287 return Types
.getTypeName(TI
);
290 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
291 FieldListRecord
&FieldList
) {
292 if (auto EC
= codeview::visitMemberRecordStream(FieldList
.Data
, *this))
295 return Error::success();
298 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
299 StringIdRecord
&String
) {
300 P
.format(" ID: {0}, String: {1}", String
.getId(), String
.getString());
301 return Error::success();
304 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
305 ArgListRecord
&Args
) {
306 auto Indices
= Args
.getIndices();
308 return Error::success();
310 auto Max
= std::max_element(Indices
.begin(), Indices
.end());
311 uint32_t W
= NumDigits(Max
->getIndex()) + 2;
313 for (auto I
: Indices
)
314 P
.formatLine("{0}: `{1}`", fmt_align(I
, AlignStyle::Right
, W
),
316 return Error::success();
319 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
320 StringListRecord
&Strings
) {
321 auto Indices
= Strings
.getIndices();
323 return Error::success();
325 auto Max
= std::max_element(Indices
.begin(), Indices
.end());
326 uint32_t W
= NumDigits(Max
->getIndex()) + 2;
328 for (auto I
: Indices
)
329 P
.formatLine("{0}: `{1}`", fmt_align(I
, AlignStyle::Right
, W
),
331 return Error::success();
334 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
335 ClassRecord
&Class
) {
336 P
.format(" `{0}`", Class
.Name
);
337 if (Class
.hasUniqueName())
338 P
.formatLine("unique name: `{0}`", Class
.UniqueName
);
339 P
.formatLine("vtable: {0}, base list: {1}, field list: {2}",
340 Class
.VTableShape
, Class
.DerivationList
, Class
.FieldList
);
341 P
.formatLine("options: {0}, sizeof {1}",
342 formatClassOptions(P
.getIndentLevel(), Class
.Options
, Stream
,
345 return Error::success();
348 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
349 UnionRecord
&Union
) {
350 P
.format(" `{0}`", Union
.Name
);
351 if (Union
.hasUniqueName())
352 P
.formatLine("unique name: `{0}`", Union
.UniqueName
);
353 P
.formatLine("field list: {0}", Union
.FieldList
);
354 P
.formatLine("options: {0}, sizeof {1}",
355 formatClassOptions(P
.getIndentLevel(), Union
.Options
, Stream
,
358 return Error::success();
361 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
, EnumRecord
&Enum
) {
362 P
.format(" `{0}`", Enum
.Name
);
363 if (Enum
.hasUniqueName())
364 P
.formatLine("unique name: `{0}`", Enum
.UniqueName
);
365 P
.formatLine("field list: {0}, underlying type: {1}", Enum
.FieldList
,
366 Enum
.UnderlyingType
);
367 P
.formatLine("options: {0}",
368 formatClassOptions(P
.getIndentLevel(), Enum
.Options
, Stream
,
370 return Error::success();
373 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
, ArrayRecord
&AT
) {
374 if (AT
.Name
.empty()) {
375 P
.formatLine("size: {0}, index type: {1}, element type: {2}", AT
.Size
,
376 AT
.IndexType
, AT
.ElementType
);
378 P
.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
379 AT
.Name
, AT
.Size
, AT
.IndexType
, AT
.ElementType
);
381 return Error::success();
384 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
385 VFTableRecord
&VFT
) {
386 P
.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
387 VFT
.VFPtrOffset
, VFT
.CompleteClass
, VFT
.OverriddenVFTable
);
388 P
.formatLine("method names: ");
389 if (!VFT
.MethodNames
.empty()) {
392 fmt_repeat(' ', P
.getIndentLevel() + strlen("method names: ")))
394 P
.print(join(VFT
.MethodNames
, Sep
));
396 return Error::success();
399 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
400 MemberFuncIdRecord
&Id
) {
401 P
.formatLine("name = {0}, type = {1}, class type = {2}", Id
.Name
,
402 Id
.FunctionType
, Id
.ClassType
);
403 return Error::success();
406 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
407 ProcedureRecord
&Proc
) {
408 P
.formatLine("return type = {0}, # args = {1}, param list = {2}",
409 Proc
.ReturnType
, Proc
.ParameterCount
, Proc
.ArgumentList
);
410 P
.formatLine("calling conv = {0}, options = {1}",
411 formatCallingConvention(Proc
.CallConv
),
412 formatFunctionOptions(Proc
.Options
));
413 return Error::success();
416 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
417 MemberFunctionRecord
&MF
) {
418 P
.formatLine("return type = {0}, # args = {1}, param list = {2}",
419 MF
.ReturnType
, MF
.ParameterCount
, MF
.ArgumentList
);
420 P
.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
421 MF
.ClassType
, MF
.ThisType
, MF
.ThisPointerAdjustment
);
422 P
.formatLine("calling conv = {0}, options = {1}",
423 formatCallingConvention(MF
.CallConv
),
424 formatFunctionOptions(MF
.Options
));
425 return Error::success();
428 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
429 FuncIdRecord
&Func
) {
430 P
.formatLine("name = {0}, type = {1}, parent scope = {2}", Func
.Name
,
431 Func
.FunctionType
, Func
.ParentScope
);
432 return Error::success();
435 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
436 TypeServer2Record
&TS
) {
437 P
.formatLine("name = {0}, age = {1}, guid = {2}", TS
.Name
, TS
.Age
, TS
.Guid
);
438 return Error::success();
441 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
442 PointerRecord
&Ptr
) {
443 P
.formatLine("referent = {0}, {1}", Ptr
.ReferentType
,
444 formatPointerAttrs(Ptr
));
445 return Error::success();
448 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
449 ModifierRecord
&Mod
) {
450 P
.formatLine("referent = {0}, modifiers = {1}", Mod
.ModifiedType
,
451 modifierOptions(Mod
.Modifiers
));
452 return Error::success();
455 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
456 VFTableShapeRecord
&Shape
) {
457 return Error::success();
460 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
461 UdtModSourceLineRecord
&U
) {
462 P
.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U
.UDT
, U
.Module
,
463 U
.SourceFile
.getIndex(), U
.LineNumber
);
464 return Error::success();
467 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
468 UdtSourceLineRecord
&U
) {
469 P
.formatLine("udt = {0}, file = {1}, line = {2}", U
.UDT
,
470 U
.SourceFile
.getIndex(), U
.LineNumber
);
471 return Error::success();
474 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
475 BitFieldRecord
&BF
) {
476 P
.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF
.Type
,
477 BF
.BitOffset
, BF
.BitSize
);
478 return Error::success();
481 Error
MinimalTypeDumpVisitor::visitKnownRecord(
482 CVType
&CVR
, MethodOverloadListRecord
&Overloads
) {
483 for (auto &M
: Overloads
.Methods
)
484 P
.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
485 M
.Type
, M
.VFTableOffset
, memberAttributes(M
.Attrs
));
486 return Error::success();
489 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
490 BuildInfoRecord
&BI
) {
491 auto Indices
= BI
.ArgIndices
;
493 return Error::success();
495 auto Max
= std::max_element(Indices
.begin(), Indices
.end());
496 uint32_t W
= NumDigits(Max
->getIndex()) + 2;
498 for (auto I
: Indices
)
499 P
.formatLine("{0}: `{1}`", fmt_align(I
, AlignStyle::Right
, W
),
501 return Error::success();
504 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
, LabelRecord
&R
) {
505 std::string Type
= (R
.Mode
== LabelType::Far
) ? "far" : "near";
506 P
.format(" type = {0}", Type
);
507 return Error::success();
510 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
511 PrecompRecord
&Precomp
) {
512 P
.format(" start index = {0:X+}, types count = {1:X+}, signature = {2:X+},"
513 " precomp path = {3}",
514 Precomp
.StartTypeIndex
, Precomp
.TypesCount
, Precomp
.Signature
,
515 Precomp
.PrecompFilePath
);
516 return Error::success();
519 Error
MinimalTypeDumpVisitor::visitKnownRecord(CVType
&CVR
,
520 EndPrecompRecord
&EP
) {
521 P
.format(" signature = {0:X+}", EP
.Signature
);
522 return Error::success();
525 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
526 NestedTypeRecord
&Nested
) {
527 P
.format(" [name = `{0}`, parent = {1}]", Nested
.Name
, Nested
.Type
);
528 return Error::success();
531 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
532 OneMethodRecord
&Method
) {
533 P
.format(" [name = `{0}`]", Method
.Name
);
534 AutoIndent
Indent(P
);
535 P
.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method
.Type
,
536 Method
.VFTableOffset
, memberAttributes(Method
.Attrs
));
537 return Error::success();
540 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
541 OverloadedMethodRecord
&Method
) {
542 P
.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
543 Method
.Name
, Method
.NumOverloads
, Method
.MethodList
);
544 return Error::success();
547 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
548 DataMemberRecord
&Field
) {
549 P
.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field
.Name
,
550 Field
.Type
, Field
.FieldOffset
, memberAttributes(Field
.Attrs
));
551 return Error::success();
554 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
555 StaticDataMemberRecord
&Field
) {
556 P
.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field
.Name
, Field
.Type
,
557 memberAttributes(Field
.Attrs
));
558 return Error::success();
561 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
562 EnumeratorRecord
&Enum
) {
563 P
.format(" [{0} = {1}]", Enum
.Name
,
564 toString(Enum
.Value
, 10, Enum
.Value
.isSigned()));
565 return Error::success();
568 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
569 BaseClassRecord
&Base
) {
570 AutoIndent
Indent(P
);
571 P
.formatLine("type = {0}, offset = {1}, attrs = {2}", Base
.Type
, Base
.Offset
,
572 memberAttributes(Base
.Attrs
));
573 return Error::success();
576 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
577 VirtualBaseClassRecord
&Base
) {
578 AutoIndent
Indent(P
);
580 "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
581 Base
.BaseType
, Base
.VBPtrType
, Base
.VBPtrOffset
, Base
.VTableIndex
);
582 P
.formatLine("attrs = {0}", memberAttributes(Base
.Attrs
));
583 return Error::success();
586 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
587 ListContinuationRecord
&Cont
) {
588 P
.format(" continuation = {0}", Cont
.ContinuationIndex
);
589 return Error::success();
592 Error
MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord
&CVR
,
594 P
.format(" type = {0}", VFP
.Type
);
595 return Error::success();