blob: 10b74cb1e500ad866ba6ed4c807a05a2aaaf92d4 [file] [log] [blame]
//===--- NodePrinter.cpp - Swift Demangling Node Printer ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the node printer for demangle node trees.
//
//===----------------------------------------------------------------------===//
#include "swift/Demangling/Demangle.h"
#include "swift/Strings.h"
#include <cstdio>
#include <cstdlib>
using namespace swift;
using namespace Demangle;
using llvm::StringRef;
[[noreturn]]
static void printer_unreachable(const char *Message) {
fprintf(stderr, "fatal error: %s\n", Message);
std::abort();
}
DemanglerPrinter &DemanglerPrinter::operator<<(unsigned long long n) & {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%llu", n);
Stream.append(buffer);
return *this;
}
DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lld",n);
Stream.append(buffer);
return *this;
}
std::string Demangle::archetypeName(Node::IndexType index,
Node::IndexType depth) {
DemanglerPrinter name;
do {
name << (char)('A' + (index % 26));
index /= 26;
} while (index);
if (depth != 0)
name << depth;
return std::move(name).str();
}
namespace {
struct QuotedString {
std::string Value;
explicit QuotedString(std::string Value) : Value(Value) {}
};
static DemanglerPrinter &operator<<(DemanglerPrinter &printer,
const QuotedString &QS) {
printer << '"';
for (auto C : QS.Value) {
switch (C) {
case '\\': printer << "\\\\"; break;
case '\t': printer << "\\t"; break;
case '\n': printer << "\\n"; break;
case '\r': printer << "\\r"; break;
case '"': printer << "\\\""; break;
case '\'': printer << '\''; break; // no need to escape these
case '\0': printer << "\\0"; break;
default:
auto c = static_cast<char>(C);
// Other ASCII control characters should get escaped.
if (c < 0x20 || c == 0x7F) {
static const char Hexdigit[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
printer << "\\x" << Hexdigit[c >> 4] << Hexdigit[c & 0xF];
} else {
printer << c;
}
break;
}
}
printer << '"';
return printer;
}
static StringRef toString(Directness d) {
switch (d) {
case Directness::Direct:
return "direct";
case Directness::Indirect:
return "indirect";
}
printer_unreachable("bad directness");
}
static StringRef toString(ValueWitnessKind k) {
switch (k) {
case ValueWitnessKind::AllocateBuffer:
return "allocateBuffer";
case ValueWitnessKind::AssignWithCopy:
return "assignWithCopy";
case ValueWitnessKind::AssignWithTake:
return "assignWithTake";
case ValueWitnessKind::DeallocateBuffer:
return "deallocateBuffer";
case ValueWitnessKind::Destroy:
return "destroy";
case ValueWitnessKind::DestroyBuffer:
return "destroyBuffer";
case ValueWitnessKind::InitializeBufferWithCopyOfBuffer:
return "initializeBufferWithCopyOfBuffer";
case ValueWitnessKind::InitializeBufferWithCopy:
return "initializeBufferWithCopy";
case ValueWitnessKind::InitializeWithCopy:
return "initializeWithCopy";
case ValueWitnessKind::InitializeBufferWithTake:
return "initializeBufferWithTake";
case ValueWitnessKind::InitializeWithTake:
return "initializeWithTake";
case ValueWitnessKind::ProjectBuffer:
return "projectBuffer";
case ValueWitnessKind::InitializeBufferWithTakeOfBuffer:
return "initializeBufferWithTakeOfBuffer";
case ValueWitnessKind::DestroyArray:
return "destroyArray";
case ValueWitnessKind::InitializeArrayWithCopy:
return "initializeArrayWithCopy";
case ValueWitnessKind::InitializeArrayWithTakeFrontToBack:
return "initializeArrayWithTakeFrontToBack";
case ValueWitnessKind::InitializeArrayWithTakeBackToFront:
return "initializeArrayWithTakeBackToFront";
case ValueWitnessKind::StoreExtraInhabitant:
return "storeExtraInhabitant";
case ValueWitnessKind::GetExtraInhabitantIndex:
return "getExtraInhabitantIndex";
case ValueWitnessKind::GetEnumTag:
return "getEnumTag";
case ValueWitnessKind::DestructiveProjectEnumData:
return "destructiveProjectEnumData";
case ValueWitnessKind::DestructiveInjectEnumTag:
return "destructiveInjectEnumTag";
}
printer_unreachable("bad value witness kind");
}
class NodePrinter {
private:
DemanglerPrinter Printer;
DemangleOptions Options;
public:
NodePrinter(DemangleOptions options) : Options(options) {}
std::string printRoot(NodePointer root) {
print(root);
return std::move(Printer).str();
}
private:
void printChildren(Node::iterator begin,
Node::iterator end,
const char *sep = nullptr) {
for (; begin != end;) {
print(*begin);
++begin;
if (sep && begin != end)
Printer << sep;
}
}
void printChildren(NodePointer pointer, const char *sep = nullptr) {
if (!pointer)
return;
Node::iterator begin = pointer->begin(), end = pointer->end();
printChildren(begin, end, sep);
}
NodePointer getFirstChildOfKind(NodePointer pointer, Node::Kind kind) {
if (!pointer)
return nullptr;
for (NodePointer &child : *pointer) {
if (child && child->getKind() == kind)
return child;
}
return nullptr;
}
void printBoundGenericNoSugar(NodePointer pointer) {
if (pointer->getNumChildren() < 2)
return;
NodePointer typelist = pointer->getChild(1);
print(pointer->getChild(0));
Printer << "<";
printChildren(typelist, ", ");
Printer << ">";
}
static bool isSwiftModule(NodePointer node) {
return (node->getKind() == Node::Kind::Module &&
node->getText() == STDLIB_NAME);
}
static bool isDebuggerGeneratedModule(NodePointer node) {
return (node->getKind() == Node::Kind::Module &&
node->getText().startswith(LLDB_EXPRESSIONS_MODULE_NAME_PREFIX));
}
static bool isIdentifier(NodePointer node, StringRef desired) {
return (node->getKind() == Node::Kind::Identifier &&
node->getText() == desired);
}
enum class SugarType {
None,
Optional,
ImplicitlyUnwrappedOptional,
Array,
Dictionary
};
/// Determine whether this is a "simple" type, from the type-simple
/// production.
bool isSimpleType(NodePointer pointer) {
switch (pointer->getKind()) {
case Node::Kind::AssociatedType:
case Node::Kind::AssociatedTypeRef:
case Node::Kind::BoundGenericClass:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BuiltinTypeName:
case Node::Kind::Class:
case Node::Kind::DependentGenericType:
case Node::Kind::DependentMemberType:
case Node::Kind::DependentGenericParamType:
case Node::Kind::DynamicSelf:
case Node::Kind::Enum:
case Node::Kind::ErrorType:
case Node::Kind::ExistentialMetatype:
case Node::Kind::Metatype:
case Node::Kind::MetatypeRepresentation:
case Node::Kind::Module:
case Node::Kind::Tuple:
case Node::Kind::Protocol:
case Node::Kind::QualifiedArchetype:
case Node::Kind::ReturnType:
case Node::Kind::SILBoxType:
case Node::Kind::SILBoxTypeWithLayout:
case Node::Kind::Structure:
case Node::Kind::TupleElementName:
case Node::Kind::Type:
case Node::Kind::TypeAlias:
case Node::Kind::TypeList:
return true;
case Node::Kind::ProtocolList:
if (pointer->getChild(0)->getNumChildren() <= 1)
return true;
return false;
case Node::Kind::Allocator:
case Node::Kind::ArgumentTuple:
case Node::Kind::AssociatedTypeMetadataAccessor:
case Node::Kind::AssociatedTypeWitnessTableAccessor:
case Node::Kind::AutoClosureType:
case Node::Kind::CFunctionPointer:
case Node::Kind::Constructor:
case Node::Kind::CurryThunk:
case Node::Kind::Deallocator:
case Node::Kind::DeclContext:
case Node::Kind::DefaultArgumentInitializer:
case Node::Kind::DependentAssociatedTypeRef:
case Node::Kind::DependentGenericSignature:
case Node::Kind::DependentGenericParamCount:
case Node::Kind::DependentGenericConformanceRequirement:
case Node::Kind::DependentGenericLayoutRequirement:
case Node::Kind::DependentGenericSameTypeRequirement:
case Node::Kind::DependentPseudogenericSignature:
case Node::Kind::Destructor:
case Node::Kind::DidSet:
case Node::Kind::DirectMethodReferenceAttribute:
case Node::Kind::Directness:
case Node::Kind::DynamicAttribute:
case Node::Kind::ExplicitClosure:
case Node::Kind::Extension:
case Node::Kind::FieldOffset:
case Node::Kind::FullTypeMetadata:
case Node::Kind::Function:
case Node::Kind::FunctionSignatureSpecialization:
case Node::Kind::FunctionSignatureSpecializationParam:
case Node::Kind::FunctionSignatureSpecializationParamKind:
case Node::Kind::FunctionSignatureSpecializationParamPayload:
case Node::Kind::FunctionType:
case Node::Kind::GenericProtocolWitnessTable:
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
case Node::Kind::GenericPartialSpecialization:
case Node::Kind::GenericPartialSpecializationNotReAbstracted:
case Node::Kind::GenericSpecialization:
case Node::Kind::GenericSpecializationNotReAbstracted:
case Node::Kind::GenericSpecializationParam:
case Node::Kind::GenericTypeMetadataPattern:
case Node::Kind::Getter:
case Node::Kind::Global:
case Node::Kind::GlobalGetter:
case Node::Kind::Identifier:
case Node::Kind::Index:
case Node::Kind::IVarInitializer:
case Node::Kind::IVarDestroyer:
case Node::Kind::ImplConvention:
case Node::Kind::ImplFunctionAttribute:
case Node::Kind::ImplFunctionType:
case Node::Kind::ImplicitClosure:
case Node::Kind::ImplParameter:
case Node::Kind::ImplResult:
case Node::Kind::ImplErrorResult:
case Node::Kind::InOut:
case Node::Kind::InfixOperator:
case Node::Kind::Initializer:
case Node::Kind::LazyProtocolWitnessTableAccessor:
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
case Node::Kind::LocalDeclName:
case Node::Kind::PrivateDeclName:
case Node::Kind::MaterializeForSet:
case Node::Kind::Metaclass:
case Node::Kind::NativeOwningAddressor:
case Node::Kind::NativeOwningMutableAddressor:
case Node::Kind::NativePinningAddressor:
case Node::Kind::NativePinningMutableAddressor:
case Node::Kind::NominalTypeDescriptor:
case Node::Kind::NonObjCAttribute:
case Node::Kind::Number:
case Node::Kind::ObjCAttribute:
case Node::Kind::ObjCBlock:
case Node::Kind::OwningAddressor:
case Node::Kind::OwningMutableAddressor:
case Node::Kind::PartialApplyForwarder:
case Node::Kind::PartialApplyObjCForwarder:
case Node::Kind::PostfixOperator:
case Node::Kind::PrefixOperator:
case Node::Kind::ProtocolConformance:
case Node::Kind::ProtocolDescriptor:
case Node::Kind::ProtocolWitness:
case Node::Kind::ProtocolWitnessTable:
case Node::Kind::ProtocolWitnessTableAccessor:
case Node::Kind::ReabstractionThunk:
case Node::Kind::ReabstractionThunkHelper:
case Node::Kind::Setter:
case Node::Kind::SILBoxLayout:
case Node::Kind::SILBoxMutableField:
case Node::Kind::SILBoxImmutableField:
case Node::Kind::SpecializationIsFragile:
case Node::Kind::SpecializationPassID:
case Node::Kind::Static:
case Node::Kind::Subscript:
case Node::Kind::Suffix:
case Node::Kind::ThinFunctionType:
case Node::Kind::TupleElement:
case Node::Kind::TypeMangling:
case Node::Kind::TypeMetadata:
case Node::Kind::TypeMetadataAccessFunction:
case Node::Kind::TypeMetadataLazyCache:
case Node::Kind::UncurriedFunctionType:
case Node::Kind::Unmanaged:
case Node::Kind::Unowned:
case Node::Kind::UnsafeAddressor:
case Node::Kind::UnsafeMutableAddressor:
case Node::Kind::ValueWitness:
case Node::Kind::ValueWitnessTable:
case Node::Kind::Variable:
case Node::Kind::VTableAttribute:
case Node::Kind::VTableThunk:
case Node::Kind::Weak:
case Node::Kind::WillSet:
case Node::Kind::WitnessTableOffset:
case Node::Kind::ReflectionMetadataBuiltinDescriptor:
case Node::Kind::ReflectionMetadataFieldDescriptor:
case Node::Kind::ReflectionMetadataAssocTypeDescriptor:
case Node::Kind::ReflectionMetadataSuperclassDescriptor:
case Node::Kind::GenericTypeParamDecl:
case Node::Kind::ThrowsAnnotation:
case Node::Kind::EmptyList:
case Node::Kind::FirstElementMarker:
case Node::Kind::VariadicMarker:
case Node::Kind::OutlinedCopy:
case Node::Kind::OutlinedConsume:
return false;
}
printer_unreachable("bad node kind");
}
SugarType findSugar(NodePointer pointer) {
if (pointer->getNumChildren() == 1 &&
pointer->getKind() == Node::Kind::Type)
return findSugar(pointer->getChild(0));
if (pointer->getNumChildren() != 2)
return SugarType::None;
if (pointer->getKind() != Node::Kind::BoundGenericEnum &&
pointer->getKind() != Node::Kind::BoundGenericStructure)
return SugarType::None;
auto unboundType = pointer->getChild(0)->getChild(0); // drill through Type
auto typeArgs = pointer->getChild(1);
if (pointer->getKind() == Node::Kind::BoundGenericEnum) {
// Swift.Optional
if (isIdentifier(unboundType->getChild(1), "Optional") &&
typeArgs->getNumChildren() == 1 &&
isSwiftModule(unboundType->getChild(0))) {
return SugarType::Optional;
}
// Swift.ImplicitlyUnwrappedOptional
if (isIdentifier(unboundType->getChild(1),
"ImplicitlyUnwrappedOptional") &&
typeArgs->getNumChildren() == 1 &&
isSwiftModule(unboundType->getChild(0))) {
return SugarType::ImplicitlyUnwrappedOptional;
}
return SugarType::None;
}
assert(pointer->getKind() == Node::Kind::BoundGenericStructure);
// Array
if (isIdentifier(unboundType->getChild(1), "Array") &&
typeArgs->getNumChildren() == 1 &&
isSwiftModule(unboundType->getChild(0))) {
return SugarType::Array;
}
// Dictionary
if (isIdentifier(unboundType->getChild(1), "Dictionary") &&
typeArgs->getNumChildren() == 2 &&
isSwiftModule(unboundType->getChild(0))) {
return SugarType::Dictionary;
}
return SugarType::None;
}
void printBoundGeneric(NodePointer pointer) {
if (pointer->getNumChildren() < 2)
return;
if (pointer->getNumChildren() != 2) {
printBoundGenericNoSugar(pointer);
return;
}
if (!Options.SynthesizeSugarOnTypes ||
pointer->getKind() == Node::Kind::BoundGenericClass)
{
// no sugar here
printBoundGenericNoSugar(pointer);
return;
}
SugarType sugarType = findSugar(pointer);
switch (sugarType) {
case SugarType::None:
printBoundGenericNoSugar(pointer);
break;
case SugarType::Optional:
case SugarType::ImplicitlyUnwrappedOptional: {
NodePointer type = pointer->getChild(1)->getChild(0);
bool needs_parens = !isSimpleType(type);
if (needs_parens)
Printer << "(";
print(type);
if (needs_parens)
Printer << ")";
Printer << (sugarType == SugarType::Optional ? "?" : "!");
break;
}
case SugarType::Array: {
NodePointer type = pointer->getChild(1)->getChild(0);
Printer << "[";
print(type);
Printer << "]";
break;
}
case SugarType::Dictionary: {
NodePointer keyType = pointer->getChild(1)->getChild(0);
NodePointer valueType = pointer->getChild(1)->getChild(1);
Printer << "[";
print(keyType);
Printer << " : ";
print(valueType);
Printer << "]";
break;
}
}
}
void printSimplifiedEntityType(NodePointer context, NodePointer entityType);
void printFunctionType(NodePointer node) {
assert(node->getNumChildren() == 2 || node->getNumChildren() == 3);
unsigned startIndex = 0;
bool throws = false;
if (node->getNumChildren() == 3) {
assert(node->getChild(0)->getKind() == Node::Kind::ThrowsAnnotation);
startIndex++;
throws = true;
}
print(node->getChild(startIndex));
if (throws) Printer << " throws";
print(node->getChild(startIndex+1));
}
void printImplFunctionType(NodePointer fn) {
enum State { Attrs, Inputs, Results } curState = Attrs;
auto transitionTo = [&](State newState) {
assert(newState >= curState);
for (; curState != newState; curState = State(curState + 1)) {
switch (curState) {
case Attrs: Printer << '('; continue;
case Inputs: Printer << ") -> ("; continue;
case Results: printer_unreachable("no state after Results");
}
printer_unreachable("bad state");
}
};
for (auto &child : *fn) {
if (child->getKind() == Node::Kind::ImplParameter) {
if (curState == Inputs) Printer << ", ";
transitionTo(Inputs);
print(child);
} else if (child->getKind() == Node::Kind::ImplResult
|| child->getKind() == Node::Kind::ImplErrorResult) {
if (curState == Results) Printer << ", ";
transitionTo(Results);
print(child);
} else {
assert(curState == Attrs);
print(child);
Printer << ' ';
}
}
transitionTo(Results);
Printer << ')';
}
void printContext(NodePointer context) {
// TODO: parenthesize local contexts?
if (Options.DisplayDebuggerGeneratedModule ||
!isDebuggerGeneratedModule(context))
{
print(context, /*asContext*/ true);
if (context->getKind() == Node::Kind::Module && !Options.DisplayModuleNames)
return;
Printer << '.';
}
}
void print(NodePointer pointer, bool asContext = false, bool suppressType = false);
unsigned printFunctionSigSpecializationParam(NodePointer pointer,
unsigned Idx);
void printSpecializationPrefix(NodePointer node, StringRef Description,
StringRef ParamPrefix = StringRef());
};
} // end anonymous namespace
static bool isExistentialType(NodePointer node) {
return (node->getKind() == Node::Kind::ExistentialMetatype ||
node->getKind() == Node::Kind::ProtocolList);
}
/// Print the relevant parameters and return the new index.
unsigned NodePrinter::printFunctionSigSpecializationParam(NodePointer pointer,
unsigned Idx) {
NodePointer firstChild = pointer->getChild(Idx);
unsigned V = firstChild->getIndex();
auto K = FunctionSigSpecializationParamKind(V);
switch (K) {
case FunctionSigSpecializationParamKind::BoxToValue:
case FunctionSigSpecializationParamKind::BoxToStack:
print(pointer->getChild(Idx++));
return Idx;
case FunctionSigSpecializationParamKind::ConstantPropFunction:
case FunctionSigSpecializationParamKind::ConstantPropGlobal: {
Printer << "[";
print(pointer->getChild(Idx++));
Printer << " : ";
const auto &text = pointer->getChild(Idx++)->getText();
std::string demangledName = demangleSymbolAsString(text);
if (demangledName.empty()) {
Printer << text;
} else {
Printer << demangledName;
}
Printer << "]";
return Idx;
}
case FunctionSigSpecializationParamKind::ConstantPropInteger:
case FunctionSigSpecializationParamKind::ConstantPropFloat:
Printer << "[";
print(pointer->getChild(Idx++));
Printer << " : ";
print(pointer->getChild(Idx++));
Printer << "]";
return Idx;
case FunctionSigSpecializationParamKind::ConstantPropString:
Printer << "[";
print(pointer->getChild(Idx++));
Printer << " : ";
print(pointer->getChild(Idx++));
Printer << "'";
print(pointer->getChild(Idx++));
Printer << "'";
Printer << "]";
return Idx;
case FunctionSigSpecializationParamKind::ClosureProp:
Printer << "[";
print(pointer->getChild(Idx++));
Printer << " : ";
print(pointer->getChild(Idx++));
Printer << ", Argument Types : [";
for (unsigned e = pointer->getNumChildren(); Idx < e;) {
NodePointer child = pointer->getChild(Idx);
// Until we no longer have a type node, keep demangling.
if (child->getKind() != Node::Kind::Type)
break;
print(child);
++Idx;
// If we are not done, print the ", ".
if (Idx < e && pointer->getChild(Idx)->hasText())
Printer << ", ";
}
Printer << "]";
return Idx;
default:
break;
}
assert(
((V & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) ||
(V & unsigned(FunctionSigSpecializationParamKind::SROA)) ||
(V & unsigned(FunctionSigSpecializationParamKind::Dead))) &&
"Invalid OptionSet");
print(pointer->getChild(Idx++));
return Idx;
}
void NodePrinter::printSpecializationPrefix(NodePointer node,
StringRef Description,
StringRef ParamPrefix) {
if (!Options.DisplayGenericSpecializations) {
Printer << "specialized ";
return;
}
Printer << Description << " <";
const char *Separator = "";
for (unsigned i = 0, e = node->getNumChildren(); i < e; ++i) {
switch (node->getChild(i)->getKind()) {
case Node::Kind::SpecializationPassID:
// We skip the SpecializationPassID since it does not contain any
// information that is useful to our users.
break;
case Node::Kind::SpecializationIsFragile:
Printer << Separator;
Separator = ", ";
print(node->getChild(i));
break;
default:
// Ignore empty specializations.
if (node->getChild(i)->hasChildren()) {
Printer << Separator << ParamPrefix;
Separator = ", ";
print(node->getChild(i));
}
break;
}
}
Printer << "> of ";
}
static bool isClassType(NodePointer pointer) {
return pointer->getKind() == Node::Kind::Class;
}
static bool useColonForEntityType(NodePointer entity, NodePointer type) {
switch (entity->getKind()) {
case Node::Kind::Variable:
case Node::Kind::Initializer:
case Node::Kind::DefaultArgumentInitializer:
case Node::Kind::IVarInitializer:
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Protocol:
case Node::Kind::TypeAlias:
case Node::Kind::OwningAddressor:
case Node::Kind::OwningMutableAddressor:
case Node::Kind::NativeOwningAddressor:
case Node::Kind::NativeOwningMutableAddressor:
case Node::Kind::NativePinningAddressor:
case Node::Kind::NativePinningMutableAddressor:
case Node::Kind::UnsafeAddressor:
case Node::Kind::UnsafeMutableAddressor:
case Node::Kind::GlobalGetter:
case Node::Kind::Getter:
case Node::Kind::Setter:
case Node::Kind::MaterializeForSet:
case Node::Kind::WillSet:
case Node::Kind::DidSet:
return true;
case Node::Kind::Subscript:
case Node::Kind::Function:
case Node::Kind::ExplicitClosure:
case Node::Kind::ImplicitClosure:
case Node::Kind::Allocator:
case Node::Kind::Constructor:
case Node::Kind::Destructor:
case Node::Kind::Deallocator:
case Node::Kind::IVarDestroyer: {
// We expect to see a function type here, but if we don't, use the colon.
type = type->getChild(0);
while (type->getKind() == Node::Kind::DependentGenericType)
type = type->getChild(1)->getChild(0);
return (type->getKind() != Node::Kind::FunctionType &&
type->getKind() != Node::Kind::UncurriedFunctionType &&
type->getKind() != Node::Kind::CFunctionPointer &&
type->getKind() != Node::Kind::ThinFunctionType);
}
default:
printer_unreachable("not an entity");
}
}
static bool isMethodContext(const NodePointer &context) {
switch (context->getKind()) {
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
case Node::Kind::Protocol:
case Node::Kind::Extension:
return true;
default:
return false;
}
}
/// Perform any desired type simplifications for an entity in Simplified mode.
void NodePrinter::printSimplifiedEntityType(NodePointer context,
NodePointer entityType) {
// Only do anything special to methods.
if (!isMethodContext(context)) return print(entityType);
// Strip off a single level of uncurried function type.
NodePointer type = entityType;
assert(type->getKind() == Node::Kind::Type);
type = type->getChild(0);
if (type->getKind() == Node::Kind::DependentGenericType) {
type = type->getChild(1)->getChild(0);
}
print(entityType);
}
void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) {
// Common code for handling entities.
auto printEntity = [&](bool hasName, bool hasType, StringRef extraName) {
if (Options.QualifyEntities)
printContext(pointer->getChild(0));
bool printType = (hasType && !suppressType);
bool useParens = (printType && asContext);
if (useParens) Printer << '(';
if (hasName) print(pointer->getChild(1));
Printer << extraName;
if (printType) {
NodePointer type = pointer->getChild(1 + unsigned(hasName));
if (useColonForEntityType(pointer, type)) {
if (Options.DisplayEntityTypes) {
Printer << " : ";
print(type);
}
} else if (!Options.DisplayEntityTypes) {
printSimplifiedEntityType(pointer->getChild(0), type);
} else {
Printer << " ";
print(type);
}
}
if (useParens) Printer << ')';
};
Node::Kind kind = pointer->getKind();
switch (kind) {
case Node::Kind::Static:
Printer << "static ";
print(pointer->getChild(0), asContext, suppressType);
return;
case Node::Kind::CurryThunk:
Printer << "curry thunk of ";
print(pointer->getChild(0), asContext, suppressType);
return;
case Node::Kind::OutlinedCopy:
Printer << "outlined copy of ";
print(pointer->getChild(0), asContext, suppressType);
return;
case Node::Kind::OutlinedConsume:
Printer << "outlined consume of ";
print(pointer->getChild(0), asContext, suppressType);
return;
case Node::Kind::Directness:
Printer << toString(Directness(pointer->getIndex())) << " ";
return;
case Node::Kind::Extension:
assert((pointer->getNumChildren() == 2 || pointer->getNumChildren() == 3)
&& "Extension expects 2 or 3 children.");
if (Options.QualifyEntities && Options.DisplayExtensionContexts) {
Printer << "(extension in ";
// Print the module where extension is defined.
print(pointer->getChild(0), true);
Printer << "):";
}
print(pointer->getChild(1), asContext);
if (pointer->getNumChildren() == 3)
print(pointer->getChild(2), true);
return;
case Node::Kind::Variable:
case Node::Kind::Function:
case Node::Kind::Subscript:
case Node::Kind::GenericTypeParamDecl:
printEntity(true, true, "");
return;
case Node::Kind::ExplicitClosure:
case Node::Kind::ImplicitClosure: {
auto index = pointer->getChild(1)->getIndex();
DemanglerPrinter printName;
printName << '(';
if (pointer->getKind() == Node::Kind::ImplicitClosure)
printName << "implicit ";
printName << "closure #" << (index + 1) << ")";
printEntity(false, false, std::move(printName).str());
return;
}
case Node::Kind::Global:
printChildren(pointer);
return;
case Node::Kind::Suffix:
if (!Options.DisplayUnmangledSuffix) return;
Printer << " with unmangled suffix " << QuotedString(pointer->getText());
return;
case Node::Kind::Initializer:
printEntity(false, false, "(variable initialization expression)");
return;
case Node::Kind::DefaultArgumentInitializer: {
auto index = pointer->getChild(1);
DemanglerPrinter strPrinter;
strPrinter << "(default argument " << index->getIndex() << ")";
printEntity(false, false, std::move(strPrinter).str());
return;
}
case Node::Kind::DeclContext:
print(pointer->getChild(0), asContext);
return;
case Node::Kind::Type:
print(pointer->getChild(0), asContext);
return;
case Node::Kind::TypeMangling:
print(pointer->getChild(0));
return;
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Protocol:
case Node::Kind::TypeAlias:
printEntity(true, false, "");
return;
case Node::Kind::LocalDeclName:
Printer << '(';
print(pointer->getChild(1));
Printer << " #" << (pointer->getChild(0)->getIndex() + 1) << ')';
return;
case Node::Kind::PrivateDeclName:
if (Options.ShowPrivateDiscriminators)
Printer << '(';
print(pointer->getChild(1));
if (Options.ShowPrivateDiscriminators)
Printer << " in " << pointer->getChild(0)->getText() << ')';
return;
case Node::Kind::Module:
if (Options.DisplayModuleNames)
Printer << pointer->getText();
return;
case Node::Kind::Identifier:
Printer << pointer->getText();
return;
case Node::Kind::Index:
Printer << pointer->getIndex();
return;
case Node::Kind::AutoClosureType:
Printer << "@autoclosure ";
printFunctionType(pointer);
return;
case Node::Kind::ThinFunctionType:
Printer << "@convention(thin) ";
printFunctionType(pointer);
return;
case Node::Kind::FunctionType:
case Node::Kind::UncurriedFunctionType:
printFunctionType(pointer);
return;
case Node::Kind::ArgumentTuple: {
bool need_parens = false;
if (pointer->getNumChildren() > 1)
need_parens = true;
else {
if (!pointer->hasChildren())
need_parens = true;
else {
Node::Kind child0_kind = pointer->getChild(0)->getKind();
if (child0_kind == Node::Kind::Type)
child0_kind = pointer->getChild(0)->getChild(0)->getKind();
if (child0_kind != Node::Kind::Tuple)
need_parens = true;
}
}
if (need_parens)
Printer << "(";
printChildren(pointer);
if (need_parens)
Printer << ")";
return;
}
case Node::Kind::Tuple: {
Printer << "(";
printChildren(pointer, ", ");
Printer << ")";
return;
}
case Node::Kind::TupleElement: {
unsigned Idx = 0;
bool isVariadic = false;
if (pointer->getNumChildren() >= 1 &&
pointer->getFirstChild()->getKind() == Node::Kind::VariadicMarker) {
isVariadic = true;
Idx++;
}
NodePointer type = nullptr;
if (pointer->getNumChildren() == Idx + 1) {
type = pointer->getChild(Idx);
} else if (pointer->getNumChildren() == Idx + 2) {
NodePointer id = pointer->getChild(Idx);
type = pointer->getChild(Idx + 1);
print(id);
}
if (isVariadic) {
SugarType Sugar = findSugar(type);
if (Sugar == SugarType::Array)
type = type->getFirstChild()->getChild(1)->getFirstChild();
print(type);
Printer << "...";
} else {
print(type);
}
return;
}
case Node::Kind::TupleElementName:
Printer << pointer->getText() << " : ";
return;
case Node::Kind::ReturnType:
if (pointer->getNumChildren() == 0)
Printer << " -> " << pointer->getText();
else {
Printer << " -> ";
printChildren(pointer);
}
return;
case Node::Kind::Weak:
Printer << "weak ";
print(pointer->getChild(0));
return;
case Node::Kind::Unowned:
Printer << "unowned ";
print(pointer->getChild(0));
return;
case Node::Kind::Unmanaged:
Printer << "unowned(unsafe) ";
print(pointer->getChild(0));
return;
case Node::Kind::InOut:
Printer << "inout ";
print(pointer->getChild(0));
return;
case Node::Kind::NonObjCAttribute:
Printer << "@nonobjc ";
return;
case Node::Kind::ObjCAttribute:
Printer << "@objc ";
return;
case Node::Kind::DirectMethodReferenceAttribute:
Printer << "super ";
return;
case Node::Kind::DynamicAttribute:
Printer << "dynamic ";
return;
case Node::Kind::VTableAttribute:
Printer << "override ";
return;
case Node::Kind::FunctionSignatureSpecialization:
return printSpecializationPrefix(pointer,
"function signature specialization");
case Node::Kind::GenericPartialSpecialization:
return printSpecializationPrefix(pointer,
"generic partial specialization", "Signature = ");
case Node::Kind::GenericPartialSpecializationNotReAbstracted:
return printSpecializationPrefix(pointer,
"generic not-reabstracted partial specialization", "Signature = ");
case Node::Kind::GenericSpecialization:
return printSpecializationPrefix(pointer,
"generic specialization");
case Node::Kind::GenericSpecializationNotReAbstracted:
return printSpecializationPrefix(pointer,
"generic not re-abstracted specialization");
case Node::Kind::SpecializationIsFragile:
Printer << "preserving fragile attribute";
return;
case Node::Kind::GenericSpecializationParam:
print(pointer->getChild(0));
for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) {
if (i == 1)
Printer << " with ";
else
Printer << " and ";
print(pointer->getChild(i));
}
return;
case Node::Kind::FunctionSignatureSpecializationParam: {
uint64_t argNum = pointer->getIndex();
Printer << "Arg[" << argNum << "] = ";
unsigned Idx = printFunctionSigSpecializationParam(pointer, 0);
for (unsigned e = pointer->getNumChildren(); Idx < e;) {
Printer << " and ";
Idx = printFunctionSigSpecializationParam(pointer, Idx);
}
return;
}
case Node::Kind::FunctionSignatureSpecializationParamPayload: {
std::string demangledName = demangleSymbolAsString(pointer->getText());
if (demangledName.empty()) {
Printer << pointer->getText();
} else {
Printer << demangledName;
}
return;
}
case Node::Kind::FunctionSignatureSpecializationParamKind: {
uint64_t raw = pointer->getIndex();
bool printedOptionSet = false;
if (raw & uint64_t(FunctionSigSpecializationParamKind::Dead)) {
printedOptionSet = true;
Printer << "Dead";
}
if (raw & uint64_t(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) {
if (printedOptionSet)
Printer << " and ";
printedOptionSet = true;
Printer << "Owned To Guaranteed";
}
if (raw & uint64_t(FunctionSigSpecializationParamKind::SROA)) {
if (printedOptionSet)
Printer << " and ";
Printer << "Exploded";
return;
}
if (printedOptionSet)
return;
switch (FunctionSigSpecializationParamKind(raw)) {
case FunctionSigSpecializationParamKind::BoxToValue:
Printer << "Value Promoted from Box";
break;
case FunctionSigSpecializationParamKind::BoxToStack:
Printer << "Stack Promoted from Box";
break;
case FunctionSigSpecializationParamKind::ConstantPropFunction:
Printer << "Constant Propagated Function";
break;
case FunctionSigSpecializationParamKind::ConstantPropGlobal:
Printer << "Constant Propagated Global";
break;
case FunctionSigSpecializationParamKind::ConstantPropInteger:
Printer << "Constant Propagated Integer";
break;
case FunctionSigSpecializationParamKind::ConstantPropFloat:
Printer << "Constant Propagated Float";
break;
case FunctionSigSpecializationParamKind::ConstantPropString:
Printer << "Constant Propagated String";
break;
case FunctionSigSpecializationParamKind::ClosureProp:
Printer << "Closure Propagated";
break;
case FunctionSigSpecializationParamKind::Dead:
case FunctionSigSpecializationParamKind::OwnedToGuaranteed:
case FunctionSigSpecializationParamKind::SROA:
printer_unreachable("option sets should have been handled earlier");
}
return;
}
case Node::Kind::SpecializationPassID:
Printer << pointer->getIndex();
return;
case Node::Kind::BuiltinTypeName:
Printer << pointer->getText();
return;
case Node::Kind::Number:
Printer << pointer->getIndex();
return;
case Node::Kind::InfixOperator:
Printer << pointer->getText() << " infix";
return;
case Node::Kind::PrefixOperator:
Printer << pointer->getText() << " prefix";
return;
case Node::Kind::PostfixOperator:
Printer << pointer->getText() << " postfix";
return;
case Node::Kind::LazyProtocolWitnessTableAccessor:
Printer << "lazy protocol witness table accessor for type ";
print(pointer->getChild(0));
Printer << " and conformance ";
print(pointer->getChild(1));
return;
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
Printer << "lazy protocol witness table cache variable for type ";
print(pointer->getChild(0));
Printer << " and conformance ";
print(pointer->getChild(1));
return;
case Node::Kind::ProtocolWitnessTableAccessor:
Printer << "protocol witness table accessor for ";
print(pointer->getFirstChild());
return;
case Node::Kind::ProtocolWitnessTable:
Printer << "protocol witness table for ";
print(pointer->getFirstChild());
return;
case Node::Kind::GenericProtocolWitnessTable:
Printer << "generic protocol witness table for ";
print(pointer->getFirstChild());
return;
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
Printer << "instantiation function for generic protocol witness table for ";
print(pointer->getFirstChild());
return;
case Node::Kind::VTableThunk: {
Printer << "vtable thunk for ";
print(pointer->getChild(1));
Printer << " dispatching to ";
print(pointer->getChild(0));
return;
}
case Node::Kind::ProtocolWitness: {
Printer << "protocol witness for ";
print(pointer->getChild(1));
Printer << " in conformance ";
print(pointer->getChild(0));
return;
}
case Node::Kind::PartialApplyForwarder:
if (Options.ShortenPartialApply)
Printer << "partial apply";
else
Printer << "partial apply forwarder";
if (pointer->hasChildren()) {
Printer << " for ";
print(pointer->getFirstChild());
}
return;
case Node::Kind::PartialApplyObjCForwarder:
if (Options.ShortenPartialApply)
Printer << "partial apply";
else
Printer << "partial apply ObjC forwarder";
if (pointer->hasChildren()) {
Printer << " for ";
print(pointer->getFirstChild());
}
return;
case Node::Kind::FieldOffset: {
print(pointer->getChild(0)); // directness
Printer << "field offset for ";
auto entity = pointer->getChild(1);
print(entity, /*asContext*/ false,
/*suppressType*/ !Options.DisplayTypeOfIVarFieldOffset);
return;
}
case Node::Kind::ReabstractionThunk:
case Node::Kind::ReabstractionThunkHelper: {
if (Options.ShortenThunk) {
Printer << "thunk for ";
print(pointer->getChild(pointer->getNumChildren() - 2));
return;
}
Printer << "reabstraction thunk ";
if (pointer->getKind() == Node::Kind::ReabstractionThunkHelper)
Printer << "helper ";
auto generics = getFirstChildOfKind(pointer, Node::Kind::DependentGenericSignature);
assert(pointer->getNumChildren() == 2 + unsigned(generics != nullptr));
if (generics) {
print(generics);
Printer << " ";
}
Printer << "from ";
print(pointer->getChild(pointer->getNumChildren() - 2));
Printer << " to ";
print(pointer->getChild(pointer->getNumChildren() - 1));
return;
}
case Node::Kind::GenericTypeMetadataPattern:
Printer << "generic type metadata pattern for ";
print(pointer->getChild(0));
return;
case Node::Kind::Metaclass:
Printer << "metaclass for ";
print(pointer->getFirstChild());
return;
case Node::Kind::ProtocolDescriptor:
Printer << "protocol descriptor for ";
print(pointer->getChild(0));
return;
case Node::Kind::FullTypeMetadata:
Printer << "full type metadata for ";
print(pointer->getChild(0));
return;
case Node::Kind::TypeMetadata:
Printer << "type metadata for ";
print(pointer->getChild(0));
return;
case Node::Kind::TypeMetadataAccessFunction:
Printer << "type metadata accessor for ";
print(pointer->getChild(0));
return;
case Node::Kind::TypeMetadataLazyCache:
Printer << "lazy cache variable for type metadata for ";
print(pointer->getChild(0));
return;
case Node::Kind::AssociatedTypeMetadataAccessor:
Printer << "associated type metadata accessor for ";
print(pointer->getChild(1));
Printer << " in ";
print(pointer->getChild(0));
return;
case Node::Kind::AssociatedTypeWitnessTableAccessor:
Printer << "associated type witness table accessor for ";
print(pointer->getChild(1));
Printer << " : ";
print(pointer->getChild(2));
Printer << " in ";
print(pointer->getChild(0));
return;
case Node::Kind::NominalTypeDescriptor:
Printer << "nominal type descriptor for ";
print(pointer->getChild(0));
return;
case Node::Kind::ValueWitness:
Printer << toString(ValueWitnessKind(pointer->getIndex()));
if (Options.ShortenValueWitness) Printer << " for ";
else Printer << " value witness for ";
print(pointer->getFirstChild());
return;
case Node::Kind::ValueWitnessTable:
Printer << "value witness table for ";
print(pointer->getFirstChild());
return;
case Node::Kind::WitnessTableOffset:
Printer << "witness table offset for ";
print(pointer->getFirstChild());
return;
case Node::Kind::BoundGenericClass:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
printBoundGeneric(pointer);
return;
case Node::Kind::DynamicSelf:
Printer << "Self";
return;
case Node::Kind::CFunctionPointer: {
Printer << "@convention(c) ";
printFunctionType(pointer);
return;
}
case Node::Kind::ObjCBlock: {
Printer << "@convention(block) ";
printFunctionType(pointer);
return;
}
case Node::Kind::SILBoxType: {
Printer << "@box ";
NodePointer type = pointer->getChild(0);
print(type);
return;
}
case Node::Kind::Metatype: {
unsigned Idx = 0;
if (pointer->getNumChildren() == 2) {
NodePointer repr = pointer->getChild(Idx);
print(repr);
Printer << " ";
Idx++;
}
NodePointer type = pointer->getChild(Idx)->getChild(0);
bool needs_parens = !isSimpleType(type);
if (needs_parens)
Printer << "(";
print(type);
if (needs_parens)
Printer << ")";
if (isExistentialType(type)) {
Printer << ".Protocol";
} else {
Printer << ".Type";
}
return;
}
case Node::Kind::ExistentialMetatype: {
unsigned Idx = 0;
if (pointer->getNumChildren() == 2) {
NodePointer repr = pointer->getChild(Idx);
print(repr);
Printer << " ";
Idx++;
}
NodePointer type = pointer->getChild(Idx);
print(type);
Printer << ".Type";
return;
}
case Node::Kind::MetatypeRepresentation: {
Printer << pointer->getText();
return;
}
case Node::Kind::AssociatedTypeRef:
print(pointer->getChild(0));
Printer << '.' << pointer->getChild(1)->getText();
return;
case Node::Kind::ProtocolList: {
NodePointer type_list = pointer->getChild(0);
if (!type_list)
return;
if (type_list->getNumChildren() == 0)
Printer << "Any";
else
printChildren(type_list, " & ");
return;
}
case Node::Kind::AssociatedType:
// Don't print for now.
return;
case Node::Kind::QualifiedArchetype: {
if (Options.ShortenArchetype) {
Printer << "(archetype)";
return;
}
if (pointer->getNumChildren() < 2)
return;
NodePointer number = pointer->getChild(0);
NodePointer decl_ctx = pointer->getChild(1);
Printer << "(archetype " << number->getIndex() << " of ";
print(decl_ctx);
Printer << ")";
return;
}
case Node::Kind::OwningAddressor:
printEntity(true, true, ".owningAddressor");
return;
case Node::Kind::OwningMutableAddressor:
printEntity(true, true, ".owningMutableAddressor");
return;
case Node::Kind::NativeOwningAddressor:
printEntity(true, true, ".nativeOwningAddressor");
return;
case Node::Kind::NativeOwningMutableAddressor:
printEntity(true, true, ".nativeOwningMutableAddressor");
return;
case Node::Kind::NativePinningAddressor:
printEntity(true, true, ".nativePinningAddressor");
return;
case Node::Kind::NativePinningMutableAddressor:
printEntity(true, true, ".nativePinningMutableAddressor");
return;
case Node::Kind::UnsafeAddressor:
printEntity(true, true, ".unsafeAddressor");
return;
case Node::Kind::UnsafeMutableAddressor:
printEntity(true, true, ".unsafeMutableAddressor");
return;
case Node::Kind::GlobalGetter:
printEntity(true, true, ".getter");
return;
case Node::Kind::Getter:
printEntity(true, true, ".getter");
return;
case Node::Kind::Setter:
printEntity(true, true, ".setter");
return;
case Node::Kind::MaterializeForSet:
printEntity(true, true, ".materializeForSet");
return;
case Node::Kind::WillSet:
printEntity(true, true, ".willset");
return;
case Node::Kind::DidSet:
printEntity(true, true, ".didset");
return;
case Node::Kind::Allocator:
printEntity(false, true,
isClassType(pointer->getChild(0))
? "__allocating_init" : "init");
return;
case Node::Kind::Constructor:
printEntity(false, true, "init");
return;
case Node::Kind::Destructor:
printEntity(false, false, "deinit");
return;
case Node::Kind::Deallocator:
printEntity(false, false,
isClassType(pointer->getChild(0))
? "__deallocating_deinit" : "deinit");
return;
case Node::Kind::IVarInitializer:
printEntity(false, false, "__ivar_initializer");
return;
case Node::Kind::IVarDestroyer:
printEntity(false, false, "__ivar_destroyer");
return;
case Node::Kind::ProtocolConformance: {
NodePointer child0 = pointer->getChild(0);
NodePointer child1 = pointer->getChild(1);
NodePointer child2 = pointer->getChild(2);
if (pointer->getNumChildren() == 4) {
// TODO: check if this is correct
Printer << "property behavior storage of ";
print(child2);
Printer << " in ";
print(child0);
Printer << " : ";
print(child1);
} else {
print(child0);
if (Options.DisplayProtocolConformances) {
Printer << " : ";
print(child1);
Printer << " in ";
print(child2);
}
}
return;
}
case Node::Kind::TypeList:
printChildren(pointer);
return;
case Node::Kind::ImplConvention:
Printer << pointer->getText();
return;
case Node::Kind::ImplFunctionAttribute:
Printer << pointer->getText();
return;
case Node::Kind::ImplErrorResult:
Printer << "@error ";
LLVM_FALLTHROUGH;
case Node::Kind::ImplParameter:
case Node::Kind::ImplResult:
printChildren(pointer, " ");
return;
case Node::Kind::ImplFunctionType:
printImplFunctionType(pointer);
return;
case Node::Kind::ErrorType:
Printer << "<ERROR TYPE>";
return;
case Node::Kind::DependentPseudogenericSignature:
case Node::Kind::DependentGenericSignature: {
Printer << '<';
unsigned depth = 0;
unsigned numChildren = pointer->getNumChildren();
for (;
depth < numChildren
&& pointer->getChild(depth)->getKind()
== Node::Kind::DependentGenericParamCount;
++depth) {
if (depth != 0)
Printer << "><";
unsigned count = pointer->getChild(depth)->getIndex();
for (unsigned index = 0; index < count; ++index) {
if (index != 0)
Printer << ", ";
// FIXME: Depth won't match when a generic signature applies to a
// method in generic type context.
Printer << archetypeName(index, depth);
}
}
if (depth != numChildren) {
if (!Options.DisplayWhereClauses) {
Printer << " where ...";
} else {
Printer << " where ";
for (unsigned i = depth; i < numChildren; ++i) {
if (i > depth)
Printer << ", ";
print(pointer->getChild(i));
}
}
}
Printer << '>';
return;
}
case Node::Kind::DependentGenericParamCount:
printer_unreachable("should be printed as a child of a "
"DependentGenericSignature");
case Node::Kind::DependentGenericConformanceRequirement: {
NodePointer type = pointer->getChild(0);
NodePointer reqt = pointer->getChild(1);
print(type);
Printer << ": ";
print(reqt);
return;
}
case Node::Kind::DependentGenericLayoutRequirement: {
NodePointer type = pointer->getChild(0);
NodePointer layout = pointer->getChild(1);
print(type);
Printer << ": ";
assert(layout->getKind() == Node::Kind::Identifier);
assert(layout->getText().size() == 1);
char c = layout->getText()[0];
StringRef name;
if (c == 'U') {
name = "_UnknownLayout";
} else if (c == 'R') {
name = "_RefCountedObject";
} else if (c == 'N') {
name = "_NativeRefCountedObject";
} else if (c == 'C') {
name = "_Class";
} else if (c == 'D') {
name = "_NativeClass";
} else if (c == 'T') {
name = "_Trivial";
} else if (c == 'E' || c == 'e') {
name = "_Trivial";
} else if (c == 'M' || c == 'm') {
name = "_TrivialAtMost";
}
Printer << name;
if (pointer->getNumChildren() > 2) {
Printer << "(";
print(pointer->getChild(2));
if (pointer->getNumChildren() > 3) {
Printer << ", ";
print(pointer->getChild(3));
}
Printer << ")";
}
return;
}
case Node::Kind::DependentGenericSameTypeRequirement: {
NodePointer fst = pointer->getChild(0);
NodePointer snd = pointer->getChild(1);
print(fst);
Printer << " == ";
print(snd);
return;
}
case Node::Kind::DependentGenericParamType: {
Printer << pointer->getText();
return;
}
case Node::Kind::DependentGenericType: {
NodePointer sig = pointer->getChild(0);
NodePointer depTy = pointer->getChild(1);
print(sig);
Printer << ' ';
print(depTy);
return;
}
case Node::Kind::DependentMemberType: {
NodePointer base = pointer->getChild(0);
print(base);
Printer << '.';
NodePointer assocTy = pointer->getChild(1);
print(assocTy);
return;
}
case Node::Kind::DependentAssociatedTypeRef: {
Printer << pointer->getText();
return;
}
case Node::Kind::ReflectionMetadataBuiltinDescriptor:
Printer << "reflection metadata builtin descriptor ";
print(pointer->getChild(0));
return;
case Node::Kind::ReflectionMetadataFieldDescriptor:
Printer << "reflection metadata field descriptor ";
print(pointer->getChild(0));
return;
case Node::Kind::ReflectionMetadataAssocTypeDescriptor:
Printer << "reflection metadata associated type descriptor ";
print(pointer->getChild(0));
return;
case Node::Kind::ReflectionMetadataSuperclassDescriptor:
Printer << "reflection metadata superclass descriptor ";
print(pointer->getChild(0));
return;
case Node::Kind::ThrowsAnnotation:
Printer<< " throws ";
return;
case Node::Kind::EmptyList:
Printer << " empty-list ";
return;
case Node::Kind::FirstElementMarker:
Printer << " first-element-marker ";
return;
case Node::Kind::VariadicMarker:
Printer << " variadic-marker ";
return;
case Node::Kind::SILBoxTypeWithLayout: {
assert(pointer->getNumChildren() == 1 || pointer->getNumChildren() == 3);
NodePointer layout = pointer->getChild(0);
assert(layout->getKind() == Node::Kind::SILBoxLayout);
NodePointer signature, genericArgs = nullptr;
if (pointer->getNumChildren() == 3) {
signature = pointer->getChild(1);
assert(signature->getKind() == Node::Kind::DependentGenericSignature);
genericArgs = pointer->getChild(2);
assert(genericArgs->getKind() == Node::Kind::TypeList);
print(signature);
Printer << ' ';
}
print(layout);
if (genericArgs) {
Printer << " <";
for (unsigned i = 0, e = genericArgs->getNumChildren(); i < e; ++i) {
if (i > 0)
Printer << ", ";
print(genericArgs->getChild(i));
}
Printer << '>';
}
return;
}
case Node::Kind::SILBoxLayout:
Printer << '{';
for (unsigned i = 0; i < pointer->getNumChildren(); ++i) {
if (i > 0)
Printer << ',';
Printer << ' ';
print(pointer->getChild(i));
}
Printer << " }";
return;
case Node::Kind::SILBoxImmutableField:
case Node::Kind::SILBoxMutableField:
Printer << (pointer->getKind() == Node::Kind::SILBoxImmutableField
? "let "
: "var ");
assert(pointer->getNumChildren() == 1
&& pointer->getChild(0)->getKind() == Node::Kind::Type);
print(pointer->getChild(0));
return;
}
printer_unreachable("bad node kind!");
}
std::string Demangle::nodeToString(NodePointer root,
const DemangleOptions &options) {
if (!root)
return "";
return NodePrinter(options).printRoot(root);
}