| //===- 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: \ |
| OB << Desc; \ |
| break; |
| |
| // Writes a space if the last token does not end with a punctuation. |
| static void outputSpaceIfNecessary(OutputBuffer &OB) { |
| if (OB.empty()) |
| return; |
| |
| char C = OB.back(); |
| if (std::isalnum(C) || C == '>') |
| OB << " "; |
| } |
| |
| static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) { |
| switch (Q) { |
| case Q_Const: |
| OB << "const"; |
| break; |
| case Q_Volatile: |
| OB << "volatile"; |
| break; |
| case Q_Restrict: |
| OB << "__restrict"; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, |
| Qualifiers Mask, bool NeedSpace) { |
| if (!(Q & Mask)) |
| return NeedSpace; |
| |
| if (NeedSpace) |
| OB << " "; |
| |
| outputSingleQualifier(OB, Mask); |
| return true; |
| } |
| |
| static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, |
| bool SpaceAfter) { |
| if (Q == Q_None) |
| return; |
| |
| size_t Pos1 = OB.getCurrentPosition(); |
| SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore); |
| SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore); |
| SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore); |
| size_t Pos2 = OB.getCurrentPosition(); |
| if (SpaceAfter && Pos2 > Pos1) |
| OB << " "; |
| } |
| |
| static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { |
| outputSpaceIfNecessary(OB); |
| |
| switch (CC) { |
| case CallingConv::Cdecl: |
| OB << "__cdecl"; |
| break; |
| case CallingConv::Fastcall: |
| OB << "__fastcall"; |
| break; |
| case CallingConv::Pascal: |
| OB << "__pascal"; |
| break; |
| case CallingConv::Regcall: |
| OB << "__regcall"; |
| break; |
| case CallingConv::Stdcall: |
| OB << "__stdcall"; |
| break; |
| case CallingConv::Thiscall: |
| OB << "__thiscall"; |
| break; |
| case CallingConv::Eabi: |
| OB << "__eabi"; |
| break; |
| case CallingConv::Vectorcall: |
| OB << "__vectorcall"; |
| break; |
| case CallingConv::Clrcall: |
| OB << "__clrcall"; |
| break; |
| case CallingConv::Swift: |
| OB << "__attribute__((__swiftcall__)) "; |
| break; |
| case CallingConv::SwiftAsync: |
| OB << "__attribute__((__swiftasynccall__)) "; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| std::string Node::toString(OutputFlags Flags) const { |
| OutputBuffer OB; |
| initializeOutputBuffer(nullptr, nullptr, OB, 1024); |
| this->output(OB, Flags); |
| OB << '\0'; |
| std::string Owned(OB.getBuffer()); |
| std::free(OB.getBuffer()); |
| return Owned; |
| } |
| |
| void PrimitiveTypeNode::outputPre(OutputBuffer &OB, 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(OB, Quals, true, false); |
| } |
| |
| void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| output(OB, Flags, ", "); |
| } |
| |
| void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, |
| StringView Separator) const { |
| if (Count == 0) |
| return; |
| if (Nodes[0]) |
| Nodes[0]->output(OB, Flags); |
| for (size_t I = 1; I < Count; ++I) { |
| OB << Separator; |
| Nodes[I]->output(OB, Flags); |
| } |
| } |
| |
| void EncodedStringLiteralNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| switch (Char) { |
| case CharKind::Wchar: |
| OB << "L\""; |
| break; |
| case CharKind::Char: |
| OB << "\""; |
| break; |
| case CharKind::Char16: |
| OB << "u\""; |
| break; |
| case CharKind::Char32: |
| OB << "U\""; |
| break; |
| } |
| OB << DecodedString << "\""; |
| if (IsTruncated) |
| OB << "..."; |
| } |
| |
| void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| if (IsNegative) |
| OB << '-'; |
| OB << Value; |
| } |
| |
| void TemplateParameterReferenceNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (ThunkOffsetCount > 0) |
| OB << "{"; |
| else if (Affinity == PointerAffinity::Pointer) |
| OB << "&"; |
| |
| if (Symbol) { |
| Symbol->output(OB, Flags); |
| if (ThunkOffsetCount > 0) |
| OB << ", "; |
| } |
| |
| if (ThunkOffsetCount > 0) |
| OB << ThunkOffsets[0]; |
| for (int I = 1; I < ThunkOffsetCount; ++I) { |
| OB << ", " << ThunkOffsets[I]; |
| } |
| if (ThunkOffsetCount > 0) |
| OB << "}"; |
| } |
| |
| void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (!TemplateParams) |
| return; |
| OB << "<"; |
| TemplateParams->output(OB, Flags); |
| OB << ">"; |
| } |
| |
| void DynamicStructorIdentifierNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (IsDestructor) |
| OB << "`dynamic atexit destructor for "; |
| else |
| OB << "`dynamic initializer for "; |
| |
| if (Variable) { |
| OB << "`"; |
| Variable->output(OB, Flags); |
| OB << "''"; |
| } else { |
| OB << "'"; |
| Name->output(OB, Flags); |
| OB << "''"; |
| } |
| } |
| |
| void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| OB << Name; |
| outputTemplateParameters(OB, Flags); |
| } |
| |
| void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, |
| 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(OB, Flags); |
| } |
| |
| void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (IsThread) |
| OB << "`local static thread guard'"; |
| else |
| OB << "`local static guard'"; |
| if (ScopeIndex > 0) |
| OB << "{" << ScopeIndex << "}"; |
| } |
| |
| void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| OB << "operator"; |
| outputTemplateParameters(OB, Flags); |
| OB << " "; |
| TargetType->output(OB, Flags); |
| } |
| |
| void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| if (IsDestructor) |
| OB << "~"; |
| Class->output(OB, Flags); |
| outputTemplateParameters(OB, Flags); |
| } |
| |
| void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| OB << "operator \"\"" << Name; |
| outputTemplateParameters(OB, Flags); |
| } |
| |
| void FunctionSignatureNode::outputPre(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (!(Flags & OF_NoAccessSpecifier)) { |
| if (FunctionClass & FC_Public) |
| OB << "public: "; |
| if (FunctionClass & FC_Protected) |
| OB << "protected: "; |
| if (FunctionClass & FC_Private) |
| OB << "private: "; |
| } |
| |
| if (!(Flags & OF_NoMemberType)) { |
| if (!(FunctionClass & FC_Global)) { |
| if (FunctionClass & FC_Static) |
| OB << "static "; |
| } |
| if (FunctionClass & FC_Virtual) |
| OB << "virtual "; |
| |
| if (FunctionClass & FC_ExternC) |
| OB << "extern \"C\" "; |
| } |
| |
| if (!(Flags & OF_NoReturnType) && ReturnType) { |
| ReturnType->outputPre(OB, Flags); |
| OB << " "; |
| } |
| |
| if (!(Flags & OF_NoCallingConvention)) |
| outputCallingConvention(OB, CallConvention); |
| } |
| |
| void FunctionSignatureNode::outputPost(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (!(FunctionClass & FC_NoParameterList)) { |
| OB << "("; |
| if (Params) |
| Params->output(OB, Flags); |
| else |
| OB << "void"; |
| |
| if (IsVariadic) { |
| if (OB.back() != '(') |
| OB << ", "; |
| OB << "..."; |
| } |
| OB << ")"; |
| } |
| |
| if (Quals & Q_Const) |
| OB << " const"; |
| if (Quals & Q_Volatile) |
| OB << " volatile"; |
| if (Quals & Q_Restrict) |
| OB << " __restrict"; |
| if (Quals & Q_Unaligned) |
| OB << " __unaligned"; |
| |
| if (IsNoexcept) |
| OB << " noexcept"; |
| |
| if (RefQualifier == FunctionRefQualifier::Reference) |
| OB << " &"; |
| else if (RefQualifier == FunctionRefQualifier::RValueReference) |
| OB << " &&"; |
| |
| if (!(Flags & OF_NoReturnType) && ReturnType) |
| ReturnType->outputPost(OB, Flags); |
| } |
| |
| void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
| OB << "[thunk]: "; |
| |
| FunctionSignatureNode::outputPre(OB, Flags); |
| } |
| |
| void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
| if (FunctionClass & FC_StaticThisAdjust) { |
| OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; |
| } else if (FunctionClass & FC_VirtualThisAdjust) { |
| if (FunctionClass & FC_VirtualThisAdjustEx) { |
| OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " |
| << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset |
| << ", " << ThisAdjust.StaticOffset << "}'"; |
| } else { |
| OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " |
| << ThisAdjust.StaticOffset << "}'"; |
| } |
| } |
| |
| FunctionSignatureNode::outputPost(OB, Flags); |
| } |
| |
| void PointerTypeNode::outputPre(OutputBuffer &OB, 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(OB, OF_NoCallingConvention); |
| } else |
| Pointee->outputPre(OB, Flags); |
| |
| outputSpaceIfNecessary(OB); |
| |
| if (Quals & Q_Unaligned) |
| OB << "__unaligned "; |
| |
| if (Pointee->kind() == NodeKind::ArrayType) { |
| OB << "("; |
| } else if (Pointee->kind() == NodeKind::FunctionSignature) { |
| OB << "("; |
| const FunctionSignatureNode *Sig = |
| static_cast<const FunctionSignatureNode *>(Pointee); |
| outputCallingConvention(OB, Sig->CallConvention); |
| OB << " "; |
| } |
| |
| if (ClassParent) { |
| ClassParent->output(OB, Flags); |
| OB << "::"; |
| } |
| |
| switch (Affinity) { |
| case PointerAffinity::Pointer: |
| OB << "*"; |
| break; |
| case PointerAffinity::Reference: |
| OB << "&"; |
| break; |
| case PointerAffinity::RValueReference: |
| OB << "&&"; |
| break; |
| default: |
| assert(false); |
| } |
| outputQualifiers(OB, Quals, false, false); |
| } |
| |
| void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
| if (Pointee->kind() == NodeKind::ArrayType || |
| Pointee->kind() == NodeKind::FunctionSignature) |
| OB << ")"; |
| |
| Pointee->outputPost(OB, Flags); |
| } |
| |
| void TagTypeNode::outputPre(OutputBuffer &OB, 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"); |
| } |
| OB << " "; |
| } |
| QualifiedName->output(OB, Flags); |
| outputQualifiers(OB, Quals, true, false); |
| } |
| |
| void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} |
| |
| void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
| ElementType->outputPre(OB, Flags); |
| outputQualifiers(OB, Quals, true, false); |
| } |
| |
| void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, |
| Node *N) const { |
| assert(N->kind() == NodeKind::IntegerLiteral); |
| IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); |
| if (ILN->Value != 0) |
| ILN->output(OB, Flags); |
| } |
| |
| void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| if (Dimensions->Count == 0) |
| return; |
| |
| outputOneDimension(OB, Flags, Dimensions->Nodes[0]); |
| for (size_t I = 1; I < Dimensions->Count; ++I) { |
| OB << "]["; |
| outputOneDimension(OB, Flags, Dimensions->Nodes[I]); |
| } |
| } |
| |
| void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
| OB << "["; |
| outputDimensionsImpl(OB, Flags); |
| OB << "]"; |
| |
| ElementType->outputPost(OB, Flags); |
| } |
| |
| void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| Name->output(OB, Flags); |
| } |
| |
| void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| Signature->outputPre(OB, Flags); |
| outputSpaceIfNecessary(OB); |
| Name->output(OB, Flags); |
| Signature->outputPost(OB, Flags); |
| } |
| |
| void VariableSymbolNode::output(OutputBuffer &OB, 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) |
| OB << AccessSpec << ": "; |
| if (!(Flags & OF_NoMemberType) && IsStatic) |
| OB << "static "; |
| |
| if (!(Flags & OF_NoVariableType) && Type) { |
| Type->outputPre(OB, Flags); |
| outputSpaceIfNecessary(OB); |
| } |
| Name->output(OB, Flags); |
| if (!(Flags & OF_NoVariableType) && Type) |
| Type->outputPost(OB, Flags); |
| } |
| |
| void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
| Identifier->output(OB, Flags); |
| } |
| void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} |
| |
| void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| Components->output(OB, Flags, "::"); |
| } |
| |
| void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| OB << "`RTTI Base Class Descriptor at ("; |
| OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " |
| << this->Flags; |
| OB << ")'"; |
| } |
| |
| void LocalStaticGuardVariableNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| Name->output(OB, Flags); |
| } |
| |
| void VcallThunkIdentifierNode::output(OutputBuffer &OB, |
| OutputFlags Flags) const { |
| OB << "`vcall'{" << OffsetInVTable << ", {flat}}"; |
| } |
| |
| void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
| outputQualifiers(OB, Quals, false, true); |
| Name->output(OB, Flags); |
| if (TargetName) { |
| OB << "{for `"; |
| TargetName->output(OB, Flags); |
| OB << "'}"; |
| } |
| } |