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