|  | //===- MicrosoftDemangle.cpp ----------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines a demangler for MSVC-style mangled symbols. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Demangle/MicrosoftDemangleNodes.h" | 
|  | #include "llvm/Demangle/DemangleConfig.h" | 
|  | #include "llvm/Demangle/Utility.h" | 
|  | #include <cctype> | 
|  | #include <string> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace ms_demangle; | 
|  |  | 
|  | #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)                             \ | 
|  | case Enum::Value:                                                            \ | 
|  | OS << Desc;                                                                \ | 
|  | break; | 
|  |  | 
|  | // Writes a space if the last token does not end with a punctuation. | 
|  | static void outputSpaceIfNecessary(OutputStream &OS) { | 
|  | if (OS.empty()) | 
|  | return; | 
|  |  | 
|  | char C = OS.back(); | 
|  | if (std::isalnum(C) || C == '>') | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) { | 
|  | switch (Q) { | 
|  | case Q_Const: | 
|  | OS << "const"; | 
|  | break; | 
|  | case Q_Volatile: | 
|  | OS << "volatile"; | 
|  | break; | 
|  | case Q_Restrict: | 
|  | OS << "__restrict"; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q, | 
|  | Qualifiers Mask, bool NeedSpace) { | 
|  | if (!(Q & Mask)) | 
|  | return NeedSpace; | 
|  |  | 
|  | if (NeedSpace) | 
|  | OS << " "; | 
|  |  | 
|  | outputSingleQualifier(OS, Mask); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore, | 
|  | bool SpaceAfter) { | 
|  | if (Q == Q_None) | 
|  | return; | 
|  |  | 
|  | size_t Pos1 = OS.getCurrentPosition(); | 
|  | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore); | 
|  | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore); | 
|  | SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore); | 
|  | size_t Pos2 = OS.getCurrentPosition(); | 
|  | if (SpaceAfter && Pos2 > Pos1) | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | static void outputCallingConvention(OutputStream &OS, CallingConv CC) { | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | switch (CC) { | 
|  | case CallingConv::Cdecl: | 
|  | OS << "__cdecl"; | 
|  | break; | 
|  | case CallingConv::Fastcall: | 
|  | OS << "__fastcall"; | 
|  | break; | 
|  | case CallingConv::Pascal: | 
|  | OS << "__pascal"; | 
|  | break; | 
|  | case CallingConv::Regcall: | 
|  | OS << "__regcall"; | 
|  | break; | 
|  | case CallingConv::Stdcall: | 
|  | OS << "__stdcall"; | 
|  | break; | 
|  | case CallingConv::Thiscall: | 
|  | OS << "__thiscall"; | 
|  | break; | 
|  | case CallingConv::Eabi: | 
|  | OS << "__eabi"; | 
|  | break; | 
|  | case CallingConv::Vectorcall: | 
|  | OS << "__vectorcall"; | 
|  | break; | 
|  | case CallingConv::Clrcall: | 
|  | OS << "__clrcall"; | 
|  | break; | 
|  | case CallingConv::Swift: | 
|  | OS << "__attribute__((__swiftcall__)) "; | 
|  | break; | 
|  | case CallingConv::SwiftAsync: | 
|  | OS << "__attribute__((__swiftasynccall__)) "; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string Node::toString(OutputFlags Flags) const { | 
|  | OutputStream OS; | 
|  | initializeOutputStream(nullptr, nullptr, OS, 1024); | 
|  | this->output(OS, Flags); | 
|  | OS << '\0'; | 
|  | std::string Owned(OS.getBuffer()); | 
|  | std::free(OS.getBuffer()); | 
|  | return Owned; | 
|  | } | 
|  |  | 
|  | void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | switch (PrimKind) { | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t"); | 
|  | } | 
|  | outputQualifiers(OS, Quals, true, false); | 
|  | } | 
|  |  | 
|  | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | output(OS, Flags, ", "); | 
|  | } | 
|  |  | 
|  | void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, | 
|  | StringView Separator) const { | 
|  | if (Count == 0) | 
|  | return; | 
|  | if (Nodes[0]) | 
|  | Nodes[0]->output(OS, Flags); | 
|  | for (size_t I = 1; I < Count; ++I) { | 
|  | OS << Separator; | 
|  | Nodes[I]->output(OS, Flags); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EncodedStringLiteralNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | switch (Char) { | 
|  | case CharKind::Wchar: | 
|  | OS << "L\""; | 
|  | break; | 
|  | case CharKind::Char: | 
|  | OS << "\""; | 
|  | break; | 
|  | case CharKind::Char16: | 
|  | OS << "u\""; | 
|  | break; | 
|  | case CharKind::Char32: | 
|  | OS << "U\""; | 
|  | break; | 
|  | } | 
|  | OS << DecodedString << "\""; | 
|  | if (IsTruncated) | 
|  | OS << "..."; | 
|  | } | 
|  |  | 
|  | void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (IsNegative) | 
|  | OS << '-'; | 
|  | OS << Value; | 
|  | } | 
|  |  | 
|  | void TemplateParameterReferenceNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (ThunkOffsetCount > 0) | 
|  | OS << "{"; | 
|  | else if (Affinity == PointerAffinity::Pointer) | 
|  | OS << "&"; | 
|  |  | 
|  | if (Symbol) { | 
|  | Symbol->output(OS, Flags); | 
|  | if (ThunkOffsetCount > 0) | 
|  | OS << ", "; | 
|  | } | 
|  |  | 
|  | if (ThunkOffsetCount > 0) | 
|  | OS << ThunkOffsets[0]; | 
|  | for (int I = 1; I < ThunkOffsetCount; ++I) { | 
|  | OS << ", " << ThunkOffsets[I]; | 
|  | } | 
|  | if (ThunkOffsetCount > 0) | 
|  | OS << "}"; | 
|  | } | 
|  |  | 
|  | void IdentifierNode::outputTemplateParameters(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (!TemplateParams) | 
|  | return; | 
|  | OS << "<"; | 
|  | TemplateParams->output(OS, Flags); | 
|  | OS << ">"; | 
|  | } | 
|  |  | 
|  | void DynamicStructorIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (IsDestructor) | 
|  | OS << "`dynamic atexit destructor for "; | 
|  | else | 
|  | OS << "`dynamic initializer for "; | 
|  |  | 
|  | if (Variable) { | 
|  | OS << "`"; | 
|  | Variable->output(OS, Flags); | 
|  | OS << "''"; | 
|  | } else { | 
|  | OS << "'"; | 
|  | Name->output(OS, Flags); | 
|  | OS << "''"; | 
|  | } | 
|  | } | 
|  |  | 
|  | void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | OS << Name; | 
|  | outputTemplateParameters(OS, Flags); | 
|  | } | 
|  |  | 
|  | void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | switch (Operator) { | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator=="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, | 
|  | "operator[]"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, | 
|  | "operator->*"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, | 
|  | "operator>="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, | 
|  | "operator&="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, | 
|  | "operator|="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, | 
|  | "operator^="); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, | 
|  | "`vector deleting dtor'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, | 
|  | "`default ctor closure'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, | 
|  | "`scalar deleting dtor'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, | 
|  | "`vector ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, | 
|  | "`vector dtor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, | 
|  | "`vector vbase ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, | 
|  | "`virtual displacement map'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, | 
|  | "`eh vector ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, | 
|  | "`eh vector dtor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, | 
|  | "`eh vector vbase ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, | 
|  | "`copy ctor closure'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, | 
|  | "`local vftable ctor closure'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, | 
|  | "operator delete[]"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, | 
|  | "`managed vector ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, | 
|  | "`managed vector dtor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, | 
|  | "`EH vector copy ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, | 
|  | "`EH vector vbase copy ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, | 
|  | "`vector copy ctor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, | 
|  | "`vector vbase copy constructor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, | 
|  | "`managed vector vbase copy constructor iterator'"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, | 
|  | "operator co_await"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); | 
|  | case IntrinsicFunctionKind::MaxIntrinsic: | 
|  | case IntrinsicFunctionKind::None: | 
|  | break; | 
|  | } | 
|  | outputTemplateParameters(OS, Flags); | 
|  | } | 
|  |  | 
|  | void LocalStaticGuardIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (IsThread) | 
|  | OS << "`local static thread guard'"; | 
|  | else | 
|  | OS << "`local static guard'"; | 
|  | if (ScopeIndex > 0) | 
|  | OS << "{" << ScopeIndex << "}"; | 
|  | } | 
|  |  | 
|  | void ConversionOperatorIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | OS << "operator"; | 
|  | outputTemplateParameters(OS, Flags); | 
|  | OS << " "; | 
|  | TargetType->output(OS, Flags); | 
|  | } | 
|  |  | 
|  | void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (IsDestructor) | 
|  | OS << "~"; | 
|  | Class->output(OS, Flags); | 
|  | outputTemplateParameters(OS, Flags); | 
|  | } | 
|  |  | 
|  | void LiteralOperatorIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | OS << "operator \"\"" << Name; | 
|  | outputTemplateParameters(OS, Flags); | 
|  | } | 
|  |  | 
|  | void FunctionSignatureNode::outputPre(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (!(Flags & OF_NoAccessSpecifier)) { | 
|  | if (FunctionClass & FC_Public) | 
|  | OS << "public: "; | 
|  | if (FunctionClass & FC_Protected) | 
|  | OS << "protected: "; | 
|  | if (FunctionClass & FC_Private) | 
|  | OS << "private: "; | 
|  | } | 
|  |  | 
|  | if (!(Flags & OF_NoMemberType)) { | 
|  | if (!(FunctionClass & FC_Global)) { | 
|  | if (FunctionClass & FC_Static) | 
|  | OS << "static "; | 
|  | } | 
|  | if (FunctionClass & FC_Virtual) | 
|  | OS << "virtual "; | 
|  |  | 
|  | if (FunctionClass & FC_ExternC) | 
|  | OS << "extern \"C\" "; | 
|  | } | 
|  |  | 
|  | if (!(Flags & OF_NoReturnType) && ReturnType) { | 
|  | ReturnType->outputPre(OS, Flags); | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | if (!(Flags & OF_NoCallingConvention)) | 
|  | outputCallingConvention(OS, CallConvention); | 
|  | } | 
|  |  | 
|  | void FunctionSignatureNode::outputPost(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (!(FunctionClass & FC_NoParameterList)) { | 
|  | OS << "("; | 
|  | if (Params) | 
|  | Params->output(OS, Flags); | 
|  | else | 
|  | OS << "void"; | 
|  |  | 
|  | if (IsVariadic) { | 
|  | if (OS.back() != '(') | 
|  | OS << ", "; | 
|  | OS << "..."; | 
|  | } | 
|  | OS << ")"; | 
|  | } | 
|  |  | 
|  | if (Quals & Q_Const) | 
|  | OS << " const"; | 
|  | if (Quals & Q_Volatile) | 
|  | OS << " volatile"; | 
|  | if (Quals & Q_Restrict) | 
|  | OS << " __restrict"; | 
|  | if (Quals & Q_Unaligned) | 
|  | OS << " __unaligned"; | 
|  |  | 
|  | if (IsNoexcept) | 
|  | OS << " noexcept"; | 
|  |  | 
|  | if (RefQualifier == FunctionRefQualifier::Reference) | 
|  | OS << " &"; | 
|  | else if (RefQualifier == FunctionRefQualifier::RValueReference) | 
|  | OS << " &&"; | 
|  |  | 
|  | if (!(Flags & OF_NoReturnType) && ReturnType) | 
|  | ReturnType->outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | OS << "[thunk]: "; | 
|  |  | 
|  | FunctionSignatureNode::outputPre(OS, Flags); | 
|  | } | 
|  |  | 
|  | void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (FunctionClass & FC_StaticThisAdjust) { | 
|  | OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; | 
|  | } else if (FunctionClass & FC_VirtualThisAdjust) { | 
|  | if (FunctionClass & FC_VirtualThisAdjustEx) { | 
|  | OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " | 
|  | << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset | 
|  | << ", " << ThisAdjust.StaticOffset << "}'"; | 
|  | } else { | 
|  | OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " | 
|  | << ThisAdjust.StaticOffset << "}'"; | 
|  | } | 
|  | } | 
|  |  | 
|  | FunctionSignatureNode::outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (Pointee->kind() == NodeKind::FunctionSignature) { | 
|  | // If this is a pointer to a function, don't output the calling convention. | 
|  | // It needs to go inside the parentheses. | 
|  | const FunctionSignatureNode *Sig = | 
|  | static_cast<const FunctionSignatureNode *>(Pointee); | 
|  | Sig->outputPre(OS, OF_NoCallingConvention); | 
|  | } else | 
|  | Pointee->outputPre(OS, Flags); | 
|  |  | 
|  | outputSpaceIfNecessary(OS); | 
|  |  | 
|  | if (Quals & Q_Unaligned) | 
|  | OS << "__unaligned "; | 
|  |  | 
|  | if (Pointee->kind() == NodeKind::ArrayType) { | 
|  | OS << "("; | 
|  | } else if (Pointee->kind() == NodeKind::FunctionSignature) { | 
|  | OS << "("; | 
|  | const FunctionSignatureNode *Sig = | 
|  | static_cast<const FunctionSignatureNode *>(Pointee); | 
|  | outputCallingConvention(OS, Sig->CallConvention); | 
|  | OS << " "; | 
|  | } | 
|  |  | 
|  | if (ClassParent) { | 
|  | ClassParent->output(OS, Flags); | 
|  | OS << "::"; | 
|  | } | 
|  |  | 
|  | switch (Affinity) { | 
|  | case PointerAffinity::Pointer: | 
|  | OS << "*"; | 
|  | break; | 
|  | case PointerAffinity::Reference: | 
|  | OS << "&"; | 
|  | break; | 
|  | case PointerAffinity::RValueReference: | 
|  | OS << "&&"; | 
|  | break; | 
|  | default: | 
|  | assert(false); | 
|  | } | 
|  | outputQualifiers(OS, Quals, false, false); | 
|  | } | 
|  |  | 
|  | void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (Pointee->kind() == NodeKind::ArrayType || | 
|  | Pointee->kind() == NodeKind::FunctionSignature) | 
|  | OS << ")"; | 
|  |  | 
|  | Pointee->outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | if (!(Flags & OF_NoTagSpecifier)) { | 
|  | switch (Tag) { | 
|  | OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); | 
|  | OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); | 
|  | } | 
|  | OS << " "; | 
|  | } | 
|  | QualifiedName->output(OS, Flags); | 
|  | outputQualifiers(OS, Quals, true, false); | 
|  | } | 
|  |  | 
|  | void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} | 
|  |  | 
|  | void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | ElementType->outputPre(OS, Flags); | 
|  | outputQualifiers(OS, Quals, true, false); | 
|  | } | 
|  |  | 
|  | void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, | 
|  | Node *N) const { | 
|  | assert(N->kind() == NodeKind::IntegerLiteral); | 
|  | IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); | 
|  | if (ILN->Value != 0) | 
|  | ILN->output(OS, Flags); | 
|  | } | 
|  |  | 
|  | void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | if (Dimensions->Count == 0) | 
|  | return; | 
|  |  | 
|  | outputOneDimension(OS, Flags, Dimensions->Nodes[0]); | 
|  | for (size_t I = 1; I < Dimensions->Count; ++I) { | 
|  | OS << "]["; | 
|  | outputOneDimension(OS, Flags, Dimensions->Nodes[I]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { | 
|  | OS << "["; | 
|  | outputDimensionsImpl(OS, Flags); | 
|  | OS << "]"; | 
|  |  | 
|  | ElementType->outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | Name->output(OS, Flags); | 
|  | } | 
|  |  | 
|  | void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | Signature->outputPre(OS, Flags); | 
|  | outputSpaceIfNecessary(OS); | 
|  | Name->output(OS, Flags); | 
|  | Signature->outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | const char *AccessSpec = nullptr; | 
|  | bool IsStatic = true; | 
|  | switch (SC) { | 
|  | case StorageClass::PrivateStatic: | 
|  | AccessSpec = "private"; | 
|  | break; | 
|  | case StorageClass::PublicStatic: | 
|  | AccessSpec = "public"; | 
|  | break; | 
|  | case StorageClass::ProtectedStatic: | 
|  | AccessSpec = "protected"; | 
|  | break; | 
|  | default: | 
|  | IsStatic = false; | 
|  | break; | 
|  | } | 
|  | if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) | 
|  | OS << AccessSpec << ": "; | 
|  | if (!(Flags & OF_NoMemberType) && IsStatic) | 
|  | OS << "static "; | 
|  |  | 
|  | if (Type) { | 
|  | Type->outputPre(OS, Flags); | 
|  | outputSpaceIfNecessary(OS); | 
|  | } | 
|  | Name->output(OS, Flags); | 
|  | if (Type) | 
|  | Type->outputPost(OS, Flags); | 
|  | } | 
|  |  | 
|  | void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { | 
|  | Identifier->output(OS, Flags); | 
|  | } | 
|  | void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} | 
|  |  | 
|  | void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | Components->output(OS, Flags, "::"); | 
|  | } | 
|  |  | 
|  | void RttiBaseClassDescriptorNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | OS << "`RTTI Base Class Descriptor at ("; | 
|  | OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " | 
|  | << this->Flags; | 
|  | OS << ")'"; | 
|  | } | 
|  |  | 
|  | void LocalStaticGuardVariableNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | Name->output(OS, Flags); | 
|  | } | 
|  |  | 
|  | void VcallThunkIdentifierNode::output(OutputStream &OS, | 
|  | OutputFlags Flags) const { | 
|  | OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; | 
|  | } | 
|  |  | 
|  | void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { | 
|  | outputQualifiers(OS, Quals, false, true); | 
|  | Name->output(OS, Flags); | 
|  | if (TargetName) { | 
|  | OS << "{for `"; | 
|  | TargetName->output(OS, Flags); | 
|  | OS << "'}"; | 
|  | } | 
|  | } |