//===--- 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/Strings.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/Optional.h" #include "swift/Basic/PrettyStackTrace.h" #include "swift/Basic/QuotedString.h" #include "llvm/Support/raw_ostream.h" #include #include #include using namespace swift; using namespace Demangle; static StringRef getNodeKindString(swift::Demangle::Node::Kind k) { switch(k) { #define NODE(ID) case Node::Kind::ID: return #ID; #include "swift/Basic/DemangleNodes.def" } llvm_unreachable("bad node kind"); } static void printNode(llvm::raw_ostream &out, const Node *node, unsigned depth) { // Indent two spaces per depth. out.indent(depth * 2); out << "kind=" << getNodeKindString(node->getKind()); if (node->hasText()) { out << ", text=\"" << node->getText() << '\"'; } if (node->hasIndex()) { out << ", index=" << node->getIndex(); } out << '\n'; for (auto &child : *node) { printNode(out, child.getPtr(), depth + 1); } } void Node::dump() const { print(llvm::errs()); } void Node::print(llvm::raw_ostream &out) const { printNode(out, this, 0); } namespace { /// A pretty-stack-trace node for demangling trees. class PrettyStackTraceNode : public llvm::PrettyStackTraceEntry { const char *Action; Node *TheNode; public: PrettyStackTraceNode(const char *action, Node *node) : Action(action), TheNode(node) {} void print(llvm::raw_ostream &out) const override { out << "While " << Action << ' '; if (!TheNode) { out << "<>\n"; } else { out << "demangling tree:\n"; printNode(out, TheNode, 4); } } }; } Node::~Node() { switch (NodePayloadKind) { case PayloadKind::None: return; case PayloadKind::Index: return; case PayloadKind::Text: TextPayload.~basic_string(); return; } llvm_unreachable("bad payload kind"); } namespace { struct FindPtr { FindPtr(Node *v) : Target(v) {} bool operator()(NodePointer sp) const { return sp.getPtr() == Target; } private: Node *Target; }; /// A class for printing to a std::string. class DemanglerPrinter { public: DemanglerPrinter() : Stream(Buffer) {} template DemanglerPrinter &operator<<(T &&value) { Stream << std::forward(value); return *this; } /// Destructively take the contents of this stream. std::string str() { return std::move(Stream.str()); } private: std::string Buffer; llvm::raw_string_ostream Stream; }; } // end anonymous namespace 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 bool isStartOfEntity(char c) { switch (c) { case 'F': case 'I': case 'v': case 'P': return true; default: return isStartOfNominalType(c); } } 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::Enum; return Node::Kind::Identifier; } static std::string archetypeName(Node::IndexType i) { DemanglerPrinter name; do { name << (char)('A' + (i % 26)); i /= 26; } while (i); return name.str(); } namespace { /// A convenient class for parsing characters out of a string. class NameSource { StringRef Text; public: NameSource(StringRef text) : Text(text) {} /// Return whether there are at least len characters remaining. bool hasAtLeast(size_t len) { return (len <= Text.size()); } bool isEmpty() { return Text.empty(); } explicit operator bool() { return !isEmpty(); } /// Return the next character without claiming it. Asserts that /// there is at least one remaining character. char peek() { return Text.front(); } /// Claim and return the next character. Asserts that there is at /// least one remaining character. char next() { char c = peek(); advanceOffset(1); return c; } /// Claim the next character if it exists and equals the given /// character. bool nextIf(char c) { if (isEmpty() || peek() != c) return false; advanceOffset(1); return true; } /// Claim the next few characters if they exactly match the given string. bool nextIf(StringRef str) { if (!Text.startswith(str)) return false; advanceOffset(str.size()); return true; } /// Return the next len characters without claiming them. Asserts /// that there are at least so many characters. StringRef slice(size_t len) { return Text.substr(0, len); } /// Claim the next len characters. void advanceOffset(size_t len) { Text = Text.substr(len); } /// Claim and return all the rest of the characters. StringRef getString() { auto result = Text; advanceOffset(Text.size()); return result; } }; /// The main class for parsing a demangling tree out of a mangled string. class Demangler { SmallVector Substitutions; SmallVector ArchetypeCounts; unsigned ArchetypeCount = 0; NameSource Mangled; NodePointer RootNode; public: Demangler(llvm::StringRef mangled) : Mangled(mangled) {} /// Attempt to demangle the source string. The root node will /// always be a Global. Extra characters at the end will be /// tolerated (and included as a Suffix node as a child of the /// Global). /// /// \return true if the mangling succeeded bool demangle() { if (!Mangled.hasAtLeast(2)) return failure(); if (Mangled.slice(2) != "_T") return failure(); if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTS") { Mangled.advanceOffset(4); auto attr = demangleSpecializedAttribute(); if (!attr) return failure(); if (!Mangled.hasAtLeast(2) || Mangled.slice(2) != "_T") return failure(); Mangled.advanceOffset(2); appendNode(attr); // The Substitution header does not share state with the rest of the // mangling. Substitutions.clear(); ArchetypeCounts.clear(); ArchetypeCount = 0; } else if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTo") { Mangled.advanceOffset(4); appendNode(Node::Kind::ObjCAttribute); } else { Mangled.advanceOffset(2); } NodePointer global = demangleGlobal(); if (!global) return failure(); appendNode(std::move(global)); // Add a suffix node if there's anything left unmangled. if (!Mangled.isEmpty()) { appendNode(Node::Kind::Suffix, Mangled.getString()); } return true; } NodePointer getDemangled() { return RootNode; } private: Node *getRootNode() { if (!RootNode) { RootNode = Node::create(Node::Kind::Global); } return RootNode.getPtr(); } Node *appendNode(NodePointer n) { return getRootNode()->addChild(std::move(n)); } Node *appendNode(Node::Kind k, std::string &&t = "") { return appendNode(Node::create(k, std::move(t))); } /// Try to demangle a child node of the given kind. If that fails, /// return; otherwise add it to the parent. #define DEMANGLE_CHILD_OR_RETURN(PARENT, CHILD_KIND) do { \ auto _node = demangle##CHILD_KIND(); \ if (!_node) return nullptr; \ (PARENT)->addChild(std::move(_node)); \ } while (false) /// Try to demangle a child node of the given kind. If that fails, /// return; otherwise add it to the parent. #define DEMANGLE_CHILD_AS_NODE_OR_RETURN(PARENT, CHILD_KIND) do { \ auto _kind = demangle##CHILD_KIND(); \ if (_kind == CHILD_KIND::Unknown) return nullptr; \ (PARENT)->addChild(Node::create(Node::Kind::CHILD_KIND, \ toString(_kind))); \ } while (false) enum class IsProtocol { yes = true, no = false }; enum class IsVariadic { yes = true, no = false }; enum class Directness { Unknown = 0, Direct, Indirect }; StringRef toString(Directness d) { switch (d) { case Directness::Direct: return "direct"; case Directness::Indirect: return "indirect"; case Directness::Unknown: llvm_unreachable("shouldn't toString an unknown directness"); } llvm_unreachable("bad directness"); } bool failure() { RootNode = Node::create(Node::Kind::Failure); return false; } Directness demangleDirectness() { if (Mangled.nextIf('d')) return Directness::Direct; if (Mangled.nextIf('i')) return Directness::Indirect; return Directness::Unknown; } bool demangleNatural(Node::IndexType &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(Node::IndexType &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, GetEnumTag, InplaceProjectEnumData, Unknown }; StringRef 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::GetEnumTag: return "getEnumTag"; case ValueWitnessKind::InplaceProjectEnumData: return "inplaceProjectEnumData"; case ValueWitnessKind::Unknown: llvm_unreachable("stringifying the unknown value witness kind?"); } llvm_unreachable("bad value witness kind"); } 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::GetEnumTag; if (c1 == 'u' && c2 == 'p') return ValueWitnessKind::InplaceProjectEnumData; return ValueWitnessKind::Unknown; } NodePointer demangleGlobal() { if (!Mangled) return nullptr; // Type metadata. if (Mangled.nextIf('M')) { if (Mangled.nextIf('P')) { auto pattern = Node::create(Node::Kind::GenericTypeMetadataPattern); DEMANGLE_CHILD_AS_NODE_OR_RETURN(pattern, Directness); DEMANGLE_CHILD_OR_RETURN(pattern, Type); return pattern; } if (Mangled.nextIf('m')) { auto metaclass = Node::create(Node::Kind::Metaclass); DEMANGLE_CHILD_OR_RETURN(metaclass, Type); return metaclass; } if (Mangled.nextIf('n')) { auto nominalType = Node::create(Node::Kind::NominalTypeDescriptor); DEMANGLE_CHILD_OR_RETURN(nominalType, Type); return nominalType; } auto metadata = Node::create(Node::Kind::TypeMetadata); DEMANGLE_CHILD_AS_NODE_OR_RETURN(metadata, Directness); DEMANGLE_CHILD_OR_RETURN(metadata, Type); return metadata; } // Partial application thunks. if (Mangled.nextIf('P')) { if (!Mangled.nextIf('A')) return nullptr; Node::Kind kind = Node::Kind::PartialApplyForwarder; if (Mangled.nextIf('o')) kind = Node::Kind::PartialApplyObjCForwarder; auto forwarder = Node::create(kind); if (Mangled.nextIf("__T")) DEMANGLE_CHILD_OR_RETURN(forwarder, Global); return forwarder; } // Top-level types, for various consumers. if (Mangled.nextIf('t')) { return demangleType(); } // Value witnesses. if (Mangled.nextIf('w')) { ValueWitnessKind w = demangleValueWitnessKind(); if (w == ValueWitnessKind::Unknown) return nullptr; auto witness = Node::create(Node::Kind::ValueWitness, toString(w)); DEMANGLE_CHILD_OR_RETURN(witness, Type); return witness; } // Offsets, value witness tables, and protocol witnesses. if (Mangled.nextIf('W')) { if (Mangled.nextIf('V')) { auto witnessTable = Node::create(Node::Kind::ValueWitnessTable); DEMANGLE_CHILD_OR_RETURN(witnessTable, Type); return witnessTable; } if (Mangled.nextIf('o')) { auto witnessTableOffset = Node::create(Node::Kind::WitnessTableOffset); DEMANGLE_CHILD_OR_RETURN(witnessTableOffset, Entity); return witnessTableOffset; } if (Mangled.nextIf('v')) { auto fieldOffset = Node::create(Node::Kind::FieldOffset); DEMANGLE_CHILD_AS_NODE_OR_RETURN(fieldOffset, Directness); DEMANGLE_CHILD_OR_RETURN(fieldOffset, Entity); return fieldOffset; } if (Mangled.nextIf('P')) { auto witnessTable = Node::create(Node::Kind::ProtocolWitnessTable); DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance); return witnessTable; } if (Mangled.nextIf('Z')) { auto accessor = Node::create(Node::Kind::LazyProtocolWitnessTableAccessor); DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance); return accessor; } if (Mangled.nextIf('z')) { auto tableTemplate = Node::create(Node::Kind::LazyProtocolWitnessTableTemplate); DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance); return tableTemplate; } if (Mangled.nextIf('D')) { auto tableGenerator = Node::create(Node::Kind::DependentProtocolWitnessTableGenerator); DEMANGLE_CHILD_OR_RETURN(tableGenerator, ProtocolConformance); return tableGenerator; } if (Mangled.nextIf('d')) { auto tableTemplate = Node::create(Node::Kind::DependentProtocolWitnessTableTemplate); DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance); return tableTemplate; } return nullptr; } // Other thunks. if (Mangled.nextIf('T')) { if (Mangled.nextIf('b')) { auto bridge = Node::create(Node::Kind::BridgeToBlockFunction); DEMANGLE_CHILD_OR_RETURN(bridge, Type); return bridge; } if (Mangled.nextIf('R')) { NodePointer thunk = Node::create(Node::Kind::ReabstractionThunkHelper); if (!demangleReabstractSignature(thunk)) return nullptr; return thunk; } if (Mangled.nextIf('r')) { NodePointer thunk = Node::create(Node::Kind::ReabstractionThunk); if (!demangleReabstractSignature(thunk)) return nullptr; return thunk; } if (Mangled.nextIf('W')) { NodePointer thunk = Node::create(Node::Kind::ProtocolWitness); DEMANGLE_CHILD_OR_RETURN(thunk, ProtocolConformance); DEMANGLE_CHILD_OR_RETURN(thunk, Entity); return thunk; } return nullptr; } // Everything else is just an entity. return demangleEntity(); } NodePointer demangleSpecializedAttribute() { NodePointer specialization = Node::create(Node::Kind::SpecializedAttribute); while (!Mangled.nextIf('_')) { NodePointer param = Node::create(Node::Kind::SpecializationParam); NodePointer type = demangleType(); if (!type) return nullptr; param->addChild(type); while (!Mangled.nextIf('_')) { NodePointer conformance = demangleProtocolConformance(); if (!conformance) return nullptr; param->addChild(conformance); } specialization->addChild(param); } return specialization; } std::string demangleOperator() { static const char op_char_table[] = "& @/= > <*!|+ %-~ ^ ."; Node::IndexType 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 demangleDeclName() { // decl-name ::= local-decl-name // local-decl-name ::= 'L' index identifier if (Mangled.nextIf('L')) { NodePointer discriminator = demangleIndexAsNode(); if (!discriminator) return nullptr; NodePointer name = demangleIdentifier(); if (!name) return nullptr; NodePointer localName = Node::create(Node::Kind::LocalDeclName); localName->addChild(std::move(discriminator)); localName->addChild(std::move(name)); return localName; } // decl-name ::= identifier return demangleIdentifier(); } NodePointer demangleIdentifier(Node::Kind kind = Node::Kind::Unknown) { if (!Mangled) return nullptr; if (Mangled.nextIf('o')) { // Operator identifiers aren't valid in the contexts that are // building more specific identifiers. if (kind != Node::Kind::Unknown) return nullptr; 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::create(Node::Kind::PrefixOperator, operatr); case 'P': return Node::create(Node::Kind::PostfixOperator, operatr); case 'i': return Node::create(Node::Kind::InfixOperator, operatr); default: return nullptr; } } } if (kind == Node::Kind::Unknown) kind = Node::Kind::Identifier; Node::IndexType length; if (demangleNatural(length)) { if (Mangled.hasAtLeast(length)) { auto identifier = Mangled.slice(length); Mangled.advanceOffset(length); return Node::create(kind, identifier); } } return nullptr; } bool demangleIndex(Node::IndexType &natural) { if (Mangled.nextIf('_')) { natural = 0; return true; } if (demangleNatural(natural)) { if (!Mangled.nextIf('_')) return false; natural++; return true; } return false; } /// Demangle an and package it as a node of some kind. NodePointer demangleIndexAsNode(Node::Kind kind = Node::Kind::Number) { Node::IndexType index; if (!demangleIndex(index)) return nullptr; return Node::create(kind, index); } NodePointer createSwiftType(Node::Kind typeKind, StringRef name) { NodePointer type = Node::create(typeKind); type->addChild(Node::create(Node::Kind::Module, STDLIB_NAME)); type->addChild(Node::create(Node::Kind::Identifier, name)); return type; } /// Demangle a , given that we've already consumed the 'S'. NodePointer demangleSubstitutionIndex() { if (!Mangled) return Node::create(Node::Kind::Failure); if (Mangled.nextIf('o')) return Node::create(Node::Kind::Module, "ObjectiveC"); if (Mangled.nextIf('C')) return Node::create(Node::Kind::Module, "C"); if (Mangled.nextIf('s')) return Node::create(Node::Kind::Module, STDLIB_NAME); if (Mangled.nextIf('a')) return createSwiftType(Node::Kind::Structure, "Array"); if (Mangled.nextIf('b')) return createSwiftType(Node::Kind::Structure, "Bool"); if (Mangled.nextIf('c')) return createSwiftType(Node::Kind::Structure, "UnicodeScalar"); if (Mangled.nextIf('d')) return createSwiftType(Node::Kind::Structure, "Float64"); if (Mangled.nextIf('f')) return createSwiftType(Node::Kind::Structure, "Float32"); if (Mangled.nextIf('i')) return createSwiftType(Node::Kind::Structure, "Int"); if (Mangled.nextIf('q')) return createSwiftType(Node::Kind::Enum, "Optional"); if (Mangled.nextIf('Q')) return createSwiftType(Node::Kind::Structure, "UncheckedOptional"); if (Mangled.nextIf('S')) return createSwiftType(Node::Kind::Structure, "String"); if (Mangled.nextIf('u')) return createSwiftType(Node::Kind::Structure, "UInt"); Node::IndexType index_sub; if (!demangleIndex(index_sub)) return Node::create(Node::Kind::Failure); if (index_sub >= Substitutions.size()) return Node::create(Node::Kind::Failure); return Substitutions[index_sub]; } NodePointer demangleModule() { if (Mangled.nextIf('S')) { NodePointer module = demangleSubstitutionIndex(); if (!module) return nullptr; if (module->getKind() != Node::Kind::Module) return nullptr; return module; } NodePointer module = demangleIdentifier(Node::Kind::Module); if (!module) return nullptr; Substitutions.push_back(module); return module; } NodePointer demangleDeclarationName(Node::Kind kind) { NodePointer context = demangleContext(); if (!context) return nullptr; auto name = demangleDeclName(); if (!name) return nullptr; auto decl = Node::create(kind); decl->addChild(context); decl->addChild(name); Substitutions.push_back(decl); return decl; } NodePointer demangleProtocolName() { NodePointer proto = demangleProtocolNameImpl(); if (!proto) return nullptr; NodePointer type = Node::create(Node::Kind::Type); type->addChild(proto); return type; } NodePointer demangleProtocolNameImpl() { // There's an ambiguity in between a substitution of // the protocol and a substitution of the protocol's context, so // we have to duplicate some of the logic from // demangleDeclarationName. if (Mangled.nextIf('S')) { NodePointer sub = demangleSubstitutionIndex(); if (!sub) return nullptr; if (sub->getKind() == Node::Kind::Protocol) return sub; if (sub->getKind() != Node::Kind::Module) return nullptr; NodePointer name = demangleDeclName(); if (!name) return nullptr; auto proto = Node::create(Node::Kind::Protocol); proto->addChild(std::move(sub)); proto->addChild(std::move(name)); Substitutions.push_back(proto); return proto; } return demangleDeclarationName(Node::Kind::Protocol); } NodePointer demangleNominalType() { if (Mangled.nextIf('S')) return demangleSubstitutionIndex(); if (Mangled.nextIf('V')) return demangleDeclarationName(Node::Kind::Structure); if (Mangled.nextIf('O')) return demangleDeclarationName(Node::Kind::Enum); if (Mangled.nextIf('C')) return demangleDeclarationName(Node::Kind::Class); if (Mangled.nextIf('P')) return demangleDeclarationName(Node::Kind::Protocol); return nullptr; } NodePointer demangleContext() { // context ::= module // context ::= entity if (!Mangled) return nullptr; if (Mangled.nextIf('S')) return demangleSubstitutionIndex(); if (isStartOfEntity(Mangled.peek())) return demangleEntity(); return demangleModule(); } NodePointer demangleProtocolList() { NodePointer proto_list = Node::create(Node::Kind::ProtocolList); NodePointer type_list = Node::create(Node::Kind::TypeList); proto_list->addChild(type_list); if (Mangled.nextIf('_')) { return proto_list; } NodePointer proto = demangleProtocolName(); if (!proto) return nullptr; type_list->addChild(proto); while (Mangled.nextIf('_') == false) { proto = demangleProtocolName(); if (!proto) return nullptr; type_list->addChild(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::create(Node::Kind::ProtocolConformance); proto_conformance->addChild(type); proto_conformance->addChild(protocol); proto_conformance->addChild(context); return proto_conformance; } /// Demangle an and add it to the given node. bool demangleEntity(NodePointer parent) { NodePointer entity = demangleEntity(); if (!entity) return failure(); parent->addChild(entity); return true; } // entity ::= entity-kind context entity-name // entity ::= nominal-type NodePointer demangleEntity() { // entity-kind Node::Kind entityBasicKind; if (Mangled.nextIf('F')) { entityBasicKind = Node::Kind::Function; } else if (Mangled.nextIf('v')) { entityBasicKind = Node::Kind::Variable; } else if (Mangled.nextIf('I')) { entityBasicKind = Node::Kind::Initializer; } else { return demangleNominalType(); } NodePointer context = demangleContext(); if (!context) return nullptr; // entity-name Node::Kind entityKind; bool hasType = true; NodePointer name; if (Mangled.nextIf('D')) { if (context->getKind() == Node::Kind::Class) entityKind = Node::Kind::Deallocator; else entityKind = Node::Kind::Destructor; hasType = false; } else if (Mangled.nextIf('d')) { entityKind = Node::Kind::Destructor; hasType = false; } else if (Mangled.nextIf('e')) { entityKind = Node::Kind::IVarInitializer; hasType = false; } else if (Mangled.nextIf('E')) { entityKind = Node::Kind::IVarDestroyer; hasType = false; } else if (Mangled.nextIf('C')) { if (context->getKind() == Node::Kind::Class) entityKind = Node::Kind::Allocator; else entityKind = Node::Kind::Constructor; } else if (Mangled.nextIf('c')) { entityKind = Node::Kind::Constructor; } else if (Mangled.nextIf('a')) { entityKind = Node::Kind::Addressor; name = demangleDeclName(); if (!name) return nullptr; } else if (Mangled.nextIf('g')) { entityKind = Node::Kind::Getter; name = demangleDeclName(); if (!name) return nullptr; } else if (Mangled.nextIf('s')) { entityKind = Node::Kind::Setter; name = demangleDeclName(); if (!name) return nullptr; } else if (Mangled.nextIf('w')) { entityKind = Node::Kind::WillSet; name = demangleDeclName(); if (!name) return nullptr; } else if (Mangled.nextIf('W')) { entityKind = Node::Kind::DidSet; name = demangleDeclName(); if (!name) return nullptr; } else if (Mangled.nextIf('U')) { entityKind = Node::Kind::ExplicitClosure; name = demangleIndexAsNode(); if (!name) return nullptr; } else if (Mangled.nextIf('u')) { entityKind = Node::Kind::ImplicitClosure; name = demangleIndexAsNode(); if (!name) return nullptr; } else if (entityBasicKind == Node::Kind::Initializer) { // entity-name ::= 'A' index if (Mangled.nextIf('A')) { entityKind = Node::Kind::DefaultArgumentInitializer; name = demangleIndexAsNode(); if (!name) return nullptr; // entity-name ::= 'i' } else if (Mangled.nextIf('i')) { entityKind = Node::Kind::Initializer; } else { return nullptr; } hasType = false; } else { entityKind = entityBasicKind; name = demangleDeclName(); if (!name) return nullptr; } NodePointer entity = Node::create(entityKind); entity->addChild(context); if (name) entity->addChild(name); if (hasType) { auto type = demangleType(); if (!type) return nullptr; entity->addChild(type); } return entity; } /// A RAII object designed for parsing generic signatures. class GenericContext { Demangler &D; public: GenericContext(Demangler &D) : D(D) { D.ArchetypeCounts.push_back(D.ArchetypeCount); } ~GenericContext() { D.ArchetypeCount = D.ArchetypeCounts.pop_back_val(); } }; /// Demangle a generic clause. /// /// \param C - not really required; just a token to prove that the caller /// has thought to enter a generic context NodePointer demangleGenerics(GenericContext &C) { DemanglerPrinter result_printer; NodePointer archetypes = Node::create(Node::Kind::Generics); // FIXME: Swallow the mangled associated type constraints. bool assocTypes = false; while (true) { if (!assocTypes && Mangled.nextIf('U')) { assocTypes = true; continue; } if (Mangled.nextIf('_')) { if (!Mangled) return nullptr; char c = Mangled.peek(); if (c != '_' && c != 'S' && (assocTypes || c != 'U') && !isStartOfIdentifier(c)) break; if (!assocTypes) archetypes->addChild(Node::create( Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount))); } else { NodePointer proto_list = demangleProtocolList(); if (!proto_list) return nullptr; if (assocTypes) continue; NodePointer arch_and_proto = Node::create(Node::Kind::ArchetypeAndProtocol); arch_and_proto->addChild(Node::create( Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount))); arch_and_proto->addChild(proto_list); archetypes->addChild(arch_and_proto); } ++ArchetypeCount; } return archetypes; } NodePointer demangleArchetypeRef(Node::IndexType depth, Node::IndexType i) { if (depth == 0 && ArchetypeCount == 0) return Node::create(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::create(Node::Kind::ArchetypeRef, archetypeName(index)); } NodePointer demangleDependentType() { // A dependent member type begins with a non-index, non-'d' character. auto c = Mangled.peek(); if (c != 'd' && c != '_' && !isdigit(c)) { NodePointer baseType = demangleType(); if (!baseType) return nullptr; NodePointer depTy = demangleIdentifier(Node::Kind::DependentMemberType); if (!depTy) return nullptr; depTy->addChild(baseType); return depTy; } // Otherwise, we have a generic parameter. Node::IndexType depth, index; if (Mangled.nextIf('d')) { if (!demangleIndex(depth)) return nullptr; depth += 1; if (!demangleIndex(index)) return nullptr; } else { depth = 0; if (!demangleIndex(index)) return nullptr; } std::string name = "T_"; { llvm::raw_string_ostream os(name); os << depth << '_' << index; os.flush(); } NodePointer paramTy = Node::create(Node::Kind::DependentGenericParamType, std::move(name)); return paramTy; } NodePointer demangleGenericSignature() { NodePointer sig = Node::create(Node::Kind::DependentGenericSignature); // First read in the parameter counts at each depth. while (!Mangled.nextIf('R')) { Node::IndexType count; if (!demangleIndex(count)) return nullptr; NodePointer countNode = Node::create(Node::Kind::DependentGenericParamCount, count); sig->addChild(countNode); } // Next read in the generic requirements. while (!Mangled.nextIf('_')) { NodePointer reqt = demangleGenericRequirement(); if (!reqt) return nullptr; sig->addChild(reqt); } return sig; } NodePointer demangleGenericRequirement() { if (Mangled.nextIf('P')) { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer requirement = demangleType(); if (!requirement) return nullptr; NodePointer reqt = Node::create(Node::Kind::DependentGenericConformanceRequirement); reqt->addChild(type); reqt->addChild(requirement); return reqt; } if (Mangled.nextIf('E')) { NodePointer first = demangleType(); if (!first) return nullptr; NodePointer second = demangleType(); if (!second) return nullptr; NodePointer reqt = Node::create(Node::Kind::DependentGenericSameTypeRequirement); reqt->addChild(first); reqt->addChild(second); return reqt; } return nullptr; } NodePointer demangleArchetypeType() { auto makeSelfType = [&](NodePointer proto) -> NodePointer { NodePointer selfType = Node::create(Node::Kind::SelfTypeRef); selfType->addChild(proto); Substitutions.push_back(selfType); return selfType; }; auto makeAssociatedType = [&](NodePointer root) -> NodePointer { NodePointer name = demangleIdentifier(); if (!name) return nullptr; NodePointer assocType = Node::create(Node::Kind::AssociatedTypeRef); assocType->addChild(root); assocType->addChild(name); Substitutions.push_back(assocType); return assocType; }; if (Mangled.nextIf('P')) { NodePointer proto = demangleProtocolName(); if (!proto) return nullptr; return makeSelfType(proto); } if (Mangled.nextIf('Q')) { NodePointer root = demangleArchetypeType(); if (!root) return nullptr; return makeAssociatedType(root); } if (Mangled.nextIf('S')) { NodePointer sub = demangleSubstitutionIndex(); if (!sub) return nullptr; if (sub->getKind() == Node::Kind::Protocol) return makeSelfType(sub); else return makeAssociatedType(sub); } if (Mangled.nextIf('d')) { Node::IndexType depth, index; if (!demangleIndex(depth)) return nullptr; if (!demangleIndex(index)) return nullptr; return demangleArchetypeRef(depth + 1, index); } if (Mangled.nextIf('q')) { NodePointer index = demangleIndexAsNode(); if (!index) return nullptr; NodePointer decl_ctx = Node::create(Node::Kind::DeclContext); NodePointer ctx = demangleContext(); if (!ctx) return nullptr; decl_ctx->addChild(ctx); NodePointer qual_atype = Node::create(Node::Kind::QualifiedArchetype); qual_atype->addChild(index); qual_atype->addChild(decl_ctx); return qual_atype; } Node::IndexType index; if (!demangleIndex(index)) return nullptr; return demangleArchetypeRef(0, index); } NodePointer demangleTuple(IsVariadic isV) { NodePointer tuple = Node::create( isV == IsVariadic::yes ? Node::Kind::VariadicTuple : Node::Kind::NonVariadicTuple); while (!Mangled.nextIf('_')) { if (!Mangled) return nullptr; NodePointer elt = Node::create(Node::Kind::TupleElement); if (isStartOfIdentifier(Mangled.peek())) { NodePointer label = demangleIdentifier(Node::Kind::TupleElementName); if (!label) return nullptr; elt->addChild(label); } NodePointer type = demangleType(); if (!type) return nullptr; elt->addChild(type); tuple->addChild(elt); } return tuple; } NodePointer postProcessReturnTypeNode (NodePointer out_args) { NodePointer out_node = Node::create(Node::Kind::ReturnType); out_node->addChild(out_args); return out_node; } NodePointer demangleType() { NodePointer type = demangleTypeImpl(); if (!type) return nullptr; NodePointer nodeType = Node::create(Node::Kind::Type); nodeType->addChild(type); return nodeType; } NodePointer demangleFunctionType(Node::Kind kind) { NodePointer in_args = demangleType(); if (!in_args) return nullptr; NodePointer out_args = demangleType(); if (!out_args) return nullptr; NodePointer block = Node::create(kind); NodePointer in_node = Node::create(Node::Kind::ArgumentTuple); block->addChild(in_node); in_node->addChild(in_args); block->addChild(postProcessReturnTypeNode(out_args)); return block; } NodePointer demangleTypeImpl() { if (!Mangled) return nullptr; char c = Mangled.next(); if (c == 'A') { Node::IndexType size; if (demangleNatural(size)) { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer array = Node::create(Node::Kind::ArrayType); array->addChild(type); array->addChild(Node::create(Node::Kind::Number, size)); return array; } return nullptr; } if (c == 'B') { if (!Mangled) return nullptr; c = Mangled.next(); if (c == 'f') { Node::IndexType size; if (demangleBuiltinSize(size)) { return Node::create( Node::Kind::BuiltinTypeName, (DemanglerPrinter() << "Builtin.Float" << size).str()); } } if (c == 'i') { Node::IndexType size; if (demangleBuiltinSize(size)) { return Node::create( Node::Kind::BuiltinTypeName, (DemanglerPrinter() << "Builtin.Int" << size).str()); } } if (c == 'v') { Node::IndexType elts; if (demangleNatural(elts)) { if (!Mangled.nextIf('B')) return nullptr; if (Mangled.nextIf('i')) { Node::IndexType size; if (!demangleBuiltinSize(size)) return nullptr; return Node::create( Node::Kind::BuiltinTypeName, (DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size) .str()); } if (Mangled.nextIf('f')) { Node::IndexType size; if (!demangleBuiltinSize(size)) return nullptr; return Node::create( Node::Kind::BuiltinTypeName, (DemanglerPrinter() << "Builtin.Vec" << elts << "xFloat" << size).str()); } if (Mangled.nextIf('p')) return Node::create( Node::Kind::BuiltinTypeName, (DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer") .str()); } } if (c == 'O') return Node::create(Node::Kind::BuiltinTypeName, "Builtin.ObjCPointer"); if (c == 'o') return Node::create(Node::Kind::BuiltinTypeName, "Builtin.ObjectPointer"); if (c == 'p') return Node::create(Node::Kind::BuiltinTypeName, "Builtin.RawPointer"); if (c == 'w') return Node::create(Node::Kind::BuiltinTypeName, "Builtin.Word"); return nullptr; } if (c == 'a') return demangleDeclarationName(Node::Kind::TypeAlias); if (c == 'b') { NodePointer in_args = demangleType(); if (!in_args) return nullptr; NodePointer out_args = demangleType(); if (!out_args) return nullptr; NodePointer block = Node::create(Node::Kind::ObjCBlock); NodePointer in_node = Node::create(Node::Kind::ArgumentTuple); block->addChild(in_node); in_node->addChild(in_args); block->addChild(postProcessReturnTypeNode(out_args)); return block; } if (c == 'D') { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer dynamicSelf = Node::create(Node::Kind::DynamicSelf); dynamicSelf->addChild(type); return dynamicSelf; } if (c == 'E') { if (!Mangled.nextIf('R')) return nullptr; if (!Mangled.nextIf('R')) return nullptr; return Node::create(Node::Kind::ErrorType, std::string()); } if (c == 'F') { return demangleFunctionType(Node::Kind::FunctionType); } if (c == 'f') { NodePointer in_args = demangleTypeImpl(); if (!in_args) return nullptr; NodePointer out_args = demangleType(); if (!out_args) return nullptr; NodePointer block = Node::create(Node::Kind::UncurriedFunctionType); block->addChild(in_args); block->addChild(postProcessReturnTypeNode(out_args)); return block; } if (c == 'G') { NodePointer type_list = Node::create(Node::Kind::TypeList); NodePointer unboundType = demangleType(); if (!unboundType) return nullptr; if (Mangled.isEmpty()) return nullptr; while (Mangled.peek() != '_') { NodePointer type = demangleType(); if (!type) return nullptr; type_list->addChild(type); if (Mangled.isEmpty()) return nullptr; } Mangled.next(); Node::Kind bound_type_kind = Node::Kind::Unknown; switch (unboundType->getChild(0)->getKind()) { // look through Type node 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::Enum: bound_type_kind = Node::Kind::BoundGenericEnum; break; default: assert(false && "trying to make a generic type application for a non class|struct|enum"); } NodePointer type_application = Node::create(bound_type_kind); type_application->addChild(unboundType); type_application->addChild(type_list); return type_application; } if (c == 'K') { return demangleFunctionType(Node::Kind::AutoClosureType); } if (c == 'M') { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer metatype = Node::create(Node::Kind::Metatype); metatype->addChild(type); return metatype; } if (c == 'P') { return demangleProtocolList(); } if (c == 'Q') { return demangleArchetypeType(); } if (c == 'q') { return demangleDependentType(); } if (c == 'R') { NodePointer inout = Node::create(Node::Kind::InOut); NodePointer type = demangleTypeImpl(); if (!type) return nullptr; inout->addChild(type); return inout; } if (c == 'S') { return demangleSubstitutionIndex(); } if (c == 'T') { return demangleTuple(IsVariadic::no); } if (c == 't') { return demangleTuple(IsVariadic::yes); } if (c == 'u') { NodePointer sig = demangleGenericSignature(); if (!sig) return nullptr; NodePointer sub = demangleType(); if (!sub) return nullptr; NodePointer dependentGenericType = Node::create(Node::Kind::DependentGenericType); dependentGenericType->addChild(sig); dependentGenericType->addChild(sub); return dependentGenericType; } if (c == 'U') { GenericContext genericContext(*this); NodePointer generics = demangleGenerics(genericContext); if (!generics) return nullptr; NodePointer base = demangleType(); if (!base) return nullptr; NodePointer genericType = Node::create(Node::Kind::GenericType); genericType->addChild(generics); genericType->addChild(base); return genericType; } if (c == 'X') { if (Mangled.nextIf('o')) { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer unowned = Node::create(Node::Kind::Unowned); unowned->addChild(type); return unowned; } if (Mangled.nextIf('w')) { NodePointer type = demangleType(); if (!type) return nullptr; NodePointer weak = Node::create(Node::Kind::Weak); weak->addChild(type); return weak; } // type ::= 'XF' impl-function-type if (Mangled.nextIf('F')) { return demangleImplFunctionType(); } return nullptr; } if (isStartOfNominalType(c)) { NodePointer nominal_type = demangleDeclarationName(nominalTypeMarkerToNodeKind(c)); return nominal_type; } return nullptr; } bool demangleReabstractSignature(NodePointer signature) { if (Mangled.nextIf('G')) { NodePointer generics = demangleGenericSignature(); if (!generics) return failure(); signature->addChild(std::move(generics)); } NodePointer srcType = demangleType(); if (!srcType) return failure(); signature->addChild(std::move(srcType)); NodePointer destType = demangleType(); if (!destType) return failure(); signature->addChild(std::move(destType)); return true; } // impl-function-type ::= impl-callee-convention impl-function-attribute* // generics? '_' impl-parameter* '_' impl-result* '_' // impl-function-attribute ::= 'Cb' // compatible with C block invocation function // impl-function-attribute ::= 'Cc' // compatible with C global function // impl-function-attribute ::= 'Cm' // compatible with Swift method // impl-function-attribute ::= 'CO' // compatible with ObjC method // impl-function-attribute ::= 'Cw' // compatible with protocol witness // impl-function-attribute ::= 'N' // noreturn // impl-function-attribute ::= 'G' // generic NodePointer demangleImplFunctionType() { NodePointer type = Node::create(Node::Kind::ImplFunctionType); if (!demangleImplCalleeConvention(type)) return nullptr; if (Mangled.nextIf('C')) { if (Mangled.nextIf('b')) addImplFunctionAttribute(type, "@objc_block"); else if (Mangled.nextIf('c')) addImplFunctionAttribute(type, "@cc(cdecl)"); else if (Mangled.nextIf('m')) addImplFunctionAttribute(type, "@cc(method)"); else if (Mangled.nextIf('O')) addImplFunctionAttribute(type, "@cc(objc_method)"); else if (Mangled.nextIf('w')) addImplFunctionAttribute(type, "@cc(witness_method)"); else return nullptr; } if (Mangled.nextIf('N')) addImplFunctionAttribute(type, "@noreturn"); // Enter a new generic context if this type is generic. Optional genericContext; if (Mangled.nextIf('G')) { genericContext.emplace(*this); NodePointer generics = demangleGenerics(genericContext.getValue()); if (!generics) return nullptr; type->addChild(generics); } // Expect the attribute terminator. if (!Mangled.nextIf('_')) return nullptr; // Demangle the parameters. if (!demangleImplParameters(type.getPtr())) return nullptr; // Demangle the result type. if (!demangleImplResults(type.getPtr())) return nullptr; return type; } enum class ImplConventionContext { Callee, Parameter, Result }; // impl-convention ::= 'a' // direct, autoreleased // impl-convention ::= 'd' // direct, no ownership transfer // impl-convention ::= 'g' // direct, guaranteed // impl-convention ::= 'i' // indirect, ownership transfer // impl-convention ::= 'l' // indirect, inout // impl-convention ::= 'o' // direct, ownership transfer Optional demangleImplConvention(ImplConventionContext ctxt) { #define CASE(CHAR, FOR_CALLEE, FOR_PARAMETER, FOR_RESULT) \ if (Mangled.nextIf(CHAR)) { \ switch (ctxt) { \ case ImplConventionContext::Callee: return (FOR_CALLEE); \ case ImplConventionContext::Parameter: return (FOR_PARAMETER); \ case ImplConventionContext::Result: return (FOR_RESULT); \ } \ llvm_unreachable("bad context"); \ } CASE('a', Nothing, Nothing, "@autoreleased") CASE('d', "@callee_unowned", "@unowned", "@unowned") CASE('g', "@callee_guaranteed", "@guaranteed", Nothing) CASE('i', Nothing, "@in", "@out") CASE('l', Nothing, "@inout", Nothing) CASE('o', "@callee_owned", "@owned", "@owned") return Nothing; #undef RETURN } // impl-callee-convention ::= 't' // impl-callee-convention ::= impl-convention bool demangleImplCalleeConvention(NodePointer type) { StringRef attr; if (Mangled.nextIf('t')) { attr = "@thin"; } else if (auto optConv = demangleImplConvention(ImplConventionContext::Callee)) { attr = optConv.getValue(); } else { return failure(); } type->addChild(Node::create(Node::Kind::ImplConvention, attr)); return true; } void addImplFunctionAttribute(NodePointer parent, StringRef attr, Node::Kind kind = Node::Kind::ImplFunctionAttribute) { parent->addChild(Node::create(kind, attr)); } // impl-parameter ::= impl-convention type bool demangleImplParameters(Node *parent) { while (!Mangled.nextIf('_')) { auto input = demangleImplParameterOrResult(Node::Kind::ImplParameter); if (!input) return false; parent->addChild(input); } return true; } // impl-result ::= impl-convention type bool demangleImplResults(Node *parent) { while (!Mangled.nextIf('_')) { auto res = demangleImplParameterOrResult(Node::Kind::ImplResult); if (!res) return false; parent->addChild(res); } return true; } NodePointer demangleImplParameterOrResult(Node::Kind kind) { auto getContext = [](Node::Kind kind) -> ImplConventionContext { if (kind == Node::Kind::ImplParameter) return ImplConventionContext::Parameter; else if (kind == Node::Kind::ImplResult) return ImplConventionContext::Result; else llvm_unreachable("unexpected node kind"); }; auto convention = demangleImplConvention(getContext(kind)); if (!convention) return nullptr; auto type = demangleType(); if (!type) return nullptr; NodePointer node = Node::create(kind); node->addChild(Node::create(Node::Kind::ImplConvention, convention.getValue())); node->addChild(type); return node; } }; } // end anonymous namespace NodePointer Demangle::demangleSymbolAsNode(llvm::StringRef mangled, const DemangleOptions &options) { PrettyStackTraceStringAction prettyStackTrace("demangling string", mangled); Demangler demangler(mangled); demangler.demangle(); return demangler.getDemangled(); } namespace { class NodePrinter { private: DemanglerPrinter Printer; DemangleOptions Options; public: NodePrinter(DemangleOptions options) : Options(options) {} std::string printRoot(Node *root) { print(root); return Printer.str(); } private: void printChildren(Node::iterator begin, Node::iterator end, const char *sep = nullptr) { for (; begin != end;) { print(begin->getPtr()); ++begin; if (sep && begin != end) Printer << sep; } } void printChildren(Node *pointer, const char *sep = nullptr) { if (!pointer) return; Node::iterator begin = pointer->begin(), end = pointer->end(); printChildren(begin, end, sep); } Node *getFirstChildOfKind(Node *pointer, Node::Kind kind) { if (!pointer) return nullptr; for (NodePointer &child : *pointer) { if (child && child->getKind() == kind) return child.getPtr(); } return nullptr; } bool typeNeedsColonForDecl(Node *type) { if (!type) return false; if (!type->hasChildren()) return false; Node *child = type->getChild(0); 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 printBoundGenericNoSugar(Node *pointer) { if (pointer->getNumChildren() < 2) return; Node *typelist = pointer->getChild(1); print(pointer->getChild(0)); Printer << "<"; printChildren(typelist, ", "); Printer << ">"; } static bool isSwiftModule(Node *node) { return (node->getKind() == Node::Kind::Module && node->getText() == STDLIB_NAME); } static bool isIdentifier(Node *node, StringRef desired) { return (node->getKind() == Node::Kind::Identifier && node->getText() == desired); } enum class SugarType { None, Optional, Array }; SugarType findSugar(NodePointer pointer) { if (pointer->getNumChildren() == 1 && pointer->getKind() == Node::Kind::Type) return findSugar(pointer->getChild(0)); if (pointer->getNumChildren() != 2) return SugarType::None; if (pointer->getKind() != Node::Kind::BoundGenericEnum && pointer->getKind() != Node::Kind::BoundGenericStructure) return SugarType::None; auto unboundType = pointer->getChild(0)->getChild(0); // drill through Type auto typeArgs = pointer->getChild(1); if (pointer->getKind() == Node::Kind::BoundGenericEnum) { // Swift.Optional if (isIdentifier(unboundType->getChild(1), "Optional") && typeArgs->getNumChildren() == 1 && isSwiftModule(unboundType->getChild(0))) { return SugarType::Optional; } } else { /*if (pointer->getKind() == Node::Kind::BoundGenericStructure)*/ // Swift.Array if (isIdentifier(unboundType->getChild(1), "Array") && typeArgs->getNumChildren() == 1 && isSwiftModule(unboundType->getChild(0))) { return SugarType::Array; } } return SugarType::None; } void printBoundGeneric(Node *pointer) { if (pointer->getNumChildren() < 2) return; if (pointer->getNumChildren() != 2) { printBoundGenericNoSugar(pointer); return; } if (Options.SynthesizeSugarOnTypes == false || pointer->getKind() == Node::Kind::BoundGenericClass) { // no sugar here printBoundGenericNoSugar(pointer); return; } SugarType sugarType = findSugar(pointer); switch (sugarType) { case SugarType::None: printBoundGenericNoSugar(pointer); break; case SugarType::Optional: { Node *type = pointer->getChild(1)->getChild(0); bool needs_parens = false; if (findSugar(type) != SugarType::None) needs_parens = true; if (needs_parens) Printer << "("; print(type); if (needs_parens) Printer << ")"; Printer << "?"; } break; case SugarType::Array: { Node *type = pointer->getChild(1)->getChild(0); bool needs_parens = false; if (findSugar(type) != SugarType::None) needs_parens = true; if (needs_parens) Printer << "("; print(type); if (needs_parens) Printer << ")"; Printer << "[]"; } break; } } void printImplFunctionType(Node *fn) { enum State { Attrs, Inputs, Results } curState = Attrs; auto transitionTo = [&](State newState) { assert(newState >= curState); for (; curState != newState; curState = State(curState + 1)) { switch (curState) { case Attrs: Printer << '('; continue; case Inputs: Printer << ") -> ("; continue; case Results: llvm_unreachable("no state after Results"); } llvm_unreachable("bad state"); } }; for (auto &child : *fn) { if (child->getKind() == Node::Kind::ImplParameter) { if (curState == Inputs) Printer << ", "; transitionTo(Inputs); print(child.getPtr()); } else if (child->getKind() == Node::Kind::ImplResult) { if (curState == Results) Printer << ", "; transitionTo(Results); print(child.getPtr()); } else { assert(curState == Attrs); print(child.getPtr()); Printer << ' '; } } transitionTo(Results); Printer << ')'; } void printContext(Node *context) { // TODO: parenthesize local contexts? print(context, /*asContext*/ true); Printer << '.'; } void print(Node *pointer, bool asContext = false, bool suppressType = false); }; } // end anonymous namespace void NodePrinter::print(Node *pointer, bool asContext, bool suppressType) { // Common code for handling entities. auto printEntity = [&](bool hasName, bool hasType, StringRef extraName) { printContext(pointer->getChild(0)); bool printType = (hasType && !suppressType); bool useParens = (printType && asContext); if (useParens) Printer << '('; if (hasName) print(pointer->getChild(1)); Printer << extraName; if (printType) { Node *type = pointer->getChild(1 + unsigned(hasName)); if (typeNeedsColonForDecl(type)) Printer << " : "; else Printer << " "; print(type); } if (useParens) Printer << ')'; }; Node::Kind kind = pointer->getKind(); switch (kind) { case Node::Kind::Failure: return; case Node::Kind::Directness: Printer << pointer->getText() << " "; return; case Node::Kind::Variable: case Node::Kind::Function: printEntity(true, true, ""); return; case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: { auto index = pointer->getChild(1)->getIndex(); DemanglerPrinter name; name << '('; if (pointer->getKind() == Node::Kind::ImplicitClosure) name << "implicit "; name << "closure #" << (index + 1) << ")"; printEntity(false, false, name.str()); return; } case Node::Kind::Global: printChildren(pointer); return; case Node::Kind::Suffix: Printer << " with unmangled suffix " << QuotedString(pointer->getText()); return; case Node::Kind::Initializer: printEntity(false, false, "(variable initialization expression)"); return; case Node::Kind::DefaultArgumentInitializer: { auto index = pointer->getChild(1); DemanglerPrinter strPrinter; strPrinter << "(default argument " << index->getIndex() << ")"; printEntity(false, false, strPrinter.str()); return; } case Node::Kind::DeclContext: print(pointer->getChild(0), asContext); return; case Node::Kind::Type: print(pointer->getChild(0), asContext); return; case Node::Kind::Class: case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Protocol: case Node::Kind::TypeAlias: printEntity(true, false, ""); return; case Node::Kind::LocalDeclName: Printer << '('; print(pointer->getChild(1)); Printer << " #" << (pointer->getChild(0)->getIndex() + 1) << ')'; return; case Node::Kind::Module: case Node::Kind::Identifier: Printer << pointer->getText(); return; case Node::Kind::AutoClosureType: Printer << "@auto_closure "; printChildren(pointer); return; case Node::Kind::FunctionType: printChildren(pointer); return; case Node::Kind::UncurriedFunctionType: { Node *metatype = pointer->getChild(0); Printer << "("; print(metatype); Printer << ")"; Node *real_func = pointer->getChild(1); real_func = real_func->getChild(0); printChildren(real_func); return; } case Node::Kind::ArgumentTuple: { bool need_parens = false; if (pointer->getNumChildren() > 1) need_parens = true; else { if (!pointer->hasChildren()) need_parens = true; else { Node::Kind child0_kind = pointer->getChild(0)->getChild(0)->getKind(); if (child0_kind != Node::Kind::VariadicTuple && child0_kind != Node::Kind::NonVariadicTuple) need_parens = true; } } if (need_parens) Printer << "("; printChildren(pointer); if (need_parens) Printer << ")"; return; } case Node::Kind::NonVariadicTuple: case Node::Kind::VariadicTuple: { Printer << "("; printChildren(pointer, ", "); if (pointer->getKind() == Node::Kind::VariadicTuple) Printer << "..."; Printer << ")"; return; } case Node::Kind::TupleElement: if (pointer->getNumChildren() == 1) { Node *type = pointer->getChild(0); print(type); } else if (pointer->getNumChildren() == 2) { Node *id = pointer->getChild(0); Node *type = pointer->getChild(1); print(id); print(type); } return; case Node::Kind::TupleElementName: Printer << pointer->getText() << " : "; return; case Node::Kind::TupleElementType: Printer << pointer->getText(); return; case Node::Kind::ReturnType: if (pointer->getNumChildren() == 0) Printer << " -> " << pointer->getText(); else { Printer << " -> "; printChildren(pointer); } return; case Node::Kind::Weak: Printer << "@weak "; print(pointer->getChild(0)); return; case Node::Kind::Unowned: Printer << "@unowned "; print(pointer->getChild(0)); return; case Node::Kind::InOut: Printer << "@inout "; print(pointer->getChild(0)); return; case Node::Kind::ObjCAttribute: Printer << "@objc "; return; case Node::Kind::SpecializedAttribute: Printer << "specialization <"; for (unsigned i = 0, e = pointer->getNumChildren(); i < e; ++i) { if (i >= 1) Printer << ", "; print(pointer->getChild(i)); } Printer << "> of "; return; case Node::Kind::SpecializationParam: print(pointer->getChild(0)); for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) { if (i == 1) Printer << " with "; else Printer << " and "; print(pointer->getChild(i)); } return; case Node::Kind::BuiltinTypeName: Printer << pointer->getText(); return; case Node::Kind::Number: Printer << pointer->getIndex(); return; case Node::Kind::ArrayType: { Node *type = pointer->getChild(0); Node *size = pointer->getChild(1); print(type); Printer << "["; print(size); Printer << "]"; return; } case Node::Kind::InfixOperator: Printer << pointer->getText() << " @infix"; return; case Node::Kind::PrefixOperator: Printer << pointer->getText() << " @prefix"; return; case Node::Kind::PostfixOperator: Printer << pointer->getText() << " @postfix"; return; case Node::Kind::DependentProtocolWitnessTableGenerator: Printer << "dependent protocol witness table generator for "; print(pointer->getFirstChild()); return; case Node::Kind::DependentProtocolWitnessTableTemplate: Printer << "dependent protocol witness table template for "; print(pointer->getFirstChild()); return; case Node::Kind::LazyProtocolWitnessTableAccessor: Printer << "lazy protocol witness table accessor for "; print(pointer->getFirstChild()); return; case Node::Kind::LazyProtocolWitnessTableTemplate: Printer << "lazy protocol witness table template for "; print(pointer->getFirstChild()); return; case Node::Kind::ProtocolWitnessTable: Printer << "protocol witness table for "; print(pointer->getFirstChild()); return; case Node::Kind::ProtocolWitness: { Printer << "protocol witness for "; print(pointer->getChild(1)); Printer << " in conformance "; print(pointer->getChild(0)); return; } case Node::Kind::PartialApplyForwarder: Printer << "partial apply forwarder"; if (pointer->hasChildren()) { Printer << " for "; print(pointer->getFirstChild()); } return; case Node::Kind::PartialApplyObjCForwarder: Printer << "partial apply ObjC forwarder"; if (pointer->hasChildren()) { Printer << " for "; print(pointer->getFirstChild()); } return; case Node::Kind::FieldOffset: { print(pointer->getChild(0)); // directness Printer << "field offset for "; auto entity = pointer->getChild(1); print(entity, /*asContext*/ false, /*suppressType*/ !Options.DisplayTypeOfIVarFieldOffset); return; } case Node::Kind::BridgeToBlockFunction: Printer << "bridge-to-block function for "; print(pointer->getFirstChild()); return; case Node::Kind::ReabstractionThunk: case Node::Kind::ReabstractionThunkHelper: { Printer << "reabstraction thunk "; if (pointer->getKind() == Node::Kind::ReabstractionThunkHelper) Printer << "helper "; auto generics = getFirstChildOfKind(pointer, Node::Kind::DependentGenericSignature); assert(pointer->getNumChildren() == 2 + unsigned(generics != nullptr)); if (generics) { print(generics); Printer << " "; } Printer << "from "; print(pointer->getChild(pointer->getNumChildren() - 2)); Printer << " to "; print(pointer->getChild(pointer->getNumChildren() - 1)); return; } case Node::Kind::GenericTypeMetadataPattern: print(pointer->getChild(0)); // directness Printer << "generic type metadata pattern for "; print(pointer->getChild(1)); return; case Node::Kind::Metaclass: Printer << "metaclass for "; print(pointer->getFirstChild()); return; case Node::Kind::TypeMetadata: print(pointer->getChild(0)); // directness Printer << "type metadata for "; print(pointer->getChild(1)); return; case Node::Kind::NominalTypeDescriptor: Printer << "nominal type descriptor for "; print(pointer->getChild(0)); return; case Node::Kind::ValueWitness: Printer << pointer->getText() << " value witness for "; print(pointer->getFirstChild()); return; case Node::Kind::ValueWitnessTable: Printer << "value witness table for "; print(pointer->getFirstChild()); return; case Node::Kind::WitnessTableOffset: Printer << "witness table offset for "; print(pointer->getFirstChild()); return; case Node::Kind::BoundGenericClass: case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: printBoundGeneric(pointer); return; case Node::Kind::DynamicSelf: Printer << "Self"; return; case Node::Kind::ObjCBlock: { Printer << "@objc_block "; Node *tuple = pointer->getChild(0); Node *rettype = pointer->getChild(1); print(tuple); print(rettype); return; } case Node::Kind::Metatype: { Node *type = pointer->getChild(0); print(type); Printer << ".Type"; return; } case Node::Kind::ArchetypeRef: Printer << pointer->getText(); return; case Node::Kind::AssociatedTypeRef: print(pointer->getChild(0)); Printer << '.' << pointer->getChild(1)->getText(); return; case Node::Kind::SelfTypeRef: print(pointer->getChild(0)); Printer << ".Self"; return; case Node::Kind::ProtocolList: { Node *type_list = pointer->getChild(0); if (!type_list) return; bool needs_proto_marker = (type_list->getNumChildren() != 1); if (needs_proto_marker) Printer << "protocol<"; printChildren(type_list, ", "); if (needs_proto_marker) Printer << ">"; return; } case Node::Kind::Generics: { if (pointer->getNumChildren() == 0) return; Printer << "<"; printChildren(pointer, ", "); Printer << ">"; return; } case Node::Kind::QualifiedArchetype: { if (pointer->getNumChildren() < 2) return; Node *number = pointer->getChild(0); Node *decl_ctx = pointer->getChild(1); Printer << "(archetype " << number->getIndex() << " of "; print(decl_ctx); Printer << ")"; return; } case Node::Kind::GenericType: { Node *atype_list = pointer->getChild(0); Node *fct_type = pointer->getChild(1)->getChild(0); print(atype_list); print(fct_type); return; } case Node::Kind::Addressor: printEntity(true, true, ".addressor"); return; case Node::Kind::Getter: printEntity(true, true, ".getter"); return; case Node::Kind::Setter: printEntity(true, true, ".setter"); return; case Node::Kind::WillSet: printEntity(true, true, ".willset"); return; case Node::Kind::DidSet: printEntity(true, true, ".didset"); return; case Node::Kind::Allocator: printEntity(false, true, "__allocating_init"); return; case Node::Kind::Constructor: printEntity(false, true, "init"); return; case Node::Kind::Destructor: printEntity(false, false, "deinit"); return; case Node::Kind::Deallocator: printEntity(false, false, "__deallocating_deinit"); return; case Node::Kind::IVarInitializer: printEntity(false, false, "__ivar_initializer"); return; case Node::Kind::IVarDestroyer: printEntity(false, false, "__ivar_destroyer"); return; case Node::Kind::ProtocolConformance: { Node *child0 = pointer->getChild(0); Node *child1 = pointer->getChild(1); Node *child2 = pointer->getChild(2); print(child0); Printer << " : "; print(child1); Printer << " in "; print(child2); return; } case Node::Kind::TypeList: printChildren(pointer); return; case Node::Kind::ArchetypeAndProtocol: { Node *child0 = pointer->getChild(0); Node *child1 = pointer->getChild(1); print(child0); Printer << " : "; print(child1); return; } case Node::Kind::ImplConvention: Printer << pointer->getText(); return; case Node::Kind::ImplFunctionAttribute: Printer << pointer->getText(); return; case Node::Kind::ImplParameter: case Node::Kind::ImplResult: printChildren(pointer, " "); return; case Node::Kind::ImplFunctionType: printImplFunctionType(pointer); return; case Node::Kind::Unknown: return; case Node::Kind::ErrorType: Printer << ""; return; case Node::Kind::DependentGenericSignature: { Printer << '<'; unsigned depth = 0; unsigned numChildren = pointer->getNumChildren(); for (; depth < numChildren && pointer->getChild(depth)->getKind() == Node::Kind::DependentGenericParamCount; ++depth) { unsigned count = pointer->getChild(depth)->getIndex(); for (unsigned index = 0; index < count; ++index) { if (depth || index) Printer << ", "; Printer << "T_" << depth << '_' << index; } } if (depth != numChildren) { Printer << " where "; for (unsigned i = depth; i < numChildren; ++i) { if (i > depth) Printer << ", "; print(pointer->getChild(i)); } } Printer << '>'; return; } case Node::Kind::DependentGenericParamCount: llvm_unreachable("should be printed as a child of a " "DependentGenericSignature"); case Node::Kind::DependentGenericConformanceRequirement: { Node *type = pointer->getChild(0); Node *reqt = pointer->getChild(1); print(type); Printer << ": "; print(reqt); return; } case Node::Kind::DependentGenericSameTypeRequirement: { Node *fst = pointer->getChild(0); Node *snd = pointer->getChild(1); print(fst); Printer << " == "; print(snd); return; } case Node::Kind::DependentGenericParamType: { Printer << pointer->getText(); return; } case Node::Kind::DependentGenericType: { Node *sig = pointer->getChild(0); Node *depTy = pointer->getChild(1); print(sig); Printer << ' '; print(depTy); return; } case Node::Kind::DependentMemberType: { Node *base = pointer->getChild(0); print(base); Printer << '.' << pointer->getText(); return; } } llvm_unreachable("bad node kind!"); } std::string Demangle::nodeToString(NodePointer root, const DemangleOptions &options) { if (!root) return ""; PrettyStackTraceNode trace("printing", root.getPtr()); return NodePrinter(options).printRoot(root.getPtr()); } std::string Demangle::demangleSymbolAsString(llvm::StringRef mangled, const DemangleOptions &options) { auto root = demangleSymbolAsNode(mangled, options); if (!root) return mangled.str(); PrettyStackTraceStringAction trace("printing the demangling of", mangled); std::string demangling = nodeToString(std::move(root), options); if (demangling.empty()) return mangled.str(); return demangling; }