1 //===- MicrosoftDemangle.cpp ----------------------------------------------===//
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 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a demangler for MSVC-style mangled symbols.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Demangle/MicrosoftDemangleNodes.h"
14 #include "llvm/Demangle/DemangleConfig.h"
15 #include "llvm/Demangle/Utility.h"
16 #include <cctype>
17 #include <string>
18
19 using namespace llvm;
20 using namespace ms_demangle;
21
22 #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
23 case Enum::Value: \
24 OS << Desc; \
25 break;
26
27 // Writes a space if the last token does not end with a punctuation.
outputSpaceIfNecessary(OutputStream & OS)28 static void outputSpaceIfNecessary(OutputStream &OS) {
29 if (OS.empty())
30 return;
31
32 char C = OS.back();
33 if (std::isalnum(C) || C == '>')
34 OS << " ";
35 }
36
outputSingleQualifier(OutputStream & OS,Qualifiers Q)37 static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
38 switch (Q) {
39 case Q_Const:
40 OS << "const";
41 break;
42 case Q_Volatile:
43 OS << "volatile";
44 break;
45 case Q_Restrict:
46 OS << "__restrict";
47 break;
48 default:
49 break;
50 }
51 }
52
outputQualifierIfPresent(OutputStream & OS,Qualifiers Q,Qualifiers Mask,bool NeedSpace)53 static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
54 Qualifiers Mask, bool NeedSpace) {
55 if (!(Q & Mask))
56 return NeedSpace;
57
58 if (NeedSpace)
59 OS << " ";
60
61 outputSingleQualifier(OS, Mask);
62 return true;
63 }
64
outputQualifiers(OutputStream & OS,Qualifiers Q,bool SpaceBefore,bool SpaceAfter)65 static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
66 bool SpaceAfter) {
67 if (Q == Q_None)
68 return;
69
70 size_t Pos1 = OS.getCurrentPosition();
71 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
72 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
73 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
74 size_t Pos2 = OS.getCurrentPosition();
75 if (SpaceAfter && Pos2 > Pos1)
76 OS << " ";
77 }
78
outputCallingConvention(OutputStream & OS,CallingConv CC)79 static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
80 outputSpaceIfNecessary(OS);
81
82 switch (CC) {
83 case CallingConv::Cdecl:
84 OS << "__cdecl";
85 break;
86 case CallingConv::Fastcall:
87 OS << "__fastcall";
88 break;
89 case CallingConv::Pascal:
90 OS << "__pascal";
91 break;
92 case CallingConv::Regcall:
93 OS << "__regcall";
94 break;
95 case CallingConv::Stdcall:
96 OS << "__stdcall";
97 break;
98 case CallingConv::Thiscall:
99 OS << "__thiscall";
100 break;
101 case CallingConv::Eabi:
102 OS << "__eabi";
103 break;
104 case CallingConv::Vectorcall:
105 OS << "__vectorcall";
106 break;
107 case CallingConv::Clrcall:
108 OS << "__clrcall";
109 break;
110 case CallingConv::Swift:
111 OS << "__attribute__((__swiftcall__)) ";
112 break;
113 default:
114 break;
115 }
116 }
117
toString(OutputFlags Flags) const118 std::string Node::toString(OutputFlags Flags) const {
119 OutputStream OS;
120 initializeOutputStream(nullptr, nullptr, OS, 1024);
121 this->output(OS, Flags);
122 OS << '\0';
123 std::string Owned(OS.getBuffer());
124 std::free(OS.getBuffer());
125 return Owned;
126 }
127
outputPre(OutputStream & OS,OutputFlags Flags) const128 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
129 switch (PrimKind) {
130 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
131 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
132 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
133 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
134 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
135 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
136 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
137 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
138 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
139 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
140 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
141 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
142 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
143 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
144 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
145 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
146 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
147 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
148 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
149 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
150 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
151 }
152 outputQualifiers(OS, Quals, true, false);
153 }
154
output(OutputStream & OS,OutputFlags Flags) const155 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
156 output(OS, Flags, ", ");
157 }
158
output(OutputStream & OS,OutputFlags Flags,StringView Separator) const159 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
160 StringView Separator) const {
161 if (Count == 0)
162 return;
163 if (Nodes[0])
164 Nodes[0]->output(OS, Flags);
165 for (size_t I = 1; I < Count; ++I) {
166 OS << Separator;
167 Nodes[I]->output(OS, Flags);
168 }
169 }
170
output(OutputStream & OS,OutputFlags Flags) const171 void EncodedStringLiteralNode::output(OutputStream &OS,
172 OutputFlags Flags) const {
173 switch (Char) {
174 case CharKind::Wchar:
175 OS << "L\"";
176 break;
177 case CharKind::Char:
178 OS << "\"";
179 break;
180 case CharKind::Char16:
181 OS << "u\"";
182 break;
183 case CharKind::Char32:
184 OS << "U\"";
185 break;
186 }
187 OS << DecodedString << "\"";
188 if (IsTruncated)
189 OS << "...";
190 }
191
output(OutputStream & OS,OutputFlags Flags) const192 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
193 if (IsNegative)
194 OS << '-';
195 OS << Value;
196 }
197
output(OutputStream & OS,OutputFlags Flags) const198 void TemplateParameterReferenceNode::output(OutputStream &OS,
199 OutputFlags Flags) const {
200 if (ThunkOffsetCount > 0)
201 OS << "{";
202 else if (Affinity == PointerAffinity::Pointer)
203 OS << "&";
204
205 if (Symbol) {
206 Symbol->output(OS, Flags);
207 if (ThunkOffsetCount > 0)
208 OS << ", ";
209 }
210
211 if (ThunkOffsetCount > 0)
212 OS << ThunkOffsets[0];
213 for (int I = 1; I < ThunkOffsetCount; ++I) {
214 OS << ", " << ThunkOffsets[I];
215 }
216 if (ThunkOffsetCount > 0)
217 OS << "}";
218 }
219
outputTemplateParameters(OutputStream & OS,OutputFlags Flags) const220 void IdentifierNode::outputTemplateParameters(OutputStream &OS,
221 OutputFlags Flags) const {
222 if (!TemplateParams)
223 return;
224 OS << "<";
225 TemplateParams->output(OS, Flags);
226 OS << ">";
227 }
228
output(OutputStream & OS,OutputFlags Flags) const229 void DynamicStructorIdentifierNode::output(OutputStream &OS,
230 OutputFlags Flags) const {
231 if (IsDestructor)
232 OS << "`dynamic atexit destructor for ";
233 else
234 OS << "`dynamic initializer for ";
235
236 if (Variable) {
237 OS << "`";
238 Variable->output(OS, Flags);
239 OS << "''";
240 } else {
241 OS << "'";
242 Name->output(OS, Flags);
243 OS << "''";
244 }
245 }
246
output(OutputStream & OS,OutputFlags Flags) const247 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
248 OS << Name;
249 outputTemplateParameters(OS, Flags);
250 }
251
output(OutputStream & OS,OutputFlags Flags) const252 void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
253 OutputFlags Flags) const {
254 switch (Operator) {
255 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
256 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
257 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
258 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
259 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
260 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
261 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
262 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
263 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
264 "operator[]");
265 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
266 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
267 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
268 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
269 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
270 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
271 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
272 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
273 "operator->*");
274 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
275 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
276 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
277 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
278 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
279 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
280 "operator>=");
281 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
282 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
283 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
284 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
285 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
286 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
287 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
288 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
289 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
290 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
291 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
292 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
293 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
294 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
295 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
296 "operator&=");
297 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
298 "operator|=");
299 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
300 "operator^=");
301 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
302 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
303 "`vector deleting dtor'");
304 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
305 "`default ctor closure'");
306 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
307 "`scalar deleting dtor'");
308 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
309 "`vector ctor iterator'");
310 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
311 "`vector dtor iterator'");
312 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
313 "`vector vbase ctor iterator'");
314 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
315 "`virtual displacement map'");
316 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
317 "`eh vector ctor iterator'");
318 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
319 "`eh vector dtor iterator'");
320 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
321 "`eh vector vbase ctor iterator'");
322 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
323 "`copy ctor closure'");
324 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
325 "`local vftable ctor closure'");
326 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
327 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
328 "operator delete[]");
329 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
330 "`managed vector ctor iterator'");
331 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
332 "`managed vector dtor iterator'");
333 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
334 "`EH vector copy ctor iterator'");
335 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
336 "`EH vector vbase copy ctor iterator'");
337 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
338 "`vector copy ctor iterator'");
339 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
340 "`vector vbase copy constructor iterator'");
341 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
342 "`managed vector vbase copy constructor iterator'");
343 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
344 "operator co_await");
345 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
346 case IntrinsicFunctionKind::MaxIntrinsic:
347 case IntrinsicFunctionKind::None:
348 break;
349 }
350 outputTemplateParameters(OS, Flags);
351 }
352
output(OutputStream & OS,OutputFlags Flags) const353 void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
354 OutputFlags Flags) const {
355 if (IsThread)
356 OS << "`local static thread guard'";
357 else
358 OS << "`local static guard'";
359 if (ScopeIndex > 0)
360 OS << "{" << ScopeIndex << "}";
361 }
362
output(OutputStream & OS,OutputFlags Flags) const363 void ConversionOperatorIdentifierNode::output(OutputStream &OS,
364 OutputFlags Flags) const {
365 OS << "operator";
366 outputTemplateParameters(OS, Flags);
367 OS << " ";
368 TargetType->output(OS, Flags);
369 }
370
output(OutputStream & OS,OutputFlags Flags) const371 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
372 if (IsDestructor)
373 OS << "~";
374 Class->output(OS, Flags);
375 outputTemplateParameters(OS, Flags);
376 }
377
output(OutputStream & OS,OutputFlags Flags) const378 void LiteralOperatorIdentifierNode::output(OutputStream &OS,
379 OutputFlags Flags) const {
380 OS << "operator \"\"" << Name;
381 outputTemplateParameters(OS, Flags);
382 }
383
outputPre(OutputStream & OS,OutputFlags Flags) const384 void FunctionSignatureNode::outputPre(OutputStream &OS,
385 OutputFlags Flags) const {
386 if (!(Flags & OF_NoAccessSpecifier)) {
387 if (FunctionClass & FC_Public)
388 OS << "public: ";
389 if (FunctionClass & FC_Protected)
390 OS << "protected: ";
391 if (FunctionClass & FC_Private)
392 OS << "private: ";
393 }
394
395 if (!(Flags & OF_NoMemberType)) {
396 if (!(FunctionClass & FC_Global)) {
397 if (FunctionClass & FC_Static)
398 OS << "static ";
399 }
400 if (FunctionClass & FC_Virtual)
401 OS << "virtual ";
402
403 if (FunctionClass & FC_ExternC)
404 OS << "extern \"C\" ";
405 }
406
407 if (!(Flags & OF_NoReturnType) && ReturnType) {
408 ReturnType->outputPre(OS, Flags);
409 OS << " ";
410 }
411
412 if (!(Flags & OF_NoCallingConvention))
413 outputCallingConvention(OS, CallConvention);
414 }
415
outputPost(OutputStream & OS,OutputFlags Flags) const416 void FunctionSignatureNode::outputPost(OutputStream &OS,
417 OutputFlags Flags) const {
418 if (!(FunctionClass & FC_NoParameterList)) {
419 OS << "(";
420 if (Params)
421 Params->output(OS, Flags);
422 else
423 OS << "void";
424
425 if (IsVariadic) {
426 if (OS.back() != '(')
427 OS << ", ";
428 OS << "...";
429 }
430 OS << ")";
431 }
432
433 if (Quals & Q_Const)
434 OS << " const";
435 if (Quals & Q_Volatile)
436 OS << " volatile";
437 if (Quals & Q_Restrict)
438 OS << " __restrict";
439 if (Quals & Q_Unaligned)
440 OS << " __unaligned";
441
442 if (IsNoexcept)
443 OS << " noexcept";
444
445 if (RefQualifier == FunctionRefQualifier::Reference)
446 OS << " &";
447 else if (RefQualifier == FunctionRefQualifier::RValueReference)
448 OS << " &&";
449
450 if (!(Flags & OF_NoReturnType) && ReturnType)
451 ReturnType->outputPost(OS, Flags);
452 }
453
outputPre(OutputStream & OS,OutputFlags Flags) const454 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
455 OS << "[thunk]: ";
456
457 FunctionSignatureNode::outputPre(OS, Flags);
458 }
459
outputPost(OutputStream & OS,OutputFlags Flags) const460 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
461 if (FunctionClass & FC_StaticThisAdjust) {
462 OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
463 } else if (FunctionClass & FC_VirtualThisAdjust) {
464 if (FunctionClass & FC_VirtualThisAdjustEx) {
465 OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
466 << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
467 << ", " << ThisAdjust.StaticOffset << "}'";
468 } else {
469 OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
470 << ThisAdjust.StaticOffset << "}'";
471 }
472 }
473
474 FunctionSignatureNode::outputPost(OS, Flags);
475 }
476
outputPre(OutputStream & OS,OutputFlags Flags) const477 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
478 if (Pointee->kind() == NodeKind::FunctionSignature) {
479 // If this is a pointer to a function, don't output the calling convention.
480 // It needs to go inside the parentheses.
481 const FunctionSignatureNode *Sig =
482 static_cast<const FunctionSignatureNode *>(Pointee);
483 Sig->outputPre(OS, OF_NoCallingConvention);
484 } else
485 Pointee->outputPre(OS, Flags);
486
487 outputSpaceIfNecessary(OS);
488
489 if (Quals & Q_Unaligned)
490 OS << "__unaligned ";
491
492 if (Pointee->kind() == NodeKind::ArrayType) {
493 OS << "(";
494 } else if (Pointee->kind() == NodeKind::FunctionSignature) {
495 OS << "(";
496 const FunctionSignatureNode *Sig =
497 static_cast<const FunctionSignatureNode *>(Pointee);
498 outputCallingConvention(OS, Sig->CallConvention);
499 OS << " ";
500 }
501
502 if (ClassParent) {
503 ClassParent->output(OS, Flags);
504 OS << "::";
505 }
506
507 switch (Affinity) {
508 case PointerAffinity::Pointer:
509 OS << "*";
510 break;
511 case PointerAffinity::Reference:
512 OS << "&";
513 break;
514 case PointerAffinity::RValueReference:
515 OS << "&&";
516 break;
517 default:
518 assert(false);
519 }
520 outputQualifiers(OS, Quals, false, false);
521 }
522
outputPost(OutputStream & OS,OutputFlags Flags) const523 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
524 if (Pointee->kind() == NodeKind::ArrayType ||
525 Pointee->kind() == NodeKind::FunctionSignature)
526 OS << ")";
527
528 Pointee->outputPost(OS, Flags);
529 }
530
outputPre(OutputStream & OS,OutputFlags Flags) const531 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
532 if (!(Flags & OF_NoTagSpecifier)) {
533 switch (Tag) {
534 OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
535 OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
536 OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
537 OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
538 }
539 OS << " ";
540 }
541 QualifiedName->output(OS, Flags);
542 outputQualifiers(OS, Quals, true, false);
543 }
544
outputPost(OutputStream & OS,OutputFlags Flags) const545 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
546
outputPre(OutputStream & OS,OutputFlags Flags) const547 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
548 ElementType->outputPre(OS, Flags);
549 outputQualifiers(OS, Quals, true, false);
550 }
551
outputOneDimension(OutputStream & OS,OutputFlags Flags,Node * N) const552 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
553 Node *N) const {
554 assert(N->kind() == NodeKind::IntegerLiteral);
555 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
556 if (ILN->Value != 0)
557 ILN->output(OS, Flags);
558 }
559
outputDimensionsImpl(OutputStream & OS,OutputFlags Flags) const560 void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
561 OutputFlags Flags) const {
562 if (Dimensions->Count == 0)
563 return;
564
565 outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
566 for (size_t I = 1; I < Dimensions->Count; ++I) {
567 OS << "][";
568 outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
569 }
570 }
571
outputPost(OutputStream & OS,OutputFlags Flags) const572 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
573 OS << "[";
574 outputDimensionsImpl(OS, Flags);
575 OS << "]";
576
577 ElementType->outputPost(OS, Flags);
578 }
579
output(OutputStream & OS,OutputFlags Flags) const580 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
581 Name->output(OS, Flags);
582 }
583
output(OutputStream & OS,OutputFlags Flags) const584 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
585 Signature->outputPre(OS, Flags);
586 outputSpaceIfNecessary(OS);
587 Name->output(OS, Flags);
588 Signature->outputPost(OS, Flags);
589 }
590
output(OutputStream & OS,OutputFlags Flags) const591 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
592 const char *AccessSpec = nullptr;
593 bool IsStatic = true;
594 switch (SC) {
595 case StorageClass::PrivateStatic:
596 AccessSpec = "private";
597 break;
598 case StorageClass::PublicStatic:
599 AccessSpec = "public";
600 break;
601 case StorageClass::ProtectedStatic:
602 AccessSpec = "protected";
603 break;
604 default:
605 IsStatic = false;
606 break;
607 }
608 if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
609 OS << AccessSpec << ": ";
610 if (!(Flags & OF_NoMemberType) && IsStatic)
611 OS << "static ";
612
613 if (Type) {
614 Type->outputPre(OS, Flags);
615 outputSpaceIfNecessary(OS);
616 }
617 Name->output(OS, Flags);
618 if (Type)
619 Type->outputPost(OS, Flags);
620 }
621
outputPre(OutputStream & OS,OutputFlags Flags) const622 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
623 Identifier->output(OS, Flags);
624 }
outputPost(OutputStream & OS,OutputFlags Flags) const625 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
626
output(OutputStream & OS,OutputFlags Flags) const627 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
628 Components->output(OS, Flags, "::");
629 }
630
output(OutputStream & OS,OutputFlags Flags) const631 void RttiBaseClassDescriptorNode::output(OutputStream &OS,
632 OutputFlags Flags) const {
633 OS << "`RTTI Base Class Descriptor at (";
634 OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
635 << this->Flags;
636 OS << ")'";
637 }
638
output(OutputStream & OS,OutputFlags Flags) const639 void LocalStaticGuardVariableNode::output(OutputStream &OS,
640 OutputFlags Flags) const {
641 Name->output(OS, Flags);
642 }
643
output(OutputStream & OS,OutputFlags Flags) const644 void VcallThunkIdentifierNode::output(OutputStream &OS,
645 OutputFlags Flags) const {
646 OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
647 }
648
output(OutputStream & OS,OutputFlags Flags) const649 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
650 outputQualifiers(OS, Quals, false, true);
651 Name->output(OS, Flags);
652 if (TargetName) {
653 OS << "{for `";
654 TargetName->output(OS, Flags);
655 OS << "'}";
656 }
657 }
658