//===--- Demangle.h - Interface to Swift symbol demangling ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file is the public API of the demangler library. // Tools which use the demangler library (like lldb) must include this - and // only this - header file. // //===----------------------------------------------------------------------===// #ifndef SWIFT_DEMANGLING_DEMANGLE_H #define SWIFT_DEMANGLING_DEMANGLE_H #include "swift/Demangling/Demangle.h" #include "swift/Demangling/Errors.h" #include "swift/Demangling/ManglingFlavor.h" #include "swift/Demangling/NamespaceMacros.h" #include "swift/Strings.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include #include #include #include #include #include namespace swift { namespace Demangle { SWIFT_BEGIN_INLINE_NAMESPACE enum class SymbolicReferenceKind : uint8_t; /// A simple default implementation that assigns letters to type parameters in /// alphabetic order. std::string genericParameterName(uint64_t depth, uint64_t index); /// Display style options for the demangler. struct DemangleOptions { bool SynthesizeSugarOnTypes = false; bool QualifyEntities = true; bool DisplayExtensionContexts = true; bool DisplayUnmangledSuffix = true; bool DisplayModuleNames = true; bool DisplayGenericSpecializations = true; bool DisplayProtocolConformances = true; bool DisplayWhereClauses = true; bool DisplayEntityTypes = true; bool DisplayLocalNameContexts = true; bool ShortenPartialApply = false; bool ShortenThunk = false; bool ShortenValueWitness = false; bool ShortenArchetype = false; bool ShowPrivateDiscriminators = true; bool ShowFunctionArgumentTypes = true; bool DisplayDebuggerGeneratedModule = true; bool DisplayStdlibModule = true; bool DisplayObjCModule = true; bool PrintForTypeName = false; bool ShowAsyncResumePartial = true; bool ShowClosureSignature = true; /// If this is nonempty, entities in this module name will not be qualified. llvm::StringRef HidingCurrentModule; /// A function to render generic parameter names. std::function GenericParameterName = genericParameterName; DemangleOptions() {} static DemangleOptions SimplifiedUIDemangleOptions() { auto Opt = DemangleOptions(); Opt.SynthesizeSugarOnTypes = true; Opt.QualifyEntities = true; Opt.DisplayExtensionContexts = false; Opt.DisplayUnmangledSuffix = false; Opt.DisplayModuleNames = false; Opt.DisplayGenericSpecializations = false; Opt.DisplayProtocolConformances = false; Opt.DisplayWhereClauses = false; Opt.DisplayEntityTypes = false; Opt.ShortenPartialApply = true; Opt.ShortenThunk = true; Opt.ShortenValueWitness = true; Opt.ShortenArchetype = true; Opt.ShowPrivateDiscriminators = false; Opt.ShowFunctionArgumentTypes = false; Opt.ShowAsyncResumePartial = false; return Opt; }; }; class Node; using NodePointer = Node *; class NodePrinter; enum class FunctionSigSpecializationParamKind : unsigned { // Option Flags use bits 0-5. This give us 6 bits implying 64 entries to // work with. ConstantPropFunction = 0, ConstantPropGlobal = 1, ConstantPropInteger = 2, ConstantPropFloat = 3, ConstantPropString = 4, ClosureProp = 5, BoxToValue = 6, BoxToStack = 7, InOutToOut = 8, ConstantPropKeyPath = 9, ConstantPropStruct = 10, ClosurePropPreviousArg = 11, // Option Set Flags use bits 6-31. This gives us 26 bits to use for option // flags. Dead = 1 << 6, OwnedToGuaranteed = 1 << 7, SROA = 1 << 8, GuaranteedToOwned = 1 << 9, ExistentialToGeneric = 1 << 10, }; enum class AutoDiffFunctionKind : char { JVP = 'f', VJP = 'r', Differential = 'd', Pullback = 'p', }; enum class MangledDifferentiabilityKind : char { NonDifferentiable = 0, Forward = 'f', Reverse = 'r', Normal = 'd', Linear = 'l', }; enum class MangledSILThunkKind : char { Invalid = 0, Identity = 'I', }; /// The pass that caused the specialization to occur. We use this to make sure /// that two passes that generate similar changes do not yield the same /// mangling. This currently cannot happen, so this is just a safety measure /// that creates separate name spaces. /// /// The number of entries is limited! See `Demangler::demangleSpecAttributes`. /// If you exceed the max, you'll need to upgrade the mangling. enum class SpecializationPass : uint8_t { AllocBoxToStack = 0, ClosureSpecializer, CapturePromotion, CapturePropagation, FunctionSignatureOpts, GenericSpecializer, MoveDiagnosticInOutToOut, AsyncDemotion, LAST = AsyncDemotion }; constexpr uint8_t MAX_SPECIALIZATION_PASS = 10; static_assert((uint8_t)SpecializationPass::LAST < MAX_SPECIALIZATION_PASS); static inline char encodeSpecializationPass(SpecializationPass Pass) { return char(uint8_t(Pass)) + '0'; } enum class ValueWitnessKind { #define VALUE_WITNESS(MANGLING, NAME) \ NAME, #include "swift/Demangling/ValueWitnessMangling.def" }; enum class Directness { Direct, Indirect }; class NodeFactory; class Context; class Node { public: enum class Kind : uint16_t { #define NODE(ID) ID, #include "swift/Demangling/DemangleNodes.def" }; using IndexType = uint64_t; using RemoteAddressType = std::pair; friend class NodeFactory; private: struct NodeVector { NodePointer *Nodes; uint32_t Number = 0; uint32_t Capacity = 0; }; union { llvm::StringRef Text; IndexType Index; NodePointer InlineChildren[2]; NodeVector Children; RemoteAddressType RemoteAddress; }; Kind NodeKind; enum class PayloadKind : uint8_t { None = 0, OneChild = 1, TwoChildren = 2, Text, Index, ManyChildren, RemoteAddress }; PayloadKind NodePayloadKind; Node(Kind k) : NodeKind(k), NodePayloadKind(PayloadKind::None) { } Node(Kind k, llvm::StringRef t) : NodeKind(k), NodePayloadKind(PayloadKind::Text) { Text = t; } Node(Kind k, IndexType index) : NodeKind(k), NodePayloadKind(PayloadKind::Index) { Index = index; } Node(Kind k, uint64_t remoteAddress, uint8_t addressSpace) : NodeKind(k), NodePayloadKind(PayloadKind::RemoteAddress) { RemoteAddress = {remoteAddress, addressSpace}; } Node(const Node &) = delete; Node &operator=(const Node &) = delete; public: Kind getKind() const { return NodeKind; } bool isSimilarTo(const Node *other) const { if (NodeKind != other->NodeKind || NodePayloadKind != other->NodePayloadKind) return false; switch (NodePayloadKind) { case PayloadKind::ManyChildren: return Children.Number == other->Children.Number; case PayloadKind::Index: return Index == other->Index; case PayloadKind::Text: return Text == other->Text; default: return true; } } static bool deepEquals(const Node *lhs, const Node *rhs) { if (lhs == rhs) return true; if ((!lhs && rhs) || (lhs && !rhs)) return false; if (!lhs->isSimilarTo(rhs)) return false; for (auto li = lhs->begin(), ri = rhs->begin(), le = lhs->end(); li != le; ++li, ++ri) { if (!deepEquals(*li, *ri)) return false; } return true; } bool isDeepEqualTo(const Node *other) const { return deepEquals(this, other); } bool hasText() const { return NodePayloadKind == PayloadKind::Text; } llvm::StringRef getText() const { assert(hasText()); return Text; } bool hasIndex() const { return NodePayloadKind == PayloadKind::Index; } uint64_t getIndex() const { assert(hasIndex()); return Index; } bool hasRemoteAddress() const { return NodePayloadKind == PayloadKind::RemoteAddress; } std::pair getRemoteAddress() const { assert(hasRemoteAddress()); return RemoteAddress; } using iterator = const NodePointer *; size_t getNumChildren() const { switch (NodePayloadKind) { case PayloadKind::OneChild: return 1; case PayloadKind::TwoChildren: return 2; case PayloadKind::ManyChildren: return Children.Number; default: return 0; } } bool hasChildren() const { return getNumChildren() != 0; } iterator begin() const { switch (NodePayloadKind) { case PayloadKind::OneChild: case PayloadKind::TwoChildren: return &InlineChildren[0]; case PayloadKind::ManyChildren: return Children.Nodes; default: return nullptr; } } iterator end() const { switch (NodePayloadKind) { case PayloadKind::OneChild: return &InlineChildren[1]; case PayloadKind::TwoChildren: return &InlineChildren[2]; case PayloadKind::ManyChildren: return Children.Nodes + Children.Number; default: return nullptr; } } NodePointer getFirstChild() const { return getChild(0); } NodePointer getLastChild() const { return getChild(getNumChildren() - 1); } NodePointer getChild(size_t index) const { if (index >= getNumChildren()) return nullptr; return begin()[index]; } // Only to be used by the demangler parsers. void addChild(NodePointer Child, NodeFactory &Factory); // Only to be used by the demangler parsers. void removeChildAt(unsigned Pos); void replaceChild(unsigned Pos, NodePointer Child); // Reverses the order of children. void reverseChildren(size_t StartingAt = 0); // Find a node by its kind, traversing the node depth-first, // and bailing out early if not found at the 'maxDepth'. NodePointer findByKind(Node::Kind kind, int maxDepth); /// Prints the whole node tree in readable form to stderr. /// /// Useful to be called from the debugger. void dump() LLVM_ATTRIBUTE_USED; }; /// Returns the length of the swift mangling prefix of the \p SymbolName. /// /// Returns 0 if \p SymbolName is not a mangled swift (>= swift 4.x) name. int getManglingPrefixLength(llvm::StringRef mangledName); /// Returns true if \p SymbolName is a mangled swift name. /// /// This does not include the old (<= swift 3.x) mangling prefix "_T". inline bool isMangledName(llvm::StringRef mangledName) { return getManglingPrefixLength(mangledName) != 0; } /// Returns true if the mangledName starts with the swift mangling prefix. /// /// This includes the old (<= swift 3.x) mangling prefix "_T". bool isSwiftSymbol(llvm::StringRef mangledName); /// Returns true if the mangledName starts with the swift mangling prefix. /// /// This includes the old (<= swift 3.x) mangling prefix "_T". bool isSwiftSymbol(const char *mangledName); /// Drops the Swift mangling prefix from the given mangled name, if there is /// one. /// /// This does not include the old (<= swift 3.x) mangling prefix "_T". llvm::StringRef dropSwiftManglingPrefix(llvm::StringRef mangledName); /// Returns true if the mangled name is an alias type name. /// /// \param mangledName A null-terminated string containing a mangled name. bool isAlias(llvm::StringRef mangledName); /// Returns true if the mangled name is a class type name. /// /// \param mangledName A null-terminated string containing a mangled name. bool isClass(llvm::StringRef mangledName); /// Returns true if the mangled name is an enum type name. /// /// \param mangledName A null-terminated string containing a mangled name. bool isEnum(llvm::StringRef mangledName); /// Returns true if the mangled name is a protocol type name. /// /// \param mangledName A null-terminated string containing a mangled name. bool isProtocol(llvm::StringRef mangledName); /// Returns true if the mangled name is a structure type name. /// /// \param mangledName A null-terminated string containing a mangled name. bool isStruct(llvm::StringRef mangledName); /// Returns true if the mangled name is an Objective-C symbol. /// /// \param mangledName A null-terminated string containing a mangled name. bool isObjCSymbol(llvm::StringRef mangledName); /// Returns true if the mangled name has the old scheme of function type /// mangling where labels are part of the type. /// /// \param mangledName A null-terminated string containing a mangled name. bool isOldFunctionTypeMangling(llvm::StringRef mangledName); class Demangler; /// The demangler context. /// /// It owns the allocated nodes which are created during demangling. /// It is always preferable to use the demangling via this context class as it /// ensures efficient memory management. Especially if demangling is done for /// multiple symbols. Typical usage: /// \code /// Context Ctx; /// for (...) { /// NodePointer Root = Ctx.demangleSymbolAsNode(MangledName); /// // Do something with Root /// Ctx.clear(); // deallocates Root /// } /// \endcode /// Declaring the context out of the loop minimizes the amount of needed memory /// allocations. /// class Context { Demangler *D; friend class Node; public: Context(); ~Context(); /// Demangle the given symbol and return the parse tree. /// /// \param MangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// /// \returns A parse tree for the demangled string - or a null pointer /// on failure. /// The lifetime of the returned node tree ends with the lifetime of the /// context or with a call of clear(). NodePointer demangleSymbolAsNode(llvm::StringRef MangledName); /// Demangle the given type and return the parse tree. /// /// \param MangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// /// \returns A parse tree for the demangled string - or a null pointer /// on failure. /// The lifetime of the returned node tree ends with the lifetime of the /// context or with a call of clear(). NodePointer demangleTypeAsNode(llvm::StringRef MangledName); /// Demangle the given symbol and return the readable name. /// /// \param MangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// /// \returns The demangled string. std::string demangleSymbolAsString(llvm::StringRef MangledName, const DemangleOptions &Options = DemangleOptions()); /// Demangle the given symbol and store the result in the `printer`. /// /// \param MangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// \param Printer The NodePrinter that will be used to demangle the symbol. /// /// \returns The demangled string. void demangleSymbolAsString(llvm::StringRef MangledName, NodePrinter &Printer); /// Demangle the given type and return the readable name. /// /// \param MangledName The mangled type string, which does _not_ start with /// a mangling prefix. /// /// \returns The demangled string. std::string demangleTypeAsString(llvm::StringRef MangledName, const DemangleOptions &Options = DemangleOptions()); /// Returns true if the mangledName refers to a thunk function. /// /// Thunk functions are either (ObjC) partial apply forwarder, swift-as-ObjC /// or ObjC-as-swift thunks or allocating init functions. bool isThunkSymbol(llvm::StringRef MangledName); /// Returns the mangled name of the target of a thunk. /// /// \returns Returns the remaining name after removing the thunk mangling /// characters from \p MangledName. If \p MangledName is not a thunk symbol /// or the thunk target cannot be derived from the mangling, an empty string /// is returned. std::string getThunkTarget(llvm::StringRef MangledName); /// Returns true if the \p mangledName refers to a function which conforms to /// the Swift calling convention. /// /// The return value is unspecified if the \p MangledName does not refer to a /// function symbol. bool hasSwiftCallingConvention(llvm::StringRef MangledName); /// Demangle the given symbol and return the module name of the symbol. /// /// \param mangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// /// \returns The module name. std::string getModuleName(llvm::StringRef mangledName); /// Deallocates all nodes. /// /// The memory which is used for nodes is not freed but recycled for the next /// demangling operation. void clear(); }; /// Standalone utility function to demangle the given symbol as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleSymbolAsString should be used instead. /// \param mangledName The mangled name string pointer. /// \param mangledNameLength The length of the mangledName string. /// \returns The demangled string. std::string demangleSymbolAsString(const char *mangledName, size_t mangledNameLength, const DemangleOptions &options = DemangleOptions()); /// Standalone utility function to demangle the given symbol as string. The /// demangled string is stored in the `printer`. /// /// If performance is an issue when demangling multiple symbols, /// \param mangledName The mangled name string pointer. /// \param mangledNameLength The length of the mangledName string. /// \param printer The NodePrinter that will be used to demangle the symbol. void demangleSymbolAsString(const llvm::StringRef mangledName, NodePrinter &printer); /// Standalone utility function to demangle the given symbol as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleSymbolAsString should be used instead. /// \param mangledName The mangled name string. /// \returns The demangled string. inline std::string demangleSymbolAsString(const std::string &mangledName, const DemangleOptions &options = DemangleOptions()) { return demangleSymbolAsString(mangledName.data(), mangledName.size(), options); } /// Standalone utility function to demangle the given symbol as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleSymbolAsString should be used instead. /// \param MangledName The mangled name string. /// \returns The demangled string. inline std::string demangleSymbolAsString(llvm::StringRef MangledName, const DemangleOptions &Options = DemangleOptions()) { return demangleSymbolAsString(MangledName.data(), MangledName.size(), Options); } /// Standalone utility function to demangle the given type as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleTypeAsString should be used instead. /// \param mangledName The mangled name string pointer. /// \param mangledNameLength The length of the mangledName string. /// \returns The demangled string. std::string demangleTypeAsString(const char *mangledName, size_t mangledNameLength, const DemangleOptions &options = DemangleOptions()); /// Standalone utility function to demangle the given type as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleTypeAsString should be used instead. /// \param mangledName The mangled name string. /// \returns The demangled string. inline std::string demangleTypeAsString(const std::string &mangledName, const DemangleOptions &options = DemangleOptions()) { return demangleTypeAsString(mangledName.data(), mangledName.size(), options); } /// Standalone utility function to demangle the given type as string. /// /// If performance is an issue when demangling multiple symbols, /// Context::demangleTypeAsString should be used instead. /// \param MangledName The mangled name string. /// \returns The demangled string. inline std::string demangleTypeAsString(llvm::StringRef MangledName, const DemangleOptions &Options = DemangleOptions()) { return demangleTypeAsString(MangledName.data(), MangledName.size(), Options); } enum class OperatorKind { NotOperator, Prefix, Postfix, Infix, }; /// A mangling error, which consists of an error code and a Node pointer struct [[nodiscard]] ManglingError { enum Code { Success = 0, AssertionFailed, Uninitialized, TooComplex, BadNodeKind, BadNominalTypeKind, NotAStorageNode, UnsupportedNodeKind, UnexpectedBuiltinVectorType, UnexpectedBuiltinType, MultipleChildNodes, WrongNodeType, WrongDependentMemberType, BadDirectness, UnknownEncoding, InvalidImplCalleeConvention, InvalidImplDifferentiability, InvalidImplCoroutineKind, InvalidImplFunctionAttribute, InvalidImplParameterConvention, InvalidImplParameterAttr, InvalidMetatypeRepresentation, MultiByteRelatedEntity, BadValueWitnessKind, NotAContextNode, }; Code code; NodePointer node; unsigned line; ManglingError() : code(Uninitialized), node(nullptr) {} ManglingError(Code c) : code(c), node(nullptr), line(0) {} ManglingError(Code c, NodePointer n, unsigned l) : code(c), node(n), line(l) {} bool isSuccess() const { return code == Success; } }; #define MANGLING_ERROR(c,n) ManglingError((c), (n), __LINE__) /// Used as a return type for mangling functions that may fail template class [[nodiscard]] ManglingErrorOr { private: ManglingError err_; T value_; public: ManglingErrorOr() : err_() {} ManglingErrorOr(ManglingError::Code code, NodePointer node = nullptr, unsigned line = 0) : err_(code, node, line) {} ManglingErrorOr(const ManglingError &err) : err_(err) {} ManglingErrorOr(const T &t) : err_(ManglingError::Success), value_(t) {} ManglingErrorOr(T &&t) : err_(ManglingError::Success), value_(std::move(t)) {} bool isSuccess() const { return err_.code == ManglingError::Success; } const ManglingError &error() const { return err_; } const T &result() const { assert(isSuccess()); return value_; } }; /// Remangle a demangled parse tree. ManglingErrorOr mangleNode(NodePointer root, Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default); using SymbolicResolver = llvm::function_ref; /// Remangle a demangled parse tree, using a callback to resolve /// symbolic references. ManglingErrorOr mangleNode(NodePointer root, SymbolicResolver resolver, Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default); /// Remangle a demangled parse tree, using a callback to resolve /// symbolic references. /// /// The returned string is owned by \p Factory. This means \p Factory must stay /// alive as long as the returned string is used. ManglingErrorOr mangleNode(NodePointer root, SymbolicResolver resolver, NodeFactory &Factory, Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default); /// Remangle in the old mangling scheme. /// /// This is only used for objc-runtime names. ManglingErrorOr mangleNodeOld(NodePointer root); /// Remangle in the old mangling scheme. /// /// This is only used for objc-runtime names. /// The returned string is owned by \p Factory. This means \p Factory must stay /// alive as long as the returned string is used. ManglingErrorOr mangleNodeOld(NodePointer node, NodeFactory &Factory); /// Remangle in the old mangling scheme and embed the name in "_Tt_". /// /// The returned string is null terminated and owned by \p Factory. This means /// \p Factory must stay alive as long as the returned string is used. ManglingErrorOr mangleNodeAsObjcCString(NodePointer node, NodeFactory &Factory); /// Transform the node structure to a string. /// /// Typical usage: /// \code /// std::string aDemangledName = /// swift::Demangler::nodeToString(aNode) /// \endcode /// /// \param Root A pointer to a parse tree generated by the demangler. /// \param Options An object encapsulating options to use to perform this /// demangling. /// /// \returns A string representing the demangled name. std::string nodeToString(NodePointer Root, const DemangleOptions &Options = DemangleOptions()); /// Transform the node structure to a string, which is stored in the `Printer`. /// /// \param Root A pointer to a parse tree generated by the demangler. /// \param Printer A NodePrinter used to pretty print the demangled Node. void nodeToString(NodePointer Root, NodePrinter &Printer); /// Transforms a mangled key path accessor thunk helper /// into the identfier/subscript that would be used to invoke it in swift code. std::string keyPathSourceString(const char *MangledName, size_t MangledNameLength); /// A class for printing to a std::string. class DemanglerPrinter { public: DemanglerPrinter() = default; DemanglerPrinter &operator<<(llvm::StringRef Value) & { Stream.append(Value.data(), Value.size()); return *this; } DemanglerPrinter &operator<<(char c) & { Stream.push_back(c); return *this; } DemanglerPrinter &operator<<(unsigned long long n) &; DemanglerPrinter &operator<<(long long n) &; DemanglerPrinter &operator<<(unsigned long n) & { return *this << (unsigned long long)n; } DemanglerPrinter &operator<<(long n) & { return *this << (long long)n; } DemanglerPrinter &operator<<(unsigned n) & { return *this << (unsigned long long)n; } DemanglerPrinter &operator<<(int n) & { return *this << (long long)n; } template DemanglerPrinter &&operator<<(T &&x) && { return std::move(*this << std::forward(x)); } DemanglerPrinter &writeHex(unsigned long long n) &; std::string &&str() && { return std::move(Stream); } llvm::StringRef getStringRef() const { return Stream; } size_t getStreamLength() { return Stream.length(); } /// Shrinks the buffer. void resetSize(size_t toPos) { assert(toPos <= Stream.size()); Stream.resize(toPos); } private: std::string Stream; }; /// Returns a the node kind \p k as string. const char *getNodeKindString(swift::Demangle::Node::Kind k); /// Prints the whole node tree \p Root in readable form into a std::string. /// /// Useful for debugging. std::string getNodeTreeAsString(NodePointer Root); bool nodeConsumesGenericArgs(Node *node); bool isSpecialized(Node *node); ManglingErrorOr getUnspecialized(Node *node, NodeFactory &Factory); /// Returns true if the node \p kind refers to a context node, e.g. a nominal /// type or a function. bool isContext(Node::Kind kind); /// Returns true if the node \p kind refers to a node which is placed before a /// function node, e.g. a specialization attribute. bool isFunctionAttr(Node::Kind kind); /// Form a StringRef around the mangled name starting at base, if the name may /// contain symbolic references. llvm::StringRef makeSymbolicMangledNameStringRef(const char *base); /// Produce the mangled name for the nominal type descriptor of a type /// referenced by its module and type name. std::string mangledNameForTypeMetadataAccessor( llvm::StringRef moduleName, llvm::StringRef typeName, Node::Kind typeKind, Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default); /// Base class for printing a Swift demangled node tree. /// /// NodePrinter is used to convert demangled Swift symbol nodes into /// human-readable string representations. It handles formatting, indentation, /// and Swift-specific syntax. /// /// The virtual methods in this class are meant to be overriden to allow /// external consumers (e.g lldb) to track the ranges of components of the /// demangled name. class NodePrinter { protected: DemanglerPrinter Printer; DemangleOptions Options; bool SpecializationPrefixPrinted = false; bool isValid = true; public: NodePrinter(DemangleOptions options) : Options(options) {} virtual ~NodePrinter() = default; virtual void printRoot(NodePointer root) { isValid = true; print(root, 0); } std::string takeString() { if (isValid) return std::move(Printer).str(); return ""; } protected: static const unsigned MaxDepth = 768; size_t getStreamLength() { return Printer.getStreamLength(); } /// Called when the node tree in valid. /// /// The demangler already catches most error cases and mostly produces valid /// node trees. But some cases are difficult to catch in the demangler and /// instead the NodePrinter bails. void setInvalid() { isValid = false; } void printChildren(Node::iterator begin, Node::iterator end, unsigned depth, const char *sep = nullptr); void printChildren(NodePointer Node, unsigned depth, const char *sep = nullptr); NodePointer getFirstChildOfKind(NodePointer Node, Node::Kind kind); void printBoundGenericNoSugar(NodePointer Node, unsigned depth); void printOptionalIndex(NodePointer node); static bool isSwiftModule(NodePointer node) { return (node->getKind() == Node::Kind::Module && node->getText() == STDLIB_NAME); } static bool isIdentifier(NodePointer node, StringRef desired) { return (node->getKind() == Node::Kind::Identifier && node->getText() == desired); } bool printContext(NodePointer Context); enum class SugarType { None, Optional, ImplicitlyUnwrappedOptional, Array, Dictionary }; enum class TypePrinting { NoType, WithColon, FunctionStyle }; /// Determine whether this is a "simple" type, from the type-simple /// production. bool isSimpleType(NodePointer Node); void printWithParens(NodePointer type, unsigned depth); SugarType findSugar(NodePointer Node); void printBoundGeneric(NodePointer Node, unsigned depth); NodePointer getChildIf(NodePointer Node, Node::Kind Kind); virtual void printFunctionParameters(NodePointer LabelList, NodePointer ParameterType, unsigned depth, bool showTypes); void printFunctionType(NodePointer LabelList, NodePointer node, unsigned depth); void printImplFunctionType(NodePointer fn, unsigned depth); virtual void printGenericSignature(NodePointer Node, unsigned depth); void printFunctionSigSpecializationParams(NodePointer Node, unsigned depth); void printNextParamChildNode(NodePointer nd, unsigned &idx, FunctionSigSpecializationParamKind kind, unsigned depth); void printSpecializationPrefix(NodePointer node, StringRef Description, unsigned depth, StringRef ParamPrefix = StringRef()); /// The main big print function. NodePointer print(NodePointer Node, unsigned depth, bool asPrefixContext = false); NodePointer printAbstractStorage(NodePointer Node, unsigned depth, bool asPrefixContent, StringRef ExtraName); /// Utility function to print entities. /// /// \param Entity The entity node to print /// \param depth The depth in the print() call tree. /// \param asPrefixContext Should the entity printed as a context which as a /// prefix to another entity, e.g. the Abc in Abc.def() /// \param TypePr How should the type of the entity be printed, if at all. /// E.g. with a colon for properties or as a function type. /// \param hasName Does the entity has a name, e.g. a function in contrast to /// an initializer. /// \param ExtraName An extra name added to the entity name (if any). /// \param ExtraIndex An extra index added to the entity name (if any), /// e.g. closure #1 /// \param OverwriteName If non-empty, print this name instead of the one /// provided by the node. Gets printed even if hasName is false. /// \return If a non-null node is returned it's a context which must be /// printed in postfix-form after the entity: " in ". NodePointer printEntity(NodePointer Entity, unsigned depth, bool asPrefixContext, TypePrinting TypePr, bool hasName, StringRef ExtraName = "", int ExtraIndex = -1, StringRef OverwriteName = ""); virtual void printFunctionName(bool hasName, llvm::StringRef &OverwriteName, llvm::StringRef &ExtraName, bool MultiWordName, int &ExtraIndex, swift::Demangle::NodePointer Entity, unsigned int depth); /// Print the type of an entity. /// /// \param Entity The entity. /// \param type The type of the entity. /// \param genericFunctionTypeList If not null, the generic argument types /// which is printed in the generic signature. /// \param depth The depth in the print() call tree. void printEntityType(NodePointer Entity, NodePointer type, NodePointer genericFunctionTypeList, unsigned depth); }; SWIFT_END_INLINE_NAMESPACE } // end namespace Demangle } // end namespace swift #endif // SWIFT_DEMANGLING_DEMANGLE_H