654 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			654 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- 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;
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
std::string Node::toString(OutputFlags Flags) const {
 | 
						|
  OutputStream OS;
 | 
						|
  initializeOutputStream(nullptr, nullptr, OS, 1024);
 | 
						|
  this->output(OS, Flags);
 | 
						|
  OS << '\0';
 | 
						|
  return {OS.getBuffer()};
 | 
						|
}
 | 
						|
 | 
						|
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 << "'}";
 | 
						|
  }
 | 
						|
  return;
 | 
						|
}
 |