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