xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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