Files
swift-mirror/lib/Basic/Demangle.cpp
2013-08-19 23:15:51 +00:00

1707 lines
51 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() {}
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; }
void swift::Demangle::Node::setNextNode(NodePointer n) {
NextNode = n;
if (ParentNode)
ParentNode->push_back_child(n);
}
void swift::Demangle::Node::insertNextNode(NodePointer n) {
if (!n || !NextNode) {
setNextNode(n);
return;
}
NodePointer prev_next = NextNode;
NextNode = n;
NodePointer end_of_chain = NextNode;
while (end_of_chain->getNextNode())
end_of_chain = end_of_chain->getNextNode();
end_of_chain->setNextNode(prev_next);
}
void swift::Demangle::Node::push_back_child(NodePointer c) {
Children.push_back(c);
c->ParentNode = this;
}
void swift::Demangle::Node::push_front_child(NodePointer c) {
Children.insert(begin(), c);
}
void swift::Demangle::Node::insert_child(swift::Demangle::Node::iterator i,
NodePointer c) {
Children.insert(i, c);
}
NodePointer
swift::Demangle::Node::child_at(swift::Demangle::Node::size_type pos) {
if (pos < size())
return Children[pos];
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<std::string, 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 { "", IsProtocol::no };
if (Mangled.nextIf('o'))
return { "ObjectiveC", IsProtocol::no };
if (Mangled.nextIf('C'))
return { "C", IsProtocol::no };
if (Mangled.nextIf('s'))
return { "swift", IsProtocol::no };
if (Mangled.nextIf('a'))
return { "swift.Slice", IsProtocol::no };
if (Mangled.nextIf('b'))
return { "swift.Bool", IsProtocol::no };
if (Mangled.nextIf('c'))
return { "swift.Char", IsProtocol::no };
if (Mangled.nextIf('d'))
return { "swift.Float64", IsProtocol::no };
if (Mangled.nextIf('f'))
return { "swift.Float32", IsProtocol::no };
if (Mangled.nextIf('i'))
return { "swift.Int64", IsProtocol::no };
if (Mangled.nextIf('S'))
return { "swift.String", IsProtocol::no };
if (Mangled.nextIf('u'))
return { "swift.UInt64", IsProtocol::no };
size_t index_sub;
if (!demangleIndex(index_sub))
return { "", IsProtocol::no };
if (index_sub >= Substitutions.size())
return { "", IsProtocol::no };
return Substitutions[index_sub];
}
NodePointer demangleSubstitutionIndex() {
Substitution sub = demangleSubstitutionIndexWithProtocol();
if (sub.first.empty())
return nullptr;
if (sub.second == IsProtocol::yes) {
return Node::makeNodePointer(Node::Kind::Protocol, sub.first);
} else {
return Node::makeNodePointer(Node::Kind::Identifier, sub.first);
}
}
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;
Substitutions.push_back({ identifier->getText(), IsProtocol::no });
if (identifier->getKind() == Node::Kind::Identifier)
identifier->setKind(Node::Kind::Module);
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();
Substitutions.push_back({ printer.str(), 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.empty())
return nullptr;
if (sub.second == IsProtocol::yes)
return Node::makeNodePointer(Node::Kind::Protocol, sub.first);
NodePointer identifier = demangleIdentifier();
if (!identifier)
return nullptr;
DemanglerPrinter printer;
printer << sub.first << "." << identifier->getText();
NodePointer result =
Node::makeNodePointer(Node::Kind::Protocol, printer.str());
Substitutions.push_back({ result->getText(), IsProtocol::yes });
return result;
}
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, identifier;
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;
}