mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Instead of crashing it just should not demangle malformed symbols. rdar://problem/32113006
1992 lines
65 KiB
C++
1992 lines
65 KiB
C++
//===--- 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/Demangling/Demangler.h"
|
|
#include "swift/Demangling/ManglingUtils.h"
|
|
#include "swift/Demangling/ManglingMacros.h"
|
|
#include "swift/Demangling/Punycode.h"
|
|
#include "swift/Strings.h"
|
|
|
|
using namespace swift;
|
|
using namespace Mangle;
|
|
using swift::Demangle::FunctionSigSpecializationParamKind;
|
|
|
|
//////////////////////////////////
|
|
// Private utility functions //
|
|
//////////////////////////////////
|
|
|
|
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/Demangling/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 {
|
|
|
|
//////////////////////////////////
|
|
// 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::reverseChildren(size_t StartingAt) {
|
|
assert(StartingAt <= NumChildren);
|
|
std::reverse(Children + StartingAt, Children + NumChildren);
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// 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::createNodeWithAllocatedText(Node::Kind K,
|
|
llvm::StringRef Text) {
|
|
return new (Allocate<Node>()) Node(K, Text);
|
|
}
|
|
NodePointer NodeFactory::createNode(Node::Kind K, const CharVector &Text) {
|
|
return createNodeWithAllocatedText(K, Text.str());
|
|
}
|
|
NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
|
|
return new (Allocate<Node>()) Node(K, llvm::StringRef(Text));
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// CharVector member functions //
|
|
//////////////////////////////////
|
|
|
|
void CharVector::append(StringRef Rhs, NodeFactory &Factory) {
|
|
if (NumElems + Rhs.size() > Capacity)
|
|
Factory.Reallocate(Elems, Capacity, /*Growth*/ Rhs.size());
|
|
memcpy(Elems + NumElems, Rhs.data(), Rhs.size());
|
|
NumElems += Rhs.size();
|
|
assert(NumElems <= Capacity);
|
|
}
|
|
|
|
void CharVector::append(int Number, NodeFactory &Factory) {
|
|
const int MaxIntPrintSize = 8;
|
|
if (NumElems + MaxIntPrintSize > Capacity)
|
|
Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxIntPrintSize);
|
|
int Length = snprintf(Elems + NumElems, MaxIntPrintSize, "%d", Number);
|
|
assert(Length > 0 && Length < MaxIntPrintSize);
|
|
NumElems += Length;
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// Demangler member functions //
|
|
//////////////////////////////////
|
|
|
|
void Demangler::clear() {
|
|
NodeStack.free();
|
|
Substitutions.free();
|
|
PendingSubstitutions.free();
|
|
NodeFactory::clear();
|
|
}
|
|
|
|
void Demangler::init(StringRef MangledName) {
|
|
NodeStack.init(*this, 16);
|
|
Substitutions.init(*this, 16);
|
|
PendingSubstitutions.init(*this, 4);
|
|
NumWords = 0;
|
|
Text = MangledName;
|
|
Pos = 0;
|
|
}
|
|
|
|
NodePointer Demangler::demangleSymbol(StringRef MangledName) {
|
|
init(MangledName);
|
|
|
|
// Demangle old-style class and protocol names, which are still used in the
|
|
// ObjC metadata.
|
|
if (nextIf("_Tt"))
|
|
return demangleObjCTypeName();
|
|
|
|
if (!nextIf(MANGLING_PREFIX_STR)
|
|
// Also accept the future mangling prefix.
|
|
// TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S".
|
|
&& !nextIf("_S"))
|
|
return nullptr;
|
|
|
|
// If any other prefixes are accepted, please update Mangler::verify.
|
|
|
|
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;
|
|
default:
|
|
Parent->addChild(Nd, *this);
|
|
break;
|
|
}
|
|
}
|
|
if (topLevel->getNumChildren() == 0)
|
|
return nullptr;
|
|
|
|
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 = createNodeWithAllocatedText(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 demangleAnyGenericType(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 demangleAnyGenericType(Node::Kind::Enum);
|
|
case 'P': return demangleAnyGenericType(Node::Kind::Protocol);
|
|
case 'Q': return demangleArchetype();
|
|
case 'R': return demangleGenericRequirement();
|
|
case 'S': return demangleStandardSubstitution();
|
|
case 'T': return demangleThunkOrSpecialization();
|
|
case 'V': return demangleAnyGenericType(Node::Kind::Structure);
|
|
case 'W': return demangleWitness();
|
|
case 'X': return demangleSpecialType();
|
|
case 'Z': return createWithChild(Node::Kind::Static, popNode(isEntity));
|
|
case 'a': return demangleAnyGenericType(Node::Kind::TypeAlias);
|
|
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() {
|
|
int RepeatCount = -1;
|
|
while (true) {
|
|
char c = nextChar();
|
|
if (isLowerLetter(c)) {
|
|
// It's a substitution with an index < 26.
|
|
NodePointer Nd = pushMultiSubstitutions(RepeatCount, c - 'a');
|
|
if (!Nd)
|
|
return nullptr;
|
|
pushNode(Nd);
|
|
RepeatCount = -1;
|
|
// A lowercase letter indicates that there are more substitutions to
|
|
// follow.
|
|
continue;
|
|
}
|
|
if (isUpperLetter(c)) {
|
|
// The last substitution.
|
|
return pushMultiSubstitutions(RepeatCount, c - 'A');
|
|
}
|
|
if (c == '_') {
|
|
// The previously demangled number is actually not a repeat count but
|
|
// the large (> 26) index of a substitution. Because it's an index we
|
|
// have to add 27 and not 26.
|
|
unsigned Idx = RepeatCount + 27;
|
|
if (Idx >= Substitutions.size())
|
|
return nullptr;
|
|
return Substitutions[Idx];
|
|
}
|
|
pushBack();
|
|
// Not a letter? Then it can only be a natural number which might be the
|
|
// repeat count or a large (> 26) substitution index.
|
|
RepeatCount = demangleNatural();
|
|
if (RepeatCount < 0)
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
NodePointer Demangler::pushMultiSubstitutions(int RepeatCount,
|
|
size_t SubstIdx) {
|
|
if (SubstIdx >= Substitutions.size())
|
|
return nullptr;
|
|
if (RepeatCount > SubstitutionMerging::MaxRepeatCount)
|
|
return nullptr;
|
|
NodePointer Nd = Substitutions[SubstIdx];
|
|
while (RepeatCount-- > 1) {
|
|
pushNode(Nd);
|
|
}
|
|
return Nd;
|
|
}
|
|
|
|
NodePointer Demangler::createSwiftType(Node::Kind typeKind, const char *name) {
|
|
return createType(createWithChildren(typeKind,
|
|
createNode(Node::Kind::Module, STDLIB_NAME),
|
|
createNode(Node::Kind::Identifier, name)));
|
|
}
|
|
|
|
NodePointer Demangler::demangleStandardSubstitution() {
|
|
switch (char c = nextChar()) {
|
|
case 'o':
|
|
return createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
|
|
case 'C':
|
|
return createNode(Node::Kind::Module, MANGLING_MODULE_C);
|
|
case 'g': {
|
|
NodePointer OptionalTy =
|
|
createType(createWithChildren(Node::Kind::BoundGenericEnum,
|
|
createSwiftType(Node::Kind::Enum, "Optional"),
|
|
createWithChild(Node::Kind::TypeList, popNode(Node::Kind::Type))));
|
|
addSubstitution(OptionalTy);
|
|
return OptionalTy;
|
|
}
|
|
default: {
|
|
pushBack();
|
|
int RepeatCount = demangleNatural();
|
|
if (RepeatCount > SubstitutionMerging::MaxRepeatCount)
|
|
return nullptr;
|
|
if (NodePointer Nd = createStandardSubstitution(nextChar())) {
|
|
while (RepeatCount-- > 1) {
|
|
pushNode(Nd);
|
|
}
|
|
return Nd;
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
NodePointer Demangler::createStandardSubstitution(char Subst) {
|
|
#define STANDARD_TYPE(KIND, MANGLING, TYPENAME) \
|
|
if (Subst == #MANGLING[0]) { \
|
|
return createSwiftType(Node::Kind::KIND, #TYPENAME); \
|
|
}
|
|
|
|
#include "swift/Demangling/StandardTypesMangling.def"
|
|
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;
|
|
}
|
|
}
|
|
CharVector 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, *this);
|
|
}
|
|
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) {
|
|
std::string PunycodedString;
|
|
if (!Punycode::decodePunycodeUTF8(Slice, PunycodedString))
|
|
return nullptr;
|
|
Identifier.append(StringRef(PunycodedString), *this);
|
|
} else {
|
|
Identifier.append(Slice, *this);
|
|
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);
|
|
if (!Ident)
|
|
return nullptr;
|
|
|
|
static const char op_char_table[] = "& @/= > <*!|+?%-~ ^ .";
|
|
|
|
CharVector OpStr;
|
|
for (signed char c : Ident->getText()) {
|
|
if (c < 0) {
|
|
// Pass through Unicode characters.
|
|
OpStr.push_back(c, *this);
|
|
continue;
|
|
}
|
|
if (!isLowerLetter(c))
|
|
return nullptr;
|
|
char o = op_char_table[c - 'a'];
|
|
if (o == ' ')
|
|
return nullptr;
|
|
OpStr.push_back(o, *this);
|
|
}
|
|
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;
|
|
CharVector name;
|
|
name.append("Builtin.Float", *this);
|
|
name.append(size, *this);
|
|
Ty = createNode(Node::Kind::BuiltinTypeName, name);
|
|
break;
|
|
}
|
|
case 'i': {
|
|
int size = demangleIndex() - 1;
|
|
if (size <= 0)
|
|
return nullptr;
|
|
CharVector name;
|
|
name.append("Builtin.Int", *this);
|
|
name.append(size, *this);
|
|
Ty = createNode(Node::Kind::BuiltinTypeName, name);
|
|
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;
|
|
CharVector name;
|
|
name.append("Builtin.Vec", *this);
|
|
name.append(elts, *this);
|
|
name.push_back('x', *this);
|
|
name.append(EltType->getText().substr(sizeof("Builtin.") - 1), *this);
|
|
Ty = createNode(Node::Kind::BuiltinTypeName, name);
|
|
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::demangleAnyGenericType(Node::Kind kind) {
|
|
NodePointer Name = popNode(isDeclName);
|
|
NodePointer Ctx = popContext();
|
|
NodePointer NTy = createType(createWithChildren(kind, Ctx, Name));
|
|
addSubstitution(NTy);
|
|
return NTy;
|
|
}
|
|
|
|
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::Tuple));
|
|
} else {
|
|
ParamsType = popNode(Node::Kind::Type);
|
|
}
|
|
return createWithChild(kind, ParamsType);
|
|
}
|
|
|
|
NodePointer Demangler::popTuple() {
|
|
NodePointer Root = createNode(Node::Kind::Tuple);
|
|
|
|
if (!popNode(Node::Kind::EmptyList)) {
|
|
bool firstElem = false;
|
|
do {
|
|
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
|
|
NodePointer TupleElmt = createNode(Node::Kind::TupleElement);
|
|
addChild(TupleElmt, popNode(Node::Kind::VariadicMarker));
|
|
if (NodePointer Ident = popNode(Node::Kind::Identifier)) {
|
|
TupleElmt->addChild(createNodeWithAllocatedText(
|
|
Node::Kind::TupleElementName, Ident->getText()),
|
|
*this);
|
|
}
|
|
NodePointer Ty = popNode(Node::Kind::Type);
|
|
if (!Ty)
|
|
return nullptr;
|
|
TupleElmt->addChild(Ty, *this);
|
|
Root->addChild(TupleElmt, *this);
|
|
} while (!firstElem);
|
|
|
|
Root->reverseChildren();
|
|
}
|
|
return createType(Root);
|
|
}
|
|
|
|
NodePointer Demangler::popTypeList() {
|
|
NodePointer Root = createNode(Node::Kind::TypeList);
|
|
|
|
if (!popNode(Node::Kind::EmptyList)) {
|
|
bool firstElem = false;
|
|
do {
|
|
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
|
|
NodePointer Ty = popNode(Node::Kind::Type);
|
|
if (!Ty)
|
|
return nullptr;
|
|
Root->addChild(Ty, *this);
|
|
} while (!firstElem);
|
|
|
|
Root->reverseChildren();
|
|
}
|
|
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() {
|
|
Vector<NodePointer> TypeListList(*this, 4);
|
|
for (;;) {
|
|
NodePointer TList = createNode(Node::Kind::TypeList);
|
|
TypeListList.push_back(TList, *this);
|
|
while (NodePointer Ty = popNode(Node::Kind::Type)) {
|
|
TList->addChild(Ty, *this);
|
|
}
|
|
TList->reverseChildren();
|
|
|
|
if (popNode(Node::Kind::EmptyList))
|
|
break;
|
|
if (!popNode(Node::Kind::FirstElementMarker))
|
|
return nullptr;
|
|
}
|
|
NodePointer Nominal = popTypeAndGetNominal();
|
|
NodePointer NTy = createType(demangleBoundGenericArgs(Nominal, TypeListList, 0));
|
|
addSubstitution(NTy);
|
|
return NTy;
|
|
}
|
|
|
|
NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
|
|
const 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 (TypeListIdx < TypeLists.size()) {
|
|
NodePointer BoundParent = nullptr;
|
|
if (Context->getKind() == Node::Kind::Extension) {
|
|
BoundParent = demangleBoundGenericArgs(Context->getChild(1), TypeLists,
|
|
TypeListIdx);
|
|
BoundParent = createWithChildren(Node::Kind::Extension,
|
|
Context->getFirstChild(),
|
|
BoundParent);
|
|
if (Context->getNumChildren() == 3) {
|
|
// Add the generic signature of the extension context.
|
|
addChild(BoundParent, Context->getChild(2));
|
|
}
|
|
} else {
|
|
BoundParent = demangleBoundGenericArgs(Context, TypeLists, TypeListIdx);
|
|
}
|
|
// 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() {
|
|
const char *attr = nullptr;
|
|
switch (nextChar()) {
|
|
case 'i': attr = "@in"; break;
|
|
case 'c':
|
|
attr = "@in_constant";
|
|
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) {
|
|
const char *attr = nullptr;
|
|
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);
|
|
|
|
const char *CAttr = nullptr;
|
|
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);
|
|
|
|
const char *FAttr = nullptr;
|
|
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)
|
|
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;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
Vector<NodePointer> AssocTyNames(*this, 4);
|
|
bool firstElem = false;
|
|
do {
|
|
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
|
|
NodePointer AssocTyName = popAssocTypeName();
|
|
if (!AssocTyName)
|
|
return nullptr;
|
|
AssocTyNames.push_back(AssocTyName, *this);
|
|
} while (!firstElem);
|
|
|
|
NodePointer Base = GenericParamIdx;
|
|
|
|
while (NodePointer AssocTy = AssocTyNames.pop_back_val()) {
|
|
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;
|
|
|
|
CharVector name;
|
|
int idxChar = index;
|
|
do {
|
|
name.push_back((char)('A' + (idxChar % 26)), *this);
|
|
idxChar /= 26;
|
|
} while (idxChar);
|
|
if (depth != 0)
|
|
name.append(depth, *this);
|
|
|
|
auto paramTy = createNode(Node::Kind::DependentGenericParamType, name);
|
|
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 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
|
|
case 'A': return createNode(Node::Kind::PartialApplyForwarder);
|
|
case 'V': {
|
|
NodePointer Base = popNode(isEntity);
|
|
NodePointer Derived = popNode(isEntity);
|
|
return createWithChildren(Node::Kind::VTableThunk, Derived, Base);
|
|
}
|
|
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();
|
|
case 'K':
|
|
case 'k': {
|
|
auto nodeKind = c == 'K' ? Node::Kind::KeyPathGetterThunkHelper
|
|
: Node::Kind::KeyPathSetterThunkHelper;
|
|
auto type = popNode();
|
|
auto sigOrDecl = popNode();
|
|
if (sigOrDecl->getKind() == Node::Kind::DependentGenericSignature) {
|
|
auto decl = popNode();
|
|
return createWithChildren(nodeKind, decl, sigOrDecl, type);
|
|
} else {
|
|
return createWithChildren(nodeKind, sigOrDecl, type);
|
|
}
|
|
}
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
NodePointer Demangler::demangleGenericSpecialization(Node::Kind SpecKind) {
|
|
NodePointer Spec = demangleSpecAttributes(SpecKind);
|
|
if (!Spec)
|
|
return nullptr;
|
|
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: {
|
|
size_t FixedChildren = Param->getNumChildren();
|
|
while (NodePointer Ty = popNode(Node::Kind::Type)) {
|
|
assert(ParamKind == FunctionSigSpecializationParamKind::ClosureProp);
|
|
Param = addChild(Param, 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, createNodeWithAllocatedText(
|
|
Node::Kind::FunctionSignatureSpecializationParamPayload, Text));
|
|
Param->reverseChildren(FixedChildren);
|
|
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.
|
|
const char *Encoding = nullptr;
|
|
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);
|
|
CharVector Str;
|
|
while (isDigit(peekChar())) {
|
|
Str.push_back(nextChar(), *this);
|
|
}
|
|
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 '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));
|
|
}
|
|
case 'r': {
|
|
return createWithChild(Node::Kind::OutlinedRetain,
|
|
popNode(Node::Kind::Type));
|
|
}
|
|
case 's': {
|
|
return createWithChild(Node::Kind::OutlinedRelease,
|
|
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 'c': {
|
|
NodePointer Superclass = popNode(Node::Kind::Type);
|
|
NodePointer Protocols = demangleProtocolList();
|
|
return createType(createWithChildren(Node::Kind::ProtocolListWithClass,
|
|
Protocols, Superclass));
|
|
}
|
|
case 'l': {
|
|
NodePointer Protocols = demangleProtocolList();
|
|
return createType(createWithChild(Node::Kind::ProtocolListWithAnyObject,
|
|
Protocols));
|
|
}
|
|
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));
|
|
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::demangleProtocolList() {
|
|
NodePointer TypeList = createNode(Node::Kind::TypeList);
|
|
NodePointer ProtoList = createWithChild(Node::Kind::ProtocolList, TypeList);
|
|
if (!popNode(Node::Kind::EmptyList)) {
|
|
bool firstElem = false;
|
|
do {
|
|
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
|
|
NodePointer Proto = popProtocol();
|
|
if (!Proto)
|
|
return nullptr;
|
|
TypeList->addChild(Proto, *this);
|
|
} while (!firstElem);
|
|
|
|
TypeList->reverseChildren();
|
|
}
|
|
return ProtoList;
|
|
}
|
|
|
|
NodePointer Demangler::demangleProtocolListType() {
|
|
NodePointer ProtoList = demangleProtocolList();
|
|
return createType(ProtoList);
|
|
}
|
|
|
|
NodePointer Demangler::demangleGenericSignature(bool hasParamCounts) {
|
|
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;
|
|
size_t NumCounts = Sig->getNumChildren();
|
|
while (NodePointer Req = popNode(isRequirement)) {
|
|
Sig->addChild(Req, *this);
|
|
}
|
|
Sig->reverseChildren(NumCounts);
|
|
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;
|
|
const char *name = nullptr;
|
|
if (c == 'U') {
|
|
name = "U";
|
|
} else if (c == 'R') {
|
|
name = "R";
|
|
} else if (c == 'N') {
|
|
name = "N";
|
|
} else if (c == 'C') {
|
|
name = "C";
|
|
} else if (c == 'D') {
|
|
name = "D";
|
|
} 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 {
|
|
// Unknown layout constraint.
|
|
return nullptr;
|
|
}
|
|
|
|
auto NameNode = createNode(Node::Kind::Identifier, name);
|
|
auto LayoutRequirement = createWithChildren(
|
|
Node::Kind::DependentGenericLayoutRequirement, ConstrTy, NameNode);
|
|
if (size)
|
|
addChild(LayoutRequirement, size);
|
|
if (alignment)
|
|
addChild(LayoutRequirement, alignment);
|
|
return LayoutRequirement;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
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/Demangling/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;
|
|
}
|
|
|
|
if (nextIf('s')) {
|
|
Nominal->addChild(createNode(Node::Kind::Module, "Swift"), *this);
|
|
} else {
|
|
NodePointer Module = demangleIdentifier();
|
|
if (!Module)
|
|
return nullptr;
|
|
Nominal->addChild(changeKind(Module, Node::Kind::Module), *this);
|
|
}
|
|
|
|
NodePointer Ident = demangleIdentifier();
|
|
if (!Ident)
|
|
return nullptr;
|
|
Nominal->addChild(Ident, *this);
|
|
|
|
if (isProto && !nextIf('_'))
|
|
return nullptr;
|
|
|
|
if (Pos < Text.size())
|
|
return nullptr;
|
|
|
|
return Global;
|
|
}
|
|
|
|
} // namespace Demangle
|
|
} // namespace swift
|