Files
swift-mirror/lib/Basic/Demangle.cpp
Joe Groff c65f4c3f43 Rework archetype mangling to follow parent hierarchy.
Use the ordinal archetype manglings only for the primary archetypes of a generic context, and define a mangling for associated types relative to their parent archetype. This will make the archetype mangling resilient in the face of our planned improvements to associated type and protocol conformance ABI. It also correctly mangles self and associated types of protocols, which my previous attempt utterly failed to accomplish.

Swift SVN r8174
2013-09-13 01:16:27 +00:00

1956 lines
60 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/Fallthrough.h"
#include "swift/Basic/LLVM.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <tuple>
#include <vector>
using namespace swift;
using namespace Demangle;
Node::size_type Node::size () {
return Children.size();
}
Node::iterator Node::begin () {
return Children.begin();
}
Node::iterator Node::end () {
return Children.end();
}
Node::const_iterator Node::begin () const {
return Children.begin();
}
Node::const_iterator Node::end () const {
return Children.end();
}
NodePointer Node::front () {
return Children.front();
}
NodePointer Node::back () {
return Children.back();
}
NodePointer Node::child_at (Node::size_type idx) {
return Children[idx];
}
Node::Node (Node::Kind k, std::string t) : NodeKind(k), NodeText(t), Successor(nullptr), Children(), Parent(nullptr), Predecessor(nullptr) {}
Node::Node (const Node& other) : NodeKind(other.NodeKind), NodeText(other.NodeText), Successor(), Children(), Parent(), Predecessor() {
for (NodePointer child : other)
push_back_child(NodePointer(new Node(*child)));
}
Node* Node::getParent () {
return Parent;
}
NodePointer Node::getNextNode () {
return Successor;
}
Node* Node::getPreviousNode () {
return Predecessor;
}
NodePointer Node::push_back_child (NodePointer child) {
NodePointer ret(child);
while (child) {
if (size())
back()->setSuccessorImpl(child);
push_back_childImpl(child);
child->setParent(this);
child = child->getNextNode();
}
return ret;
}
void Node::setParent (Node *parent) {
Node* ptr = this;
while (ptr) {
ptr->setParentImpl(parent);
ptr = ptr->getNextNode().getPtr();
}
}
void Node::setNextNode (NodePointer successor) {
if (getParent())
insertSiblingImpl(successor);
else
setSuccessorImpl(successor);
}
Node::Kind Node::getKind() {
return NodeKind;
}
void Node::setKind (Node::Kind k) {
NodeKind = k;
}
std::string Node::getText() {
return NodeText;
}
void Node::setText (const std::string &t) {
NodeText.assign(t);
}
void Node::setParentImpl (Node *parent) {
Parent = parent;
}
void Node::setSuccessorImpl (NodePointer successor) {
Successor = successor;
successor->Predecessor = this;
}
void Node::push_back_childImpl (NodePointer child) {
Children.push_back(child);
}
void Node::insertSiblingImpl (NodePointer child) {
iterator pBegin = getParent()->begin();
iterator pEnd = getParent()->end();
iterator prev_pos = std::find_if(pBegin,pEnd,FindPtr(this));
if (prev_pos == pEnd) {
getParent()->push_back_child(child);
}
else {
prev_pos++;
if (prev_pos == pEnd) {
getParent()->push_back_child(child);
}
else {
child->setParentImpl(getParent());
NodePointer old_next = getNextNode();
getParent()->Children.insert(prev_pos,child);
if (old_next) {
NodePointer end_of_chain = child;
while (end_of_chain->getNextNode())
end_of_chain = end_of_chain->getNextNode();
end_of_chain->setSuccessorImpl(old_next);
}
setSuccessorImpl(child);
}
}
}
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();
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::Directness, toString(d));
appendNode(Node::Kind::GenericTypeMetadataPattern)->push_back_child(type);
return true;
}
if (Mangled.nextIf('m')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::Metaclass)->push_back_child(type);
return true;
}
Directness d = demangleDirectness();
appendNode(Node::Kind::Directness, toString(d));
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::TypeMetadata)->push_back_child(type);
return true;
}
if (Mangled.nextIf('n')) {
if (Mangled.nextIf('k') && Mangled.nextIf('_')) {
bool entity_ok = demangleEntity(appendNode(Node::Kind::ProtocolWitness));
if (!entity_ok)
return failure();
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))->push_back_child(type);
return true;
}
if (Mangled.nextIf('W')) {
if (Mangled.nextIf('V')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::ValueWitnessTable)->push_back_child(type);
return true;
}
if (Mangled.nextIf('o')) {
bool entity_ok = demangleEntity(appendNode(Node::Kind::WitnessTableOffset));
if (!entity_ok)
return failure();
return true;
}
if (Mangled.nextIf('v')) {
Directness d = demangleDirectness();
appendNode(Node::Kind::Directness, toString(d));
bool entity_ok = demangleEntity(appendNode(Node::Kind::FieldOffset));
if (!entity_ok)
return failure();
return true;
}
if (Mangled.nextIf('P')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::ProtocolWitnessTable))->push_back_child(conformance);
return true;
}
if (Mangled.nextIf('Z')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::LazyProtocolWitnessTableAccessor))->push_back_child(conformance);
return true;
}
if (Mangled.nextIf('z')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::LazyProtocolWitnessTableTemplate))->push_back_child(conformance);
return true;
}
if (Mangled.nextIf('D')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::DependentProtocolWitnessTableGenerator))->push_back_child(conformance);
return true;
}
if (Mangled.nextIf('d')) {
NodePointer conformance = demangleProtocolConformance();
if (!conformance)
return failure();
appendNode(Node::makeNodePointer(Node::Kind::DependentProtocolWitnessTableTemplate))->push_back_child(conformance);
return true;
}
return failure();
}
if (Mangled.nextIf('T')) {
if (Mangled.nextIf('b')) {
NodePointer type = demangleType();
if (!type)
return failure();
appendNode(Node::Kind::BridgeToBlockFunction)->push_back_child(type);
return true;
}
return failure();
}
if (Mangled.nextIf('L')) {
bool entity_ok = demangleEntity(appendNode(Node::Kind::LocalEntity));
if (!entity_ok)
return failure();
return true;
}
NodePointer decl = Node::makeNodePointer(Node::Kind::Declaration);
appendNode(decl);
if (!demangleEntity(decl))
return failure();
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::Path);
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::Path);
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::Path);
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::Path);
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::Path);
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::Path);
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::Path);
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::Path);
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::Path);
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;
if (identifier->getKind() != Node::Kind::Path)
identifier->setKind(Node::Kind::Module);
return identifier;
}
return nullptr;
}
NodePointer demangleDeclarationName(Node::Kind identifier_type) {
Node::Kind context_type = Node::Kind::Unknown;
NodePointer context;
NodePointer identifier;
context = demangleContextImpl(&context_type);
if (!context)
return nullptr;
identifier = demangleIdentifier();
if (!identifier)
return nullptr;
IsProtocol is_proto = IsProtocol::no;
if (identifier_type != Node::Kind::Unknown) {
identifier->setKind(identifier_type);
if (identifier_type == Node::Kind::Protocol)
is_proto = IsProtocol::yes;
}
else if (context_type != Node::Kind::Unknown) {
identifier->setKind(context_type);
if (context_type == Node::Kind::Protocol)
is_proto = IsProtocol::yes;
}
if (context->getKind() == Node::Kind::Path) {
context->push_back_child(identifier);
NodePointer path = Node::makeNodePointer(Node::Kind::Path);
straightenNestedDeclContext(context, path);
context = path;
}
else {
context->setNextNode(identifier);
NodePointer path = Node::makeNodePointer(Node::Kind::Path);
path->push_back_child(context);
context = path;
}
NodePointer nominaltype = NodePointer(new Node(*context));
Substitutions.push_back({ nominaltype, is_proto });
return context;
}
NodePointer demangleProtocolName() {
if (Mangled.nextIf('S')) {
Substitution sub = demangleSubstitutionIndexWithProtocol();
if (!sub.first)
return nullptr;
if (sub.second == IsProtocol::yes) {
NodePointer subProto = Node::makeNodePointer(sub.first->getKind(),sub.first->getText());
for (NodePointer child : *sub.first) {
subProto->push_back_child(Node::makeNodePointer(child->getKind(),child->getText()));
}
return subProto;
}
NodePointer identifier = demangleIdentifier();
if (!identifier)
return nullptr;
NodePointer nominaltype = Node::makeNodePointer(Node::Kind::Path);
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 result;
if ((result = demangleDeclarationName(Node::Kind::Protocol))) {
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 nominalType;
if ((nominalType = demangleDeclarationName(nominalTypeMarkerToNodeKind(c))))
return nominalType;
return nullptr;
}
NodePointer demangleContextImpl(Node::Kind *inferred_context_type = nullptr) {
if (!Mangled)
return nullptr;
NodePointer demangled_ctx(nullptr);
char c = Mangled.peek();
if (isStartOfIdentifier(c) || c == 'S') {
demangled_ctx = demangleModule();
}
if (isStartOfNominalType(c)) {
if (inferred_context_type) {
*inferred_context_type = nominalTypeMarkerToNodeKind(c);
}
demangled_ctx = demangleNominalType();
}
if (c == 'P') {
Mangled.next();
demangled_ctx = demangleProtocolName();
}
return demangled_ctx;
}
void straightenNestedDeclContext (NodePointer src, NodePointer& dest) {
Node::Kind srcKind = src->getKind();
switch (srcKind) {
case swift::Demangle::Node::Kind::Class:
case swift::Demangle::Node::Kind::Structure:
case swift::Demangle::Node::Kind::Union:
case swift::Demangle::Node::Kind::Module:
case swift::Demangle::Node::Kind::Protocol:
dest->push_back_child(Node::makeNodePointer(srcKind,src->getText()));
break;
case swift::Demangle::Node::Kind::Path:
for (NodePointer child : *src) {
straightenNestedDeclContext(child, dest);
}
break;
default:
break;
}
}
NodePointer demangleContext(Node::Kind *inferred_context_type = nullptr) {
if (!Mangled)
return nullptr;
NodePointer demangled_ctx(demangleContextImpl(inferred_context_type));
if (!demangled_ctx)
return nullptr;
NodePointer ret(Node::makeNodePointer(Node::Kind::Path));
straightenNestedDeclContext(demangled_ctx, ret);
return ret;
}
std::pair<NodePointer,NodePointer> demangleDecl() {
std::pair<NodePointer,NodePointer> ret;
NodePointer identifier = demangleIdentifier();
if (!identifier)
return ret;
NodePointer type = demangleType();
if (!type)
return ret;
ret.first = identifier;
ret.second = type;
return ret;
}
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;
}
Node::Kind getDeclContextType (NodePointer declContext) {
if (declContext->getKind() != Node::Kind::Path)
return Node::Kind::Unknown;
for (NodePointer child : *declContext) {
Node::Kind childKind = child->getKind();
switch (childKind) {
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Union:
case Node::Kind::Protocol:
return childKind;
default:
continue;
}
}
return Node::Kind::Unknown;
}
Node::Kind getTypeKind (NodePointer type) {
if (type->getKind() != Node::Kind::Type)
return Node::Kind::Unknown;
if (type->size() == 0)
return Node::Kind::Unknown;
NodePointer child = type->child_at(0);
if (child->getKind() == Node::Kind::Path)
return getDeclContextType(child);
return child->getKind();
}
bool demangleEntity(NodePointer decl) {
NodePointer context = demangleContext();
if (!context)
return failure();
Node::Kind idKind = getDeclContextType(context);
if (Mangled.nextIf('D')) {
if (idKind == Node::Kind::Class)
context->push_back_child(Node::makeNodePointer(Node::Kind::Deallocator));
else
context->push_back_child(Node::makeNodePointer(Node::Kind::Destructor));
decl->push_back_child(context);
return true;
}
if (Mangled.nextIf('d')) {
context->push_back_child(Node::makeNodePointer(Node::Kind::Destructor));
decl->push_back_child(context);
return true;
}
if (Mangled.nextIf('C')) {
NodePointer type = demangleType();
if (!type)
return failure();
if (idKind == Node::Kind::Class)
context->push_back_child(Node::makeNodePointer(Node::Kind::Allocator));
else
context->push_back_child(Node::makeNodePointer(Node::Kind::Constructor));
decl->push_back_child(context);
decl->push_back_child(type);
return true;
}
if (Mangled.nextIf('c')) {
NodePointer type = demangleType();
if (!type)
return failure();
context->push_back_child(Node::makeNodePointer(Node::Kind::Constructor));
decl->push_back_child(context);
decl->push_back_child(type);
return true;
}
std::pair<NodePointer,NodePointer> demangledDecl = demangleDecl();
if (demangledDecl.first.getPtr() == nullptr || demangledDecl.second.getPtr() == nullptr)
return nullptr;
if (Mangled.nextIf('a')) {
context->push_back_child(demangledDecl.first);
context->push_back_child(Node::makeNodePointer(Node::Kind::Addressor));
decl->push_back_child(context);
decl->push_back_child(demangledDecl.second);
} else if (Mangled.nextIf('g')) {
context->push_back_child(demangledDecl.first);
context->push_back_child(Node::makeNodePointer(Node::Kind::Getter));
decl->push_back_child(context);
decl->push_back_child(demangledDecl.second);
} else if (Mangled.nextIf('s')) {
context->push_back_child(demangledDecl.first);
context->push_back_child(Node::makeNodePointer(Node::Kind::Setter));
decl->push_back_child(context);
decl->push_back_child(demangledDecl.second);
} else {
context->push_back_child(demangledDecl.first);
decl->push_back_child(context);
decl->push_back_child(demangledDecl.second);
}
return true;
}
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 demangleArchetypeType() {
auto makeSelfType = [&](NodePointer proto) -> NodePointer {
NodePointer selfType
= Node::makeNodePointer(Node::Kind::SelfTypeRef);
selfType->push_back_child(proto);
Substitutions.push_back({ selfType, IsProtocol::no });
return selfType;
};
auto makeAssociatedType = [&](NodePointer root) -> NodePointer {
NodePointer name = demangleIdentifier();
if (!name) return nullptr;
NodePointer assocType
= Node::makeNodePointer(Node::Kind::AssociatedTypeRef);
assocType->push_back_child(root);
assocType->push_back_child(name);
Substitutions.push_back({ assocType, IsProtocol::no });
return assocType;
};
if (Mangled.nextIf('P')) {
NodePointer proto = demangleProtocolName();
if (!proto) return nullptr;
return makeSelfType(proto);
}
if (Mangled.nextIf('Q')) {
NodePointer root = demangleArchetypeType();
if (!root) return nullptr;
return makeAssociatedType(root);
}
if (Mangled.nextIf('S')) {
Substitution sub = demangleSubstitutionIndexWithProtocol();
if (!sub.first) return nullptr;
if (sub.second == IsProtocol::yes)
return makeSelfType(sub.first);
else
return makeAssociatedType(sub.first);
}
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);
}
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) {
NodePointer out_node = Node::makeNodePointer(Node::Kind::ReturnType);
out_node->push_back_child(out_args);
return out_node;
}
NodePointer demangleType() {
NodePointer type = demangleTypeImpl();
if (!type)
return nullptr;
NodePointer nodeType = Node::makeNodePointer(Node::Kind::Type);
nodeType->push_back_child(type);
return nodeType;
}
NodePointer demangleTypeImpl() {
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 = demangleTypeImpl();
if (!in_args)
return nullptr;
NodePointer out_args = demangleType();
if (!out_args)
return nullptr;
NodePointer block =
Node::makeNodePointer(Node::Kind::UncurriedFunctionType);
block->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 unboundType = demangleType();
if (!unboundType)
return nullptr;
while (Mangled.peek() != '_') {
NodePointer type = demangleType();
if (!type)
return nullptr;
type_list->push_back_child(type);
}
Mangled.next();
Node::Kind bound_type_kind = Node::Kind::Unknown;
switch (getTypeKind(unboundType)) {
case Node::Kind::Class:
bound_type_kind = Node::Kind::BoundGenericClass;
break;
case Node::Kind::Structure:
bound_type_kind = Node::Kind::BoundGenericStructure;
break;
case Node::Kind::Union:
bound_type_kind = Node::Kind::BoundGenericUnion;
break;
default:
assert(false && "trying to make a generic type application for a non class|struct|union");
}
NodePointer type_application =
Node::makeNodePointer(bound_type_kind);
type_application->push_back_child(unboundType);
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);
metatype->push_back_child(type);
return metatype;
}
if (c == 'P') {
return demangleProtocolList();
}
if (c == 'Q') {
return demangleArchetypeType();
}
if (c == 'R') {
NodePointer byref = Node::makeNodePointer(Node::Kind::ByRef);
NodePointer type = demangleTypeImpl();
if (!type)
return nullptr;
byref->push_back_child(type);
return byref;
}
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 nominal_type = demangleDeclarationName(nominalTypeMarkerToNodeKind(c));
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);
if (child->getKind() == Node::Kind::Path) {
toString(child, printer);
printer << ".";
}
else {
while (child) {
printer << child->getText();
child = child->getNextNode();
if (child)
printer << ".";
}
}
printer << name;
if (pointer->size() > 1) {
child = pointer->child_at(1);
if (child) {
printer << " : ";
toString(child, printer);
}
}
}
NodePointer getFirstChildOfKind (NodePointer pointer, Node::Kind kind) {
if (!pointer)
return nullptr;
for (NodePointer child : *pointer) {
if (child && child->getKind() == kind)
return child;
}
return nullptr;
}
bool typeNeedsColonForDecl (NodePointer type) {
if (!type)
return false;
if (type->size() == 0)
return false;
NodePointer child = type->child_at(0);
if (!child)
return false;
Node::Kind child_kind = child->getKind();
switch (child_kind) {
case Node::Kind::UncurriedFunctionType:
case Node::Kind::FunctionType:
return false;
case Node::Kind::GenericType:
return typeNeedsColonForDecl(getFirstChildOfKind(type, Node::Kind::UncurriedFunctionType));
default:
return true;
}
}
void toString(NodePointer pointer, DemanglerPrinter &printer) {
while (pointer) {
Node::Kind kind = pointer->getKind();
switch (kind) {
case swift::Demangle::Node::Kind::Failure:
return;
case swift::Demangle::Node::Kind::Directness:
printer << pointer->getText() << " ";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::LocalEntity:
printer << "local ";
SWIFT_FALLTHROUGH;
case swift::Demangle::Node::Kind::Declaration:
{
NodePointer path = getFirstChildOfKind(pointer, Node::Kind::Path);
NodePointer type = getFirstChildOfKind(pointer, Node::Kind::Type);
toString(path, printer);
if (typeNeedsColonForDecl(type))
printer << " : ";
else
printer << " ";
toString(type, printer);
break;
}
case swift::Demangle::Node::Kind::Path:
{
toStringChildren(pointer, printer, ".");
break;
}
case swift::Demangle::Node::Kind::Type:
{
toString(pointer->child_at(0), 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::FunctionName:
break;
case swift::Demangle::Node::Kind::FunctionType:
toStringChildren(pointer, printer);
break;
case swift::Demangle::Node::Kind::DeclarationName:
break;
case swift::Demangle::Node::Kind::DeclarationType:
toStringChildren(pointer, printer, ".");
break;
case swift::Demangle::Node::Kind::UncurriedFunctionType: {
NodePointer metatype = pointer->child_at(0);
if (!metatype)
break;
printer << "(";
toString(metatype, printer);
printer << ")";
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::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)->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] ";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::Unowned:
printer << "[unowned] ";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::ByRef:
printer << "[byref] ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::ObjCAttribute:
printer << "[objc] ";
pointer = pointer->getNextNode(); continue;
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]";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::PrefixOperator:
printer << pointer->getText() << " [prefix]";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::PostfixOperator:
printer << pointer->getText() << " [postfix]";
pointer = pointer->getNextNode(); continue;
case swift::Demangle::Node::Kind::DependentProtocolWitnessTableGenerator:
printer << "dependent protocol witness table generator for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::DependentProtocolWitnessTableTemplate:
printer << "dependent protocol witness table template for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableAccessor:
printer << "lazy protocol witness table accessor for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableTemplate:
printer << "lazy protocol witness table template for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::ProtocolWitnessTable:
printer << "protocol witness table for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::ProtocolWitness:
printer << "protocol witness for ";
{
NodePointer path = getFirstChildOfKind(pointer, Node::Kind::Path);
NodePointer type = getFirstChildOfKind(pointer, Node::Kind::Type);
toString(path,printer);
if (typeNeedsColonForDecl(type))
printer << " : ";
else
printer << " ";
toString(type, printer);
break;
}
case swift::Demangle::Node::Kind::FieldOffset:
printer << "field offset for ";
{
NodePointer path = getFirstChildOfKind(pointer, Node::Kind::Path);
NodePointer type = getFirstChildOfKind(pointer, Node::Kind::Type);
toString(path,printer);
if (typeNeedsColonForDecl(type))
printer << " : ";
else
printer << " ";
toString(type, printer);
break;
}
case swift::Demangle::Node::Kind::BridgeToBlockFunction:
printer << "bridge-to-block function for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::GenericTypeMetadataPattern:
printer << "generic type metadata pattern for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::Metaclass:
printer << "metaclass for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::TypeMetadata:
printer << "type metadata for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::ValueWitnessKind:
printer << pointer->getText() << " value witness for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::ValueWitnessTable:
printer << "value witness table for ";
pointer = pointer->child_at(0); continue;
case swift::Demangle::Node::Kind::WitnessTableOffset:
printer << "witness table offset for ";
{
NodePointer path = getFirstChildOfKind(pointer, Node::Kind::Path);
NodePointer type = getFirstChildOfKind(pointer, Node::Kind::Type);
toString(path,printer);
if (typeNeedsColonForDecl(type))
printer << " : ";
else
printer << " ";
toString(type, printer);
break;
}
case swift::Demangle::Node::Kind::BoundGenericClass:
case swift::Demangle::Node::Kind::BoundGenericStructure:
case swift::Demangle::Node::Kind::BoundGenericUnion: {
if (pointer->size() < 2)
break;
NodePointer typelist = pointer->child_at(1);
if (!typelist)
break;
NodePointer type0 = pointer->child_at(0);
if (!type0)
break;
toString(type0, printer);
printer << "<";
toStringChildren(typelist, printer, ", ");
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:
case swift::Demangle::Node::Kind::ArchetypeRef:
printer << pointer->getText();
break;
case swift::Demangle::Node::Kind::AssociatedTypeRef:
toString(pointer->child_at(0), printer);
printer << '.' << pointer->child_at(1)->getText();
break;
case swift::Demangle::Node::Kind::SelfTypeRef:
toString(pointer->child_at(0), printer);
printer << ".Self";
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::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)->child_at(0);
toString(atype_list, printer);
toString(fct_type, printer);
break;
}
case swift::Demangle::Node::Kind::Addressor: {
printer << "addressor";
break;
}
case swift::Demangle::Node::Kind::Getter: {
printer << "getter";
break;
}
case swift::Demangle::Node::Kind::Setter: {
printer << "setter";
break;
}
case swift::Demangle::Node::Kind::Allocator:
printer << "__allocating_constructor";
break;
case swift::Demangle::Node::Kind::Constructor:
printer << "constructor";
break;
case swift::Demangle::Node::Kind::Destructor:
printer << "destructor";
break;
case swift::Demangle::Node::Kind::Deallocator:
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 ";
toString(child2, printer);
break;
}
case swift::Demangle::Node::Kind::Substitution:
case swift::Demangle::Node::Kind::TypeName:
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.reset();
}
}
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;
}