mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The previous implementation of the tree structure for the demangler had a bug in the low-level tree management code which caused the tree structure to diverge depending on whether nodes were added as siblings or children. This checkin fixes the issue by making sure that the tree of nodes is kept coherent at all times. Some adjustments are necessary to ensure the nodes were still generated properly and correctly turned into strings Added a new test case Swift SVN r7643
1849 lines
58 KiB
C++
1849 lines
58 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;
|
|
|
|
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::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();
|
|
appendNode(Node::Kind::Directness, toString(d));
|
|
appendNode(Node::Kind::GenericTypeMetadataPattern);
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('m')) {
|
|
appendNode(Node::Kind::Metaclass);
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
Directness d = demangleDirectness();
|
|
appendNode(Node::Kind::Directness, toString(d));
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(Node::Kind::TypeMetadata);
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('n')) {
|
|
if (Mangled.nextIf('k') && Mangled.nextIf('_')) {
|
|
NodePointer entity = demangleEntity();
|
|
if (!entity)
|
|
return failure();
|
|
appendNode(Node::Kind::ProtocolWitness);
|
|
appendNode(entity);
|
|
return true;
|
|
} else
|
|
return failure();
|
|
}
|
|
if (Mangled.nextIf('t')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('w')) {
|
|
ValueWitnessKind w = demangleValueWitnessKind();
|
|
if (w == ValueWitnessKind::Unknown)
|
|
return failure();
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(Node::Kind::ValueWitnessKind, toString(w));
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('W')) {
|
|
if (Mangled.nextIf('V')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(Node::Kind::ValueWitnessTable);
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('o')) {
|
|
NodePointer entity = demangleEntity();
|
|
if (!entity)
|
|
return failure();
|
|
appendNode(Node::Kind::WitnessTableOffset);
|
|
appendNode(entity);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('v')) {
|
|
Directness d = demangleDirectness();
|
|
appendNode(Node::Kind::Directness, toString(d));
|
|
NodePointer entity = demangleEntity();
|
|
if (!entity)
|
|
return failure();
|
|
appendNode(Node::Kind::FieldOffset);
|
|
appendNode(entity);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('P')) {
|
|
NodePointer conformance = demangleProtocolConformance();
|
|
if (!conformance)
|
|
return failure();
|
|
appendNode(Node::makeNodePointer(Node::Kind::ProtocolWitnessTable));
|
|
appendNode(conformance);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('Z')) {
|
|
NodePointer conformance = demangleProtocolConformance();
|
|
if (!conformance)
|
|
return failure();
|
|
appendNode(Node::makeNodePointer(
|
|
Node::Kind::LazyProtocolWitnessTableAccessor));
|
|
appendNode(conformance);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('z')) {
|
|
NodePointer conformance = demangleProtocolConformance();
|
|
if (!conformance)
|
|
return failure();
|
|
appendNode(Node::makeNodePointer(
|
|
Node::Kind::LazyProtocolWitnessTableTemplate));
|
|
appendNode(conformance);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('D')) {
|
|
NodePointer conformance = demangleProtocolConformance();
|
|
if (!conformance)
|
|
return failure();
|
|
appendNode(Node::makeNodePointer(
|
|
Node::Kind::DependentProtocolWitnessTableGenerator));
|
|
appendNode(conformance);
|
|
return true;
|
|
}
|
|
if (Mangled.nextIf('d')) {
|
|
NodePointer conformance = demangleProtocolConformance();
|
|
if (!conformance)
|
|
return failure();
|
|
appendNode(Node::makeNodePointer(
|
|
Node::Kind::DependentProtocolWitnessTableTemplate));
|
|
appendNode(conformance);
|
|
return true;
|
|
}
|
|
return failure();
|
|
}
|
|
if (Mangled.nextIf('T')) {
|
|
if (Mangled.nextIf('b')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return failure();
|
|
appendNode(Node::Kind::BridgeToBlockFunction);
|
|
appendNode(type);
|
|
return true;
|
|
}
|
|
return failure();
|
|
}
|
|
if (Mangled.nextIf('L')) {
|
|
NodePointer entity = demangleEntity();
|
|
if (!entity)
|
|
return failure();
|
|
appendNode(Node::Kind::LocalEntity);
|
|
appendNode(entity);
|
|
return true;
|
|
}
|
|
NodePointer entity = demangleEntity();
|
|
if (!entity)
|
|
return failure();
|
|
appendNode(entity);
|
|
return true;
|
|
}
|
|
|
|
std::string demangleOperator() {
|
|
static const char op_char_table[] = "& @/= > <*!|+ %-~ ^ .";
|
|
size_t length;
|
|
if (demangleNatural(length)) {
|
|
if (Mangled.hasAtLeast(length)) {
|
|
std::string op_base = Mangled.slice(length);
|
|
Mangled.advanceOffset(length);
|
|
DemanglerPrinter op;
|
|
size_t op_base_size = op_base.size();
|
|
for (size_t idx = 0; idx < op_base_size; ++idx) {
|
|
char c = op_base[idx];
|
|
if (c < 'a' || c > 'z')
|
|
return "";
|
|
char o = op_char_table[c - 'a'];
|
|
if (o == ' ')
|
|
return "";
|
|
op << o;
|
|
}
|
|
return op.str();
|
|
} else
|
|
return "";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
NodePointer demangleIdentifier() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
if (Mangled.nextIf('o')) {
|
|
char op_mode = Mangled.next();
|
|
if (op_mode != 'p' && op_mode != 'P' && op_mode != 'i')
|
|
return nullptr;
|
|
std::string operatr = demangleOperator();
|
|
if (operatr.size()) {
|
|
switch (op_mode) {
|
|
case 'p':
|
|
return Node::makeNodePointer(Node::Kind::PrefixOperator, operatr);
|
|
case 'P':
|
|
return Node::makeNodePointer(Node::Kind::PostfixOperator, operatr);
|
|
case 'i':
|
|
return Node::makeNodePointer(Node::Kind::InfixOperator, operatr);
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
size_t length;
|
|
if (demangleNatural(length)) {
|
|
if (Mangled.hasAtLeast(length)) {
|
|
auto identifier = Mangled.slice(length);
|
|
Mangled.advanceOffset(length);
|
|
return Node::makeNodePointer(Node::Kind::Identifier, identifier);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool demangleIndex(size_t &natural) {
|
|
if (Mangled.nextIf('_')) {
|
|
natural = 0;
|
|
return true;
|
|
}
|
|
if (demangleNatural(natural)) {
|
|
if (!Mangled.nextIf('_'))
|
|
return false;
|
|
natural++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
NodePointer compactNode(NodePointer head, Node::Kind outputKind,
|
|
char separator = '.') {
|
|
DemanglerPrinter printer;
|
|
while (head) {
|
|
printer << head->getText();
|
|
head = head->getNextNode();
|
|
if (head)
|
|
printer << separator;
|
|
}
|
|
return Node::makeNodePointer(outputKind, printer.str());
|
|
}
|
|
|
|
Substitution demangleSubstitutionIndexWithProtocol() {
|
|
if (!Mangled)
|
|
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
|
|
if (Mangled.nextIf('o'))
|
|
return { Node::makeNodePointer(Node::Kind::Module,"ObjectiveC"), IsProtocol::no };
|
|
if (Mangled.nextIf('C'))
|
|
return { Node::makeNodePointer(Node::Kind::Module,"C"), IsProtocol::no };
|
|
if (Mangled.nextIf('s'))
|
|
return { Node::makeNodePointer(Node::Kind::Module,"swift"), IsProtocol::no };
|
|
if (Mangled.nextIf('a')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Slice"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('b')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Bool"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('c')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Char"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('d')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Float64"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Float32"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('i')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Int64"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('q')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"Optional"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"String"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
if (Mangled.nextIf('u')) {
|
|
NodePointer type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
type->push_back_child(Node::makeNodePointer(Node::Kind::Module,"swift"))->setNextNode(
|
|
Node::makeNodePointer(Node::Kind::Structure,"UInt64"));
|
|
return { type, IsProtocol::no };
|
|
}
|
|
size_t index_sub;
|
|
if (!demangleIndex(index_sub))
|
|
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
|
|
if (index_sub >= Substitutions.size())
|
|
return { Node::makeNodePointer(Node::Kind::Failure), IsProtocol::no };
|
|
return Substitutions[index_sub];
|
|
}
|
|
|
|
NodePointer demangleSubstitutionIndex() {
|
|
Substitution sub = demangleSubstitutionIndexWithProtocol();
|
|
if (!sub.first)
|
|
return nullptr;
|
|
return NodePointer(new Node(*sub.first.getPtr()));
|
|
}
|
|
|
|
NodePointer demangleSubstitution() {
|
|
if (Mangled.nextIf('S'))
|
|
return demangleSubstitutionIndex();
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleModule() {
|
|
char c = Mangled.peek();
|
|
if (isStartOfIdentifier(c)) {
|
|
NodePointer identifier = demangleIdentifier();
|
|
if (!identifier)
|
|
return nullptr;
|
|
if (identifier->getKind() == Node::Kind::Identifier)
|
|
identifier->setKind(Node::Kind::Module);
|
|
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
|
|
Substitutions.push_back( { copy_identifier, IsProtocol::no });
|
|
return identifier;
|
|
}
|
|
if (c == 'S') {
|
|
NodePointer identifier = demangleSubstitution();
|
|
if (!identifier)
|
|
return nullptr;
|
|
if (identifier->getKind() != Node::Kind::NominalType)
|
|
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 = demangleContextImpl(&context_type);
|
|
if (!context)
|
|
return false;
|
|
identifier = demangleIdentifier();
|
|
if (!identifier)
|
|
return false;
|
|
DemanglerPrinter printer;
|
|
printer << context->getText() << "." << identifier->getText();
|
|
NodePointer nominaltype = Node::makeNodePointer(Node::Kind::NominalType);
|
|
NodePointer copy_context = Node::makeNodePointer(context->getKind(),context->getText());
|
|
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
|
|
if (isA == IsProtocol::yes)
|
|
copy_identifier->setKind(Node::Kind::Protocol);
|
|
nominaltype->push_back_child(copy_context)->setNextNode(copy_identifier);
|
|
Substitutions.push_back({ nominaltype, isA });
|
|
if (context_type != Node::Kind::Unknown)
|
|
identifier->setKind(context_type);
|
|
return true;
|
|
}
|
|
|
|
NodePointer demangleProtocolName() {
|
|
if (Mangled.nextIf('S')) {
|
|
Substitution sub = demangleSubstitutionIndexWithProtocol();
|
|
if (!sub.first)
|
|
return nullptr;
|
|
if (sub.second == IsProtocol::yes)
|
|
return sub.first;
|
|
NodePointer identifier = demangleIdentifier();
|
|
if (!identifier)
|
|
return nullptr;
|
|
NodePointer nominaltype = Node::makeNodePointer(Node::Kind::NominalType);
|
|
NodePointer copy_context = NodePointer(new Node(*sub.first.getPtr()));
|
|
identifier->setKind(Node::Kind::Protocol);
|
|
NodePointer copy_identifier = Node::makeNodePointer(identifier->getKind(),identifier->getText());
|
|
nominaltype->push_back_child(copy_context)->setNextNode(copy_identifier);
|
|
Substitutions.push_back({ nominaltype, IsProtocol::yes });
|
|
return nominaltype;
|
|
}
|
|
NodePointer context, identifier;
|
|
if (demangleDeclarationName(context, identifier, IsProtocol::yes)) {
|
|
DemanglerPrinter printer;
|
|
while (context) {
|
|
printer << context->getText() << ".";
|
|
context = context->getNextNode();
|
|
}
|
|
printer << identifier->getText();
|
|
NodePointer result =
|
|
Node::makeNodePointer(Node::Kind::Protocol, printer.str());
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleNominalType() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
char c = Mangled.next();
|
|
if (c == 'S')
|
|
return demangleSubstitutionIndex();
|
|
if (!isStartOfNominalType(c))
|
|
return nullptr;
|
|
NodePointer context, identifier;
|
|
if (!demangleDeclarationName(context, identifier, IsProtocol::no))
|
|
return nullptr;
|
|
NodePointer nominalType = Node::makeNodePointer(Node::Kind::NominalType);
|
|
nominalType->push_back_child(context)->setNextNode(identifier);
|
|
identifier->setKind(nominalTypeMarkerToNodeKind(c));
|
|
return nominalType;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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::DeclarationContext));
|
|
ret->push_back_child(demangled_ctx);
|
|
return ret;
|
|
}
|
|
|
|
NodePointer demangleDeclWithContext(NodePointer context) {
|
|
NodePointer identifier = demangleIdentifier();
|
|
if (!identifier)
|
|
return nullptr;
|
|
NodePointer declIdentifier = Node::makeNodePointer(Node::Kind::DeclarationIdentifier);
|
|
declIdentifier->push_back_child(identifier);
|
|
return demangleDeclTypeWithContextAndName(context, declIdentifier);
|
|
}
|
|
|
|
NodePointer demangleDeclTypeWithContextAndName(NodePointer context,
|
|
NodePointer identifier) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer decl =
|
|
Node::makeNodePointer(Node::Kind::Declaration);
|
|
NodePointer declType = Node::makeNodePointer(Node::Kind::DeclarationType);
|
|
declType->push_back_child(type);
|
|
decl->push_back_child(context);
|
|
decl->push_back_child(identifier);
|
|
decl->push_back_child(declType);
|
|
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;
|
|
}
|
|
|
|
Node::Kind getDeclContextType (NodePointer declContext) {
|
|
if (declContext->getKind() != Node::Kind::DeclarationContext)
|
|
return Node::Kind::Unknown;
|
|
if (declContext->front()->getKind() == Node::Kind::NominalType) {
|
|
for (NodePointer child : *declContext->front()) {
|
|
Node::Kind childKind = child->getKind();
|
|
switch (childKind) {
|
|
case Node::Kind::Class:
|
|
case Node::Kind::Structure:
|
|
case Node::Kind::Union:
|
|
return childKind;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (declContext->front()->getKind() == Node::Kind::Protocol)
|
|
return Node::Kind::Protocol;
|
|
if (declContext->front()->getKind() == Node::Kind::Module)
|
|
return Node::Kind::Module;
|
|
if (declContext->front()->getKind() == Node::Kind::FunctionType)
|
|
return Node::Kind::FunctionType;
|
|
return Node::Kind::Unknown;
|
|
}
|
|
|
|
NodePointer demangleEntity() {
|
|
NodePointer context = demangleContext();
|
|
if (!context)
|
|
return nullptr;
|
|
Node::Kind idKind = getDeclContextType(context);
|
|
NodePointer decl;
|
|
if (Mangled.nextIf('D')) {
|
|
if (idKind == 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 (idKind == Node::Kind::Class)
|
|
decl = Node::makeNodePointer(Node::Kind::Allocator);
|
|
else
|
|
decl = Node::makeNodePointer(Node::Kind::Constructor);
|
|
decl->push_back_child(context);
|
|
decl->push_back_child(type);
|
|
return decl;
|
|
}
|
|
if (Mangled.nextIf('c')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
decl = Node::makeNodePointer(Node::Kind::Constructor);
|
|
decl->push_back_child(context);
|
|
decl->push_back_child(type);
|
|
return decl;
|
|
}
|
|
NodePointer decl_with_ctx = demangleDeclWithContext(context);
|
|
if (!decl_with_ctx)
|
|
return nullptr;
|
|
if (Mangled.nextIf('a')) {
|
|
decl = Node::makeNodePointer(Node::Kind::Addressor);
|
|
decl->push_back_child(decl_with_ctx);
|
|
} else if (Mangled.nextIf('g')) {
|
|
decl = Node::makeNodePointer(Node::Kind::Getter);
|
|
decl->push_back_child(decl_with_ctx);
|
|
} else if (Mangled.nextIf('s')) {
|
|
decl = Node::makeNodePointer(Node::Kind::Setter);
|
|
decl->push_back_child(decl_with_ctx);
|
|
} else {
|
|
decl = decl_with_ctx;
|
|
}
|
|
return decl;
|
|
}
|
|
|
|
NodePointer demangleArchetypes() {
|
|
DemanglerPrinter result_printer;
|
|
NodePointer archetypes = Node::makeNodePointer(Node::Kind::ArchetypeList);
|
|
while (true) {
|
|
if (Mangled.nextIf('_')) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
char c = Mangled.peek();
|
|
if (c != '_' && c != 'S' && !isStartOfIdentifier(c))
|
|
break;
|
|
archetypes->push_back_child(Node::makeNodePointer(
|
|
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
|
|
} else {
|
|
NodePointer proto_list = demangleProtocolList();
|
|
if (!proto_list)
|
|
return nullptr;
|
|
NodePointer arch_and_proto =
|
|
Node::makeNodePointer(Node::Kind::ArchetypeAndProtocol);
|
|
arch_and_proto->push_back_child(Node::makeNodePointer(
|
|
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
|
|
arch_and_proto->push_back_child(proto_list);
|
|
archetypes->push_back_child(arch_and_proto);
|
|
}
|
|
++ArchetypeCount;
|
|
}
|
|
return archetypes;
|
|
}
|
|
|
|
NodePointer demangleArchetypeRef(size_t depth, size_t i) {
|
|
if (depth == 0 && ArchetypeCount == 0)
|
|
return Node::makeNodePointer(Node::Kind::ArchetypeRef, archetypeName(i));
|
|
size_t length = ArchetypeCounts.size();
|
|
if (depth >= length)
|
|
return nullptr;
|
|
size_t index = ArchetypeCounts[length - 1 - depth] + i;
|
|
size_t max =
|
|
(depth == 0) ? ArchetypeCount : ArchetypeCounts[length - depth];
|
|
if (index >= max)
|
|
return nullptr;
|
|
return Node::makeNodePointer(Node::Kind::ArchetypeRef,
|
|
archetypeName(index));
|
|
}
|
|
|
|
NodePointer demangleTuple(IsVariadic isV) {
|
|
NodePointer tuple = Node::makeNodePointer(
|
|
isV == IsVariadic::yes ? Node::Kind::VariadicTuple
|
|
: Node::Kind::NonVariadicTuple);
|
|
while (Mangled.nextIf('_') == false) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
NodePointer tuple_element =
|
|
Node::makeNodePointer(Node::Kind::TupleElement);
|
|
NodePointer identifier;
|
|
NodePointer type;
|
|
if (isStartOfIdentifier(Mangled.peek())) {
|
|
identifier = demangleIdentifier();
|
|
if (!identifier)
|
|
return nullptr;
|
|
identifier->setKind(Node::Kind::TupleElementName);
|
|
}
|
|
type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
if (type->getNextNode() && type->getKind() != Node::Kind::ProtocolList)
|
|
type = compactNode(type, Node::Kind::TupleElementType);
|
|
if (identifier)
|
|
tuple_element->push_back_child(identifier);
|
|
tuple_element->push_back_child(type);
|
|
tuple->push_back_child(tuple_element);
|
|
}
|
|
return tuple;
|
|
}
|
|
|
|
NodePointer postProcessReturnTypeNode (NodePointer out_args) {
|
|
Node::Kind out_args_kind = out_args->getKind();
|
|
if (out_args_kind == Node::Kind::Identifier ||
|
|
out_args_kind == Node::Kind::Class ||
|
|
out_args_kind == Node::Kind::Module ||
|
|
out_args_kind == Node::Kind::Structure ||
|
|
out_args_kind == Node::Kind::Union) {
|
|
return compactNode(out_args, Node::Kind::ReturnType);
|
|
} else {
|
|
NodePointer out_node = Node::makeNodePointer(Node::Kind::ReturnType);
|
|
out_node->push_back_child(out_args);
|
|
return out_node;
|
|
}
|
|
}
|
|
|
|
NodePointer demangleType() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
char c = Mangled.next();
|
|
if (c == 'A') {
|
|
size_t size;
|
|
if (demangleNatural(size)) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer array = Node::makeNodePointer(Node::Kind::ArrayType);
|
|
array->push_back_child(type);
|
|
array->push_back_child(Node::makeNodePointer(
|
|
Node::Kind::Number, (DemanglerPrinter() << size).str()));
|
|
return array;
|
|
}
|
|
return nullptr;
|
|
}
|
|
if (c == 'B') {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
c = Mangled.next();
|
|
if (c == 'f') {
|
|
size_t size;
|
|
if (demangleBuiltinSize(size)) {
|
|
return Node::makeNodePointer(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Float" << size).str());
|
|
}
|
|
}
|
|
if (c == 'i') {
|
|
size_t size;
|
|
if (demangleBuiltinSize(size)) {
|
|
return Node::makeNodePointer(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Int" << size).str());
|
|
}
|
|
}
|
|
if (c == 'v') {
|
|
size_t elts;
|
|
if (demangleNatural(elts)) {
|
|
if (!Mangled.nextIf('B'))
|
|
return nullptr;
|
|
if (Mangled.nextIf('i')) {
|
|
size_t size;
|
|
if (!demangleBuiltinSize(size))
|
|
return nullptr;
|
|
return Node::makeNodePointer(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
|
|
.str());
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
size_t size;
|
|
if (!demangleBuiltinSize(size))
|
|
return nullptr;
|
|
return Node::makeNodePointer(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xFloat"
|
|
<< size).str());
|
|
}
|
|
if (Mangled.nextIf('p'))
|
|
return Node::makeNodePointer(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
|
|
.str());
|
|
}
|
|
}
|
|
if (c == 'O')
|
|
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
|
|
"Builtin.ObjCPointer");
|
|
if (c == 'o')
|
|
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
|
|
"Builtin.ObjectPointer");
|
|
if (c == 'p')
|
|
return Node::makeNodePointer(Node::Kind::BuiltinTypeName,
|
|
"Builtin.RawPointer");
|
|
return nullptr;
|
|
}
|
|
if (c == 'b') {
|
|
NodePointer in_args = demangleType();
|
|
if (!in_args)
|
|
return nullptr;
|
|
NodePointer out_args = demangleType();
|
|
if (!out_args)
|
|
return nullptr;
|
|
NodePointer block = Node::makeNodePointer(Node::Kind::ObjCBlock);
|
|
NodePointer in_node = Node::makeNodePointer(Node::Kind::ArgumentTuple);
|
|
block->push_back_child(in_node);
|
|
in_node->push_back_child(in_args);
|
|
block->push_back_child(postProcessReturnTypeNode(out_args));
|
|
return block;
|
|
}
|
|
if (c == 'F') {
|
|
NodePointer in_args = demangleType();
|
|
if (!in_args)
|
|
return nullptr;
|
|
NodePointer out_args = demangleType();
|
|
if (!out_args)
|
|
return nullptr;
|
|
NodePointer block = Node::makeNodePointer(Node::Kind::FunctionType);
|
|
NodePointer in_node = Node::makeNodePointer(Node::Kind::ArgumentTuple);
|
|
block->push_back_child(in_node);
|
|
in_node->push_back_child(in_args);
|
|
block->push_back_child(postProcessReturnTypeNode(out_args));
|
|
return block;
|
|
}
|
|
if (c == 'f') {
|
|
NodePointer in_args = demangleType();
|
|
if (!in_args)
|
|
return nullptr;
|
|
NodePointer out_args = demangleType();
|
|
if (!out_args)
|
|
return nullptr;
|
|
NodePointer block =
|
|
Node::makeNodePointer(Node::Kind::UncurriedFunctionType);
|
|
NodePointer in_node =
|
|
Node::makeNodePointer(Node::Kind::UncurriedFunctionMetaType);
|
|
block->push_back_child(in_node);
|
|
in_node->push_back_child(in_args);
|
|
block->push_back_child(postProcessReturnTypeNode(out_args));
|
|
return block;
|
|
}
|
|
if (c == 'G') {
|
|
NodePointer type_list = Node::makeNodePointer(Node::Kind::TypeList);
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer type_list_entry =
|
|
Node::makeNodePointer(Node::Kind::TypeListEntry);
|
|
type_list_entry->push_back_child(type);
|
|
type_list->push_back_child(type_list_entry);
|
|
while (Mangled.peek() != '_') {
|
|
type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
type_list_entry = Node::makeNodePointer(Node::Kind::TypeListEntry);
|
|
type_list_entry->push_back_child(type);
|
|
type_list->push_back_child(type_list_entry);
|
|
}
|
|
Mangled.next();
|
|
NodePointer type_application =
|
|
Node::makeNodePointer(Node::Kind::GenericTypeApplication);
|
|
type_application->push_back_child(type_list);
|
|
return type_application;
|
|
}
|
|
if (c == 'M') {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer metatype = Node::makeNodePointer(Node::Kind::MetaType);
|
|
NodePointer type_entry = Node::makeNodePointer(Node::Kind::TypeListEntry);
|
|
type_entry->push_back_child(type);
|
|
metatype->push_back_child(type_entry);
|
|
return metatype;
|
|
}
|
|
if (c == 'P') {
|
|
return demangleProtocolList();
|
|
}
|
|
if (c == 'Q') {
|
|
if (Mangled.nextIf('d')) {
|
|
size_t depth, index;
|
|
if (!demangleIndex(depth))
|
|
return nullptr;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
return demangleArchetypeRef(depth + 1, index);
|
|
}
|
|
size_t index;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
return demangleArchetypeRef(0, index);
|
|
}
|
|
if (c == 'R') {
|
|
NodePointer byref = Node::makeNodePointer(Node::Kind::ByRef);
|
|
byref->setNextNode(demangleType());
|
|
if (byref->getNextNode())
|
|
return byref;
|
|
return nullptr;
|
|
}
|
|
if (c == 'S') {
|
|
return demangleSubstitutionIndex();
|
|
}
|
|
if (c == 'T') {
|
|
return demangleTuple(IsVariadic::no);
|
|
}
|
|
if (c == 't') {
|
|
return demangleTuple(IsVariadic::yes);
|
|
}
|
|
if (c == 'U') {
|
|
ArchetypeCounts.push_back(ArchetypeCount);
|
|
NodePointer archetypes = demangleArchetypes();
|
|
if (!archetypes)
|
|
return nullptr;
|
|
NodePointer base = demangleType();
|
|
if (!base)
|
|
return nullptr;
|
|
ArchetypeCount = ArchetypeCounts.back();
|
|
ArchetypeCounts.pop_back();
|
|
NodePointer generics = Node::makeNodePointer(Node::Kind::GenericType);
|
|
generics->push_back_child(archetypes);
|
|
generics->push_back_child(base);
|
|
return generics;
|
|
}
|
|
if (c == 'X') {
|
|
if (c == 'o') {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = Node::makeNodePointer(Node::Kind::Unowned);
|
|
unowned->setNextNode(type);
|
|
return unowned;
|
|
}
|
|
if (c == 'w') {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = Node::makeNodePointer(Node::Kind::Weak);
|
|
unowned->setNextNode(type);
|
|
return unowned;
|
|
}
|
|
return nullptr;
|
|
}
|
|
if (isStartOfNominalType(c)) {
|
|
NodePointer context(nullptr), identifier(nullptr);
|
|
if (!demangleDeclarationName(context, identifier, IsProtocol::no))
|
|
return nullptr;
|
|
context->setNextNode(identifier);
|
|
identifier->setKind(nominalTypeMarkerToNodeKind(c));
|
|
NodePointer nominal_type = Node::makeNodePointer(Node::Kind::NominalType);
|
|
nominal_type->push_back_child(context);
|
|
return nominal_type;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
class MangledNameSource {
|
|
public:
|
|
MangledNameSource(StringRef mangled);
|
|
|
|
char peek();
|
|
|
|
bool nextIf(char c);
|
|
|
|
char next();
|
|
|
|
bool isEmpty();
|
|
|
|
explicit operator bool();
|
|
|
|
std::string slice(size_t size);
|
|
|
|
std::string getString();
|
|
|
|
size_t getOffset();
|
|
|
|
size_t getSize();
|
|
|
|
bool hasAtLeast(size_t n);
|
|
|
|
void advanceOffset(size_t by);
|
|
|
|
private:
|
|
StringRef Mangled;
|
|
size_t Offset;
|
|
};
|
|
|
|
std::vector<Substitution> Substitutions;
|
|
std::vector<int> ArchetypeCounts;
|
|
int ArchetypeCount;
|
|
MangledNameSource Mangled;
|
|
NodePointer RootNode;
|
|
NodePointer CurrentNode;
|
|
};
|
|
|
|
Demangler::MangledNameSource::MangledNameSource(StringRef Mangled)
|
|
: Mangled(Mangled), Offset(0) {}
|
|
|
|
char Demangler::MangledNameSource::peek() { return Mangled.front(); }
|
|
|
|
bool Demangler::MangledNameSource::nextIf(char c) {
|
|
if (isEmpty())
|
|
return false;
|
|
char real_c = peek();
|
|
if (real_c == c) {
|
|
advanceOffset(1);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
char Demangler::MangledNameSource::next() {
|
|
char c = peek();
|
|
advanceOffset(1);
|
|
return c;
|
|
}
|
|
|
|
bool Demangler::MangledNameSource::isEmpty() { return Mangled.empty(); }
|
|
|
|
Demangler::MangledNameSource::operator bool() { return isEmpty() == false; }
|
|
|
|
std::string Demangler::MangledNameSource::slice(size_t size) {
|
|
return Mangled.substr(0, size);
|
|
}
|
|
|
|
std::string Demangler::MangledNameSource::getString() { return Mangled.data(); }
|
|
|
|
size_t Demangler::MangledNameSource::getOffset() { return Offset; }
|
|
|
|
size_t Demangler::MangledNameSource::getSize() { return Mangled.size(); }
|
|
|
|
bool Demangler::MangledNameSource::hasAtLeast(size_t n) {
|
|
if (n > getSize())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void Demangler::MangledNameSource::advanceOffset(size_t by) {
|
|
Offset += by;
|
|
Mangled = Mangled.substr(by);
|
|
}
|
|
|
|
NodePointer swift::Demangle::demangleSymbolAsNode(llvm::StringRef mangled) {
|
|
Demangler demangler(mangled);
|
|
demangler.demangle();
|
|
return demangler.getDemangled();
|
|
}
|
|
|
|
void toString(NodePointer pointer, DemanglerPrinter &printer);
|
|
|
|
void toStringChildren (Node::iterator begin, Node::iterator end, DemanglerPrinter &printer, const char *sep = nullptr) {
|
|
for (; begin != end;) {
|
|
toString(*begin, printer);
|
|
++begin;
|
|
if (sep && begin != end)
|
|
printer << sep;
|
|
}
|
|
}
|
|
|
|
void toStringChildren (NodePointer pointer, DemanglerPrinter &printer, const char *sep = nullptr) {
|
|
if (!pointer)
|
|
return;
|
|
Node::iterator begin = pointer->begin(), end = pointer->end();
|
|
toStringChildren(begin, end, printer, sep);
|
|
}
|
|
|
|
void toStringLifeCycleEntity (NodePointer pointer, DemanglerPrinter &printer, const char* name) {
|
|
NodePointer child = pointer->child_at(0);
|
|
if (child->getKind() == Node::Kind::DeclarationContext) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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::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::DeclarationIdentifier:
|
|
printer << ".";
|
|
toString(pointer->child_at(0), printer);
|
|
printer << " : ";
|
|
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::DeclarationContext:
|
|
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;
|
|
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] ";
|
|
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->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::ObjCAttribute:
|
|
printer << "[objc] ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::LocalEntity:
|
|
printer << "local ";
|
|
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->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::DependentProtocolWitnessTableTemplate:
|
|
printer << "dependent protocol witness table template for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableAccessor:
|
|
printer << "lazy protocol witness table accessor for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::LazyProtocolWitnessTableTemplate:
|
|
printer << "lazy protocol witness table template for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::ProtocolWitnessTable:
|
|
printer << "protocol witness table for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::ProtocolWitness:
|
|
printer << "protocol witness for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::FieldOffset:
|
|
printer << "field offset for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::BridgeToBlockFunction:
|
|
printer << "bridge-to-block function for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::GenericTypeMetadataPattern:
|
|
printer << "generic type metadata pattern for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::Metaclass:
|
|
printer << "metaclass for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::TypeMetadata:
|
|
printer << "type metadata for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::ValueWitnessKind:
|
|
printer << pointer->getText() << " value witness for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::ValueWitnessTable:
|
|
printer << "value witness table for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
case swift::Demangle::Node::Kind::WitnessTableOffset:
|
|
printer << "witness table offset for ";
|
|
pointer = pointer->getNextNode(); continue;
|
|
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:
|
|
case swift::Demangle::Node::Kind::ArchetypeRef:
|
|
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::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 ";
|
|
toString(child2, printer);
|
|
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.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;
|
|
}
|