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