660 lines
22 KiB
C++
Vendored
660 lines
22 KiB
C++
Vendored
//===- 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/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);
|
|
StringView SV = OB;
|
|
std::string Owned(SV.begin(), SV.end());
|
|
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 << "'}";
|
|
}
|
|
}
|