Add a basic "re-mangler", which turns a parsed

demangling tree back into a mangled string.

Also, extend the demangling API in a few obvious
ways, and simplify testing for failure in the
node-returning APIs by having them simply return
null instead of a spurious Failure node.

Also, preserve slightly more information in the
demangling tree.  The goal here is eventually to
always allow a perfect round-trip through the
demangler parse tree.  This patch gets us close,
but we're not quite there yet.

Tests to follow.

Swift SVN r24473
This commit is contained in:
John McCall
2015-01-16 06:33:08 +00:00
parent cb702a9035
commit bb675b6ac9
9 changed files with 1821 additions and 502 deletions

View File

@@ -17,6 +17,7 @@
#include <string>
#include <vector>
#include <cassert>
#include <iosfwd>
namespace llvm {
class raw_ostream;
@@ -35,6 +36,52 @@ struct DemangleOptions {
class Node;
typedef std::shared_ptr<Node> NodePointer;
enum class FunctionSigSpecializationParamInfoKind : unsigned {
// Option Flags use bits 0-5. This give us 6 bits implying 64 entries to
// work with.
Dead=0,
ConstantPropFunction=1,
ConstantPropGlobal=2,
ConstantPropInteger=3,
ConstantPropFloat=4,
ConstantPropString=5,
ClosureProp=6,
InOutToValue=7,
// Option Set Flags use bits 6-31. This gives us 26 bits to use for option
// flags.
OwnedToGuaranteed=1 << 6,
SROA=1 << 7,
};
enum class ValueWitnessKind {
AllocateBuffer,
AssignWithCopy,
AssignWithTake,
DeallocateBuffer,
Destroy,
DestroyBuffer,
InitializeBufferWithCopyOfBuffer,
InitializeBufferWithCopy,
InitializeWithCopy,
InitializeBufferWithTake,
InitializeWithTake,
ProjectBuffer,
InitializeBufferWithTakeOfBuffer,
DestroyArray,
InitializeArrayWithCopy,
InitializeArrayWithTakeFrontToBack,
InitializeArrayWithTakeBackToFront,
StoreExtraInhabitant,
GetExtraInhabitantIndex,
GetEnumTag,
InplaceProjectEnumData
};
enum class Directness {
Direct, Indirect
};
class Node : public std::enable_shared_from_this<Node> {
public:
enum class Kind : uint16_t {
@@ -130,19 +177,114 @@ public:
/// Typical usage:
/// \code
/// NodePointer aDemangledName =
/// swift::Demangler::demangleSymbolAsNode("SomeSwiftMangledName")
/// \endcode
///
/// \param mangledName The mangled string.
/// \param options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A parse tree for the demangled string - or a null pointer
/// on failure.
///
NodePointer
demangleSymbolAsNode(const char *mangledName, size_t mangledNameLength,
const DemangleOptions &options = DemangleOptions());
inline NodePointer
demangleSymbolAsNode(const std::string &mangledName,
const DemangleOptions &options = DemangleOptions()) {
return demangleSymbolAsNode(mangledName.data(), mangledName.size(), options);
}
/// \brief Demangle the given string as a Swift symbol.
///
/// Typical usage:
/// \code
/// std::string aDemangledName =
/// swift::Demangler::demangleSymbol("SomeSwiftMangledName")
/// \endcode
///
/// \param MangledName The mangled string.
/// \param Options An object encapsulating options to use to perform this demangling.
/// \param mangledName The mangled string.
/// \param options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A parse tree for the demangled string - or a Failure node on
/// failure.
/// \returns A string representing the demangled name.
///
std::string
demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
const DemangleOptions &options = DemangleOptions());
inline std::string
demangleSymbolAsString(const std::string &mangledName,
const DemangleOptions &options = DemangleOptions()) {
return demangleSymbolAsString(mangledName.data(), mangledName.size(),
options);
}
/// \brief Demangle the given string as a Swift type.
///
/// Typical usage:
/// \code
/// NodePointer aDemangledName =
/// swift::Demangler::demangleTypeAsNode("SomeSwiftMangledName")
/// \endcode
///
/// \param mangledName The mangled string.
/// \param options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A parse tree for the demangled string - or a null pointer
/// on failure.
///
NodePointer
demangleSymbolAsNode(const char *MangledName, size_t MangledNameLength,
const DemangleOptions &Options = DemangleOptions());
demangleTypeAsNode(const char *mangledName, size_t mangledNameLength,
const DemangleOptions &options = DemangleOptions());
inline NodePointer
demangleTypeAsNode(const std::string &mangledName,
const DemangleOptions &options = DemangleOptions()) {
return demangleTypeAsNode(mangledName.data(), mangledName.size(), options);
}
/// \brief Demangle the given string as a Swift type mangling.
///
/// \param mangledName The mangled string.
/// \param options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A string representing the demangled name.
std::string
demangleTypeAsString(const char *mangledName, size_t mangledNameLength,
const DemangleOptions &options = DemangleOptions());
inline std::string
demangleTypeAsString(const std::string &mangledName,
const DemangleOptions &options = DemangleOptions()) {
return demangleTypeAsString(mangledName.data(), mangledName.size(), options);
}
enum class OperatorKind {
NotOperator,
Prefix,
Postfix,
Infix
};
/// \brief Mangle an identifier using Swift's mangling rules.
void mangleIdentifier(const char *data, size_t length,
OperatorKind operatorKind, std::ostream &out,
bool usePunycode = true);
/// \brief Remangle a demangled parse tree.
///
/// This should always round-trip perfectly with demangleSymbolAsNode.
std::string mangleNode(const NodePointer &root);
/// \brief Write a mangling of the given parse tree into the given stream.
///
/// This should always round-trip perfectly with demangleSymbolAsNode.
void mangleNode(NodePointer root, std::ostream &out);
/// \brief Transform the node structure in a string.
///
@@ -160,41 +302,6 @@ demangleSymbolAsNode(const char *MangledName, size_t MangledNameLength,
std::string nodeToString(NodePointer Root,
const DemangleOptions &Options = DemangleOptions());
/// \brief Demangle the given string as a Swift symbol.
///
/// Typical usage:
/// \code
/// std::string aDemangledName =
/// swift::Demangler::demangleSymbol("SomeSwiftMangledName")
/// \endcode
///
/// \param MangledName The mangled string.
/// \param Options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A string representing the demangled name.
///
std::string
demangleSymbolAsString(const char *MangledName, size_t MangledNameLength,
const DemangleOptions &Options = DemangleOptions());
inline std::string
demangleSymbolAsString(std::string MangledName,
const DemangleOptions &Options = DemangleOptions()) {
return demangleSymbolAsString(MangledName.data(), MangledName.size());
}
/// \brief Demangle the given string as a Swift type name.
///
/// \param MangledName The mangled string.
/// \param Options An object encapsulating options to use to perform this demangling.
///
///
/// \returns A string representing the demangled name.
std::string
demangleTypeAsString(const char *MangledName, size_t MangledNameLength,
const DemangleOptions &Options = DemangleOptions());
} // end namespace Demangle
} // end namespace swift

View File

@@ -18,22 +18,28 @@
/// NODE(ID)
/// The node's enumerator value is Node::Kind::ID.
NODE(Failure)
NODE(Allocator)
NODE(ArchetypeAndProtocol)
/// CONTEXT_NODE(ID)
/// Nodes that can serve as contexts for other entities.
#ifndef CONTEXT_NODE
#define CONTEXT_NODE(ID) NODE(ID)
#endif
CONTEXT_NODE(Allocator)
NODE(Archetype)
NODE(ArchetypeRef)
NODE(ArgumentTuple)
NODE(AssociatedType)
NODE(AssociatedTypeRef)
NODE(AutoClosureType)
NODE(BoundGenericClass)
NODE(BoundGenericEnum)
NODE(BoundGenericStructure)
NODE(BuiltinTypeName)
NODE(Class)
NODE(Constructor)
NODE(Deallocator)
CONTEXT_NODE(Class)
CONTEXT_NODE(Constructor)
CONTEXT_NODE(Deallocator)
NODE(DeclContext)
NODE(DefaultArgumentInitializer)
CONTEXT_NODE(DefaultArgumentInitializer)
NODE(DependentGenericSignature)
NODE(DependentGenericParamCount)
NODE(DependentGenericConformanceRequirement)
@@ -43,63 +49,68 @@ NODE(DependentMemberType)
NODE(DependentGenericParamType)
NODE(DependentProtocolWitnessTableGenerator)
NODE(DependentProtocolWitnessTableTemplate)
NODE(Destructor)
NODE(DidSet)
CONTEXT_NODE(Destructor)
CONTEXT_NODE(DidSet)
NODE(Directness)
NODE(DynamicAttribute)
NODE(DynamicSelf)
NODE(Enum)
CONTEXT_NODE(Enum)
NODE(ErrorType)
NODE(ExistentialMetatype)
NODE(ExplicitClosure)
NODE(Extension)
CONTEXT_NODE(ExplicitClosure)
CONTEXT_NODE(Extension)
NODE(FieldOffset)
NODE(Function)
CONTEXT_NODE(Function)
NODE(FunctionSignatureSpecialization)
NODE(FunctionSignatureSpecializationParam)
NODE(FunctionSignatureSpecializationParamInfo)
NODE(FunctionType)
NODE(Generics)
NODE(GenericSpecialization)
NODE(GenericSpecializationParam)
NODE(GenericType)
NODE(GenericTypeMetadataPattern)
NODE(Getter)
CONTEXT_NODE(Getter)
NODE(Global)
NODE(GlobalGetter)
CONTEXT_NODE(GlobalGetter)
NODE(Identifier)
NODE(IVarInitializer)
NODE(IVarDestroyer)
CONTEXT_NODE(IVarInitializer)
CONTEXT_NODE(IVarDestroyer)
NODE(ImplConvention)
NODE(ImplFunctionAttribute)
NODE(ImplFunctionType)
NODE(ImplicitClosure)
CONTEXT_NODE(ImplicitClosure)
NODE(ImplParameter)
NODE(ImplResult)
NODE(InOut)
NODE(InfixOperator)
NODE(Initializer)
CONTEXT_NODE(Initializer)
NODE(LazyProtocolWitnessTableAccessor)
NODE(LazyProtocolWitnessTableTemplate)
NODE(LocalDeclName)
NODE(MaterializeForSet)
CONTEXT_NODE(MaterializeForSet)
NODE(Metatype)
NODE(MetatypeRepresentation)
NODE(Metaclass)
NODE(Module)
NODE(NativeOwningAddressor)
NODE(NativeOwningMutableAddressor)
NODE(NativePinningAddressor)
NODE(NativePinningMutableAddressor)
CONTEXT_NODE(Module)
CONTEXT_NODE(NativeOwningAddressor)
CONTEXT_NODE(NativeOwningMutableAddressor)
CONTEXT_NODE(NativePinningAddressor)
CONTEXT_NODE(NativePinningMutableAddressor)
NODE(NominalTypeDescriptor)
NODE(NonObjCAttribute)
NODE(NonVariadicTuple)
NODE(Number)
NODE(ObjCAttribute)
NODE(ObjCBlock)
NODE(OwningAddressor)
NODE(OwningMutableAddressor)
CONTEXT_NODE(OwningAddressor)
CONTEXT_NODE(OwningMutableAddressor)
NODE(PartialApplyForwarder)
NODE(PartialApplyObjCForwarder)
NODE(PostfixOperator)
NODE(PrefixOperator)
NODE(PrivateDeclName)
NODE(Protocol)
CONTEXT_NODE(Protocol)
NODE(ProtocolConformance)
NODE(ProtocolList)
NODE(ProtocolWitness)
@@ -109,37 +120,32 @@ NODE(ReabstractionThunk)
NODE(ReabstractionThunkHelper)
NODE(ReturnType)
NODE(SelfTypeRef)
NODE(Setter)
NODE(SpecializedAttribute)
NODE(SpecializationKind)
NODE(GenericSpecializationParam)
NODE(FunctionSignatureSpecializationParam)
NODE(FunctionSignatureSpecializationParamInfo)
NODE(Structure)
NODE(Subscript)
CONTEXT_NODE(Setter)
CONTEXT_NODE(Structure)
CONTEXT_NODE(Subscript)
NODE(Suffix)
NODE(ThinFunctionType)
NODE(TupleElement)
NODE(TupleElementName)
NODE(TupleElementType)
NODE(Type)
NODE(TypeAlias)
NODE(TypeList)
NODE(TypeMangling)
NODE(TypeMetadata)
NODE(TypeMetadataAccessFunction)
NODE(TypeMetadataLazyCache)
NODE(UncurriedFunctionType)
NODE(Unknown)
NODE(Unmanaged)
NODE(Unowned)
NODE(UnsafeAddressor)
NODE(UnsafeMutableAddressor)
CONTEXT_NODE(UnsafeAddressor)
CONTEXT_NODE(UnsafeMutableAddressor)
NODE(ValueWitness)
NODE(ValueWitnessTable)
NODE(Variable)
CONTEXT_NODE(Variable)
NODE(VariadicTuple)
NODE(Weak)
NODE(WillSet)
CONTEXT_NODE(WillSet)
NODE(WitnessTableOffset)
#undef CONTEXT_NODE
#undef NODE

View File

@@ -21,6 +21,7 @@
#include "swift/AST/Initializer.h"
#include "swift/AST/Module.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/Demangle.h"
#include "swift/Basic/Punycode.h"
#include "clang/Basic/CharInfo.h"
#include "clang/AST/Decl.h"
@@ -31,36 +32,19 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <sstream>
using namespace swift;
using namespace Mangle;
bool Mangler::UsePrivateDiscriminators = true;
/// Translate the given operator character into its mangled form.
///
/// Current operator characters: @/=-+*%<>!&|^~ and the special operator '..'
static char mangleOperatorChar(char op) {
switch (op) {
case '&': return 'a'; // 'and'
case '@': return 'c'; // 'commercial at sign'
case '/': return 'd'; // 'divide'
case '=': return 'e'; // 'equal'
case '>': return 'g'; // 'greater'
case '<': return 'l'; // 'less'
case '*': return 'm'; // 'multiply'
case '!': return 'n'; // 'negate'
case '|': return 'o'; // 'or'
case '+': return 'p'; // 'plus'
case '?': return 'q'; // 'question'
case '%': return 'r'; // 'remainder'
case '-': return 's'; // 'subtract'
case '~': return 't'; // 'tilde'
case '^': return 'x'; // 'xor'
case '.': return 'z'; // 'zperiod' (the z is silent)
default:
return op;
static bool isNonAscii(StringRef str) {
for (unsigned char c : str) {
if (c >= 0x80)
return true;
}
return false;
}
namespace {
@@ -77,64 +61,24 @@ namespace {
};
}
static bool isNonAscii(StringRef str) {
for (unsigned char c : str) {
if (c >= 0x80)
return true;
}
return false;
}
/// Mangle a StringRef as an identifier into a buffer.
void Mangler::mangleIdentifier(StringRef str, OperatorFixity fixity,
bool isOperator) {
std::string punycodeBuf;
if (UsePunycode) {
// If the identifier contains non-ASCII character, we mangle
// with an initial X and Punycode the identifier string.
if (isNonAscii(str)) {
Buffer << 'X';
Punycode::encodePunycodeUTF8(str, punycodeBuf);
str = punycodeBuf;
}
}
// Mangle normal identifiers as
// count identifier-char+
// where the count is the number of characters in the identifier,
// and where individual identifier characters represent themselves.
if (!isOperator) {
Buffer << str.size() << str;
return;
}
// Mangle operator identifiers as
// operator ::= 'o' operator-fixity count operator-char+
// operator-fixity ::= 'p' // prefix
// operator-fixity ::= 'P' // postfix
// operator-fixity ::= 'i' // infix
// where the count is the number of characters in the operator,
// and where the individual operator characters are translated.
Buffer << 'o';
auto operatorKind = [=]() -> Demangle::OperatorKind {
if (!isOperator) return Demangle::OperatorKind::NotOperator;
switch (fixity) {
case OperatorFixity::NotOperator:
llvm_unreachable("operator mangled without fixity specified!");
case OperatorFixity::Infix:
Buffer << 'i';
break;
case OperatorFixity::Prefix:
Buffer << 'p';
break;
case OperatorFixity::Postfix:
Buffer << 'P';
break;
case OperatorFixity::NotOperator:return Demangle::OperatorKind::NotOperator;
case OperatorFixity::Prefix: return Demangle::OperatorKind::Prefix;
case OperatorFixity::Postfix: return Demangle::OperatorKind::Postfix;
case OperatorFixity::Infix: return Demangle::OperatorKind::Infix;
}
llvm_unreachable("invalid operator fixity");
}();
// Mangle ASCII operators directly.
Buffer << str.size();
for (char c : str) {
Buffer << mangleOperatorChar(c);
}
std::ostringstream stream;
Demangle::mangleIdentifier(str.data(), str.size(), operatorKind, stream,
UsePunycode);
Buffer << stream.str();
}
/// Mangle an identifier into the buffer.

View File

@@ -16,6 +16,7 @@ add_swift_library(swiftBasic
Punycode.cpp
PunycodeUTF8.cpp
QuotedString.cpp
Remangle.cpp
SourceLoc.cpp
StringExtras.cpp
TaskQueue.cpp

View File

@@ -189,29 +189,6 @@ static std::string archetypeName(Node::IndexType i) {
namespace {
using FunctionSigSpecializationParamInfoKindIntBase = unsigned;
enum class FunctionSigSpecializationParamInfoKind
: FunctionSigSpecializationParamInfoKindIntBase {
// Option Flags use bits 0-5. This give us 6 bits implying 64 entries to
// work with.
Dead=0,
ConstantPropFunction=1,
ConstantPropGlobal=2,
ConstantPropInteger=3,
ConstantPropFloat=4,
ConstantPropString=5,
ClosureProp=6,
InOutToValue=7,
// Option Set Flags use bits 6-31. This gives us 26 bits to use for option
// flags.
OwnedToGuaranteed=1 << 6,
SROA=1 << 7,
};
} // end anonymous namespace
namespace {
/// A convenient class for parsing characters out of a string.
class NameSource {
StringRef Text;
@@ -277,207 +254,17 @@ public:
}
};
/// The main class for parsing a demangling tree out of a mangled string.
class Demangler {
std::vector<NodePointer> Substitutions;
std::vector<unsigned> 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();
// First demangle any specialization prefixes.
if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTS") {
do {
Mangled.advanceOffset(4);
auto attr = demangleSpecializedAttribute();
if (!attr)
return failure();
appendNode(attr);
// The Substitution header does not share state with the rest of the
// mangling.
Substitutions.clear();
ArchetypeCounts.clear();
ArchetypeCount = 0;
} while (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTS");
// Then check that we have a global.
if (!Mangled.hasAtLeast(2) || Mangled.slice(2) != "_T")
return failure();
Mangled.advanceOffset(2);
} else if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTo") {
Mangled.advanceOffset(4);
appendNode(Node::Kind::ObjCAttribute);
} else if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTO") {
Mangled.advanceOffset(4);
appendNode(Node::Kind::NonObjCAttribute);
} else if (Mangled.hasAtLeast(4) && Mangled.slice(4) == "_TTD") {
Mangled.advanceOffset(4);
appendNode(Node::Kind::DynamicAttribute);
} 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;
}
bool demangleTypeName() {
NodePointer global = demangleType();
if (!global) return failure();
appendNode(std::move(global));
return true;
}
NodePointer getDemangled() { return RootNode; }
private:
NodePointer getRootNode() {
if (!RootNode) {
RootNode = NodeFactory::create(Node::Kind::Global);
}
return RootNode;
}
NodePointer appendNode(NodePointer n) {
return getRootNode()->addChild(std::move(n));
}
NodePointer appendNode(Node::Kind k, std::string &&t = "") {
return appendNode(NodeFactory::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(NodeFactory::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) {
static StringRef toString(Directness d) {
switch (d) {
case Directness::Direct:
return "direct";
case Directness::Indirect:
return "indirect";
case Directness::Unknown:
unreachable("shouldn't toString an unknown directness");
}
unreachable("bad directness");
}
bool failure() {
RootNode = NodeFactory::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,
InitializeBufferWithTakeOfBuffer,
DestroyArray,
InitializeArrayWithCopy,
InitializeArrayWithTakeFrontToBack,
InitializeArrayWithTakeBackToFront,
StoreExtraInhabitant,
GetExtraInhabitantIndex,
GetEnumTag,
InplaceProjectEnumData,
Unknown
};
StringRef toString(ValueWitnessKind k) {
static StringRef toString(ValueWitnessKind k) {
switch (k) {
case ValueWitnessKind::AllocateBuffer:
return "allocateBuffer";
@@ -521,18 +308,139 @@ private:
return "getEnumTag";
case ValueWitnessKind::InplaceProjectEnumData:
return "inplaceProjectEnumData";
case ValueWitnessKind::Unknown:
unreachable("stringifying the unknown value witness kind?");
}
unreachable("bad value witness kind");
}
ValueWitnessKind demangleValueWitnessKind() {
/// The main class for parsing a demangling tree out of a mangled string.
class Demangler {
std::vector<NodePointer> Substitutions;
std::vector<unsigned> ArchetypeCounts;
unsigned ArchetypeCount = 0;
NameSource Mangled;
public:
Demangler(llvm::StringRef mangled) : Mangled(mangled) {}
/// 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.hasValue()) return nullptr; \
(PARENT)->addChild(NodeFactory::create(Node::Kind::CHILD_KIND, \
unsigned(*_kind))); \
} while (false)
/// 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
NodePointer demangleTopLevel() {
if (!Mangled.nextIf("_T"))
return nullptr;
NodePointer topLevel = NodeFactory::create(Node::Kind::Global);
// First demangle any specialization prefixes.
if (Mangled.nextIf("TS")) {
do {
DEMANGLE_CHILD_OR_RETURN(topLevel, SpecializedAttribute);
// The Substitution header does not share state with the rest
// of the mangling.
Substitutions.clear();
ArchetypeCounts.clear();
ArchetypeCount = 0;
} while (Mangled.nextIf("_TTS"));
// Then check that we have a global.
if (!Mangled.nextIf("_T"))
return nullptr;
} else if (Mangled.nextIf("To")) {
topLevel->addChild(NodeFactory::create(Node::Kind::ObjCAttribute));
} else if (Mangled.nextIf("TO")) {
topLevel->addChild(NodeFactory::create(Node::Kind::NonObjCAttribute));
} else if (Mangled.nextIf("TD")) {
topLevel->addChild(NodeFactory::create(Node::Kind::DynamicAttribute));
}
DEMANGLE_CHILD_OR_RETURN(topLevel, Global);
// Add a suffix node if there's anything left unmangled.
if (!Mangled.isEmpty()) {
topLevel->addChild(NodeFactory::create(Node::Kind::Suffix,
Mangled.getString()));
}
return topLevel;
}
NodePointer demangleTypeName() {
return demangleType();
}
private:
enum class IsProtocol {
yes = true, no = false
};
enum class IsVariadic {
yes = true, no = false
};
Optional<Directness> demangleDirectness() {
if (Mangled.nextIf('d'))
return Directness::Direct;
if (Mangled.nextIf('i'))
return Directness::Indirect;
return None;
}
bool demangleNatural(Node::IndexType &num) {
if (!Mangled)
return ValueWitnessKind::Unknown;
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;
}
Optional<ValueWitnessKind> demangleValueWitnessKind() {
if (!Mangled)
return None;
char c1 = Mangled.next();
if (!Mangled)
return ValueWitnessKind::Unknown;
return None;
char c2 = Mangled.next();
if (c1 == 'a' && c2 == 'l')
return ValueWitnessKind::AllocateBuffer;
@@ -576,7 +484,7 @@ private:
return ValueWitnessKind::GetEnumTag;
if (c1 == 'u' && c2 == 'p')
return ValueWitnessKind::InplaceProjectEnumData;
return ValueWitnessKind::Unknown;
return None;
}
NodePointer demangleGlobal() {
@@ -634,16 +542,18 @@ private:
// Top-level types, for various consumers.
if (Mangled.nextIf('t')) {
return demangleType();
auto type = NodeFactory::create(Node::Kind::TypeMangling);
DEMANGLE_CHILD_OR_RETURN(type, Type);
return type;
}
// Value witnesses.
if (Mangled.nextIf('w')) {
ValueWitnessKind w = demangleValueWitnessKind();
if (w == ValueWitnessKind::Unknown)
Optional<ValueWitnessKind> w = demangleValueWitnessKind();
if (!w.hasValue())
return nullptr;
auto witness =
NodeFactory::create(Node::Kind::ValueWitness, toString(w));
NodeFactory::create(Node::Kind::ValueWitness, unsigned(w.getValue()));
DEMANGLE_CHILD_OR_RETURN(witness, Type);
return witness;
}
@@ -728,9 +638,7 @@ private:
}
NodePointer demangleGenericSpecialization() {
auto specialization = NodeFactory::create(Node::Kind::SpecializedAttribute);
auto kind = NodeFactory::create(Node::Kind::SpecializationKind, "generic");
specialization->addChild(kind);
auto specialization = NodeFactory::create(Node::Kind::GenericSpecialization);
while (!Mangled.nextIf('_')) {
// Otherwise, we have another parameter. Demangle the type.
@@ -753,25 +661,11 @@ private:
return specialization;
}
bool skipGlobal() {
// Find how far we need to go to skip the global.
StringRef before = Mangled.str();
Demangler d(before);
bool result = d.demangle();
if (!result)
return false;
NodePointer n = d.getDemangled();
unsigned suffixSize = n->getChild(n->getNumChildren()-1)->getText().size();
Mangled.advanceOffset(before.size() - suffixSize);
return true;
}
/// TODO: This is an atrocity. Come up with a shorter name.
#define FUNCSIGSPEC_CREATE_INFO_KIND(kind) \
NodeFactory::create( \
Node::Kind::FunctionSignatureSpecializationParamInfo, \
FunctionSigSpecializationParamInfoKindIntBase( \
FunctionSigSpecializationParamInfoKind::kind))
unsigned(FunctionSigSpecializationParamInfoKind::kind))
NodePointer demangleFuncSigSpecializationConstantProp() {
// Then figure out what was actually constant propagated. First check if
@@ -835,29 +729,21 @@ private:
}
NodePointer demangleFunctionSignatureSpecialization() {
auto specialization = NodeFactory::create(Node::Kind::SpecializedAttribute);
auto kind = NodeFactory::create(Node::Kind::SpecializationKind, "function signature");
specialization->addChild(kind);
auto specialization = NodeFactory::create(Node::Kind::FunctionSignatureSpecialization);
unsigned paramCount = 0;
// Until we hit the last '_' in our specialization info...
while (!Mangled.nextIf('_')) {
// Try to eat an n. If we succeed don't create any nodes and
// continue. This is because we do not represent unmodified arguments in
// the demangling.
if (Mangled.nextIf("n_")) {
paramCount++;
continue;
}
// Create the parameter.
NodePointer param =
NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParam,
paramCount);
// First handle options.
if (Mangled.nextIf("d_")) {
if (Mangled.nextIf("n_")) {
// Leave the parameter empty.
} else if (Mangled.nextIf("d_")) {
auto result = FUNCSIGSPEC_CREATE_INFO_KIND(Dead);
if (!result)
return nullptr;
@@ -902,9 +788,6 @@ private:
param->addChild(result);
}
if (!param || param->getNumChildren() == 0) {
return nullptr;
}
specialization->addChild(param);
paramCount++;
}
@@ -929,9 +812,8 @@ private:
return demangleFunctionSignatureSpecialization();
}
// For now just return a specialized attribute if we don't know what we are
// demangling. We will assert in a later commit.
return NodeFactory::create(Node::Kind::SpecializedAttribute);
// We don't know how to handle this specialization.
return nullptr;
}
NodePointer demangleDeclName() {
@@ -965,7 +847,7 @@ private:
return demangleIdentifier();
}
NodePointer demangleIdentifier(Node::Kind kind = Node::Kind::Unknown) {
NodePointer demangleIdentifier(Optional<Node::Kind> kind = None) {
if (!Mangled)
return nullptr;
@@ -985,7 +867,7 @@ private:
isOperator = true;
// Operator identifiers aren't valid in the contexts that are
// building more specific identifiers.
if (kind != Node::Kind::Unknown) return nullptr;
if (kind.hasValue()) return nullptr;
char op_mode = Mangled.next();
switch (op_mode) {
@@ -1003,7 +885,7 @@ private:
}
}
if (kind == Node::Kind::Unknown) kind = Node::Kind::Identifier;
if (!kind.hasValue()) kind = Node::Kind::Identifier;
Node::IndexType length;
if (!demangleNatural(length))
@@ -1042,7 +924,7 @@ private:
identifier = opDecodeBuffer;
}
return NodeFactory::create(kind, identifier);
return NodeFactory::create(*kind, identifier);
}
bool demangleIndex(Node::IndexType &natural) {
@@ -1077,7 +959,7 @@ private:
/// Demangle a <substitution>, given that we've already consumed the 'S'.
NodePointer demangleSubstitutionIndex() {
if (!Mangled)
return NodeFactory::create(Node::Kind::Failure);
return nullptr;
if (Mangled.nextIf('o'))
return NodeFactory::create(Node::Kind::Module, "ObjectiveC");
if (Mangled.nextIf('C'))
@@ -1106,9 +988,9 @@ private:
return createSwiftType(Node::Kind::Structure, "UInt");
Node::IndexType index_sub;
if (!demangleIndex(index_sub))
return NodeFactory::create(Node::Kind::Failure);
return nullptr;
if (index_sub >= Substitutions.size())
return NodeFactory::create(Node::Kind::Failure);
return nullptr;
return Substitutions[index_sub];
}
@@ -1216,18 +1098,11 @@ private:
NodePointer proto_list = NodeFactory::create(Node::Kind::ProtocolList);
NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
proto_list->addChild(type_list);
if (Mangled.nextIf('_')) {
return proto_list;
}
while (!Mangled.nextIf('_')) {
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);
type_list->addChild(std::move(proto));
}
return proto_list;
}
@@ -1406,40 +1281,42 @@ private:
/// \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 = NodeFactory::create(Node::Kind::Generics);
// FIXME: Swallow the mangled associated type constraints.
bool assocTypes = false;
Node::Kind nodeKind = Node::Kind::Archetype;
while (true) {
if (!assocTypes && Mangled.nextIf('U')) {
assocTypes = true;
if (nodeKind == Node::Kind::Archetype && Mangled.nextIf('U')) {
nodeKind = Node::Kind::AssociatedType;
continue;
}
NodePointer protocolList;
if (Mangled.nextIf('_')) {
if (!Mangled)
return nullptr;
char c = Mangled.peek();
if (c != '_' && c != 'S'
&& (assocTypes || c != 'U')
&& (nodeKind == Node::Kind::AssociatedType || c != 'U')
&& !isStartOfIdentifier(c))
break;
if (!assocTypes)
archetypes->addChild(NodeFactory::create(
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
} else {
NodePointer proto_list = demangleProtocolList();
if (!proto_list)
protocolList = demangleProtocolList();
if (!protocolList)
return nullptr;
if (assocTypes)
continue;
NodePointer arch_and_proto =
NodeFactory::create(Node::Kind::ArchetypeAndProtocol);
arch_and_proto->addChild(NodeFactory::create(
Node::Kind::ArchetypeRef, archetypeName(ArchetypeCount)));
arch_and_proto->addChild(proto_list);
archetypes->addChild(arch_and_proto);
}
++ArchetypeCount;
NodePointer archetype;
if (nodeKind == Node::Kind::Archetype) {
archetype =
NodeFactory::create(nodeKind, archetypeName(ArchetypeCount++));
} else {
archetype = NodeFactory::create(nodeKind);
}
if (protocolList) {
archetype->addChild(std::move(protocolList));
}
archetypes->addChild(std::move(archetype));
}
return archetypes;
}
@@ -1800,13 +1677,11 @@ private:
return block;
}
if (c == 'G') {
NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
NodePointer unboundType = demangleType();
if (!unboundType)
return nullptr;
if (Mangled.isEmpty())
return nullptr;
while (Mangled.peek() != '_') {
NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
while (!Mangled.nextIf('_')) {
NodePointer type = demangleType();
if (!type)
return nullptr;
@@ -1814,8 +1689,7 @@ private:
if (Mangled.isEmpty())
return nullptr;
}
Mangled.next();
Node::Kind bound_type_kind = Node::Kind::Unknown;
Node::Kind bound_type_kind;
switch (unboundType->getChild(0)->getKind()) { // look through Type node
case Node::Kind::Class:
bound_type_kind = Node::Kind::BoundGenericClass;
@@ -1827,7 +1701,7 @@ private:
bound_type_kind = Node::Kind::BoundGenericEnum;
break;
default:
assert(false && "trying to make a generic type application for a non class|struct|enum");
return nullptr;
}
NodePointer type_application =
NodeFactory::create(bound_type_kind);
@@ -1983,16 +1857,16 @@ private:
bool demangleReabstractSignature(NodePointer signature) {
if (Mangled.nextIf('G')) {
NodePointer generics = demangleGenericSignature();
if (!generics) return failure();
if (!generics) return false;
signature->addChild(std::move(generics));
}
NodePointer srcType = demangleType();
if (!srcType) return failure();
if (!srcType) return false;
signature->addChild(std::move(srcType));
NodePointer destType = demangleType();
if (!destType) return failure();
if (!destType) return false;
signature->addChild(std::move(destType));
return true;
@@ -2101,7 +1975,7 @@ private:
attr = demangleImplConvention(ImplConventionContext::Callee);
}
if (attr.empty()) {
return failure();
return false;
}
type->addChild(NodeFactory::create(Node::Kind::ImplConvention, attr));
return true;
@@ -2161,17 +2035,15 @@ swift::Demangle::demangleSymbolAsNode(const char *MangledName,
size_t MangledNameLength,
const DemangleOptions &Options) {
Demangler demangler(StringRef(MangledName, MangledNameLength));
demangler.demangle();
return demangler.getDemangled();
return demangler.demangleTopLevel();
}
static NodePointer
demangleTypeAsNode(const char *MangledName,
NodePointer
swift::Demangle::demangleTypeAsNode(const char *MangledName,
size_t MangledNameLength,
const DemangleOptions &Options) {
Demangler demangler(StringRef(MangledName, MangledNameLength));
demangler.demangleTypeName();
return demangler.getDemangled();
return demangler.demangleTypeName();
}
namespace {
@@ -2267,8 +2139,9 @@ private:
/// production.
bool isSimpleType(NodePointer pointer) {
switch (pointer->getKind()) {
case Node::Kind::ArchetypeAndProtocol:
case Node::Kind::Archetype:
case Node::Kind::ArchetypeRef:
case Node::Kind::AssociatedType:
case Node::Kind::AssociatedTypeRef:
case Node::Kind::BoundGenericClass:
case Node::Kind::BoundGenericEnum:
@@ -2292,14 +2165,12 @@ private:
case Node::Kind::SelfTypeRef:
case Node::Kind::Structure:
case Node::Kind::TupleElementName:
case Node::Kind::TupleElementType:
case Node::Kind::Type:
case Node::Kind::TypeAlias:
case Node::Kind::TypeList:
case Node::Kind::VariadicTuple:
return true;
case Node::Kind::Failure:
case Node::Kind::Allocator:
case Node::Kind::ArgumentTuple:
case Node::Kind::AutoClosureType:
@@ -2321,8 +2192,13 @@ private:
case Node::Kind::Extension:
case Node::Kind::FieldOffset:
case Node::Kind::Function:
case Node::Kind::FunctionSignatureSpecialization:
case Node::Kind::FunctionSignatureSpecializationParam:
case Node::Kind::FunctionSignatureSpecializationParamInfo:
case Node::Kind::FunctionType:
case Node::Kind::Generics:
case Node::Kind::GenericSpecialization:
case Node::Kind::GenericSpecializationParam:
case Node::Kind::GenericType:
case Node::Kind::GenericTypeMetadataPattern:
case Node::Kind::Getter:
@@ -2368,20 +2244,15 @@ private:
case Node::Kind::ReabstractionThunk:
case Node::Kind::ReabstractionThunkHelper:
case Node::Kind::Setter:
case Node::Kind::SpecializedAttribute:
case Node::Kind::SpecializationKind:
case Node::Kind::GenericSpecializationParam:
case Node::Kind::FunctionSignatureSpecializationParam:
case Node::Kind::FunctionSignatureSpecializationParamInfo:
case Node::Kind::Subscript:
case Node::Kind::Suffix:
case Node::Kind::ThinFunctionType:
case Node::Kind::TupleElement:
case Node::Kind::TypeMangling:
case Node::Kind::TypeMetadata:
case Node::Kind::TypeMetadataAccessFunction:
case Node::Kind::TypeMetadataLazyCache:
case Node::Kind::UncurriedFunctionType:
case Node::Kind::Unknown:
case Node::Kind::Unmanaged:
case Node::Kind::Unowned:
case Node::Kind::UnsafeAddressor:
@@ -2581,10 +2452,8 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
Node::Kind kind = pointer->getKind();
switch (kind) {
case Node::Kind::Failure:
return;
case Node::Kind::Directness:
Printer << pointer->getText() << " ";
Printer << toString(Directness(pointer->getIndex())) << " ";
return;
case Node::Kind::Extension:
assert(pointer->getNumChildren() == 2 && "Extension expects 2 children.");
@@ -2632,6 +2501,9 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
case Node::Kind::Type:
print(pointer->getChild(0), asContext);
return;
case Node::Kind::TypeMangling:
print(pointer->getChild(0));
return;
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Enum:
@@ -2718,9 +2590,6 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
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();
@@ -2754,19 +2623,26 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
case Node::Kind::DynamicAttribute:
Printer << "dynamic ";
return;
case Node::Kind::SpecializedAttribute:
print(pointer->getChild(0));
Printer << " specialization <";
for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) {
if (i >= 2)
case Node::Kind::FunctionSignatureSpecialization:
case Node::Kind::GenericSpecialization: {
if (pointer->getKind() == Node::Kind::FunctionSignatureSpecialization) {
Printer << "function signature specialization <";
} else {
Printer << "generic specialization <";
}
bool hasPrevious = false;
for (unsigned i = 0, e = pointer->getNumChildren(); i < e; ++i) {
// Ignore empty specializations.
if (!pointer->getChild(i)->hasChildren())
continue;
if (hasPrevious)
Printer << ", ";
print(pointer->getChild(i));
hasPrevious = true;
}
Printer << "> of ";
return;
case Node::Kind::SpecializationKind:
Printer << pointer->getText();
return;
}
case Node::Kind::GenericSpecializationParam:
print(pointer->getChild(0));
for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) {
@@ -2938,7 +2814,8 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
print(pointer->getChild(0));
return;
case Node::Kind::ValueWitness:
Printer << pointer->getText() << " value witness for ";
Printer << toString(ValueWitnessKind(pointer->getIndex()))
<< " value witness for ";
print(pointer->getFirstChild());
return;
case Node::Kind::ValueWitnessTable:
@@ -3027,10 +2904,27 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
if (pointer->getNumChildren() == 0)
return;
Printer << "<";
printChildren(pointer, ", ");
print(pointer->getChild(0));
for (unsigned i = 1, e = pointer->getNumChildren(); i != e; ++i) {
auto child = pointer->getChild(i);
if (child->getKind() != Node::Kind::Archetype) break;
Printer << ", ";
print(child);
}
Printer << ">";
return;
}
case Node::Kind::Archetype: {
Printer << pointer->getText();
if (pointer->hasChildren()) {
Printer << " : ";
print(pointer->getChild(0));
}
return;
}
case Node::Kind::AssociatedType:
// Don't print for now.
return;
case Node::Kind::QualifiedArchetype: {
if (pointer->getNumChildren() < 2)
return;
@@ -3122,14 +3016,6 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
case Node::Kind::TypeList:
printChildren(pointer);
return;
case Node::Kind::ArchetypeAndProtocol: {
NodePointer child0 = pointer->getChild(0);
NodePointer child1 = pointer->getChild(1);
print(child0);
Printer << " : ";
print(child1);
return;
}
case Node::Kind::ImplConvention:
Printer << pointer->getText();
return;
@@ -3143,8 +3029,6 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
case Node::Kind::ImplFunctionType:
printImplFunctionType(pointer);
return;
case Node::Kind::Unknown:
return;
case Node::Kind::ErrorType:
Printer << "<ERROR TYPE>";
return;
@@ -3253,3 +3137,4 @@ std::string Demangle::demangleTypeAsString(const char *MangledName,
return mangled.str();
return demangling;
}

View File

@@ -32,6 +32,10 @@ static void printNode(llvm::raw_ostream &Out, const Node *node,
unsigned depth) {
// Indent two spaces per depth.
Out.indent(depth * 2);
if (!node) {
Out << "<<NULL>>";
return;
}
Out << "kind=" << getNodeKindString(node->getKind());
if (node->hasText()) {
Out << ", text=\"" << node->getText() << '\"';

1361
lib/Basic/Remangle.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,10 @@ static llvm::cl::opt<bool>
TreeOnly("tree-only",
llvm::cl::desc("Tree-only mode (do not show the demangled string)"));
static llvm::cl::opt<bool>
RemangleMode("remangle",
llvm::cl::desc("Remangle mode (show the remangled string)"));
static llvm::cl::opt<bool>
DisableSugar("no-sugar",
llvm::cl::desc("No sugar mode (disable common language idioms such as ? and [] from the output)"));
@@ -54,6 +58,11 @@ static void demangle(llvm::raw_ostream &os, llvm::StringRef name,
llvm::outs() << "Demangling for " << name << '\n';
swift::demangle_wrappers::NodeDumper(pointer).print(llvm::outs());
}
if (RemangleMode) {
llvm::outs() << "Remangling for " << name << " ---> ";
llvm::outs() << swift::Demangle::mangleNode(pointer);
llvm::outs() << '\n';
}
if (!TreeOnly) {
std::string string = swift::Demangle::nodeToString(pointer, options);
if (!CompactMode)

View File

@@ -1129,18 +1129,20 @@ static int doPrintAST(const CompilerInvocation &InitInvok,
demangle_wrappers::demangleSymbolAsNode(MangledNameToFind);
using NodeKind = Demangle::Node::Kind;
if (node->getKind() != NodeKind::Global) {
if (!node) {
llvm::errs() << "Unable to demangle name.\n";
return EXIT_FAILURE;
}
node = node->getFirstChild();
// FIXME: Look up things other than types.
if (node->getKind() != NodeKind::Type) {
if (node->getKind() != NodeKind::TypeMangling) {
llvm::errs() << "Name does not refer to a type.\n";
return EXIT_FAILURE;
}
node = node->getFirstChild();
assert(node->getKind() == NodeKind::Type);
node = node->getFirstChild();
switch (node->getKind()) {
case NodeKind::Class: