//===--- 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 #include #include 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 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: 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 demangleDecl() { std::pair 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 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 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') { 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); 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 Substitutions; std::vector 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::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; }