blob: 70ded115733accac8d3741a8dfc344e37f07e581 [file] [log] [blame]
//===--- Demangler.cpp - String to Node-Tree Demangling -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 implements new Swift de-mangler.
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/Demangler.h"
#include "swift/Basic/ManglingUtils.h"
#include "swift/Basic/ManglingMacros.h"
#include "swift/Basic/Punycode.h"
#include "swift/Basic/Range.h"
#include "swift/Strings.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Compiler.h"
using namespace swift;
using namespace NewMangling;
using swift::Demangle::FunctionSigSpecializationParamKind;
//////////////////////////////////
// Private utility functions //
//////////////////////////////////
[[noreturn]]
static void demangler_unreachable(const char *Message) {
fprintf(stderr, "fatal error: %s\n", Message);
std::abort();
}
namespace {
static bool isDeclName(Node::Kind kind) {
switch (kind) {
case Node::Kind::Identifier:
case Node::Kind::LocalDeclName:
case Node::Kind::PrivateDeclName:
case Node::Kind::PrefixOperator:
case Node::Kind::PostfixOperator:
case Node::Kind::InfixOperator:
return true;
default:
return false;
}
}
static bool isContext(Node::Kind kind) {
switch (kind) {
#define NODE(ID)
#define CONTEXT_NODE(ID) \
case Node::Kind::ID:
#include "swift/Basic/DemangleNodes.def"
return true;
default:
return false;
}
}
static bool isNominal(Node::Kind kind) {
switch (kind) {
case Node::Kind::Structure:
case Node::Kind::Class:
case Node::Kind::Enum:
case Node::Kind::Protocol:
return true;
default:
return false;
}
}
static bool isEntity(Node::Kind kind) {
// Also accepts some kind which are not entities.
if (kind == Node::Kind::Type)
return true;
return isContext(kind);
}
static bool isRequirement(Node::Kind kind) {
switch (kind) {
case Node::Kind::DependentGenericSameTypeRequirement:
case Node::Kind::DependentGenericLayoutRequirement:
case Node::Kind::DependentGenericConformanceRequirement:
return true;
default:
return false;
}
}
static bool isFunctionAttr(Node::Kind kind) {
switch (kind) {
case Node::Kind::FunctionSignatureSpecialization:
case Node::Kind::GenericSpecialization:
case Node::Kind::GenericSpecializationNotReAbstracted:
case Node::Kind::GenericPartialSpecialization:
case Node::Kind::GenericPartialSpecializationNotReAbstracted:
case Node::Kind::ObjCAttribute:
case Node::Kind::NonObjCAttribute:
case Node::Kind::DynamicAttribute:
case Node::Kind::DirectMethodReferenceAttribute:
case Node::Kind::VTableAttribute:
case Node::Kind::PartialApplyForwarder:
case Node::Kind::PartialApplyObjCForwarder:
return true;
default:
return false;
}
}
} // anonymous namespace
namespace swift {
namespace Demangle {
//////////////////////////////////
// Context member functions //
//////////////////////////////////
Context::Context() : D(new Demangler) {
}
Context::~Context() {
delete D;
}
void Context::clear() {
D->clear();
}
NodePointer Context::demangleSymbolAsNode(llvm::StringRef MangledName) {
#ifndef NO_NEW_DEMANGLING
if (MangledName.startswith(MANGLING_PREFIX_STR)) {
return D->demangleSymbol(MangledName);
}
#endif
return demangleOldSymbolAsNode(MangledName, *D);
}
NodePointer Context::demangleTypeAsNode(llvm::StringRef MangledName) {
return D->demangleType(MangledName);
}
std::string Context::demangleSymbolAsString(llvm::StringRef MangledName,
const DemangleOptions &Options) {
NodePointer root = demangleSymbolAsNode(MangledName);
if (!root) return MangledName.str();
std::string demangling = nodeToString(root, Options);
if (demangling.empty())
return MangledName.str();
return demangling;
}
std::string Context::demangleTypeAsString(llvm::StringRef MangledName,
const DemangleOptions &Options) {
NodePointer root = demangleTypeAsNode(MangledName);
if (!root) return MangledName.str();
std::string demangling = nodeToString(root, Options);
if (demangling.empty())
return MangledName.str();
return demangling;
}
bool Context::isThunkSymbol(llvm::StringRef MangledName) {
if (MangledName.startswith(MANGLING_PREFIX_STR)) {
// First do a quick check
if (MangledName.endswith("TA") || // partial application forwarder
MangledName.endswith("Ta") || // ObjC partial application forwarder
MangledName.endswith("To") || // swift-as-ObjC thunk
MangledName.endswith("TO")) { // ObjC-as-swift thunk
// To avoid false positives, we need to fully demangle the symbol.
NodePointer Nd = D->demangleSymbol(MangledName);
if (!Nd || Nd->getKind() != Node::Kind::Global ||
Nd->getNumChildren() == 0)
return false;
switch (Nd->getFirstChild()->getKind()) {
case Node::Kind::ObjCAttribute:
case Node::Kind::NonObjCAttribute:
case Node::Kind::PartialApplyObjCForwarder:
case Node::Kind::PartialApplyForwarder:
return true;
default:
break;
}
}
return false;
}
if (MangledName.startswith("_T")) {
// Old mangling.
StringRef Remaining = MangledName.substr(2);
if (Remaining.startswith("To") || // swift-as-ObjC thunk
Remaining.startswith("TO") || // ObjC-as-swift thunk
Remaining.startswith("PA")) { // (ObjC) partial application forwarder
return true;
}
}
return false;
}
NodePointer Context::createNode(Node::Kind K) {
return D->createNode(K);
}
NodePointer Context::createNode(Node::Kind K, Node::IndexType Index) {
return D->createNode(K, Index);
}
NodePointer Context::createNode(Node::Kind K, llvm::StringRef Text) {
return D->createNode(K, Text);
}
//////////////////////////////////
// Public utility functions //
//////////////////////////////////
std::string demangleSymbolAsString(const char *MangledName,
size_t MangledNameLength,
const DemangleOptions &Options) {
Context Ctx;
return Ctx.demangleSymbolAsString(StringRef(MangledName, MangledNameLength),
Options);
}
std::string demangleTypeAsString(const char *MangledName,
size_t MangledNameLength,
const DemangleOptions &Options) {
Context Ctx;
return Ctx.demangleTypeAsString(StringRef(MangledName, MangledNameLength),
Options);
}
//////////////////////////////////
// Node member functions //
//////////////////////////////////
void Node::addChild(NodePointer Child, NodeFactory &Factory) {
assert(Child && "adding null child!");
if (NumChildren >= ReservedChildren)
Factory.Reallocate(Children, ReservedChildren, 1);
assert(NumChildren < ReservedChildren);
Children[NumChildren++] = Child;
}
void Node::addChild(NodePointer Child, Context &Ctx) {
addChild(Child, *Ctx.D);
}
//////////////////////////////////
// NodeFactory member functions //
//////////////////////////////////
void NodeFactory::freeSlabs(Slab *slab) {
while (slab) {
Slab *prev = slab->Previous;
#ifdef NODE_FACTORY_DEBUGGING
std::cerr << " free slab = " << slab << "\n";
#endif
free(slab);
slab = prev;
}
}
void NodeFactory::clear() {
if (CurrentSlab) {
freeSlabs(CurrentSlab->Previous);
// Recycle the last allocated slab.
// Note that the size of the last slab is at least as big as all previous
// slabs combined. Therefore it's not worth the effort of reusing all slabs.
// The slab size also stays the same. So at some point the demangling
// process converges to a single large slab across repeated demangle-clear
// cycles.
CurrentSlab->Previous = nullptr;
CurPtr = (char *)(CurrentSlab + 1);
assert(End == CurPtr + SlabSize);
}
}
NodePointer NodeFactory::createNode(Node::Kind K) {
return new (Allocate<Node>()) Node(K);
}
NodePointer NodeFactory::createNode(Node::Kind K, Node::IndexType Index) {
return new (Allocate<Node>()) Node(K, Index);
}
NodePointer NodeFactory::createNode(Node::Kind K, llvm::StringRef Text) {
return new (Allocate<Node>()) Node(K, Text.copy(*this));
}
NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
return new (Allocate<Node>()) Node(K, llvm::StringRef(Text));
}
//////////////////////////////////
// Demangler member functions //
//////////////////////////////////
void Demangler::init(StringRef MangledName) {
NodeStack.clear();
Substitutions.clear();
PendingSubstitutions.clear();
NumWords = 0;
Text = MangledName;
Pos = 0;
}
NodePointer Demangler::demangleSymbol(StringRef MangledName) {
init(MangledName);
if (!nextIf(MANGLING_PREFIX_STR))
return nullptr;
NodePointer topLevel = createNode(Node::Kind::Global);
parseAndPushNodes();
// Let a trailing '_' be part of the not demangled suffix.
popNode(Node::Kind::FirstElementMarker);
size_t EndPos = (NodeStack.empty() ? 0 : NodeStack.back().Pos);
NodePointer Parent = topLevel;
while (NodePointer FuncAttr = popNode(isFunctionAttr)) {
Parent->addChild(FuncAttr, *this);
if (FuncAttr->getKind() == Node::Kind::PartialApplyForwarder ||
FuncAttr->getKind() == Node::Kind::PartialApplyObjCForwarder)
Parent = FuncAttr;
}
for (const NodeWithPos &NWP : NodeStack) {
NodePointer Nd = NWP.Node;
switch (Nd->getKind()) {
case Node::Kind::Type:
Parent->addChild(Nd->getFirstChild(), *this);
break;
case Node::Kind::Identifier:
if (StringRef(Nd->getText()).startswith("_T")) {
NodePointer Global = demangleOldSymbolAsNode(Nd->getText(), *this);
if (Global && Global->getKind() == Node::Kind::Global) {
for (NodePointer Child : *Global) {
Parent->addChild(Child, *this);
}
break;
}
}
LLVM_FALLTHROUGH;
default:
Parent->addChild(Nd, *this);
break;
}
}
if (EndPos < Text.size()) {
topLevel->addChild(createNode(Node::Kind::Suffix, Text.substr(EndPos)), *this);
}
return topLevel;
}
NodePointer Demangler::demangleType(StringRef MangledName) {
init(MangledName);
parseAndPushNodes();
if (NodePointer Result = popNode())
return Result;
return createNode(Node::Kind::Suffix, Text);
}
void Demangler::parseAndPushNodes() {
int Idx = 0;
while (!Text.empty()) {
NodePointer Node = demangleOperator();
if (!Node)
break;
pushNode(Node);
Idx++;
}
}
NodePointer Demangler::addChild(NodePointer Parent, NodePointer Child) {
if (!Parent || !Child)
return nullptr;
Parent->addChild(Child, *this);
return Parent;
}
NodePointer Demangler::createWithChild(Node::Kind kind,
NodePointer Child) {
if (!Child)
return nullptr;
NodePointer Nd = createNode(kind);
Nd->addChild(Child, *this);
return Nd;
}
NodePointer Demangler::createType(NodePointer Child) {
return createWithChild(Node::Kind::Type, Child);
}
NodePointer Demangler::Demangler::createWithChildren(Node::Kind kind,
NodePointer Child1, NodePointer Child2) {
if (!Child1 || !Child2)
return nullptr;
NodePointer Nd = createNode(kind);
Nd->addChild(Child1, *this);
Nd->addChild(Child2, *this);
return Nd;
}
NodePointer Demangler::createWithChildren(Node::Kind kind,
NodePointer Child1,
NodePointer Child2,
NodePointer Child3) {
if (!Child1 || !Child2 || !Child3)
return nullptr;
NodePointer Nd = createNode(kind);
Nd->addChild(Child1, *this);
Nd->addChild(Child2, *this);
Nd->addChild(Child3, *this);
return Nd;
}
NodePointer Demangler::changeKind(NodePointer Node, Node::Kind NewKind) {
if (!Node)
return nullptr;
NodePointer NewNode = nullptr;
if (Node->hasText()) {
NewNode = createNode(NewKind, Node->getText());
} else if (Node->hasIndex()) {
NewNode = createNode(NewKind, Node->getIndex());
} else {
NewNode = createNode(NewKind);
}
for (NodePointer Child : *Node) {
NewNode->addChild(Child, *this);
}
return NewNode;
}
NodePointer Demangler::demangleOperator() {
switch (char c = nextChar()) {
case 'A': return demangleMultiSubstitutions();
case 'B': return demangleBuiltinType();
case 'C': return demangleNominalType(Node::Kind::Class);
case 'D': return createWithChild(Node::Kind::TypeMangling,
popNode(Node::Kind::Type));
case 'E': return demangleExtensionContext();
case 'F': return demanglePlainFunction();
case 'G': return demangleBoundGenericType();
case 'I': return demangleImplFunctionType();
case 'K': return createNode(Node::Kind::ThrowsAnnotation);
case 'L': return demangleLocalIdentifier();
case 'M': return demangleMetatype();
case 'N': return createWithChild(Node::Kind::TypeMetadata,
popNode(Node::Kind::Type));
case 'O': return demangleNominalType(Node::Kind::Enum);
case 'P': return demangleNominalType(Node::Kind::Protocol);
case 'Q': return demangleArchetype();
case 'R': return demangleGenericRequirement();
case 'S': return demangleKnownType();
case 'T': return demangleThunkOrSpecialization();
case 'V': return demangleNominalType(Node::Kind::Structure);
case 'W': return demangleWitness();
case 'X': return demangleSpecialType();
case 'Z': return createWithChild(Node::Kind::Static, popNode(isEntity));
case 'a': return demangleTypeAlias();
case 'c': return popFunctionType(Node::Kind::FunctionType);
case 'd': return createNode(Node::Kind::VariadicMarker);
case 'f': return demangleFunctionEntity();
case 'i': return demangleEntity(Node::Kind::Subscript);
case 'l': return demangleGenericSignature(/*hasParamCounts*/ false);
case 'm': return createType(createWithChild(Node::Kind::Metatype,
popNode(Node::Kind::Type)));
case 'o': return demangleOperatorIdentifier();
case 'p': return demangleProtocolListType();
case 'q': return createType(demangleGenericParamIndex());
case 'r': return demangleGenericSignature(/*hasParamCounts*/ true);
case 's': return createNode(Node::Kind::Module, STDLIB_NAME);
case 't': return popTuple();
case 'u': return demangleGenericType();
case 'v': return demangleEntity(Node::Kind::Variable);
case 'w': return demangleValueWitness();
case 'x': return createType(getDependentGenericParamType(0, 0));
case 'y': return createNode(Node::Kind::EmptyList);
case 'z': return createType(createWithChild(Node::Kind::InOut,
popTypeAndGetChild()));
case '_': return createNode(Node::Kind::FirstElementMarker);
default:
pushBack();
return demangleIdentifier();
}
}
int Demangler::demangleNatural() {
if (!isDigit(peekChar()))
return -1000;
int num = 0;
while (true) {
char c = peekChar();
if (!isDigit(c))
return num;
int newNum = (10 * num) + (c - '0');
if (newNum < num)
return -1000;
num = newNum;
nextChar();
}
}
int Demangler::demangleIndex() {
if (nextIf('_'))
return 0;
int num = demangleNatural();
if (num >= 0 && nextIf('_'))
return num + 1;
return -1000;
}
NodePointer Demangler::demangleIndexAsNode() {
int Idx = demangleIndex();
if (Idx >= 0)
return createNode(Node::Kind::Number, Idx);
return nullptr;
}
NodePointer Demangler::demangleMultiSubstitutions() {
while (true) {
char c = nextChar();
if (isLowerLetter(c)) {
unsigned Idx = c - 'a';
if (Idx >= Substitutions.size())
return nullptr;
pushNode(Substitutions[Idx]);
continue;
}
if (isUpperLetter(c)) {
unsigned Idx = c - 'A';
if (Idx >= Substitutions.size())
return nullptr;
return Substitutions[Idx];
}
pushBack();
unsigned Idx = demangleIndex() + 26;
if (Idx >= Substitutions.size())
return nullptr;
return Substitutions[Idx];
}
}
NodePointer Demangler::createSwiftType(Node::Kind typeKind, StringRef name) {
return createType(createWithChildren(typeKind,
createNode(Node::Kind::Module, STDLIB_NAME),
createNode(Node::Kind::Identifier, name)));
}
NodePointer Demangler::demangleKnownType() {
switch (nextChar()) {
case 'o':
return createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
case 'C':
return createNode(Node::Kind::Module, MANGLING_MODULE_C);
case 'a':
return createSwiftType(Node::Kind::Structure, "Array");
case 'b':
return createSwiftType(Node::Kind::Structure, "Bool");
case 'c':
return createSwiftType(Node::Kind::Structure, "UnicodeScalar");
case 'd':
return createSwiftType(Node::Kind::Structure, "Double");
case 'f':
return createSwiftType(Node::Kind::Structure, "Float");
case 'i':
return createSwiftType(Node::Kind::Structure, "Int");
case 'V':
return createSwiftType(Node::Kind::Structure, "UnsafeRawPointer");
case 'v':
return createSwiftType(Node::Kind::Structure, "UnsafeMutableRawPointer");
case 'P':
return createSwiftType(Node::Kind::Structure, "UnsafePointer");
case 'p':
return createSwiftType(Node::Kind::Structure, "UnsafeMutablePointer");
case 'q':
return createSwiftType(Node::Kind::Enum, "Optional");
case 'Q':
return createSwiftType(Node::Kind::Enum, "ImplicitlyUnwrappedOptional");
case 'R':
return createSwiftType(Node::Kind::Structure, "UnsafeBufferPointer");
case 'r':
return createSwiftType(Node::Kind::Structure, "UnsafeMutableBufferPointer");
case 'S':
return createSwiftType(Node::Kind::Structure, "String");
case 'u':
return createSwiftType(Node::Kind::Structure, "UInt");
case 'g':
return createType(createWithChildren(Node::Kind::BoundGenericEnum,
createSwiftType(Node::Kind::Enum, "Optional"),
createWithChild(Node::Kind::TypeList, popNode(Node::Kind::Type))));
default:
return nullptr;
}
}
NodePointer Demangler::demangleIdentifier() {
bool hasWordSubsts = false;
bool isPunycoded = false;
char c = peekChar();
if (!isDigit(c))
return nullptr;
if (c == '0') {
nextChar();
if (peekChar() == '0') {
nextChar();
isPunycoded = true;
} else {
hasWordSubsts = true;
}
}
std::string Identifier;
do {
while (hasWordSubsts && isLetter(peekChar())) {
char c = nextChar();
int WordIdx = 0;
if (isLowerLetter(c)) {
WordIdx = c - 'a';
} else {
assert(isUpperLetter(c));
WordIdx = c - 'A';
hasWordSubsts = false;
}
if (WordIdx >= NumWords)
return nullptr;
assert(WordIdx < MaxNumWords);
StringRef Slice = Words[WordIdx];
Identifier.append(Slice.data(), Slice.size());
}
if (nextIf('0'))
break;
int numChars = demangleNatural();
if (numChars <= 0)
return nullptr;
if (isPunycoded)
nextIf('_');
if (Pos + numChars > Text.size())
return nullptr;
StringRef Slice = StringRef(Text.data() + Pos, numChars);
if (isPunycoded) {
if (!Punycode::decodePunycodeUTF8(Slice, Identifier))
return nullptr;
} else {
Identifier.append(Slice.data(), Slice.size());
int wordStartPos = -1;
for (int Idx = 0, End = (int)Slice.size(); Idx <= End; ++Idx) {
char c = (Idx < End ? Slice[Idx] : 0);
if (wordStartPos >= 0 && isWordEnd(c, Slice[Idx - 1])) {
if (Idx - wordStartPos >= 2 && NumWords < MaxNumWords) {
StringRef word(Slice.begin() + wordStartPos, Idx - wordStartPos);
Words[NumWords++] = word;
}
wordStartPos = -1;
}
if (wordStartPos < 0 && isWordStart(c)) {
wordStartPos = Idx;
}
}
}
Pos += numChars;
} while (hasWordSubsts);
if (Identifier.empty())
return nullptr;
NodePointer Ident = createNode(Node::Kind::Identifier, Identifier);
addSubstitution(Ident);
return Ident;
}
NodePointer Demangler::demangleOperatorIdentifier() {
NodePointer Ident = popNode(Node::Kind::Identifier);
static const char op_char_table[] = "& @/= > <*!|+?%-~ ^ .";
std::string OpStr;
OpStr.reserve(Ident->getText().size());
for (signed char c : Ident->getText()) {
if (c < 0) {
// Pass through Unicode characters.
OpStr.push_back(c);
continue;
}
if (!isLowerLetter(c))
return nullptr;
char o = op_char_table[c - 'a'];
if (o == ' ')
return nullptr;
OpStr.push_back(o);
}
switch (nextChar()) {
case 'i': return createNode(Node::Kind::InfixOperator, OpStr);
case 'p': return createNode(Node::Kind::PrefixOperator, OpStr);
case 'P': return createNode(Node::Kind::PostfixOperator, OpStr);
default: return nullptr;
}
}
NodePointer Demangler::demangleLocalIdentifier() {
if (nextIf('L')) {
NodePointer discriminator = popNode(Node::Kind::Identifier);
NodePointer name = popNode(isDeclName);
return createWithChildren(Node::Kind::PrivateDeclName, discriminator, name);
}
NodePointer discriminator = demangleIndexAsNode();
NodePointer name = popNode(isDeclName);
return createWithChildren(Node::Kind::LocalDeclName, discriminator, name);
}
NodePointer Demangler::popModule() {
if (NodePointer Ident = popNode(Node::Kind::Identifier))
return changeKind(Ident, Node::Kind::Module);
return popNode(Node::Kind::Module);
}
NodePointer Demangler::popContext() {
if (NodePointer Mod = popModule())
return Mod;
if (NodePointer Ty = popNode(Node::Kind::Type)) {
if (Ty->getNumChildren() != 1)
return nullptr;
NodePointer Child = Ty->getFirstChild();
if (!isContext(Child->getKind()))
return nullptr;
return Child;
}
return popNode(isContext);
}
NodePointer Demangler::popTypeAndGetChild() {
NodePointer Ty = popNode(Node::Kind::Type);
if (!Ty || Ty->getNumChildren() != 1)
return nullptr;
return Ty->getFirstChild();
}
NodePointer Demangler::popTypeAndGetNominal() {
NodePointer Child = popTypeAndGetChild();
if (Child && isNominal(Child->getKind()))
return Child;
return nullptr;
}
NodePointer Demangler::demangleBuiltinType() {
NodePointer Ty = nullptr;
switch (nextChar()) {
case 'b':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.BridgeObject");
break;
case 'B':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.UnsafeValueBuffer");
break;
case 'f': {
int size = demangleIndex() - 1;
if (size <= 0)
return nullptr;
Ty = createNode(Node::Kind::BuiltinTypeName,
std::move(DemanglerPrinter() << "Builtin.Float" << size).str());
break;
}
case 'i': {
int size = demangleIndex() - 1;
if (size <= 0)
return nullptr;
Ty = createNode(Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Int" << size).str());
break;
}
case 'v': {
int elts = demangleIndex() - 1;
if (elts <= 0)
return nullptr;
NodePointer EltType = popTypeAndGetChild();
if (!EltType || EltType->getKind() != Node::Kind::BuiltinTypeName ||
!EltType->getText().startswith("Builtin."))
return nullptr;
Ty = createNode(Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "x" <<
EltType->getText().substr(sizeof("Builtin.") - 1)).str());
break;
}
case 'O':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.UnknownObject");
break;
case 'o':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.NativeObject");
break;
case 'p':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.RawPointer");
break;
case 'w':
Ty = createNode(Node::Kind::BuiltinTypeName,
"Builtin.Word");
break;
default:
return nullptr;
}
return createType(Ty);
}
NodePointer Demangler::demangleNominalType(Node::Kind kind) {
NodePointer Name = popNode(isDeclName);
NodePointer Ctx = popContext();
NodePointer NTy = createType(createWithChildren(kind, Ctx, Name));
addSubstitution(NTy);
return NTy;
}
NodePointer Demangler::demangleTypeAlias() {
NodePointer Name = popNode(isDeclName);
NodePointer Ctx = popContext();
return createType(createWithChildren(Node::Kind::TypeAlias, Ctx, Name));
}
NodePointer Demangler::demangleExtensionContext() {
NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
NodePointer Module = popModule();
NodePointer Type = popTypeAndGetNominal();
NodePointer Ext = createWithChildren(Node::Kind::Extension, Module, Type);
if (GenSig)
Ext = addChild(Ext, GenSig);
return Ext;
}
NodePointer Demangler::demanglePlainFunction() {
NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
NodePointer Type = popFunctionType(Node::Kind::FunctionType);
if (GenSig) {
Type = createType(createWithChildren(Node::Kind::DependentGenericType,
GenSig, Type));
}
NodePointer Name = popNode(isDeclName);
NodePointer Ctx = popContext();
return createWithChildren(Node::Kind::Function, Ctx, Name, Type);
}
NodePointer Demangler::popFunctionType(Node::Kind kind) {
NodePointer FuncType = createNode(kind);
addChild(FuncType, popNode(Node::Kind::ThrowsAnnotation));
FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ArgumentTuple));
FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ReturnType));
return createType(FuncType);
}
NodePointer Demangler::popFunctionParams(Node::Kind kind) {
NodePointer ParamsType = nullptr;
if (popNode(Node::Kind::EmptyList)) {
ParamsType = createType(createNode(Node::Kind::NonVariadicTuple));
} else {
ParamsType = popNode(Node::Kind::Type);
}
return createWithChild(kind, ParamsType);
}
NodePointer Demangler::popTuple() {
NodePointer Root = createNode(popNode(Node::Kind::VariadicMarker) ?
Node::Kind::VariadicTuple :
Node::Kind::NonVariadicTuple);
if (!popNode(Node::Kind::EmptyList)) {
std::vector<NodePointer> Nodes;
bool firstElem = false;
do {
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
NodePointer TupleElmt = createNode(Node::Kind::TupleElement);
if (NodePointer Ident = popNode(Node::Kind::Identifier)) {
TupleElmt->addChild(createNode(Node::Kind::TupleElementName,
Ident->getText()), *this);
}
NodePointer Ty = popNode(Node::Kind::Type);
if (!Ty)
return nullptr;
TupleElmt->addChild(Ty, *this);
Nodes.push_back(TupleElmt);
} while (!firstElem);
while (NodePointer TupleElmt = pop_back_val(Nodes)) {
Root->addChild(TupleElmt, *this);
}
}
return createType(Root);
}
NodePointer Demangler::popTypeList() {
NodePointer Root = createNode(Node::Kind::TypeList);
if (!popNode(Node::Kind::EmptyList)) {
std::vector<NodePointer> Nodes;
bool firstElem = false;
do {
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
NodePointer Ty = popNode(Node::Kind::Type);
if (!Ty)
return nullptr;
Nodes.push_back(Ty);
} while (!firstElem);
while (NodePointer Ty = pop_back_val(Nodes)) {
Root->addChild(Ty, *this);
}
}
return Root;
}
NodePointer Demangler::popProtocol() {
NodePointer Name = popNode(isDeclName);
NodePointer Ctx = popContext();
NodePointer Proto = createWithChildren(Node::Kind::Protocol, Ctx, Name);
return createType(Proto);
}
NodePointer Demangler::demangleBoundGenericType() {
std::vector<NodePointer> TypeListList;
std::vector<NodePointer> Types;
for (;;) {
NodePointer TList = createNode(Node::Kind::TypeList);
TypeListList.push_back(TList);
while (NodePointer Ty = popNode(Node::Kind::Type)) {
Types.push_back(Ty);
}
while (NodePointer Ty = pop_back_val(Types)) {
TList->addChild(Ty, *this);
}
if (popNode(Node::Kind::EmptyList))
break;
if (!popNode(Node::Kind::FirstElementMarker))
return nullptr;
}
NodePointer Nominal = popTypeAndGetNominal();
return createType(demangleBoundGenericArgs(Nominal, TypeListList, 0));
}
NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
const std::vector<NodePointer> &TypeLists,
size_t TypeListIdx) {
if (!Nominal || Nominal->getNumChildren() < 2)
return nullptr;
if (TypeListIdx >= TypeLists.size())
return nullptr;
NodePointer args = TypeLists[TypeListIdx];
// Generic arguments for the outermost type come first.
NodePointer Context = Nominal->getFirstChild();
if (Context->getKind() != Node::Kind::Module &&
Context->getKind() != Node::Kind::Function &&
Context->getKind() != Node::Kind::Extension) {
NodePointer BoundParent = demangleBoundGenericArgs(Context, TypeLists,
TypeListIdx + 1);
// Rebuild this type with the new parent type, which may have
// had its generic arguments applied.
Nominal = createWithChildren(Nominal->getKind(), BoundParent,
Nominal->getChild(1));
if (!Nominal)
return nullptr;
}
// If there were no arguments at this level there is nothing left
// to do.
if (args->getNumChildren() == 0)
return Nominal;
Node::Kind kind;
switch (Nominal->getKind()) {
case Node::Kind::Class:
kind = Node::Kind::BoundGenericClass;
break;
case Node::Kind::Structure:
kind = Node::Kind::BoundGenericStructure;
break;
case Node::Kind::Enum:
kind = Node::Kind::BoundGenericEnum;
break;
default:
return nullptr;
}
return createWithChildren(kind, createType(Nominal), args);
}
NodePointer Demangler::demangleImplParamConvention() {
StringRef attr;
switch (nextChar()) {
case 'i': attr = "@in"; break;
case 'l': attr = "@inout"; break;
case 'b': attr = "@inout_aliasable"; break;
case 'n': attr = "@in_guaranteed"; break;
case 'x': attr = "@owned"; break;
case 'g': attr = "@guaranteed"; break;
case 'e': attr = "@deallocating"; break;
case 'y': attr = "@unowned"; break;
default:
pushBack();
return nullptr;
}
return createWithChild(Node::Kind::ImplParameter,
createNode(Node::Kind::ImplConvention, attr));
}
NodePointer Demangler::demangleImplResultConvention(Node::Kind ConvKind) {
StringRef attr;
switch (nextChar()) {
case 'r': attr = "@out"; break;
case 'o': attr = "@owned"; break;
case 'd': attr = "@unowned"; break;
case 'u': attr = "@unowned_inner_pointer"; break;
case 'a': attr = "@autoreleased"; break;
default:
pushBack();
return nullptr;
}
return createWithChild(ConvKind,
createNode(Node::Kind::ImplConvention, attr));
}
NodePointer Demangler::demangleImplFunctionType() {
NodePointer type = createNode(Node::Kind::ImplFunctionType);
NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
if (GenSig && nextIf('P'))
GenSig = changeKind(GenSig, Node::Kind::DependentPseudogenericSignature);
StringRef CAttr;
switch (nextChar()) {
case 'y': CAttr = "@callee_unowned"; break;
case 'g': CAttr = "@callee_guaranteed"; break;
case 'x': CAttr = "@callee_owned"; break;
case 't': CAttr = "@convention(thin)"; break;
default: return nullptr;
}
type->addChild(createNode(Node::Kind::ImplConvention, CAttr), *this);
StringRef FAttr;
switch (nextChar()) {
case 'B': FAttr = "@convention(block)"; break;
case 'C': FAttr = "@convention(c)"; break;
case 'M': FAttr = "@convention(method)"; break;
case 'O': FAttr = "@convention(objc_method)"; break;
case 'K': FAttr = "@convention(closure)"; break;
case 'W': FAttr = "@convention(witness_method)"; break;
default:
pushBack();
break;
}
if (!FAttr.empty())
type->addChild(createNode(Node::Kind::ImplFunctionAttribute, FAttr), *this);
addChild(type, GenSig);
int NumTypesToAdd = 0;
while (NodePointer Param = demangleImplParamConvention()) {
type = addChild(type, Param);
NumTypesToAdd++;
}
while (NodePointer Result = demangleImplResultConvention(
Node::Kind::ImplResult)) {
type = addChild(type, Result);
NumTypesToAdd++;
}
if (nextIf('z')) {
NodePointer ErrorResult = demangleImplResultConvention(
Node::Kind::ImplErrorResult);
if (!ErrorResult)
return nullptr;
type = addChild(type, ErrorResult);
NumTypesToAdd++;
}
if (!nextIf('_'))
return nullptr;
for (int Idx = 0; Idx < NumTypesToAdd; ++Idx) {
NodePointer ConvTy = popNode(Node::Kind::Type);
if (!ConvTy)
return nullptr;
type->getChild(type->getNumChildren() - Idx - 1)->addChild(ConvTy, *this);
}
return createType(type);
}
NodePointer Demangler::demangleMetatype() {
switch (nextChar()) {
case 'f':
return createWithPoppedType(Node::Kind::FullTypeMetadata);
case 'P':
return createWithPoppedType(Node::Kind::GenericTypeMetadataPattern);
case 'a':
return createWithPoppedType(Node::Kind::TypeMetadataAccessFunction);
case 'L':
return createWithPoppedType(Node::Kind::TypeMetadataLazyCache);
case 'm':
return createWithPoppedType(Node::Kind::Metaclass);
case 'n':
return createWithPoppedType(Node::Kind::NominalTypeDescriptor);
case 'p':
return createWithChild(Node::Kind::ProtocolDescriptor, popProtocol());
case 'B':
return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
popNode(Node::Kind::Type));
case 'F':
return createWithChild(Node::Kind::ReflectionMetadataFieldDescriptor,
popNode(Node::Kind::Type));
case 'A':
return createWithChild(Node::Kind::ReflectionMetadataAssocTypeDescriptor,
popProtocolConformance());
case 'C': {
NodePointer Ty = popNode(Node::Kind::Type);
if (!Ty || !isNominal(Ty->getChild(0)->getKind()))
return nullptr;
return createWithChild(Node::Kind::ReflectionMetadataSuperclassDescriptor,
Ty->getChild(0));
}
default:
return nullptr;
}
}
static std::string getArchetypeName(Node::IndexType index,
Node::IndexType depth) {
DemanglerPrinter name;
do {
name << (char)('A' + (index % 26));
index /= 26;
} while (index);
if (depth != 0)
name << depth;
return std::move(name).str();
}
NodePointer Demangler::demangleArchetype() {
switch (nextChar()) {
case 'a': {
NodePointer Ident = popNode(Node::Kind::Identifier);
NodePointer ArcheTy = popTypeAndGetChild();
NodePointer AssocTy = createType(
createWithChildren(Node::Kind::AssociatedTypeRef, ArcheTy, Ident));
addSubstitution(AssocTy);
return AssocTy;
}
case 'q': {
NodePointer Idx = demangleIndexAsNode();
NodePointer Ctx = popContext();
NodePointer DeclCtx = createWithChild(Node::Kind::DeclContext, Ctx);
return createType(createWithChildren(Node::Kind::QualifiedArchetype,
Idx, DeclCtx));
}
case 'y': {
NodePointer T = demangleAssociatedTypeSimple(demangleGenericParamIndex());
addSubstitution(T);
return T;
}
case 'z': {
NodePointer T = demangleAssociatedTypeSimple(getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
case 'Y': {
NodePointer T = demangleAssociatedTypeCompound(demangleGenericParamIndex());
addSubstitution(T);
return T;
}
case 'Z': {
NodePointer T = demangleAssociatedTypeCompound(getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
default:
return nullptr;
}
}
NodePointer Demangler::demangleAssociatedTypeSimple(
NodePointer GenericParamIdx) {
NodePointer GPI = createType(GenericParamIdx);
NodePointer ATName = popAssocTypeName();
return createType(createWithChildren(Node::Kind::DependentMemberType,
GPI, ATName));
}
NodePointer Demangler::demangleAssociatedTypeCompound(
NodePointer GenericParamIdx) {
std::vector<NodePointer> AssocTyNames;
bool firstElem = false;
do {
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
NodePointer AssocTyName = popAssocTypeName();
if (!AssocTyName)
return nullptr;
AssocTyNames.push_back(AssocTyName);
} while (!firstElem);
NodePointer Base = GenericParamIdx;
while (NodePointer AssocTy = pop_back_val(AssocTyNames)) {
NodePointer depTy = createNode(Node::Kind::DependentMemberType);
depTy = addChild(depTy, createType(Base));
Base = addChild(depTy, AssocTy);
}
return createType(Base);
}
NodePointer Demangler::popAssocTypeName() {
NodePointer Proto = popNode(Node::Kind::Type);
if (Proto && Proto->getFirstChild()->getKind() != Node::Kind::Protocol)
return nullptr;
NodePointer Id = popNode(Node::Kind::Identifier);
NodePointer AssocTy = changeKind(Id, Node::Kind::DependentAssociatedTypeRef);
addChild(AssocTy, Proto);
return AssocTy;
}
NodePointer Demangler::getDependentGenericParamType(int depth, int index) {
if (depth < 0 || index < 0)
return nullptr;
DemanglerPrinter PrintName;
PrintName << getArchetypeName(index, depth);
auto paramTy = createNode(Node::Kind::DependentGenericParamType,
std::move(PrintName).str());
paramTy->addChild(createNode(Node::Kind::Index, depth), *this);
paramTy->addChild(createNode(Node::Kind::Index, index), *this);
return paramTy;
}
NodePointer Demangler::demangleGenericParamIndex() {
if (nextIf('d')) {
int depth = demangleIndex() + 1;
int index = demangleIndex();
return getDependentGenericParamType(depth, index);
}
if (nextIf('z')) {
return getDependentGenericParamType(0, 0);
}
return getDependentGenericParamType(0, demangleIndex() + 1);
}
NodePointer Demangler::popProtocolConformance() {
NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
NodePointer Module = popModule();
NodePointer Proto = popProtocol();
NodePointer Type = popNode(Node::Kind::Type);
NodePointer Ident = nullptr;
if (!Type) {
// Property behavior conformance
Ident = popNode(Node::Kind::Identifier);
Type = popNode(Node::Kind::Type);
}
if (GenSig) {
Type = createType(createWithChildren(Node::Kind::DependentGenericType,
GenSig, Type));
}
NodePointer Conf = createWithChildren(Node::Kind::ProtocolConformance,
Type, Proto, Module);
addChild(Conf, Ident);
return Conf;
}
NodePointer Demangler::demangleThunkOrSpecialization() {
switch (char c = nextChar()) {
case 'c': return createWithChild(Node::Kind::CurryThunk, popNode(isEntity));
case 'o': return createNode(Node::Kind::ObjCAttribute);
case 'O': return createNode(Node::Kind::NonObjCAttribute);
case 'D': return createNode(Node::Kind::DynamicAttribute);
case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute);
case 'V': return createNode(Node::Kind::VTableAttribute);
case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
case 'W': {
NodePointer Entity = popNode(isEntity);
NodePointer Conf = popProtocolConformance();
return createWithChildren(Node::Kind::ProtocolWitness, Conf, Entity);
}
case 'R':
case 'r': {
NodePointer Thunk = createNode(c == 'R' ?
Node::Kind::ReabstractionThunkHelper :
Node::Kind::ReabstractionThunk);
if (NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature))
addChild(Thunk, GenSig);
NodePointer Ty2 = popNode(Node::Kind::Type);
Thunk = addChild(Thunk, popNode(Node::Kind::Type));
return addChild(Thunk, Ty2);
}
case'g':
return demangleGenericSpecialization(Node::Kind::GenericSpecialization);
case'G':
return demangleGenericSpecialization(Node::Kind::
GenericSpecializationNotReAbstracted);
case'p': {
NodePointer Spec = demangleSpecAttributes(Node::Kind::
GenericPartialSpecialization);
NodePointer Param = createWithChild(Node::Kind::GenericSpecializationParam,
popNode(Node::Kind::Type));
return addChild(Spec, Param);
}
case'P': {
NodePointer Spec = demangleSpecAttributes(Node::Kind::
GenericPartialSpecializationNotReAbstracted);
NodePointer Param = createWithChild(Node::Kind::GenericSpecializationParam,
popNode(Node::Kind::Type));
return addChild(Spec, Param);
}
case'f':
return demangleFunctionSpecialization();
default:
return nullptr;
}
}
NodePointer Demangler::demangleGenericSpecialization(Node::Kind SpecKind) {
NodePointer Spec = demangleSpecAttributes(SpecKind);
NodePointer TyList = popTypeList();
if (!TyList)
return nullptr;
for (NodePointer Ty : *TyList) {
Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty), *this);
}
return Spec;
}
NodePointer Demangler::demangleFunctionSpecialization() {
NodePointer Spec = demangleSpecAttributes(
Node::Kind::FunctionSignatureSpecialization, /*demangleUniqueID*/ true);
unsigned ParamIdx = 0;
while (Spec && !nextIf('_')) {
Spec = addChild(Spec, demangleFuncSpecParam(ParamIdx));
ParamIdx++;
}
if (!nextIf('n'))
Spec = addChild(Spec, demangleFuncSpecParam(Node::IndexType(~0)));
if (!Spec)
return nullptr;
// Add the required parameters in reverse order.
for (size_t Idx = 0, Num = Spec->getNumChildren(); Idx < Num; ++Idx) {
NodePointer Param = Spec->getChild(Num - Idx - 1);
if (Param->getKind() != Node::Kind::FunctionSignatureSpecializationParam)
continue;
if (Param->getNumChildren() == 0)
continue;
NodePointer KindNd = Param->getFirstChild();
assert(KindNd->getKind() ==
Node::Kind::FunctionSignatureSpecializationParamKind);
auto ParamKind = (FunctionSigSpecializationParamKind)KindNd->getIndex();
switch (ParamKind) {
case FunctionSigSpecializationParamKind::ConstantPropFunction:
case FunctionSigSpecializationParamKind::ConstantPropGlobal:
case FunctionSigSpecializationParamKind::ConstantPropString:
case FunctionSigSpecializationParamKind::ClosureProp: {
std::vector<NodePointer> Types;
while (NodePointer Ty = popNode(Node::Kind::Type)) {
assert(ParamKind == FunctionSigSpecializationParamKind::ClosureProp);
Types.push_back(Ty);
}
NodePointer Name = popNode(Node::Kind::Identifier);
if (!Name)
return nullptr;
StringRef Text = Name->getText();
if (ParamKind ==
FunctionSigSpecializationParamKind::ConstantPropString &&
Text.size() > 0 && Text[0] == '_') {
// A '_' escapes a leading digit or '_' of a string constant.
Text = Text.drop_front(1);
}
addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamPayload, Text));
while (NodePointer Ty = pop_back_val(Types)) {
Param = addChild(Param, Ty);
}
break;
}
default:
break;
}
}
return Spec;
}
NodePointer Demangler::demangleFuncSpecParam(Node::IndexType ParamIdx) {
NodePointer Param = createNode(
Node::Kind::FunctionSignatureSpecializationParam, ParamIdx);
switch (nextChar()) {
case 'n':
return Param;
case 'c':
// Consumes an identifier and multiple type parameters.
// The parameters will be added later.
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
uint64_t(FunctionSigSpecializationParamKind::ClosureProp)));
case 'p': {
switch (nextChar()) {
case 'f':
// Consumes an identifier parameter, which will be added later.
return addChild(
Param,
createNode(Node::Kind::FunctionSignatureSpecializationParamKind,
Node::IndexType(FunctionSigSpecializationParamKind::
ConstantPropFunction)));
case 'g':
// Consumes an identifier parameter, which will be added later.
return addChild(
Param,
createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
Node::IndexType(
FunctionSigSpecializationParamKind::ConstantPropGlobal)));
case 'i':
return addFuncSpecParamNumber(Param,
FunctionSigSpecializationParamKind::ConstantPropInteger);
case 'd':
return addFuncSpecParamNumber(Param,
FunctionSigSpecializationParamKind::ConstantPropFloat);
case 's': {
// Consumes an identifier parameter (the string constant),
// which will be added later.
StringRef Encoding;
switch (nextChar()) {
case 'b': Encoding = "u8"; break;
case 'w': Encoding = "u16"; break;
case 'c': Encoding = "objc"; break;
default: return nullptr;
}
addChild(Param,
createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
Node::IndexType(
swift::Demangle::FunctionSigSpecializationParamKind::
ConstantPropString)));
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamPayload,
Encoding));
}
default:
return nullptr;
}
}
case 'd': {
unsigned Value = unsigned(FunctionSigSpecializationParamKind::Dead);
if (nextIf('G'))
Value |= unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed);
if (nextIf('X'))
Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind, Value));
}
case 'g': {
unsigned Value = unsigned(FunctionSigSpecializationParamKind::
OwnedToGuaranteed);
if (nextIf('X'))
Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind, Value));
}
case 'x':
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
unsigned(FunctionSigSpecializationParamKind::SROA)));
case 'i':
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
unsigned(FunctionSigSpecializationParamKind::BoxToValue)));
case 's':
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamKind,
unsigned(FunctionSigSpecializationParamKind::BoxToStack)));
default:
return nullptr;
}
}
NodePointer Demangler::addFuncSpecParamNumber(NodePointer Param,
FunctionSigSpecializationParamKind Kind) {
Param->addChild(createNode(
Node::Kind::FunctionSignatureSpecializationParamKind, unsigned(Kind)),
*this);
std::string Str;
while (isDigit(peekChar())) {
Str += nextChar();
}
if (Str.empty())
return nullptr;
return addChild(Param, createNode(
Node::Kind::FunctionSignatureSpecializationParamPayload, Str));
}
NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind,
bool demangleUniqueID) {
bool isFragile = nextIf('q');
int PassID = (int)nextChar() - '0';
if (PassID < 0 || PassID > 9)
return nullptr;
int Idx = -1;
if (demangleUniqueID)
Idx = demangleNatural();
NodePointer SpecNd = nullptr;
if (Idx >= 0) {
SpecNd = createNode(SpecKind, Idx);
} else {
SpecNd = createNode(SpecKind);
}
if (isFragile)
SpecNd->addChild(createNode(Node::Kind::SpecializationIsFragile),
*this);
SpecNd->addChild(createNode(Node::Kind::SpecializationPassID, PassID),
*this);
return SpecNd;
}
NodePointer Demangler::demangleWitness() {
switch (nextChar()) {
case 'V':
return createWithChild(Node::Kind::ValueWitnessTable,
popNode(Node::Kind::Type));
case 'o':
return createWithChild(Node::Kind::WitnessTableOffset, popNode(isEntity));
case 'v': {
unsigned Directness;
switch (nextChar()) {
case 'd': Directness = unsigned(Directness::Direct); break;
case 'i': Directness = unsigned(Directness::Indirect); break;
default: return nullptr;
}
return createWithChildren(Node::Kind::FieldOffset,
createNode(Node::Kind::Directness, Directness),
popNode(isEntity));
}
case 'P':
return createWithChild(Node::Kind::ProtocolWitnessTable,
popProtocolConformance());
case 'G':
return createWithChild(Node::Kind::GenericProtocolWitnessTable,
popProtocolConformance());
case 'I':
return createWithChild(
Node::Kind::GenericProtocolWitnessTableInstantiationFunction,
popProtocolConformance());
case 'l': {
NodePointer Conf = popProtocolConformance();
NodePointer Type = popNode(Node::Kind::Type);
return createWithChildren(Node::Kind::LazyProtocolWitnessTableAccessor,
Type, Conf);
}
case 'L': {
NodePointer Conf = popProtocolConformance();
NodePointer Type = popNode(Node::Kind::Type);
return createWithChildren(
Node::Kind::LazyProtocolWitnessTableCacheVariable, Type, Conf);
}
case 'a':
return createWithChild(Node::Kind::ProtocolWitnessTableAccessor,
popProtocolConformance());
case 't': {
NodePointer Name = popNode(isDeclName);
NodePointer Conf = popProtocolConformance();
return createWithChildren(Node::Kind::AssociatedTypeMetadataAccessor,
Conf, Name);
}
case 'T': {
NodePointer ProtoTy = popNode(Node::Kind::Type);
NodePointer Name = popNode(isDeclName);
NodePointer Conf = popProtocolConformance();
return createWithChildren(Node::Kind::AssociatedTypeWitnessTableAccessor,
Conf, Name, ProtoTy);
}
case 'y': {
return createWithChild(Node::Kind::OutlinedCopy,
popNode(Node::Kind::Type));
}
case 'e': {
return createWithChild(Node::Kind::OutlinedConsume,
popNode(Node::Kind::Type));
}
default:
return nullptr;
}
}
NodePointer Demangler::demangleSpecialType() {
switch (auto specialChar = nextChar()) {
case 'f':
return popFunctionType(Node::Kind::ThinFunctionType);
case 'K':
return popFunctionType(Node::Kind::AutoClosureType);
case 'U':
return popFunctionType(Node::Kind::UncurriedFunctionType);
case 'B':
return popFunctionType(Node::Kind::ObjCBlock);
case 'C':
return popFunctionType(Node::Kind::CFunctionPointer);
case 'o':
return createType(createWithChild(Node::Kind::Unowned,
popNode(Node::Kind::Type)));
case 'u':
return createType(createWithChild(Node::Kind::Unmanaged,
popNode(Node::Kind::Type)));
case 'w':
return createType(createWithChild(Node::Kind::Weak,
popNode(Node::Kind::Type)));
case 'b':
return createType(createWithChild(Node::Kind::SILBoxType,
popNode(Node::Kind::Type)));
case 'D':
return createType(createWithChild(Node::Kind::DynamicSelf,
popNode(Node::Kind::Type)));
case 'M': {
NodePointer MTR = demangleMetatypeRepresentation();
NodePointer Type = popNode(Node::Kind::Type);
return createType(createWithChildren(Node::Kind::Metatype, MTR, Type));
}
case 'm': {
NodePointer MTR = demangleMetatypeRepresentation();
NodePointer Type = popNode(Node::Kind::Type);
return createType(createWithChildren(Node::Kind::ExistentialMetatype,
MTR, Type));
}
case 'p':
return createType(createWithChild(Node::Kind::ExistentialMetatype,
popNode(Node::Kind::Type)));
case 'X':
case 'x': {
// SIL box types.
NodePointer signature = nullptr, genericArgs = nullptr;
if (specialChar == 'X') {
signature = popNode(Node::Kind::DependentGenericSignature);
if (!signature)
return nullptr;
genericArgs = popTypeList();
if (!genericArgs)
return nullptr;
}
auto fieldTypes = popTypeList();
if (!fieldTypes)
return nullptr;
// Build layout.
auto layout = createNode(Node::Kind::SILBoxLayout);
for (unsigned i = 0, e = fieldTypes->getNumChildren(); i < e; ++i) {
auto fieldType = fieldTypes->getChild(i);
assert(fieldType->getKind() == Node::Kind::Type);
bool isMutable = false;
// 'inout' typelist mangling is used to represent mutable fields.
if (fieldType->getChild(0)->getKind() == Node::Kind::InOut) {
isMutable = true;
fieldType = createType(fieldType->getChild(0)->getChild(0));
}
auto field = createNode(isMutable
? Node::Kind::SILBoxMutableField
: Node::Kind::SILBoxImmutableField);
field->addChild(fieldType, *this);
layout->addChild(field, *this);
}
auto boxTy = createNode(Node::Kind::SILBoxTypeWithLayout);
boxTy->addChild(layout, *this);
if (signature) {
boxTy->addChild(signature, *this);
assert(genericArgs);
boxTy->addChild(genericArgs, *this);
}
return createType(boxTy);
}
case 'e':
return createType(createNode(Node::Kind::ErrorType, StringRef()));
default:
return nullptr;
}
}
NodePointer Demangler::demangleMetatypeRepresentation() {
switch (nextChar()) {
case 't':
return createNode(Node::Kind::MetatypeRepresentation, "@thin");
case 'T':
return createNode(Node::Kind::MetatypeRepresentation, "@thick");
case 'o':
return createNode(Node::Kind::MetatypeRepresentation,
"@objc_metatype");
default:
return nullptr;
}
}
NodePointer Demangler::demangleFunctionEntity() {
enum { None, Type, TypeAndName, TypeAndIndex, Index } Args;
Node::Kind Kind = Node::Kind::EmptyList;
switch (nextChar()) {
case 'D': Args = None; Kind = Node::Kind::Deallocator; break;
case 'd': Args = None; Kind = Node::Kind::Destructor; break;
case 'E': Args = None; Kind = Node::Kind::IVarDestroyer; break;
case 'e': Args = None; Kind = Node::Kind::IVarInitializer; break;
case 'i': Args = None; Kind = Node::Kind::Initializer; break;
case 'C': Args = Type; Kind = Node::Kind::Allocator; break;
case 'c': Args = Type; Kind = Node::Kind::Constructor; break;
case 'g': Args = TypeAndName; Kind = Node::Kind::Getter; break;
case 'G': Args = TypeAndName; Kind = Node::Kind::GlobalGetter; break;
case 's': Args = TypeAndName; Kind = Node::Kind::Setter; break;
case 'm': Args = TypeAndName; Kind = Node::Kind::MaterializeForSet; break;
case 'w': Args = TypeAndName; Kind = Node::Kind::WillSet; break;
case 'W': Args = TypeAndName; Kind = Node::Kind::DidSet; break;
case 'a':
Args = TypeAndName;
switch (nextChar()) {
case 'O': Kind = Node::Kind::OwningMutableAddressor; break;
case 'o': Kind = Node::Kind::NativeOwningMutableAddressor; break;
case 'P': Kind = Node::Kind::NativePinningMutableAddressor; break;
case 'u': Kind = Node::Kind::UnsafeMutableAddressor; break;
default: return nullptr;
}
break;
case 'l':
Args = TypeAndName;
switch (nextChar()) {
case 'O': Kind = Node::Kind::OwningAddressor; break;
case 'o': Kind = Node::Kind::NativeOwningAddressor; break;
case 'p': Kind = Node::Kind::NativePinningAddressor; break;
case 'u': Kind = Node::Kind::UnsafeAddressor; break;
default: return nullptr;
}
break;
case 'U': Args = TypeAndIndex; Kind = Node::Kind::ExplicitClosure; break;
case 'u': Args = TypeAndIndex; Kind = Node::Kind::ImplicitClosure; break;
case 'A': Args = Index; Kind = Node::Kind::DefaultArgumentInitializer; break;
case 'p': return demangleEntity(Node::Kind::GenericTypeParamDecl);
default: return nullptr;
}
NodePointer Child1 = nullptr, Child2 = nullptr;
switch (Args) {
case None:
break;
case Type:
Child1 = popNode(Node::Kind::Type);
break;
case TypeAndName:
Child2 = popNode(Node::Kind::Type);
Child1 = popNode(isDeclName);
break;
case TypeAndIndex:
Child1 = demangleIndexAsNode();
Child2 = popNode(Node::Kind::Type);
break;
case Index:
Child1 = demangleIndexAsNode();
break;
}
NodePointer Entity = createWithChild(Kind, popContext());
switch (Args) {
case None:
break;
case Type:
case Index:
Entity = addChild(Entity, Child1);
break;
case TypeAndName:
case TypeAndIndex:
Entity = addChild(Entity, Child1);
Entity = addChild(Entity, Child2);
break;
}
return Entity;
}
NodePointer Demangler::demangleEntity(Node::Kind Kind) {
NodePointer Type = popNode(Node::Kind::Type);
NodePointer Name = popNode(isDeclName);
NodePointer Context = popContext();
return createWithChildren(Kind, Context, Name, Type);
}
NodePointer Demangler::demangleProtocolListType() {
NodePointer TypeList = createNode(Node::Kind::TypeList);
NodePointer ProtoList = createWithChild(Node::Kind::ProtocolList, TypeList);
if (!popNode(Node::Kind::EmptyList)) {
std::vector<NodePointer> ProtoNames;
bool firstElem = false;
do {
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
NodePointer Proto = popProtocol();
if (!Proto)
return nullptr;
ProtoNames.push_back(Proto);
} while (!firstElem);
while (NodePointer Proto = pop_back_val(ProtoNames)) {
TypeList->addChild(Proto, *this);
}
}
return createType(ProtoList);
}
NodePointer Demangler::demangleGenericSignature(bool hasParamCounts) {
std::vector<NodePointer> Requirements;
while (NodePointer Req = popNode(isRequirement)) {
Requirements.push_back(Req);
}
NodePointer Sig = createNode(Node::Kind::DependentGenericSignature);
if (hasParamCounts) {
while (!nextIf('l')) {
int count = 0;
if (!nextIf('z'))
count = demangleIndex() + 1;
if (count < 0)
return nullptr;
Sig->addChild(createNode(Node::Kind::DependentGenericParamCount,
count), *this);
}
} else {
Sig->addChild(createNode(Node::Kind::DependentGenericParamCount, 1),
*this);
}
if (Sig->getNumChildren() == 0)
return nullptr;
while (NodePointer Req = pop_back_val(Requirements)) {
Sig->addChild(Req, *this);
}
return Sig;
}
NodePointer Demangler::demangleGenericRequirement() {
enum { Generic, Assoc, CompoundAssoc, Substitution } TypeKind;
enum { Protocol, BaseClass, SameType, Layout } ConstraintKind;
switch (nextChar()) {
case 'c': ConstraintKind = BaseClass; TypeKind = Assoc; break;
case 'C': ConstraintKind = BaseClass; TypeKind = CompoundAssoc; break;
case 'b': ConstraintKind = BaseClass; TypeKind = Generic; break;
case 'B': ConstraintKind = BaseClass; TypeKind = Substitution; break;
case 't': ConstraintKind = SameType; TypeKind = Assoc; break;
case 'T': ConstraintKind = SameType; TypeKind = CompoundAssoc; break;
case 's': ConstraintKind = SameType; TypeKind = Generic; break;
case 'S': ConstraintKind = SameType; TypeKind = Substitution; break;
case 'm': ConstraintKind = Layout; TypeKind = Assoc; break;
case 'M': ConstraintKind = Layout; TypeKind = CompoundAssoc; break;
case 'l': ConstraintKind = Layout; TypeKind = Generic; break;
case 'L': ConstraintKind = Layout; TypeKind = Substitution; break;
case 'p': ConstraintKind = Protocol; TypeKind = Assoc; break;
case 'P': ConstraintKind = Protocol; TypeKind = CompoundAssoc; break;
case 'Q': ConstraintKind = Protocol; TypeKind = Substitution; break;
default: ConstraintKind = Protocol; TypeKind = Generic; pushBack(); break;
}
NodePointer ConstrTy = nullptr;
switch (TypeKind) {
case Generic:
ConstrTy = createType(demangleGenericParamIndex());
break;
case Assoc:
ConstrTy = demangleAssociatedTypeSimple(demangleGenericParamIndex());
addSubstitution(ConstrTy);
break;
case CompoundAssoc:
ConstrTy = demangleAssociatedTypeCompound(demangleGenericParamIndex());
addSubstitution(ConstrTy);
break;
case Substitution:
ConstrTy = popNode(Node::Kind::Type);
break;
}
switch (ConstraintKind) {
case Protocol:
return createWithChildren(
Node::Kind::DependentGenericConformanceRequirement, ConstrTy,
popProtocol());
case BaseClass:
return createWithChildren(
Node::Kind::DependentGenericConformanceRequirement, ConstrTy,
popNode(Node::Kind::Type));
case SameType:
return createWithChildren(Node::Kind::DependentGenericSameTypeRequirement,
ConstrTy, popNode(Node::Kind::Type));
case Layout: {
auto c = nextChar();
NodePointer size = nullptr;
NodePointer alignment = nullptr;
StringRef name;
if (c == 'U') {
name = "U";
} else if (c == 'R') {
name = "R";
} else if (c == 'N') {
name = "N";
} else if (c == 'T') {
name = "T";
} else if (c == 'E') {
size = demangleIndexAsNode();
if (!size)
return nullptr;
alignment = demangleIndexAsNode();
name = "E";
} else if (c == 'e') {
size = demangleIndexAsNode();
if (!size)
return nullptr;
name = "e";
} else if (c == 'M') {
size = demangleIndexAsNode();
if (!size)
return nullptr;
alignment = demangleIndexAsNode();
name = "M";
} else if (c == 'm') {
size = demangleIndexAsNode();
if (!size)
return nullptr;
name = "m";
} else {
demangler_unreachable("Unknown layout constraint");
}
auto NameNode = createNode(Node::Kind::Identifier, name);
auto LayoutRequirement = createWithChildren(
Node::Kind::DependentGenericLayoutRequirement, ConstrTy, NameNode);
if (size)
LayoutRequirement->addChild(size, *this);
if (alignment)
LayoutRequirement->addChild(alignment, *this);
return LayoutRequirement;
}
}
demangler_unreachable("Unhandled TypeKind in switch.");
}
NodePointer Demangler::demangleGenericType() {
NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
NodePointer Ty = popNode(Node::Kind::Type);
return createType(createWithChildren(Node::Kind::DependentGenericType,
GenSig, Ty));
}
static int decodeValueWitnessKind(StringRef CodeStr) {
#define VALUE_WITNESS(MANGLING, NAME) \
if (CodeStr == #MANGLING) return (int)ValueWitnessKind::NAME;
#include "swift/Basic/ValueWitnessMangling.def"
return -1;
}
NodePointer Demangler::demangleValueWitness() {
char Code[2];
Code[0] = nextChar();
Code[1] = nextChar();
int Kind = decodeValueWitnessKind(StringRef(Code, 2));
if (Kind < 0)
return nullptr;
NodePointer VW = createNode(Node::Kind::ValueWitness, unsigned(Kind));
return addChild(VW, popNode(Node::Kind::Type));
}
NodePointer Demangler::demangleObjCTypeName() {
NodePointer Ty = createNode(Node::Kind::Type);
NodePointer Global = addChild(createNode(Node::Kind::Global),
addChild(createNode(Node::Kind::TypeMangling), Ty));
NodePointer Nominal = nullptr;
bool isProto = false;
if (nextIf('C')) {
Nominal = createNode(Node::Kind::Class);
addChild(Ty, Nominal);
} else if (nextIf('P')) {
isProto = true;
Nominal = createNode(Node::Kind::Protocol);
addChild(Ty, addChild(createNode(Node::Kind::ProtocolList),
addChild(createNode(Node::Kind::TypeList),
addChild(createNode(Node::Kind::Type), Nominal))));
} else {
return nullptr;
}
NodePointer Ident = demangleIdentifier();
if (!Ident)
return nullptr;
Nominal->addChild(changeKind(Ident, Node::Kind::Module), *this);
Ident = demangleIdentifier();
if (!Ident)
return nullptr;
Nominal->addChild(Ident, *this);
if (isProto && !nextIf('_'))
return nullptr;
if (Pos < Text.size())
return nullptr;
return Global;
}
} // end namespace NewMangling
} // end namespace swift