Files
swift-mirror/lib/Basic/Demangle.cpp
Enrico Granata f2ba4c8c59 This commit changes the way the Demangler handles substitutions
Previously, substitutions were treated as unstructured text chunks, but this was causing problems when using the demangler as a source of structured type information
This patch ensures that substitutions are properly stored as the type they represent for later semantic reconstruction



Swift SVN r7494
2013-08-23 00:21:26 +00:00

1751 lines
54 KiB
C++

//===--- Demangle.cpp - Swift Name Demangling -----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===---------------------------------------------------------------------===//
//
// This file implements declaration name demangling in Swift.
//
//===---------------------------------------------------------------------===//
#include "swift/Basic/Demangle.h"
#include "swift/Basic/LLVM.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <tuple>
#include <vector>
using namespace swift;
using namespace Demangle;
swift::Demangle::Node::Node(Kind k, std::string t)
: ParentNode(nullptr), TextContent(t), NodeKind(k), NextNode(nullptr),
Children() {}
swift::Demangle::Node::Node (const Node& other) {
NodeKind = other.NodeKind;
TextContent = other.TextContent;
ParentNode = other.ParentNode;
Children = other.Children;
NextNode = other.NextNode;
}
llvm::StringRef swift::Demangle::Node::getText() { return TextContent; }
void swift::Demangle::Node::setText(std::string t) { TextContent.assign(t); }
swift::Demangle::Node::Kind swift::Demangle::Node::getKind() {
return NodeKind;
}
void swift::Demangle::Node::setKind(swift::Demangle::Node::Kind k) {
NodeKind = k;
}
NodePointer swift::Demangle::Node::getNextNode() { return NextNode; }
NodePointer swift::Demangle::Node::setNextNode(NodePointer n) {
NextNode = n;
if (ParentNode)
ParentNode->push_back_child(n);
return n;
}
NodePointer swift::Demangle::Node::push_back_child(NodePointer c) {
Children.push_back(c);
c->ParentNode = this;
return c;
}
NodePointer
swift::Demangle::Node::child_at(swift::Demangle::Node::size_type pos) {
if (pos < size())
return Children[pos];
return NodePointer(nullptr);
}
NodePointer swift::Demangle::Node::front() {
if (size())
return Children.front();
return NodePointer(nullptr);
}
NodePointer swift::Demangle::Node::back() {
if (size())
return Children.back();
return NodePointer(nullptr);
}
swift::Demangle::Node::iterator swift::Demangle::Node::begin() {
return Children.begin();
}
swift::Demangle::Node::iterator swift::Demangle::Node::end() {
return Children.end();
}
swift::Demangle::Node::const_iterator swift::Demangle::Node::begin() const {
return Children.begin();
}
swift::Demangle::Node::const_iterator swift::Demangle::Node::end() const {
return Children.end();
}
swift::Demangle::Node::size_type swift::Demangle::Node::size() {
return Children.size();
}
class DemanglerPrinter {
public:
DemanglerPrinter() : Buffer(), BackendPrinter(Buffer) {}
DemanglerPrinter &operator<<(std::string s) {
BackendPrinter << s;
return *this;
}
DemanglerPrinter &operator<<(const char *cstr) {
BackendPrinter << cstr;
return *this;
}
DemanglerPrinter &operator<<(char c) {
BackendPrinter << c;
return *this;
}
DemanglerPrinter &operator<<(size_t sz) {
BackendPrinter << sz;
return *this;
}
std::string &str() { return BackendPrinter.str(); }
private:
std::string Buffer;
llvm::raw_string_ostream BackendPrinter;
};
static bool isStartOfIdentifier(char c) {
if (c >= '0' && c <= '9')
return true;
return c == 'o';
}
static bool isStartOfNominalType(char c) {
switch (c) {
case 'C':
case 'V':
case 'O':
return true;
default:
return false;
}
}
static Node::Kind nominalTypeMarkerToNodeKind(char c) {
if (c == 'C')
return Node::Kind::Class;
if (c == 'V')
return Node::Kind::Structure;
if (c == 'O')
return Node::Kind::Union;
return Node::Kind::Identifier;
}
static std::string archetypeName(size_t i) {
DemanglerPrinter name;
do {
name << (char)('A' + (i % 26));
i /= 26;
} while (i);
return name.str();
}
NodePointer Node::makeNodePointer(Kind k, std::string t) {
return NodePointer(new Node(k, t));
}
class Demangler {
public:
Demangler(llvm::StringRef mangled)
: Substitutions(), ArchetypeCounts(), ArchetypeCount(), Mangled(mangled),
RootNode(), CurrentNode() {}
~Demangler() {}
NodePointer appendNode(NodePointer n) {
if (!RootNode) {
RootNode = n;
CurrentNode = RootNode;
} else {
CurrentNode->setNextNode(n);
CurrentNode = n;
}
return CurrentNode;
}
NodePointer appendNode(Node::Kind k, std::string t = "") {
if (!RootNode) {
RootNode = NodePointer(new Node(k, t));
CurrentNode = RootNode;
} else {
CurrentNode->setNextNode(NodePointer(new Node(k, t)));
CurrentNode = CurrentNode->getNextNode();
}
return CurrentNode;
}
void insertChildNode(Node::Kind k, std::string t = "") {
assert(CurrentNode.getPtr() && "Need a current node");
CurrentNode->push_back_child(NodePointer(new Node(k, t)));
}
bool demangle() {
if (!Mangled.hasAtLeast(2))
return failure();
if (Mangled.slice(2) != "_T")
return failure();
if (Mangled.hasAtLeast(4)) {
if (Mangled.slice(4) == "_TTo") {
Mangled.advanceOffset(4);
appendNode(Node::Kind::ObjCAttribute);
if (!demangleGlobal())
return false;
return true;
}
}
Mangled.advanceOffset(2);
if (!demangleGlobal())
return false;
return true;
}
NodePointer getDemangled() { return RootNode; }
private:
enum class IsProtocol {
yes = true, no = false
};
enum class IsVariadic {
yes = true, no = false
};
typedef std::pair<NodePointer, IsProtocol> Substitution;
enum class Directness {
Direct, Indirect, Unkown
};
const char *toString(Directness d) {
switch (d) {
case Directness::Direct:
return "direct";
case Directness::Indirect:
return "indirect";
default:
return "unknown";
}
}
bool failure() {
RootNode = NodePointer(new Node(Node::Kind::Failure, ""));
CurrentNode = RootNode;
return false;
}
Directness demangleDirectness() {
if (Mangled.nextIf('d'))
return Directness::Direct;
if (Mangled.nextIf('i'))
return Directness::Indirect;
return Directness::Unkown;
}
bool demangleNatural(size_t &num) {
if (!Mangled)
return false;
char c = Mangled.next();
if (c < '0' || c > '9')
return false;
num = (c - '0');
while (true) {
if (!Mangled) {
return true;
}
c = Mangled.peek();
if (c < '0' || c > '9') {
return true;
} else {
num = (10 * num) + (c - '0');
}
Mangled.next();
}
}
bool demangleBuiltinSize(size_t &num) {
if (!demangleNatural(num))
return false;
if (Mangled.nextIf('_'))
return true;
return false;
}
enum class ValueWitnessKind {
AllocateBuffer,
AssignWithCopy,
AssignWithTake,
DeallocateBuffer,
Destroy,
DestroyBuffer,
InitializeBufferWithCopyOfBuffer,
InitializeBufferWithCopy,
InitializeWithCopy,
InitializeBufferWithTake,
InitializeWithTake,
ProjectBuffer,
Typeof,
StoreExtraInhabitant,
GetExtraInhabitantIndex,
GetUnionTag,
InplaceProjectUnionData,
Unknown
};
const char *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::Typeof:
return "typeof";
case ValueWitnessKind::StoreExtraInhabitant:
return "storeExtraInhabitant";
case ValueWitnessKind::GetExtraInhabitantIndex:
return "getExtraInhabitantIndex";
case ValueWitnessKind::GetUnionTag:
return "getUnionTag";
case ValueWitnessKind::InplaceProjectUnionData:
return "inplaceProjectUnionData";
default:
return "unknown";
}
}
ValueWitnessKind demangleValueWitnessKind() {
if (!Mangled)
return ValueWitnessKind::Unknown;
char c1 = Mangled.next();
if (!Mangled)
return ValueWitnessKind::Unknown;
char c2 = Mangled.next();
if (c1 == 'a' && c2 == 'l')
return ValueWitnessKind::AllocateBuffer;
if (c1 == 'c' && c2 == 'a')
return ValueWitnessKind::AssignWithCopy;
if (c1 == 't' && c2 == 'a')
return ValueWitnessKind::AssignWithTake;
if (c1 == 'd' && c2 == 'e')
return ValueWitnessKind::DeallocateBuffer;
if (c1 == 'x' && c2 == 'x')
return ValueWitnessKind::Destroy;
if (c1 == 'X' && c2 == 'X')
return ValueWitnessKind::DestroyBuffer;
if (c1 == 'C' && c2 == 'P')
return ValueWitnessKind::InitializeBufferWithCopyOfBuffer;
if (c1 == 'C' && c2 == 'p')
return ValueWitnessKind::InitializeBufferWithCopy;
if (c1 == 'c' && c2 == 'p')
return ValueWitnessKind::InitializeWithCopy;
if (c1 == 'T' && c2 == 'k')
return ValueWitnessKind::InitializeBufferWithTake;
if (c1 == 't' && c2 == 'k')
return ValueWitnessKind::InitializeWithTake;
if (c1 == 'p' && c2 == 'r')
return ValueWitnessKind::ProjectBuffer;
if (c1 == 't' && c2 == 'y')
return ValueWitnessKind::Typeof;
if (c1 == 'x' && c2 == 's')
return ValueWitnessKind::StoreExtraInhabitant;
if (c1 == 'x' && c2 == 'g')
return ValueWitnessKind::GetExtraInhabitantIndex;
if (c1 == 'u' && c2 == 'g')
return ValueWitnessKind::GetUnionTag;
if (c1 == 'u' && c2 == 'p')
return ValueWitnessKind::InplaceProjectUnionData;
return ValueWitnessKind::Unknown;
}
bool demangleGlobal() {
if (!Mangled)
return failure();
if (Mangled.nextIf('M')) {
if (Mangled.nextIf('P')) {
Directness d = demangleDirectness();
if (d == Directness::Unkown)
return failure();
appendNode(Node::Kind::Directness, toString(d));
appendNode(Node::Kind::GenericTypeMetadataPattern);
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(type);
return true;
}
if (Mangled.nextIf('m')) {
appendNode(Node::Kind::Metaclass);
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(type);
return true;
}
Directness d = demangleDirectness();
appendNode(Node::Kind::Directness, toString(d));
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::TypeMetadata);
appendNode(type);
return true;
}
if (Mangled.nextIf('n')) {
if (Mangled.nextIf('k') && Mangled.nextIf('_')) {
NodePointer entity = demangleEntity();
if (!entity)
return failure();
appendNode(Node::Kind::ProtocolWitness);
appendNode(entity);
return true;
} else
return failure();
}
if (Mangled.nextIf('t')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(type);
return true;
}
if (Mangled.nextIf('w')) {
ValueWitnessKind w = demangleValueWitnessKind();
if (w == ValueWitnessKind::Unknown)
return failure();
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::ValueWitnessKind, toString(w));
appendNode(type);
return true;
}
if (Mangled.nextIf('W')) {
if (Mangled.nextIf('V')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::ValueWitnessTable);
appendNode(type);
return true;
}
if (Mangled.nextIf('o')) {
NodePointer entity = demangleEntity();
if (!entity)
return failure();
appendNode(Node::Kind::WitnessTableOffset);
appendNode(entity);
return true;
}
if (Mangled.nextIf('v')) {
Directness d = demangleDirectness();
appendNode(Node::Kind::Directness, toString(d));
NodePointer entity = demangleEntity();
if (!entity)
return failure();
appendNode(Node::Kind::FieldOffset);
appendNode(entity);
return true;
}
if (Mangled.nextIf('P')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::ProtocolWitnessTable));
appendNode(conformance);
return true;
}
if (Mangled.nextIf('Z')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(
Node::Kind::LazyProtocolWitnessTableAccessor));
appendNode(conformance);
return true;
}
if (Mangled.nextIf('z')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(
Node::Kind::LazyProtocolWitnessTableTemplate));
appendNode(conformance);
return true;
}
if (Mangled.nextIf('D')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(
Node::Kind::DependentProtocolWitnessTableGenerator));
appendNode(conformance);
return true;
}
if (Mangled.nextIf('d')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(
Node::Kind::DependentProtocolWitnessTableTemplate));
appendNode(conformance);
return true;
}
return failure();
}
if (Mangled.nextIf('T')) {
if (Mangled.nextIf('b')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::BridgeToBlockFunction);
appendNode(type);
return true;
}
return failure();
}
if (Mangled.nextIf('L')) {
NodePointer entity = demangleEntity();
if (!entity)
return failure();
appendNode(Node::Kind::LocalEntity);
appendNode(entity);
return true;
}
NodePointer entity = demangleEntity();
if (!entity)
return failure();
appendNode(entity);
return true;
}
std::string demangleOperator() {
static const char op_char_table[] = "& @/= > <*!|+ %-~ ^ .";
size_t length;
if (demangleNatural(length)) {
if (Mangled.hasAtLeast(length)) {
std::string op_base = Mangled.slice(length);
Mangled.advanceOffset(length);
DemanglerPrinter op;
size_t op_base_size = op_base.size();
for (size_t idx = 0; idx < op_base_size; ++idx) {
char c = op_base[idx];
if (c < 'a' || c > 'z')
return "";
char o = op_char_table[c - 'a'];
if (o == ' ')
return "";
op << o;
}
return op.str();
} else
return "";
}
return "";
}
NodePointer demangleIdentifier() {
if (!Mangled)
return nullptr;
if (Mangled.nextIf('o')) {
char op_mode = Mangled.next();
if (op_mode != 'p' && op_mode != 'P' && op_mode != 'i')
return nullptr;
std::string operatr = demangleOperator();
if (operatr.size()) {
switch (op_mode) {
case 'p':
return Node::makeNodePointer(Node::Kind::PrefixOperator, operatr);
case 'P':
return Node::makeNodePointer(Node::Kind::PostfixOperator, operatr);
case 'i':
return Node::makeNodePointer(Node::Kind::InfixOperator, operatr);
default:
return nullptr;
}
}
}
size_t length;
if (demangleNatural(length)) {
if (Mangled.hasAtLeast(length)) {
auto identifier = Mangled.slice(length);
Mangled.advanceOffset(length);
return Node::makeNodePointer(Node::Kind::Identifier, identifier);
}
}
return nullptr;
}
bool demangleIndex(size_t &natural) {
if (Mangled.nextIf('_')) {
natural = 0;
return true;
}
if (demangleNatural(natural)) {
if (!Mangled.nextIf('_'))
return false;
natural++;
return true;
}
return false;
}
NodePointer compactNode(NodePointer head, Node::Kind outputKind,
char separator = '.') {
DemanglerPrinter printer;
while (head) {
printer << head->getText();
head = head->getNextNode();
if (head)
printer << separator;
}
return Node::makeNodePointer(outputKind, printer.str());
}
Substitution demangleSubstitutionIndexWithProtocol() {
if (!Mangled)
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
if (Mangled.nextIf('o'))
return { Node::makeNodePointer(Node::Kind::Module,"ObjectiveC"), IsProtocol::no };
if (Mangled.nextIf('C'))
return { Node::makeNodePointer(Node::Kind::Module,"C"), IsProtocol::no };
if (Mangled.nextIf('s'))
return { Node::makeNodePointer(Node::Kind::Module,"swift"), IsProtocol::no };
if (Mangled.nextIf('a')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Slice"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('b')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Bool"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('c')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Char"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('d')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Float64"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('f')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Float32"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('i')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Int64"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('q')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"Optional"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('S')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"String"));
return { type, IsProtocol::no };
}
if (Mangled.nextIf('u')) {
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
Node::makeNodePointer(Node::Kind::Structure,"UInt64"));
return { type, IsProtocol::no };
}
size_t index_sub;
if (!demangleIndex(index_sub))
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
if (index_sub >= Substitutions.size())
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
return Substitutions[index_sub];
}
NodePointer demangleSubstitutionIndex() {
Substitution sub = demangleSubstitutionIndexWithProtocol();
if (!sub.first)
return nullptr;
return NodePointer(new Node(*sub.first.getPtr()));
}
NodePointer demangleSubstitution() {
if (Mangled.nextIf('S'))
return demangleSubstitutionIndex();
return nullptr;
}
NodePointer demangleModule() {
char c = Mangled.peek();
if (isStartOfIdentifier(c)) {
NodePointer identifier = demangleIdentifier();
if (!identifier)
return nullptr;
if (identifier->getKind() == Node::Kind::Identifier)
identifier->setKind(Node::Kind::Module);
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
Substitutions.push_back( { copy_identifier, IsProtocol::no });
return identifier;
}
if (c == 'S') {
NodePointer identifier = demangleSubstitution();
if (!identifier)
return nullptr;
identifier->setKind(Node::Kind::Module);
return identifier;
}
return nullptr;
}
bool demangleDeclarationName(NodePointer &context, NodePointer &identifier,
IsProtocol isA) {
Node::Kind context_type = Node::Kind::Unknown;
context = demangleContext(&context_type);
if (!context)
return false;
identifier = demangleIdentifier();
if (!identifier)
return false;
DemanglerPrinter printer;
printer << context->getText() << "." << identifier->getText();
NodePointer nominaltype = Node::makeNodePointer(Node::Kind::NominalType);
NodePointer copy_context = Node::makeNodePointer(context->getKind(),context->getText());
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
if (isA == IsProtocol::yes)
copy_identifier->setKind(Node::Kind::Protocol);
nominaltype->push_back_child(copy_context)->setNextNode(copy_identifier);
Substitutions.push_back({ nominaltype, isA });
if (context_type != Node::Kind::Unknown)
identifier->setKind(context_type);
return true;
}
NodePointer demangleProtocolName() {
if (Mangled.nextIf('S')) {
Substitution sub = demangleSubstitutionIndexWithProtocol();
if (!sub.first)
return nullptr;
if (sub.second == IsProtocol::yes)
return sub.first;
NodePointer identifier = demangleIdentifier();
if (!identifier)
return nullptr;
NodePointer nominaltype = Node::makeNodePointer(Node::Kind::NominalType);
NodePointer copy_context = NodePointer(new Node(*sub.first.getPtr()));
identifier->setKind(Node::Kind::Protocol);
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
nominaltype->push_back_child(copy_context)->setNextNode(copy_identifier);
Substitutions.push_back({ nominaltype, IsProtocol::yes });
return nominaltype;
}
NodePointer context, identifier;
if (demangleDeclarationName(context, identifier, IsProtocol::yes)) {
DemanglerPrinter printer;
while (context) {
printer << context->getText() << ".";
context = context->getNextNode();
}
printer << identifier->getText();
NodePointer result =
Node::makeNodePointer(Node::Kind::Protocol, printer.str());
return result;
}
return nullptr;
}
NodePointer demangleNominalType() {
if (!Mangled)
return nullptr;
char c = Mangled.next();
if (c == 'S')
return demangleSubstitutionIndex();
if (!isStartOfNominalType(c))
return nullptr;
NodePointer context, identifier;
if (!demangleDeclarationName(context, identifier, IsProtocol::no))
return nullptr;
identifier->setKind(nominalTypeMarkerToNodeKind(c));
context->setNextNode(identifier);
return context;
}
NodePointer demangleContext(Node::Kind *inferred_context_type = nullptr) {
if (!Mangled)
return nullptr;
char c = Mangled.peek();
if (isStartOfIdentifier(c) || c == 'S') {
return demangleModule();
}
if (isStartOfNominalType(c)) {
if (inferred_context_type) {
*inferred_context_type = nominalTypeMarkerToNodeKind(c);
}
return demangleNominalType();
}
if (c == 'P') {
Mangled.next();
return demangleProtocolName();
}
return nullptr;
}
NodePointer demangleDeclWithContext(NodePointer context) {
NodePointer identifier = demangleIdentifier();
if (!identifier)
return nullptr;
return demangleDeclTypeWithContextAndName(context, identifier);
}
NodePointer demangleDeclTypeWithContextAndName(NodePointer context,
NodePointer identifier) {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer decl =
Node::makeNodePointer(swift::Demangle::Node::Kind::Declaration);
Node::Kind id_kind = identifier->getKind();
if (id_kind != Node::Kind::InfixOperator &&
id_kind != Node::Kind::PrefixOperator &&
id_kind != Node::Kind::PostfixOperator)
identifier->setKind(Node::Kind::DeclIdentifier);
decl->push_back_child(context);
decl->push_back_child(identifier);
decl->push_back_child(type);
return decl;
}
NodePointer demangleProtocolList() {
NodePointer proto_list = Node::makeNodePointer(Node::Kind::ProtocolList);
if (Mangled.nextIf('_')) {
return proto_list;
}
NodePointer proto = demangleProtocolName();
if (!proto)
return nullptr;
proto_list->push_back_child(proto);
while (Mangled.nextIf('_') == false) {
proto = demangleProtocolName();
if (!proto)
return nullptr;
proto_list->push_back_child(proto);
}
return proto_list;
}
NodePointer demangleProtocolConformance() {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer protocol = demangleProtocolName();
if (!protocol)
return nullptr;
NodePointer context = demangleContext();
if (!context)
return nullptr;
NodePointer proto_conformance =
Node::makeNodePointer(Node::Kind::ProtocolConformance);
proto_conformance->push_back_child(type);
proto_conformance->push_back_child(protocol);
proto_conformance->push_back_child(context);
return proto_conformance;
}
NodePointer demangleEntity() {
NodePointer context = demangleContext();
if (!context)
return nullptr;
NodePointer identifier = context->getNextNode();
NodePointer decl;
if (Mangled.nextIf('D')) {
if (identifier && identifier->getKind() == Node::Kind::Class)
decl = Node::makeNodePointer(Node::Kind::Deallocator);
else
decl = Node::makeNodePointer(Node::Kind::Destructor);
decl->push_back_child(context);
return decl;
}
if (Mangled.nextIf('d')) {
decl = Node::makeNodePointer(Node::Kind::Destructor);
decl->push_back_child(context);
return decl;
}
if (Mangled.nextIf('C')) {
NodePointer type = demangleType();
if (!type)
return nullptr;
if (identifier && identifier->getKind() == Node::Kind::Class)
decl = Node::makeNodePointer(Node::Kind::Allocator);
else
decl = Node::makeNodePointer(Node::Kind::Constructor);
decl->push_back_child(context);
decl->push_back_child(type);
return decl;
}
if (Mangled.nextIf('c')) {
NodePointer type = demangleType();
if (!type)
return nullptr;
decl = Node::makeNodePointer(Node::Kind::Constructor);
decl->push_back_child(context);
decl->push_back_child(type);
return decl;
}
NodePointer decl_with_ctx = demangleDeclWithContext(context);
if (!decl_with_ctx)
return nullptr;
if (Mangled.nextIf('a')) {
decl = Node::makeNodePointer(Node::Kind::Addressor);
decl->push_back_child(decl_with_ctx);
} else if (Mangled.nextIf('g')) {
decl = Node::makeNodePointer(Node::Kind::Getter);
decl->push_back_child(decl_with_ctx);
} else if (Mangled.nextIf('s')) {
decl = Node::makeNodePointer(Node::Kind::Setter);
decl->push_back_child(decl_with_ctx);
} else {
decl = decl_with_ctx;
}
return decl;
}
NodePointer demangleArchetypes() {
DemanglerPrinter result_printer;
NodePointer archetypes = Node::makeNodePointer(Node::Kind::ArchetypeList);
while (true) {
if (Mangled.nextIf('_')) {
if (!Mangled)
return nullptr;
char c = Mangled.peek();
if (c != '_' && c != 'S' && !isStartOfIdentifier(c))
break;
archetypes->push_back_child(Node::makeNodePointer(
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
} else {
NodePointer proto_list = demangleProtocolList();
if (!proto_list)
return nullptr;
NodePointer arch_and_proto =
Node::makeNodePointer(Node::Kind::ArchetypeAndProtocol);
arch_and_proto->push_back_child(Node::makeNodePointer(
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
arch_and_proto->push_back_child(proto_list);
archetypes->push_back_child(arch_and_proto);
}
++ArchetypeCount;
}
return archetypes;
}
NodePointer demangleArchetypeRef(size_t depth, size_t i) {
if (depth == 0 && ArchetypeCount == 0)
return Node::makeNodePointer(Node::Kind::ArchetypeRef, archetypeName(i));
size_t length = ArchetypeCounts.size();
if (depth >= length)
return nullptr;
size_t index = ArchetypeCounts[length - 1 - depth] + i;
size_t max =
(depth == 0) ? ArchetypeCount : ArchetypeCounts[length - depth];
if (index >= max)
return nullptr;
return Node::makeNodePointer(Node::Kind::ArchetypeRef,
archetypeName(index));
}
NodePointer demangleTuple(IsVariadic isV) {
NodePointer tuple = Node::makeNodePointer(
isV == IsVariadic::yes ? Node::Kind::VariadicTuple
: Node::Kind::NonVariadicTuple);
while (Mangled.nextIf('_') == false) {
if (!Mangled)
return nullptr;
NodePointer tuple_element =
Node::makeNodePointer(Node::Kind::TupleElement);
NodePointer identifier;
NodePointer type;
if (isStartOfIdentifier(Mangled.peek())) {
identifier = demangleIdentifier();
if (!identifier)
return nullptr;
identifier->setKind(Node::Kind::TupleElementName);
}
type = demangleType();
if (!type)
return nullptr;
if (type->getNextNode() && type->getKind() != Node::Kind::ProtocolList)
type = compactNode(type, Node::Kind::TupleElementType);
if (identifier)
tuple_element->push_back_child(identifier);
tuple_element->push_back_child(type);
tuple->push_back_child(tuple_element);
}
return tuple;
}
NodePointer postProcessReturnTypeNode (NodePointer out_args) {
Node::Kind out_args_kind = out_args->getKind();
if (out_args_kind == Node::Kind::Identifier ||
out_args_kind == Node::Kind::Class ||
out_args_kind == Node::Kind::Module ||
out_args_kind == Node::Kind::Structure ||
out_args_kind == Node::Kind::Union) {
return compactNode(out_args, Node::Kind::ReturnType);
} else {
NodePointer out_node = Node::makeNodePointer(Node::Kind::ReturnType);
out_node->push_back_child(out_args);
return out_node;
}
}
NodePointer demangleType() {
if (!Mangled)
return nullptr;
char c = Mangled.next();
if (c == 'A') {
size_t size;
if (demangleNatural(size)) {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer array = Node::makeNodePointer(Node::Kind::ArrayType);
array->push_back_child(type);
array->push_back_child(Node::makeNodePointer(
Node::Kind::Number, (DemanglerPrinter() << size).str()));
return array;
}
return nullptr;
}
if (c == 'B') {
if (!Mangled)
return nullptr;
c = Mangled.next();
if (c == 'f') {
size_t size;
if (demangleBuiltinSize(size)) {
return Node::makeNodePointer(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Float" << size).str());
}
}
if (c == 'i') {
size_t size;
if (demangleBuiltinSize(size)) {
return Node::makeNodePointer(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Int" << size).str());
}
}
if (c == 'v') {
size_t elts;
if (demangleNatural(elts)) {
if (!Mangled.nextIf('B'))
return nullptr;
if (Mangled.nextIf('i')) {
size_t size;
if (!demangleBuiltinSize(size))
return nullptr;
return Node::makeNodePointer(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
.str());
}
if (Mangled.nextIf('f')) {
size_t size;
if (!demangleBuiltinSize(size))
return nullptr;
return Node::makeNodePointer(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xFloat"
<< size).str());
}
if (Mangled.nextIf('p'))
return Node::makeNodePointer(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
.str());
}
}
if (c == 'O')
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
"Builtin.ObjCPointer");
if (c == 'o')
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
"Builtin.ObjectPointer");
if (c == 'p')
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
"Builtin.RawPointer");
return nullptr;
}
if (c == 'b') {
NodePointer in_args = demangleType();
if (!in_args)
return nullptr;
NodePointer out_args = demangleType();
if (!out_args)
return nullptr;
NodePointer block = Node::makeNodePointer(Node::Kind::ObjCBlock);
NodePointer in_node = Node::makeNodePointer(Node::Kind::ArgumentTuple);
block->push_back_child(in_node);
in_node->push_back_child(in_args);
block->push_back_child(postProcessReturnTypeNode(out_args));
return block;
}
if (c == 'F') {
NodePointer in_args = demangleType();
if (!in_args)
return nullptr;
NodePointer out_args = demangleType();
if (!out_args)
return nullptr;
NodePointer block = Node::makeNodePointer(Node::Kind::FunctionType);
NodePointer in_node = Node::makeNodePointer(Node::Kind::ArgumentTuple);
block->push_back_child(in_node);
in_node->push_back_child(in_args);
block->push_back_child(postProcessReturnTypeNode(out_args));
return block;
}
if (c == 'f') {
NodePointer in_args = demangleType();
if (!in_args)
return nullptr;
NodePointer out_args = demangleType();
if (!out_args)
return nullptr;
NodePointer block =
Node::makeNodePointer(Node::Kind::UncurriedFunctionType);
NodePointer in_node =
Node::makeNodePointer(Node::Kind::UncurriedFunctionMetaType);
block->push_back_child(in_node);
in_node->push_back_child(in_args);
block->push_back_child(postProcessReturnTypeNode(out_args));
return block;
}
if (c == 'G') {
NodePointer type_list = Node::makeNodePointer(Node::Kind::TypeList);
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer type_list_entry =
Node::makeNodePointer(Node::Kind::TypeListEntry);
type_list_entry->push_back_child(type);
type_list->push_back_child(type_list_entry);
while (Mangled.peek() != '_') {
type = demangleType();
if (!type)
return nullptr;
type_list_entry = Node::makeNodePointer(Node::Kind::TypeListEntry);
type_list_entry->push_back_child(type);
type_list->push_back_child(type_list_entry);
}
Mangled.next();
NodePointer type_application =
Node::makeNodePointer(Node::Kind::GenericTypeApplication);
type_application->push_back_child(type_list);
return type_application;
}
if (c == 'M') {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer metatype = Node::makeNodePointer(Node::Kind::MetaType);
NodePointer type_entry = Node::makeNodePointer(Node::Kind::TypeListEntry);
type_entry->push_back_child(type);
metatype->push_back_child(type_entry);
return metatype;
}
if (c == 'P') {
return demangleProtocolList();
}
if (c == 'Q') {
if (Mangled.nextIf('d')) {
size_t depth, index;
if (!demangleIndex(depth))
return nullptr;
if (!demangleIndex(index))
return nullptr;
return demangleArchetypeRef(depth + 1, index);
}
size_t index;
if (!demangleIndex(index))
return nullptr;
return demangleArchetypeRef(0, index);
}
if (c == 'R') {
NodePointer byref = Node::makeNodePointer(Node::Kind::ByRef);
byref->setNextNode(demangleType());
if (byref->getNextNode())
return byref;
return nullptr;
}
if (c == 'S') {
return demangleSubstitutionIndex();
}
if (c == 'T') {
return demangleTuple(IsVariadic::no);
}
if (c == 't') {
return demangleTuple(IsVariadic::yes);
}
if (c == 'U') {
ArchetypeCounts.push_back(ArchetypeCount);
NodePointer archetypes = demangleArchetypes();
if (!archetypes)
return nullptr;
NodePointer base = demangleType();
if (!base)
return nullptr;
ArchetypeCount = ArchetypeCounts.back();
ArchetypeCounts.pop_back();
NodePointer generics = Node::makeNodePointer(Node::Kind::GenericType);
generics->push_back_child(archetypes);
generics->push_back_child(base);
return generics;
}
if (c == 'X') {
if (c == 'o') {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer unowned = Node::makeNodePointer(Node::Kind::Unowned);
unowned->setNextNode(type);
return unowned;
}
if (c == 'w') {
NodePointer type = demangleType();
if (!type)
return nullptr;
NodePointer unowned = Node::makeNodePointer(Node::Kind::Weak);
unowned->setNextNode(type);
return unowned;
}
return nullptr;
}
if (isStartOfNominalType(c)) {
NodePointer context(nullptr), identifier(nullptr);
if (!demangleDeclarationName(context, identifier, IsProtocol::no))
return nullptr;
context->setNextNode(identifier);
identifier->setKind(nominalTypeMarkerToNodeKind(c));
NodePointer nominal_type = Node::makeNodePointer(Node::Kind::NominalType);
nominal_type->push_back_child(context);
return nominal_type;
}
return nullptr;
}
class MangledNameSource {
public:
MangledNameSource(StringRef mangled);
char peek();
bool nextIf(char c);
char next();
bool isEmpty();
explicit operator bool();
std::string slice(size_t size);
std::string getString();
size_t getOffset();
size_t getSize();
bool hasAtLeast(size_t n);
void advanceOffset(size_t by);
private:
StringRef Mangled;
size_t Offset;
};
std::vector<Substitution> Substitutions;
std::vector<int> ArchetypeCounts;
int ArchetypeCount;
MangledNameSource Mangled;
NodePointer RootNode;
NodePointer CurrentNode;
};
Demangler::MangledNameSource::MangledNameSource(StringRef Mangled)
: Mangled(Mangled), Offset(0) {}
char Demangler::MangledNameSource::peek() { return Mangled.front(); }
bool Demangler::MangledNameSource::nextIf(char c) {
if (isEmpty())
return false;
char real_c = peek();
if (real_c == c) {
advanceOffset(1);
return true;
}
return false;
}
char Demangler::MangledNameSource::next() {
char c = peek();
advanceOffset(1);
return c;
}
bool Demangler::MangledNameSource::isEmpty() { return Mangled.empty(); }
Demangler::MangledNameSource::operator bool() { return isEmpty() == false; }
std::string Demangler::MangledNameSource::slice(size_t size) {
return Mangled.substr(0, size);
}
std::string Demangler::MangledNameSource::getString() { return Mangled.data(); }
size_t Demangler::MangledNameSource::getOffset() { return Offset; }
size_t Demangler::MangledNameSource::getSize() { return Mangled.size(); }
bool Demangler::MangledNameSource::hasAtLeast(size_t n) {
if (n > getSize())
return false;
return true;
}
void Demangler::MangledNameSource::advanceOffset(size_t by) {
Offset += by;
Mangled = Mangled.substr(by);
}
NodePointer swift::Demangle::demangleSymbolAsNode(llvm::StringRef mangled) {
Demangler demangler(mangled);
demangler.demangle();
return demangler.getDemangled();
}
void toString(NodePointer pointer, DemanglerPrinter &printer);
void toStringChildren (Node::iterator begin, Node::iterator end, DemanglerPrinter &printer, const char *sep = nullptr) {
for (; begin != end;) {
toString(*begin, printer);
++begin;
if (sep && begin != end)
printer << sep;
}
}
void toStringChildren (NodePointer pointer, DemanglerPrinter &printer, const char *sep = nullptr) {
if (!pointer)
return;
Node::iterator begin = pointer->begin(), end = pointer->end();
toStringChildren(begin, end, printer, sep);
}
void toStringLifeCycleEntity (NodePointer pointer, DemanglerPrinter &printer, const char* name) {
NodePointer child = pointer->child_at(0);
while (child) {
printer << child->getText();
child = child->getNextNode();
if (child)
printer << ".";
}
printer << name;
child = pointer->child_at(1);
if (child) {
printer << " : ";
toString(child, printer);
}
}
void toString(NodePointer pointer, DemanglerPrinter &printer) {
if (!pointer)
return;
Node::Kind kind = pointer->getKind();
switch (kind) {
case swift::Demangle::Node::Kind::Failure:
return;
case swift::Demangle::Node::Kind::Directness:
printer << pointer->getText() << " ";
break;
case swift::Demangle::Node::Kind::Declaration:
toStringChildren(pointer, printer);
break;
case swift::Demangle::Node::Kind::Module:
case swift::Demangle::Node::Kind::Class:
case swift::Demangle::Node::Kind::Structure:
case swift::Demangle::Node::Kind::Union:
printer << pointer->getText() << ".";
break;
case swift::Demangle::Node::Kind::Identifier:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::DeclIdentifier:
printer << pointer->getText() << " : ";
break;
case swift::Demangle::Node::Kind::FunctionName:
break;
case swift::Demangle::Node::Kind::FunctionType:
toStringChildren(pointer, printer);
break;
case swift::Demangle::Node::Kind::UncurriedFunctionType: {
NodePointer metatype = pointer->child_at(0);
if (!metatype)
break;
DemanglerPrinter sub_printer;
toString(metatype, sub_printer);
printer << sub_printer.str();
NodePointer real_func = pointer->child_at(1);
if (!real_func)
break;
real_func = real_func->child_at(0);
toStringChildren(real_func, printer);
break;
}
case swift::Demangle::Node::Kind::UncurriedFunctionMetaType:
printer << "(";
toStringChildren(pointer, printer);
printer << ")";
break;
case swift::Demangle::Node::Kind::ArgumentTuple: {
bool need_parens = false;
if (pointer->size() > 1)
need_parens = true;
else {
if (pointer->size() == 0)
need_parens = true;
else {
Node::Kind child0_kind = pointer->child_at(0)->getKind();
if (child0_kind != Node::Kind::VariadicTuple &&
child0_kind != Node::Kind::NonVariadicTuple)
need_parens = true;
}
}
if (need_parens)
printer << "(";
toStringChildren(pointer, printer);
if (need_parens)
printer << ")";
break;
}
case swift::Demangle::Node::Kind::NonVariadicTuple:
case swift::Demangle::Node::Kind::VariadicTuple: {
printer << "(";
toStringChildren(pointer, printer, ", ");
if (pointer->getKind() == swift::Demangle::Node::Kind::VariadicTuple)
printer << "...";
printer << ")";
break;
}
case swift::Demangle::Node::Kind::TupleElement: {
if (pointer->size() == 1) {
NodePointer type = pointer->child_at(0);
toString(type, printer);
} else if (pointer->size() == 2) {
NodePointer id = pointer->child_at(0);
NodePointer type = pointer->child_at(1);
toString(id, printer);
toString(type, printer);
}
break;
}
case swift::Demangle::Node::Kind::TupleElementName:
printer << pointer->getText() << " : ";
break;
case swift::Demangle::Node::Kind::TupleElementType:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::ReturnType: {
if (pointer->size() == 0)
printer << " -> " << pointer->getText();
else {
printer << " -> ";
toStringChildren(pointer, printer);
}
break;
}
case swift::Demangle::Node::Kind::Weak:
printer << "[weak] ";
break;
case swift::Demangle::Node::Kind::Unowned:
printer << "[unowned] ";
break;
case swift::Demangle::Node::Kind::ByRef:
printer << "[byref] ";
break;
case swift::Demangle::Node::Kind::ObjCAttribute:
printer << "[objc] ";
break;
case swift::Demangle::Node::Kind::LocalEntity:
printer << "local ";
break;
case swift::Demangle::Node::Kind::BuiltinTypeName:
case swift::Demangle::Node::Kind::BaseName:
case swift::Demangle::Node::Kind::Number:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::ArrayType: {
NodePointer type = pointer->child_at(0);
NodePointer size = pointer->child_at(1);
toString(type, printer);
printer << "[";
toString(size, printer);
printer << "]";
break;
}
case swift::Demangle::Node::Kind::InfixOperator:
printer << pointer->getText() << " [infix] : ";
break;
case swift::Demangle::Node::Kind::PrefixOperator:
printer << pointer->getText() << " [prefix] : ";
break;
case swift::Demangle::Node::Kind::PostfixOperator:
printer << pointer->getText() << " [postfix] : ";
break;
case swift::Demangle::Node::Kind::DependentProtocolWitnessTableGenerator:
printer << "dependent protocol witness table generator for ";
break;
case swift::Demangle::Node::Kind::DependentProtocolWitnessTableTemplate:
printer << "dependent protocol witness table template for ";
break;
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableAccessor:
printer << "lazy protocol witness table accessor for ";
break;
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableTemplate:
printer << "lazy protocol witness table template for ";
break;
case swift::Demangle::Node::Kind::ProtocolWitnessTable:
printer << "protocol witness table for ";
break;
case swift::Demangle::Node::Kind::ProtocolWitness:
printer << "protocol witness for ";
break;
case swift::Demangle::Node::Kind::FieldOffset:
printer << "field offset for ";
break;
case swift::Demangle::Node::Kind::BridgeToBlockFunction:
printer << "bridge-to-block function for ";
break;
case swift::Demangle::Node::Kind::GenericTypeMetadataPattern:
printer << "generic type metadata pattern for ";
break;
case swift::Demangle::Node::Kind::Metaclass:
printer << "metaclass for ";
break;
case swift::Demangle::Node::Kind::TypeMetadata:
printer << "type metadata for ";
break;
case swift::Demangle::Node::Kind::ValueWitnessKind:
printer << pointer->getText() << " value witness for ";
break;
case swift::Demangle::Node::Kind::ValueWitnessTable:
printer << "value witness table for ";
break;
case swift::Demangle::Node::Kind::WitnessTableOffset:
printer << "witness table offset for ";
break;
case swift::Demangle::Node::Kind::GenericTypeApplication: {
NodePointer typelist = pointer->child_at(0);
if (!typelist)
break;
NodePointer type0 = typelist->child_at(0);
toString(type0, printer);
printer << "<";
Node::size_type count = typelist->size();
for (Node::size_type i = 1; i < count;) {
toString(typelist->child_at(i), printer);
if (++i < count)
printer << ", ";
}
printer << ">";
break;
}
case swift::Demangle::Node::Kind::NominalType: {
NodePointer first = pointer->child_at(0);
while (first) {
printer << first->getText();
first = first->getNextNode();
if (first)
printer << ".";
}
break;
}
case swift::Demangle::Node::Kind::TypeListEntry:
toStringChildren(pointer, printer);
break;
case swift::Demangle::Node::Kind::ObjCBlock: {
printer << "[objc_block] ";
NodePointer tuple = pointer->child_at(0);
NodePointer rettype = pointer->child_at(1);
toString(tuple, printer);
toString(rettype, printer);
break;
}
case swift::Demangle::Node::Kind::MetaType: {
NodePointer type = pointer->child_at(0);
toString(type, printer);
printer << ".metatype";
break;
}
case swift::Demangle::Node::Kind::Protocol:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::ProtocolList: {
if (pointer->size() == 1) {
toString(pointer->child_at(0), printer);
break;
}
printer << "protocol<";
toStringChildren(pointer, printer, ", ");
printer << ">";
break;
}
case swift::Demangle::Node::Kind::ArchetypeRef:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::ArchetypeList: {
if (pointer->size() == 0)
break;
printer << "<";
toStringChildren(pointer, printer, ", ");
printer << ">";
break;
}
case swift::Demangle::Node::Kind::GenericType: {
NodePointer atype_list = pointer->child_at(0);
NodePointer fct_type = pointer->child_at(1);
toString(atype_list, printer);
NodePointer args = fct_type->child_at(0);
NodePointer ret = fct_type->child_at(1);
toString(args, printer);
toString(ret, printer);
break;
}
case swift::Demangle::Node::Kind::Addressor: {
NodePointer decl = pointer->child_at(0);
toString(decl, printer);
printer << " addressor";
break;
}
case swift::Demangle::Node::Kind::Getter: {
NodePointer decl = pointer->child_at(0);
toString(decl, printer);
printer << " getter";
break;
}
case swift::Demangle::Node::Kind::Setter: {
NodePointer decl = pointer->child_at(0);
toString(decl, printer);
printer << " setter";
break;
}
case swift::Demangle::Node::Kind::Allocator:
toStringLifeCycleEntity(pointer, printer, ".__allocating_constructor");
break;
case swift::Demangle::Node::Kind::Constructor:
toStringLifeCycleEntity(pointer, printer, ".constructor");
break;
case swift::Demangle::Node::Kind::Destructor:
toStringLifeCycleEntity(pointer, printer, ".destructor");
break;
case swift::Demangle::Node::Kind::Deallocator:
toStringLifeCycleEntity(pointer, printer, ".__deallocating_destructor");
break;
case swift::Demangle::Node::Kind::ProtocolConformance: {
NodePointer child0 = pointer->child_at(0);
NodePointer child1 = pointer->child_at(1);
NodePointer child2 = pointer->child_at(2);
if (!child0 || !child1 || !child2)
break;
toString(child0, printer);
printer << " : ";
toString(child1, printer);
printer << " in " << child2->getText();
break;
}
case swift::Demangle::Node::Kind::Substitution:
case swift::Demangle::Node::Kind::TypeName:
case swift::Demangle::Node::Kind::UncurriedFunctionFunctionType:
case swift::Demangle::Node::Kind::TypeList:
case swift::Demangle::Node::Kind::ArchetypeAndProtocol: {
NodePointer child0 = pointer->child_at(0);
NodePointer child1 = pointer->child_at(1);
toString(child0, printer);
printer << " : ";
toString(child1, printer);
break;
}
case swift::Demangle::Node::Kind::Unknown:
break;
}
pointer = pointer->getNextNode();
toString(pointer, printer);
}
std::string swift::Demangle::nodeToString(NodePointer pointer) {
if (!pointer)
return "";
DemanglerPrinter printer;
toString(pointer, printer);
return printer.str();
}
std::string swift::Demangle::demangleSymbolAsString(llvm::StringRef mangled) {
std::string demangling = nodeToString(demangleSymbolAsNode(mangled));
if (demangling.empty())
return mangled.str();
return demangling;
}