brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.1 KiB · 17c6aab Raw
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