671 lines · cpp
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-exception6//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, 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, Q_Const, SpaceBefore);71 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);72 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, 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(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, Quals, true, false);156}157 158void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const {159 output(OB, Flags, ", ");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 else237 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 else361 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, 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 else426 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.VtordispOffset470 << ", " << 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, OF_NoCallingConvention);487 } else488 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, 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, Quals, false, 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, Quals, true, 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, Quals, true, 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, Dimensions->Nodes[0]);572 for (size_t I = 1; I < Dimensions->Count; ++I) {573 OB << "][";574 outputOneDimension(OB, Flags, 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, "::");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, Quals, false, true);664 Name->output(OB, Flags);665 if (TargetNames) {666 OB << "{for `";667 TargetNames->output(OB, Flags, "'s `");668 OB << "'}";669 }670}671