Files
swift-mirror/lib/Demangling/OldDemangler.cpp
Michael Gottesman cb2d7560a4 [rbi] Fix demangling of sending results.
The issue here is that the demangler (since we have a postfix mangling) parses
parameters/results/etc and then uses earlier postfix type arguments to attach
the relevant types to the parameters/results/etc. Since the flag for a sending
result was placed in between the parameters and results, we get an off by one
error.

Rather than fix that specific issue by introducing an offset for the off by one
error, I used the fact that the impl-function part of the mangling is not ABI
and can be modified to move the bit used to signify a sending result to before
the parameters so the whole problem is avoided.

I also while I was doing this looked through the sending result mangling for any
further issues and fixed them as I found them.

rdar://141962865
2025-01-14 15:38:02 -08:00

2412 lines
80 KiB
C++

//===--- OldDemangler.cpp - Old Swift 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 Swift symbol demangling with the old scheme.
//
//===----------------------------------------------------------------------===//
#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Demangling/ManglingUtils.h"
#include "swift/Demangling/Punycode.h"
#include "swift/Strings.h"
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <optional>
#include <vector>
using namespace swift;
using namespace Demangle;
namespace {
struct FindPtr {
FindPtr(Node *v) : Target(v) {}
bool operator()(NodePointer sp) const {
return sp == Target;
}
private:
Node *Target;
};
} // end anonymous namespace
static bool isStartOfIdentifier(char c) {
if (c >= '0' && c <= '9')
return true;
return c == 'o';
}
static bool isStartOfNominalType(char c) {
switch (c) {
case 'C':
case 'V':
case 'O':
return true;
default:
return false;
}
}
static bool isStartOfEntity(char c) {
switch (c) {
case 'F':
case 'I':
case 'v':
case 'P':
case 's':
case 'Z':
return true;
default:
return isStartOfNominalType(c);
}
}
static Node::Kind nominalTypeMarkerToNodeKind(char c) {
if (c == 'C')
return Node::Kind::Class;
if (c == 'V')
return Node::Kind::Structure;
if (c == 'O')
return Node::Kind::Enum;
return Node::Kind::Identifier;
}
namespace {
/// A convenient class for parsing characters out of a string.
class NameSource {
StringRef Text;
public:
NameSource(StringRef text) : Text(text) {}
/// Return whether there are at least len characters remaining.
bool hasAtLeast(size_t len) { return (len <= Text.size()); }
bool isEmpty() { return Text.empty(); }
explicit operator bool() { return !isEmpty(); }
/// Return the next character without claiming it. Asserts that
/// there is at least one remaining character.
char peek() {
if (isEmpty()) {
// Return an otherwise unused character to prevent crashes for malformed
// symbols.
return '.';
}
return Text.front();
}
/// Claim and return the next character. Asserts that there is at
/// least one remaining character.
char next() {
char c = peek();
if (!isEmpty())
advanceOffset(1);
return c;
}
/// Claim the next character if it exists and equals the given
/// character.
bool nextIf(char c) {
if (isEmpty() || peek() != c) return false;
advanceOffset(1);
return true;
}
/// Claim the next few characters if they exactly match the given string.
bool nextIf(StringRef str) {
if (!Text.starts_with(str)) return false;
advanceOffset(str.size());
return true;
}
/// Return the next len characters without claiming them. Asserts
/// that there are at least so many characters.
StringRef slice(size_t len) { return Text.substr(0, len); }
/// Return the current string ref without claiming any characters.
StringRef str() { return Text; }
/// Claim the next len characters.
void advanceOffset(size_t len) {
Text = Text.substr(len);
}
/// Claim and return all the rest of the characters.
StringRef getString() {
auto result = Text;
advanceOffset(Text.size());
return result;
}
bool readUntil(char c, std::string &result) {
std::optional<char> c2;
while (!isEmpty() && (c2 = peek()).value() != c) {
result.push_back(c2.value());
advanceOffset(1);
}
return c2.has_value() && c2.value() == c;
}
};
/// The main class for parsing a demangling tree out of a mangled string.
class OldDemangler {
std::vector<NodePointer> Substitutions;
NameSource Mangled;
NodeFactory &Factory;
static const unsigned MaxDepth = 1024;
public:
OldDemangler(llvm::StringRef mangled, NodeFactory &Factory)
: Mangled(mangled), Factory(Factory) {}
/// Try to demangle a child node of the given kind. If that fails,
/// return; otherwise add it to the parent.
#define DEMANGLE_CHILD_OR_RETURN(PARENT, CHILD_KIND, DEPTH) \
do { \
auto _node = demangle##CHILD_KIND(DEPTH); \
if (!_node) \
return nullptr; \
addChild(PARENT, _node); \
} while (false)
/// Try to demangle a child node of the given kind. If that fails,
/// return; otherwise add it to the parent.
#define DEMANGLE_CHILD_AS_NODE_OR_RETURN(PARENT, CHILD_KIND, DEPTH) \
do { \
auto _kind = demangle##CHILD_KIND(DEPTH); \
if (!_kind.has_value()) \
return nullptr; \
addChild(PARENT, \
Factory.createNode(Node::Kind::CHILD_KIND, unsigned(*_kind))); \
} while (false)
/// Attempt to demangle the source string. The root node will
/// always be a Global. Extra characters at the end will be
/// tolerated (and included as a Suffix node as a child of the
/// Global).
///
/// \return true if the mangling succeeded
NodePointer demangleTopLevel() {
if (!Mangled.nextIf("_T"))
return nullptr;
NodePointer topLevel = Factory.createNode(Node::Kind::Global);
// First demangle any specialization prefixes.
if (Mangled.nextIf("TS")) {
do {
DEMANGLE_CHILD_OR_RETURN(topLevel, SpecializedAttribute, 0);
// The Substitution header does not share state with the rest
// of the mangling.
Substitutions.clear();
} while (Mangled.nextIf("_TTS"));
// Then check that we have a global.
if (!Mangled.nextIf("_T"))
return nullptr;
} else if (Mangled.nextIf("To")) {
addChild(topLevel, Factory.createNode(Node::Kind::ObjCAttribute));
} else if (Mangled.nextIf("TO")) {
addChild(topLevel, Factory.createNode(Node::Kind::NonObjCAttribute));
} else if (Mangled.nextIf("TD")) {
addChild(topLevel, Factory.createNode(Node::Kind::DynamicAttribute));
} else if (Mangled.nextIf("Td")) {
addChild(topLevel, Factory.createNode(
Node::Kind::DirectMethodReferenceAttribute));
} else if (Mangled.nextIf("TV")) {
addChild(topLevel, Factory.createNode(Node::Kind::VTableAttribute));
}
DEMANGLE_CHILD_OR_RETURN(topLevel, Global, 0);
// Add a suffix node if there's anything left unmangled.
if (!Mangled.isEmpty()) {
addChild(topLevel, Factory.createNode(Node::Kind::Suffix,
Mangled.getString()));
}
return topLevel;
}
NodePointer demangleTypeName(unsigned depth) { return demangleType(depth); }
private:
enum class IsVariadic {
yes = true, no = false
};
void addChild(NodePointer Parent, NodePointer Child) {
Parent->addChild(Child, Factory);
}
std::optional<Directness> demangleDirectness(unsigned depth) {
if (Mangled.nextIf('d'))
return Directness::Direct;
if (Mangled.nextIf('i'))
return Directness::Indirect;
return std::nullopt;
}
bool demangleNatural(Node::IndexType &num, unsigned depth) {
if (!Mangled)
return false;
char c = Mangled.next();
if (c < '0' || c > '9')
return false;
num = (c - '0');
while (true) {
if (!Mangled) {
return true;
}
c = Mangled.peek();
if (c < '0' || c > '9') {
return true;
} else {
num = (10 * num) + (c - '0');
}
Mangled.next();
}
}
bool demangleBuiltinSize(Node::IndexType &num, unsigned depth) {
if (!demangleNatural(num, depth + 1))
return false;
if (Mangled.nextIf('_'))
return true;
return false;
}
std::optional<ValueWitnessKind> demangleValueWitnessKind(unsigned depth) {
char Code[2];
if (!Mangled)
return std::nullopt;
Code[0] = Mangled.next();
if (!Mangled)
return std::nullopt;
Code[1] = Mangled.next();
StringRef CodeStr(Code, 2);
#define VALUE_WITNESS(MANGLING, NAME) \
if (CodeStr == #MANGLING) return ValueWitnessKind::NAME;
#include "swift/Demangling/ValueWitnessMangling.def"
return std::nullopt;
}
NodePointer demangleGlobal(unsigned depth) {
if (depth > OldDemangler::MaxDepth || !Mangled)
return nullptr;
// Type metadata.
if (Mangled.nextIf('M')) {
if (Mangled.nextIf('P')) {
auto pattern =
Factory.createNode(Node::Kind::GenericTypeMetadataPattern);
DEMANGLE_CHILD_OR_RETURN(pattern, Type, depth + 1);
return pattern;
}
if (Mangled.nextIf('a')) {
auto accessor =
Factory.createNode(Node::Kind::TypeMetadataAccessFunction);
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
return accessor;
}
if (Mangled.nextIf('L')) {
auto cache = Factory.createNode(Node::Kind::TypeMetadataLazyCache);
DEMANGLE_CHILD_OR_RETURN(cache, Type, depth + 1);
return cache;
}
if (Mangled.nextIf('m')) {
auto metaclass = Factory.createNode(Node::Kind::Metaclass);
DEMANGLE_CHILD_OR_RETURN(metaclass, Type, depth + 1);
return metaclass;
}
if (Mangled.nextIf('n')) {
auto nominalType =
Factory.createNode(Node::Kind::NominalTypeDescriptor);
DEMANGLE_CHILD_OR_RETURN(nominalType, Type, depth + 1);
return nominalType;
}
if (Mangled.nextIf('f')) {
auto metadata = Factory.createNode(Node::Kind::FullTypeMetadata);
DEMANGLE_CHILD_OR_RETURN(metadata, Type, depth + 1);
return metadata;
}
if (Mangled.nextIf('p')) {
auto metadata = Factory.createNode(Node::Kind::ProtocolDescriptor);
DEMANGLE_CHILD_OR_RETURN(metadata, ProtocolName, depth + 1);
return metadata;
}
auto metadata = Factory.createNode(Node::Kind::TypeMetadata);
DEMANGLE_CHILD_OR_RETURN(metadata, Type, depth + 1);
return metadata;
}
// Partial application thunks.
if (Mangled.nextIf("PA")) {
Node::Kind kind = Node::Kind::PartialApplyForwarder;
if (Mangled.nextIf('o'))
kind = Node::Kind::PartialApplyObjCForwarder;
auto forwarder = Factory.createNode(kind);
if (Mangled.nextIf("__T"))
DEMANGLE_CHILD_OR_RETURN(forwarder, Global, depth + 1);
return forwarder;
}
// Top-level types, for various consumers.
if (Mangled.nextIf('t')) {
auto type = Factory.createNode(Node::Kind::TypeMangling);
DEMANGLE_CHILD_OR_RETURN(type, Type, depth + 1);
return type;
}
// Value witnesses.
if (Mangled.nextIf('w')) {
std::optional<ValueWitnessKind> w = demangleValueWitnessKind(depth + 1);
if (!w.has_value())
return nullptr;
auto witness =
Factory.createNode(Node::Kind::ValueWitness);
NodePointer Idx = Factory.createNode(Node::Kind::Index,
unsigned(w.value()));
witness->addChild(Idx, Factory);
DEMANGLE_CHILD_OR_RETURN(witness, Type, depth + 1);
return witness;
}
// Offsets, value witness tables, and protocol witnesses.
if (Mangled.nextIf('W')) {
if (Mangled.nextIf('V')) {
auto witnessTable = Factory.createNode(Node::Kind::ValueWitnessTable);
DEMANGLE_CHILD_OR_RETURN(witnessTable, Type, depth + 1);
return witnessTable;
}
if (Mangled.nextIf('v')) {
auto fieldOffset = Factory.createNode(Node::Kind::FieldOffset);
DEMANGLE_CHILD_AS_NODE_OR_RETURN(fieldOffset, Directness, depth + 1);
DEMANGLE_CHILD_OR_RETURN(fieldOffset, Entity, depth + 1);
return fieldOffset;
}
if (Mangled.nextIf('P')) {
auto witnessTable =
Factory.createNode(Node::Kind::ProtocolWitnessTable);
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
return witnessTable;
}
if (Mangled.nextIf('G')) {
auto witnessTable =
Factory.createNode(Node::Kind::GenericProtocolWitnessTable);
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
return witnessTable;
}
if (Mangled.nextIf('I')) {
auto witnessTable = Factory.createNode(
Node::Kind::GenericProtocolWitnessTableInstantiationFunction);
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance, depth + 1);
return witnessTable;
}
if (Mangled.nextIf('l')) {
auto accessor =
Factory.createNode(Node::Kind::LazyProtocolWitnessTableAccessor);
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
return accessor;
}
if (Mangled.nextIf('L')) {
auto accessor =
Factory.createNode(Node::Kind::LazyProtocolWitnessTableCacheVariable);
DEMANGLE_CHILD_OR_RETURN(accessor, Type, depth + 1);
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
return accessor;
}
if (Mangled.nextIf('a')) {
auto tableTemplate =
Factory.createNode(Node::Kind::ProtocolWitnessTableAccessor);
DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance, depth + 1);
return tableTemplate;
}
if (Mangled.nextIf('t')) {
auto accessor = Factory.createNode(
Node::Kind::AssociatedTypeMetadataAccessor);
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName, depth + 1);
return accessor;
}
if (Mangled.nextIf('T')) {
auto accessor = Factory.createNode(
Node::Kind::AssociatedTypeWitnessTableAccessor);
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance, depth + 1);
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName, depth + 1);
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName, depth + 1);
return accessor;
}
return nullptr;
}
// Other thunks.
if (Mangled.nextIf('T')) {
if (Mangled.nextIf('R')) {
auto thunk = Factory.createNode(Node::Kind::ReabstractionThunkHelper);
if (!demangleReabstractSignature(thunk, depth + 1))
return nullptr;
return thunk;
}
if (Mangled.nextIf('r')) {
auto thunk = Factory.createNode(Node::Kind::ReabstractionThunk);
if (!demangleReabstractSignature(thunk, depth + 1))
return nullptr;
return thunk;
}
if (Mangled.nextIf('W')) {
NodePointer thunk = Factory.createNode(Node::Kind::ProtocolWitness);
DEMANGLE_CHILD_OR_RETURN(thunk, ProtocolConformance, depth + 1);
// The entity is mangled in its own generic context.
DEMANGLE_CHILD_OR_RETURN(thunk, Entity, depth + 1);
return thunk;
}
return nullptr;
}
// Everything else is just an entity.
return demangleEntity(depth + 1);
}
NodePointer demangleGenericSpecialization(NodePointer specialization,
unsigned depth) {
if (depth > OldDemangler::MaxDepth)
return nullptr;
while (!Mangled.nextIf('_')) {
// Otherwise, we have another parameter. Demangle the type.
NodePointer param = Factory.createNode(Node::Kind::GenericSpecializationParam);
DEMANGLE_CHILD_OR_RETURN(param, Type, depth + 1);
// Then parse any conformances until we find an underscore. Pop off the
// underscore since it serves as the end of our mangling list.
while (!Mangled.nextIf('_')) {
DEMANGLE_CHILD_OR_RETURN(param, ProtocolConformance, depth + 1);
}
// Add the parameter to our specialization list.
specialization->addChild(param, Factory);
}
return specialization;
}
/// TODO: This is an atrocity. Come up with a shorter name.
#define FUNCSIGSPEC_CREATE_PARAM_KIND(kind) \
Factory.createNode( \
Node::Kind::FunctionSignatureSpecializationParamKind, \
Node::IndexType(FunctionSigSpecializationParamKind::kind))
#define FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(payload) \
Factory.createNode(Node::Kind::FunctionSignatureSpecializationParamPayload, \
payload)
bool demangleFuncSigSpecializationConstantProp(NodePointer parent,
unsigned depth) {
// Then figure out what was actually constant propagated. First check if
// we have a function.
if (Mangled.nextIf("fr")) {
// Demangle the identifier
NodePointer name = demangleIdentifier(depth + 1);
if (!name || !Mangled.nextIf('_'))
return false;
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFunction), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
return true;
}
if (Mangled.nextIf('g')) {
NodePointer name = demangleIdentifier(depth + 1);
if (!name || !Mangled.nextIf('_'))
return false;
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropGlobal), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
return true;
}
if (Mangled.nextIf('i')) {
std::string Str;
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
return false;
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropInteger), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str), Factory);
return true;
}
if (Mangled.nextIf("fl")) {
std::string Str;
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
return false;
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFloat), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str), Factory);
return true;
}
if (Mangled.nextIf("s")) {
// Skip: 'e' encoding 'v' str. encoding is a 0 or 1 and str is a string of
// length less than or equal to 32. We do not specialize strings with a
// length greater than 32.
if (!Mangled.nextIf('e'))
return false;
char encoding = Mangled.peek();
if (encoding != '0' && encoding != '1')
return false;
std::string encodingStr;
if (encoding == '0')
encodingStr += "u8";
else
encodingStr += "u16";
Mangled.advanceOffset(1);
if (!Mangled.nextIf('v'))
return false;
NodePointer str = demangleIdentifier(depth + 1);
if (!str || !Mangled.nextIf('_'))
return false;
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropString), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(encodingStr), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(str->getText()), Factory);
return true;
}
// Unknown constant prop specialization
return false;
}
bool demangleFuncSigSpecializationClosureProp(NodePointer parent,
unsigned depth) {
// We don't actually demangle the function or types for now. But we do want
// to signal that we specialized a closure.
NodePointer name = demangleIdentifier(depth + 1);
if (!name) {
return false;
}
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ClosureProp), Factory);
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()), Factory);
// Then demangle types until we fail.
NodePointer type = nullptr;
while (Mangled.peek() != '_' && (type = demangleType(depth + 1))) {
parent->addChild(type, Factory);
}
// Eat last '_'
if (!Mangled.nextIf('_'))
return false;
return true;
}
NodePointer
demangleFunctionSignatureSpecialization(NodePointer specialization,
unsigned depth) {
// Until we hit the last '_' in our specialization info...
while (!Mangled.nextIf('_')) {
// Create the parameter.
NodePointer param =
Factory.createNode(Node::Kind::FunctionSignatureSpecializationParam);
// First handle options.
if (Mangled.nextIf("n_")) {
// Leave the parameter empty.
} else if (Mangled.nextIf("cp")) {
if (!demangleFuncSigSpecializationConstantProp(param, depth + 1))
return nullptr;
} else if (Mangled.nextIf("cl")) {
if (!demangleFuncSigSpecializationClosureProp(param, depth + 1))
return nullptr;
} else if (Mangled.nextIf("i_")) {
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToValue);
if (!result)
return nullptr;
param->addChild(result, Factory);
} else if (Mangled.nextIf("k_")) {
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToStack);
if (!result)
return nullptr;
param->addChild(result, Factory);
} else if (Mangled.nextIf("r_")) {
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(InOutToOut);
if (!result)
return nullptr;
param->addChild(result, Factory);
} else {
// Otherwise handle option sets.
unsigned Value = 0;
if (Mangled.nextIf('d')) {
Value |=
unsigned(FunctionSigSpecializationParamKind::Dead);
}
if (Mangled.nextIf('g')) {
Value |=
unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed);
}
if (Mangled.nextIf('o')) {
Value |=
unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned);
}
if (Mangled.nextIf('s')) {
Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
}
if (!Mangled.nextIf('_'))
return nullptr;
if (!Value)
return nullptr;
auto result = Factory.createNode(
Node::Kind::FunctionSignatureSpecializationParamKind, Value);
if (!result)
return nullptr;
param->addChild(result, Factory);
}
specialization->addChild(param, Factory);
}
return specialization;
}
#undef FUNCSIGSPEC_CREATE_PARAM_KIND
#undef FUNCSIGSPEC_CREATE_PARAM_PAYLOAD
NodePointer demangleSpecializedAttribute(unsigned depth) {
bool isNotReAbstracted = false;
if (Mangled.nextIf("g") || (isNotReAbstracted = Mangled.nextIf("r"))) {
auto spec = Factory.createNode(isNotReAbstracted ?
Node::Kind::GenericSpecializationNotReAbstracted :
Node::Kind::GenericSpecialization);
// Create a node if the specialization is serialized.
if (Mangled.nextIf("q")) {
auto kind = Node::Kind::IsSerialized;
spec->addChild(Factory.createNode(kind), Factory);
}
// Create a node for the pass id.
spec->addChild(Factory.createNode(Node::Kind::SpecializationPassID,
unsigned(Mangled.next() - 48)), Factory);
// And then mangle the generic specialization.
return demangleGenericSpecialization(spec, depth + 1);
}
if (Mangled.nextIf("f")) {
auto spec =
Factory.createNode(Node::Kind::FunctionSignatureSpecialization);
// Create a node if the specialization is serialized.
if (Mangled.nextIf("q")) {
auto kind = Node::Kind::IsSerialized;
spec->addChild(Factory.createNode(kind), Factory);
}
// Add the pass id.
spec->addChild(Factory.createNode(Node::Kind::SpecializationPassID,
unsigned(Mangled.next() - 48)), Factory);
// Then perform the function signature specialization.
return demangleFunctionSignatureSpecialization(spec, depth + 1);
}
// We don't know how to handle this specialization.
return nullptr;
}
NodePointer demangleDeclName(unsigned depth) {
// decl-name ::= local-decl-name
// local-decl-name ::= 'L' index identifier
if (Mangled.nextIf('L')) {
NodePointer discriminator = demangleIndexAsNode(depth + 1);
if (!discriminator) return nullptr;
NodePointer name = demangleIdentifier(depth + 1);
if (!name) return nullptr;
NodePointer localName = Factory.createNode(Node::Kind::LocalDeclName);
localName->addChild(discriminator, Factory);
localName->addChild(name, Factory);
return localName;
} else if (Mangled.nextIf('P')) {
NodePointer discriminator = demangleIdentifier(depth + 1);
if (!discriminator) return nullptr;
NodePointer name = demangleIdentifier(depth + 1);
if (!name) return nullptr;
auto privateName = Factory.createNode(Node::Kind::PrivateDeclName);
privateName->addChild(discriminator, Factory);
privateName->addChild(name, Factory);
return privateName;
}
// decl-name ::= identifier
return demangleIdentifier(depth + 1);
}
NodePointer
demangleIdentifier(unsigned depth,
std::optional<Node::Kind> kind = std::nullopt) {
if (!Mangled)
return nullptr;
bool isPunycoded = Mangled.nextIf('X');
std::string decodeBuffer;
auto decode = [&](StringRef s) -> StringRef {
if (!isPunycoded)
return s;
if (!Punycode::decodePunycodeUTF8(s, decodeBuffer))
return {};
return decodeBuffer;
};
bool isOperator = false;
if (Mangled.nextIf('o')) {
isOperator = true;
// Operator identifiers aren't valid in the contexts that are
// building more specific identifiers.
if (kind.has_value()) return nullptr;
char op_mode = Mangled.next();
switch (op_mode) {
case 'p':
kind = Node::Kind::PrefixOperator;
break;
case 'P':
kind = Node::Kind::PostfixOperator;
break;
case 'i':
kind = Node::Kind::InfixOperator;
break;
default:
return nullptr;
}
}
if (!kind.has_value()) kind = Node::Kind::Identifier;
Node::IndexType length;
if (!demangleNatural(length, depth + 1))
return nullptr;
if (!Mangled.hasAtLeast(length))
return nullptr;
StringRef identifier = Mangled.slice(length);
Mangled.advanceOffset(length);
// Decode Unicode identifiers.
identifier = decode(identifier);
if (identifier.empty())
return nullptr;
// Decode operator names.
std::string opDecodeBuffer;
if (isOperator) {
// abcdefghijklmnopqrstuvwxyz
static const char op_char_table[] = "& @/= > <*!|+?%-~ ^ .";
opDecodeBuffer.reserve(identifier.size());
for (signed char c : identifier) {
if (c < 0) {
// Pass through Unicode characters.
opDecodeBuffer.push_back(c);
continue;
}
if (c < 'a' || c > 'z')
return nullptr;
char o = op_char_table[c - 'a'];
if (o == ' ')
return nullptr;
opDecodeBuffer.push_back(o);
}
identifier = opDecodeBuffer;
}
return Factory.createNode(*kind, identifier);
}
bool demangleIndex(Node::IndexType &natural, unsigned depth) {
if (Mangled.nextIf('_')) {
natural = 0;
return true;
}
if (demangleNatural(natural, depth + 1)) {
if (!Mangled.nextIf('_'))
return false;
++natural;
return true;
}
return false;
}
/// Demangle an <index> and package it as a node of some kind.
NodePointer demangleIndexAsNode(unsigned depth,
Node::Kind kind = Node::Kind::Number) {
Node::IndexType index;
if (!demangleIndex(index, depth))
return nullptr;
return Factory.createNode(kind, index);
}
NodePointer createSwiftType(Node::Kind typeKind, StringRef name) {
NodePointer type = Factory.createNode(typeKind);
type->addChild(Factory.createNode(Node::Kind::Module, STDLIB_NAME), Factory);
type->addChild(Factory.createNode(Node::Kind::Identifier, name), Factory);
return type;
}
/// Demangle a <substitution>, given that we've already consumed the 'S'.
NodePointer demangleSubstitutionIndex(unsigned depth) {
if (!Mangled)
return nullptr;
if (Mangled.nextIf('o'))
return Factory.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
if (Mangled.nextIf('C'))
return Factory.createNode(Node::Kind::Module,
MANGLING_MODULE_CLANG_IMPORTER);
if (Mangled.nextIf('a'))
return createSwiftType(Node::Kind::Structure, "Array");
if (Mangled.nextIf('b'))
return createSwiftType(Node::Kind::Structure, "Bool");
if (Mangled.nextIf('c'))
return createSwiftType(Node::Kind::Structure, "UnicodeScalar");
if (Mangled.nextIf('d'))
return createSwiftType(Node::Kind::Structure, "Double");
if (Mangled.nextIf('f'))
return createSwiftType(Node::Kind::Structure, "Float");
if (Mangled.nextIf('i'))
return createSwiftType(Node::Kind::Structure, "Int");
if (Mangled.nextIf('V'))
return createSwiftType(Node::Kind::Structure, "UnsafeRawPointer");
if (Mangled.nextIf('v'))
return createSwiftType(Node::Kind::Structure, "UnsafeMutableRawPointer");
if (Mangled.nextIf('P'))
return createSwiftType(Node::Kind::Structure, "UnsafePointer");
if (Mangled.nextIf('p'))
return createSwiftType(Node::Kind::Structure, "UnsafeMutablePointer");
if (Mangled.nextIf('q'))
return createSwiftType(Node::Kind::Enum, "Optional");
if (Mangled.nextIf('Q'))
return createSwiftType(Node::Kind::Enum, "ImplicitlyUnwrappedOptional");
if (Mangled.nextIf('R'))
return createSwiftType(Node::Kind::Structure, "UnsafeBufferPointer");
if (Mangled.nextIf('r'))
return createSwiftType(Node::Kind::Structure, "UnsafeMutableBufferPointer");
if (Mangled.nextIf('S'))
return createSwiftType(Node::Kind::Structure, "String");
if (Mangled.nextIf('u'))
return createSwiftType(Node::Kind::Structure, "UInt");
Node::IndexType index_sub;
if (!demangleIndex(index_sub, depth))
return nullptr;
if (index_sub >= Substitutions.size())
return nullptr;
return Substitutions[index_sub];
}
NodePointer demangleModule(unsigned depth) {
if (Mangled.nextIf('s')) {
return Factory.createNode(Node::Kind::Module, STDLIB_NAME);
}
if (Mangled.nextIf('S')) {
NodePointer module = demangleSubstitutionIndex(depth + 1);
if (!module)
return nullptr;
if (module->getKind() != Node::Kind::Module)
return nullptr;
return module;
}
NodePointer module = demangleIdentifier(depth + 1, Node::Kind::Module);
if (!module) return nullptr;
Substitutions.push_back(module);
return module;
}
NodePointer demangleDeclarationName(Node::Kind kind, unsigned depth) {
NodePointer context = demangleContext(depth + 1);
if (!context) return nullptr;
auto name = demangleDeclName(depth + 1);
if (!name) return nullptr;
auto decl = Factory.createNode(kind);
decl->addChild(context, Factory);
decl->addChild(name, Factory);
Substitutions.push_back(decl);
return decl;
}
NodePointer demangleProtocolName(unsigned depth) {
NodePointer proto = demangleProtocolNameImpl(depth);
if (!proto) return nullptr;
NodePointer type = Factory.createNode(Node::Kind::Type);
type->addChild(proto, Factory);
return type;
}
NodePointer demangleProtocolNameGivenContext(NodePointer context,
unsigned depth) {
NodePointer name = demangleDeclName(depth + 1);
if (!name) return nullptr;
auto proto = Factory.createNode(Node::Kind::Protocol);
proto->addChild(context, Factory);
proto->addChild(name, Factory);
Substitutions.push_back(proto);
return proto;
}
NodePointer demangleProtocolNameImpl(unsigned depth) {
if (depth > OldDemangler::MaxDepth)
return nullptr;
// There's an ambiguity in <protocol> between a substitution of
// the protocol and a substitution of the protocol's context, so
// we have to duplicate some of the logic from
// demangleDeclarationName.
if (Mangled.nextIf('S')) {
NodePointer sub = demangleSubstitutionIndex(depth + 1);
if (!sub) return nullptr;
if (sub->getKind() == Node::Kind::Protocol)
return sub;
if (sub->getKind() != Node::Kind::Module)
return nullptr;
return demangleProtocolNameGivenContext(sub, depth + 1);
}
if (Mangled.nextIf('s')) {
NodePointer stdlib = Factory.createNode(Node::Kind::Module, STDLIB_NAME);
return demangleProtocolNameGivenContext(stdlib, depth + 1);
}
return demangleDeclarationName(Node::Kind::Protocol, depth + 1);
}
NodePointer demangleNominalType(unsigned depth) {
if (Mangled.nextIf('S'))
return demangleSubstitutionIndex(depth + 1);
if (Mangled.nextIf('V'))
return demangleDeclarationName(Node::Kind::Structure, depth + 1);
if (Mangled.nextIf('O'))
return demangleDeclarationName(Node::Kind::Enum, depth + 1);
if (Mangled.nextIf('C'))
return demangleDeclarationName(Node::Kind::Class, depth + 1);
if (Mangled.nextIf('P'))
return demangleDeclarationName(Node::Kind::Protocol, depth + 1);
return nullptr;
}
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
unsigned depth) {
if (nominalType->getNumChildren() == 0)
return nullptr;
// Generic arguments for the outermost type come first.
NodePointer parentOrModule = nominalType->getChild(0);
if (parentOrModule->getKind() != Node::Kind::Module &&
parentOrModule->getKind() != Node::Kind::Function &&
parentOrModule->getKind() != Node::Kind::Extension) {
parentOrModule = demangleBoundGenericArgs(parentOrModule, depth + 1);
if (!parentOrModule)
return nullptr;
// Rebuild this type with the new parent type, which may have
// had its generic arguments applied.
NodePointer result = Factory.createNode(nominalType->getKind());
result->addChild(parentOrModule, Factory);
for (unsigned ndx = 1; ndx < nominalType->getNumChildren(); ++ndx)
result->addChild(nominalType->getChild(ndx), Factory);
nominalType = result;
}
NodePointer args = Factory.createNode(Node::Kind::TypeList);
while (!Mangled.nextIf('_')) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
args->addChild(type, Factory);
if (Mangled.isEmpty())
return nullptr;
}
// If there were no arguments at this level there is nothing left
// to do.
if (args->getNumChildren() == 0)
return nominalType;
// Otherwise, build a bound generic type node from the unbound
// type and arguments.
NodePointer unboundType = Factory.createNode(Node::Kind::Type);
unboundType->addChild(nominalType, Factory);
Node::Kind kind;
switch (nominalType->getKind()) { // look through Type node
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;
}
NodePointer result = Factory.createNode(kind);
result->addChild(unboundType, Factory);
result->addChild(args, Factory);
return result;
}
NodePointer demangleBoundGenericType(unsigned depth) {
// bound-generic-type ::= 'G' nominal-type (args+ '_')+
//
// Each level of nominal type nesting has its own list of arguments.
NodePointer nominalType = demangleNominalType(depth + 1);
if (!nominalType)
return nullptr;
return demangleBoundGenericArgs(nominalType, depth + 1);
}
NodePointer demangleContext(unsigned depth) {
// context ::= module
// context ::= entity
// context ::= 'E' module context (extension defined in a different module)
// context ::= 'e' module context generic-signature (constrained extension)
if (!Mangled) return nullptr;
if (Mangled.nextIf('E')) {
NodePointer ext = Factory.createNode(Node::Kind::Extension);
NodePointer def_module = demangleModule(depth + 1);
if (!def_module) return nullptr;
NodePointer type = demangleContext(depth + 1);
if (!type) return nullptr;
ext->addChild(def_module, Factory);
ext->addChild(type, Factory);
return ext;
}
if (Mangled.nextIf('e')) {
NodePointer ext = Factory.createNode(Node::Kind::Extension);
NodePointer def_module = demangleModule(depth + 1);
if (!def_module) return nullptr;
NodePointer sig = demangleGenericSignature(depth + 1);
// The generic context is currently re-specified by the type mangling.
// If we ever remove 'self' from manglings, we should stop resetting the
// context here.
if (!sig) return nullptr;
NodePointer type = demangleContext(depth + 1);
if (!type) return nullptr;
ext->addChild(def_module, Factory);
ext->addChild(type, Factory);
ext->addChild(sig, Factory);
return ext;
}
if (Mangled.nextIf('S'))
return demangleSubstitutionIndex(depth + 1);
if (Mangled.nextIf('s'))
return Factory.createNode(Node::Kind::Module, STDLIB_NAME);
if (Mangled.nextIf('G'))
return demangleBoundGenericType(depth + 1);
if (isStartOfEntity(Mangled.peek()))
return demangleEntity(depth + 1);
return demangleModule(depth + 1);
}
NodePointer demangleProtocolList(unsigned depth) {
NodePointer proto_list = Factory.createNode(Node::Kind::ProtocolList);
NodePointer type_list = Factory.createNode(Node::Kind::TypeList);
proto_list->addChild(type_list, Factory);
while (!Mangled.nextIf('_')) {
NodePointer proto = demangleProtocolName(depth + 1);
if (!proto)
return nullptr;
type_list->addChild(proto, Factory);
}
return proto_list;
}
NodePointer demangleProtocolConformance(unsigned depth) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer protocol = demangleProtocolName(depth + 1);
if (!protocol)
return nullptr;
NodePointer context = demangleContext(depth + 1);
if (!context)
return nullptr;
NodePointer proto_conformance =
Factory.createNode(Node::Kind::ProtocolConformance);
proto_conformance->addChild(type, Factory);
proto_conformance->addChild(protocol, Factory);
proto_conformance->addChild(context, Factory);
return proto_conformance;
}
// entity ::= entity-kind context entity-name
// entity ::= nominal-type
NodePointer demangleEntity(unsigned depth) {
if (depth > OldDemangler::MaxDepth)
return nullptr;
// static?
bool isStatic = Mangled.nextIf('Z');
// entity-kind
Node::Kind entityBasicKind;
if (Mangled.nextIf('F')) {
entityBasicKind = Node::Kind::Function;
} else if (Mangled.nextIf('v')) {
entityBasicKind = Node::Kind::Variable;
} else if (Mangled.nextIf('I')) {
entityBasicKind = Node::Kind::Initializer;
} else if (Mangled.nextIf('i')) {
entityBasicKind = Node::Kind::Subscript;
} else {
return demangleNominalType(depth + 1);
}
NodePointer context = demangleContext(depth + 1);
if (!context) return nullptr;
// entity-name
Node::Kind entityKind;
bool hasType = true;
// Wrap the enclosed entity in a variable or subscript node
bool wrapEntity = false;
NodePointer name = nullptr;
if (Mangled.nextIf('D')) {
entityKind = Node::Kind::Deallocator;
hasType = false;
} else if (Mangled.nextIf('Z')) {
entityKind = Node::Kind::IsolatedDeallocator;
hasType = false;
} else if (Mangled.nextIf('d')) {
entityKind = Node::Kind::Destructor;
hasType = false;
} else if (Mangled.nextIf('e')) {
entityKind = Node::Kind::IVarInitializer;
hasType = false;
} else if (Mangled.nextIf('E')) {
entityKind = Node::Kind::IVarDestroyer;
hasType = false;
} else if (Mangled.nextIf('C')) {
entityKind = Node::Kind::Allocator;
} else if (Mangled.nextIf('c')) {
entityKind = Node::Kind::Constructor;
} else if (Mangled.nextIf('a')) {
wrapEntity = true;
if (Mangled.nextIf('O')) {
entityKind = Node::Kind::OwningMutableAddressor;
} else if (Mangled.nextIf('o')) {
entityKind = Node::Kind::NativeOwningMutableAddressor;
} else if (Mangled.nextIf('p')) {
entityKind = Node::Kind::NativePinningMutableAddressor;
} else if (Mangled.nextIf('u')) {
entityKind = Node::Kind::UnsafeMutableAddressor;
} else {
return nullptr;
}
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('l')) {
wrapEntity = true;
if (Mangled.nextIf('O')) {
entityKind = Node::Kind::OwningAddressor;
} else if (Mangled.nextIf('o')) {
entityKind = Node::Kind::NativeOwningAddressor;
} else if (Mangled.nextIf('p')) {
entityKind = Node::Kind::NativePinningAddressor;
} else if (Mangled.nextIf('u')) {
entityKind = Node::Kind::UnsafeAddressor;
} else {
return nullptr;
}
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('g')) {
wrapEntity = true;
entityKind = Node::Kind::Getter;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('G')) {
wrapEntity = true;
entityKind = Node::Kind::GlobalGetter;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('s')) {
wrapEntity = true;
entityKind = Node::Kind::Setter;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('m')) {
wrapEntity = true;
entityKind = Node::Kind::MaterializeForSet;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('w')) {
wrapEntity = true;
entityKind = Node::Kind::WillSet;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('W')) {
wrapEntity = true;
entityKind = Node::Kind::DidSet;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('r')) {
wrapEntity = true;
entityKind = Node::Kind::ReadAccessor;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('M')) {
wrapEntity = true;
entityKind = Node::Kind::ModifyAccessor;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('U')) {
entityKind = Node::Kind::ExplicitClosure;
name = demangleIndexAsNode(depth + 1);
if (!name) return nullptr;
} else if (Mangled.nextIf('u')) {
entityKind = Node::Kind::ImplicitClosure;
name = demangleIndexAsNode(depth + 1);
if (!name) return nullptr;
} else if (entityBasicKind == Node::Kind::Initializer) {
// entity-name ::= 'A' index
if (Mangled.nextIf('A')) {
entityKind = Node::Kind::DefaultArgumentInitializer;
name = demangleIndexAsNode(depth + 1);
if (!name) return nullptr;
// entity-name ::= 'i'
} else if (Mangled.nextIf('i')) {
entityKind = Node::Kind::Initializer;
} else {
return nullptr;
}
hasType = false;
} else {
entityKind = entityBasicKind;
name = demangleDeclName(depth + 1);
if (!name) return nullptr;
}
NodePointer entity = Factory.createNode(entityKind);
if (wrapEntity) {
// Create a subscript or variable node and make it the accessor's child
NodePointer wrappedEntity;
bool isSubscript = false;
// Rewrite the subscript's name to match the new mangling scheme
switch (name->getKind()) {
case Node::Kind::Identifier:
if (name->getText() == "subscript") {
isSubscript = true;
// Subscripts have no 'subscript' identifier name
name = nullptr;
}
break;
case Node::Kind::PrivateDeclName: // identifier file-discriminator?
if (name->getNumChildren() > 1 &&
name->getChild(1)->getText() == "subscript") {
isSubscript = true;
auto discriminator = name->getChild(0);
// Create new PrivateDeclName with no 'subscript' identifier child
name = Factory.createNode(Node::Kind::PrivateDeclName);
name->addChild(discriminator, Factory);
}
break;
default:
break;
}
// Create wrapped entity node
if (isSubscript) {
wrappedEntity = Factory.createNode(Node::Kind::Subscript);
} else {
wrappedEntity = Factory.createNode(Node::Kind::Variable);
}
wrappedEntity->addChild(context, Factory);
// Variables mangle their name before their type
if (!isSubscript)
wrappedEntity->addChild(name, Factory);
if (hasType) {
auto type = demangleType(depth + 1);
if (!type) return nullptr;
wrappedEntity->addChild(type, Factory);
}
// Subscripts mangle their file-discriminator after the type
if (isSubscript && name)
wrappedEntity->addChild(name, Factory);
entity->addChild(wrappedEntity, Factory);
} else {
entity->addChild(context, Factory);
if (name) entity->addChild(name, Factory);
if (hasType) {
auto type = demangleType(depth + 1);
if (!type) return nullptr;
entity->addChild(type, Factory);
}
}
if (isStatic) {
auto staticNode = Factory.createNode(Node::Kind::Static);
staticNode->addChild(entity, Factory);
return staticNode;
}
return entity;
}
NodePointer getDependentGenericParamType(unsigned depth, unsigned index) {
DemanglerPrinter PrintName;
PrintName << genericParameterName(depth, index);
auto paramTy = Factory.createNode(Node::Kind::DependentGenericParamType);
paramTy->addChild(Factory.createNode(Node::Kind::Index, depth), Factory);
paramTy->addChild(Factory.createNode(Node::Kind::Index, index), Factory);
return paramTy;
}
NodePointer demangleGenericParamIndex(unsigned depth) {
Node::IndexType paramDepth, index;
if (Mangled.nextIf('d')) {
if (!demangleIndex(paramDepth, depth + 1))
return nullptr;
paramDepth += 1;
if (!demangleIndex(index, depth + 1))
return nullptr;
} else if (Mangled.nextIf('x')) {
paramDepth = 0;
index = 0;
} else {
if (!demangleIndex(index, depth + 1))
return nullptr;
paramDepth = 0;
index += 1;
}
return getDependentGenericParamType(paramDepth, index);
}
NodePointer demangleDependentMemberTypeName(NodePointer base,
unsigned depth) {
assert(base->getKind() == Node::Kind::Type
&& "base should be a type");
NodePointer assocTy = nullptr;
if (Mangled.nextIf('S')) {
assocTy = demangleSubstitutionIndex(depth + 1);
if (!assocTy)
return nullptr;
if (assocTy->getKind() != Node::Kind::DependentAssociatedTypeRef)
return nullptr;
} else {
NodePointer protocol = nullptr;
if (Mangled.nextIf('P')) {
protocol = demangleProtocolName(depth + 1);
if (!protocol) return nullptr;
}
// TODO: If the protocol name was elided from the assoc type mangling,
// we could try to fish it out of the generic signature constraints on the
// base.
NodePointer ID = demangleIdentifier(depth + 1);
if (!ID) return nullptr;
assocTy = Factory.createNode(Node::Kind::DependentAssociatedTypeRef);
if (!assocTy) return nullptr;
assocTy->addChild(ID, Factory);
if (protocol)
assocTy->addChild(protocol, Factory);
Substitutions.push_back(assocTy);
}
NodePointer depTy = Factory.createNode(Node::Kind::DependentMemberType);
depTy->addChild(base, Factory);
depTy->addChild(assocTy, Factory);
return depTy;
}
NodePointer demangleAssociatedTypeSimple(unsigned depth) {
// Demangle the base type.
auto base = demangleGenericParamIndex(depth + 1);
if (!base)
return nullptr;
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
nodeType->addChild(base, Factory);
// Demangle the associated type name.
return demangleDependentMemberTypeName(nodeType, depth + 1);
}
NodePointer demangleAssociatedTypeCompound(unsigned depth) {
// Demangle the base type.
auto base = demangleGenericParamIndex(depth + 1);
if (!base)
return nullptr;
// Demangle the associated type chain.
while (!Mangled.nextIf('_')) {
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
nodeType->addChild(base, Factory);
base = demangleDependentMemberTypeName(nodeType, depth + 1);
if (!base)
return nullptr;
}
return base;
}
NodePointer demangleDependentType(unsigned depth) {
if (!Mangled)
return nullptr;
// A dependent member type begins with a non-index, non-'d' character.
auto c = Mangled.peek();
if (c != 'd' && c != '_' && !Mangle::isDigit(c)) {
NodePointer baseType = demangleType(depth + 1);
if (!baseType) return nullptr;
return demangleDependentMemberTypeName(baseType, depth + 1);
}
// Otherwise, we have a generic parameter.
return demangleGenericParamIndex(depth + 1);
}
NodePointer demangleConstrainedTypeImpl(unsigned depth) {
// The constrained type can only be a generic parameter or an associated
// type thereof. The 'q' introducer is thus left off of generic params.
if (Mangled.nextIf('w')) {
return demangleAssociatedTypeSimple(depth + 1);
}
if (Mangled.nextIf('W')) {
return demangleAssociatedTypeCompound(depth + 1);
}
return demangleGenericParamIndex(depth + 1);
}
NodePointer demangleConstrainedType(unsigned depth) {
auto type = demangleConstrainedTypeImpl(depth);
if (!type)
return nullptr;
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
nodeType->addChild(type, Factory);
return nodeType;
}
NodePointer demangleGenericSignature(unsigned depth,
bool isPseudogeneric = false) {
auto sig =
Factory.createNode(isPseudogeneric
? Node::Kind::DependentPseudogenericSignature
: Node::Kind::DependentGenericSignature);
// First read in the parameter counts at each depth.
Node::IndexType count = ~(Node::IndexType)0;
auto addCount = [&]{
auto countNode =
Factory.createNode(Node::Kind::DependentGenericParamCount, count);
sig->addChild(countNode, Factory);
};
while (Mangled.peek() != 'R' && Mangled.peek() != 'r') {
if (Mangled.nextIf('z')) {
count = 0;
} else if (demangleIndex(count, depth + 1)) {
count += 1;
} else {
return nullptr;
}
addCount();
}
// No mangled parameters means we have exactly one.
if (count == ~(Node::IndexType)0) {
count = 1;
addCount();
}
// Next read in the generic requirements, if any.
if (Mangled.nextIf('r'))
return sig;
if (!Mangled.nextIf('R'))
return nullptr;
while (!Mangled.nextIf('r')) {
NodePointer reqt = demangleGenericRequirement(depth + 1);
if (!reqt) return nullptr;
sig->addChild(reqt, Factory);
}
return sig;
}
NodePointer demangleMetatypeRepresentation(unsigned depth) {
if (Mangled.nextIf('t'))
return Factory.createNode(Node::Kind::MetatypeRepresentation, "@thin");
if (Mangled.nextIf('T'))
return Factory.createNode(Node::Kind::MetatypeRepresentation, "@thick");
if (Mangled.nextIf('o'))
return Factory.createNode(Node::Kind::MetatypeRepresentation,
"@objc_metatype");
// Unknown metatype representation
return nullptr;
}
NodePointer demangleGenericRequirement(unsigned depth) {
NodePointer constrainedType = demangleConstrainedType(depth + 1);
if (!constrainedType)
return nullptr;
if (Mangled.nextIf('z')) {
NodePointer second = demangleType(depth + 1);
if (!second) return nullptr;
auto reqt = Factory.createNode(
Node::Kind::DependentGenericSameTypeRequirement);
reqt->addChild(constrainedType, Factory);
reqt->addChild(second, Factory);
return reqt;
}
if (Mangled.nextIf('l')) {
StringRef name;
Node::Kind kind;
Node::IndexType size = SIZE_MAX;
Node::IndexType alignment = SIZE_MAX;
if (Mangled.nextIf('U')) {
kind = Node::Kind::Identifier;
name = "U";
} else if (Mangled.nextIf('R')) {
kind = Node::Kind::Identifier;
name = "R";
} else if (Mangled.nextIf('N')) {
kind = Node::Kind::Identifier;
name = "N";
} else if (Mangled.nextIf('T')) {
kind = Node::Kind::Identifier;
name = "T";
} else if (Mangled.nextIf('B')) {
kind = Node::Kind::Identifier;
name = "B";
} else if (Mangled.nextIf('E')) {
kind = Node::Kind::Identifier;
if (!demangleNatural(size, depth + 1))
return nullptr;
if (!Mangled.nextIf('_'))
return nullptr;
if (!demangleNatural(alignment, depth + 1))
return nullptr;
name = "E";
} else if (Mangled.nextIf('e')) {
kind = Node::Kind::Identifier;
if (!demangleNatural(size, depth + 1))
return nullptr;
name = "e";
} else if (Mangled.nextIf('M')) {
kind = Node::Kind::Identifier;
if (!demangleNatural(size, depth + 1))
return nullptr;
if (!Mangled.nextIf('_'))
return nullptr;
if (!demangleNatural(alignment, depth + 1))
return nullptr;
name = "M";
} else if (Mangled.nextIf('m')) {
kind = Node::Kind::Identifier;
if (!demangleNatural(size, depth + 1))
return nullptr;
name = "m";
} else if (Mangled.nextIf('S')) {
kind = Node::Kind::Identifier;
if (!demangleNatural(size, depth + 1))
return nullptr;
name = "S";
} else {
return nullptr;
}
NodePointer second = Factory.createNode(kind, name);
if (!second) return nullptr;
auto reqt = Factory.createNode(
Node::Kind::DependentGenericLayoutRequirement);
reqt->addChild(constrainedType, Factory);
reqt->addChild(second, Factory);
if (size != SIZE_MAX) {
reqt->addChild(Factory.createNode(Node::Kind::Number, size), Factory);
if (alignment != SIZE_MAX)
reqt->addChild(Factory.createNode(Node::Kind::Number, alignment), Factory);
}
return reqt;
}
// Base class constraints are introduced by a class type mangling, which
// will begin with either 'C' or 'S'.
if (!Mangled)
return nullptr;
NodePointer constraint = nullptr;
auto next = Mangled.peek();
if (next == 'C') {
constraint = demangleType(depth + 1);
if (!constraint) return nullptr;
} else if (next == 'S') {
// A substitution may be either the module name of a protocol or a full
// type name.
NodePointer typeName = nullptr;
Mangled.next();
NodePointer sub = demangleSubstitutionIndex(depth + 1);
if (!sub) return nullptr;
if (sub->getKind() == Node::Kind::Protocol
|| sub->getKind() == Node::Kind::Class) {
typeName = sub;
} else if (sub->getKind() == Node::Kind::Module) {
typeName = demangleProtocolNameGivenContext(sub, depth + 1);
if (!typeName)
return nullptr;
} else {
return nullptr;
}
constraint = Factory.createNode(Node::Kind::Type);
constraint->addChild(typeName, Factory);
} else {
constraint = demangleProtocolName(depth + 1);
if (!constraint)
return nullptr;
}
auto reqt = Factory.createNode(
Node::Kind::DependentGenericConformanceRequirement);
reqt->addChild(constrainedType, Factory);
reqt->addChild(constraint, Factory);
return reqt;
}
NodePointer demangleArchetypeType(unsigned depth) {
auto makeAssociatedType = [&](NodePointer root) -> NodePointer {
NodePointer name = demangleIdentifier(depth + 1);
if (!name)
return nullptr;
auto assocType = Factory.createNode(Node::Kind::AssociatedTypeRef);
assocType->addChild(root, Factory);
assocType->addChild(name, Factory);
Substitutions.push_back(assocType);
return assocType;
};
if (Mangled.nextIf('Q')) {
NodePointer root = demangleArchetypeType(depth + 1);
if (!root) return nullptr;
return makeAssociatedType(root);
}
if (Mangled.nextIf('S')) {
NodePointer sub = demangleSubstitutionIndex(depth + 1);
if (!sub) return nullptr;
return makeAssociatedType(sub);
}
if (Mangled.nextIf('s')) {
NodePointer stdlib = Factory.createNode(Node::Kind::Module, STDLIB_NAME);
return makeAssociatedType(stdlib);
}
return nullptr;
}
NodePointer demangleTuple(IsVariadic isV, unsigned depth) {
NodePointer tuple = Factory.createNode(Node::Kind::Tuple);
NodePointer elt = nullptr;
while (!Mangled.nextIf('_')) {
if (!Mangled)
return nullptr;
elt = Factory.createNode(Node::Kind::TupleElement);
if (isStartOfIdentifier(Mangled.peek())) {
NodePointer label =
demangleIdentifier(depth + 1, Node::Kind::TupleElementName);
if (!label)
return nullptr;
elt->addChild(label, Factory);
}
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
elt->addChild(type, Factory);
tuple->addChild(elt, Factory);
}
if (isV == IsVariadic::yes && elt) {
elt->reverseChildren();
NodePointer marker = Factory.createNode(Node::Kind::VariadicMarker);
elt->addChild(marker, Factory);
elt->reverseChildren();
}
return tuple;
}
NodePointer postProcessReturnTypeNode (NodePointer out_args) {
NodePointer out_node = Factory.createNode(Node::Kind::ReturnType);
out_node->addChild(out_args, Factory);
return out_node;
}
NodePointer demangleType(unsigned depth) {
NodePointer type = demangleTypeImpl(depth);
if (!type)
return nullptr;
NodePointer nodeType = Factory.createNode(Node::Kind::Type);
nodeType->addChild(type, Factory);
return nodeType;
}
NodePointer demangleFunctionType(Node::Kind kind, unsigned depth) {
bool throws = false, concurrent = false, async = false;
auto diffKind = MangledDifferentiabilityKind::NonDifferentiable;
NodePointer globalActorType = nullptr;
if (Mangled) {
throws = Mangled.nextIf('z');
concurrent = Mangled.nextIf('y');
async = Mangled.nextIf('Z');
if (Mangled.nextIf('D')) {
switch (auto kind = (MangledDifferentiabilityKind)Mangled.next()) {
case MangledDifferentiabilityKind::Forward:
case MangledDifferentiabilityKind::Reverse:
case MangledDifferentiabilityKind::Normal:
case MangledDifferentiabilityKind::Linear:
diffKind = kind;
break;
case MangledDifferentiabilityKind::NonDifferentiable:
assert(false && "Impossible case 'NonDifferentiable'");
}
}
if (Mangled.nextIf('Y')) {
globalActorType = demangleType(depth + 1);
if (!globalActorType)
return nullptr;
}
}
NodePointer in_args = demangleType(depth + 1);
if (!in_args)
return nullptr;
NodePointer out_args = demangleType(depth + 1);
if (!out_args)
return nullptr;
NodePointer block = Factory.createNode(kind);
if (throws) {
block->addChild(Factory.createNode(Node::Kind::ThrowsAnnotation), Factory);
}
if (async) {
block->addChild(Factory.createNode(Node::Kind::AsyncAnnotation), Factory);
}
if (concurrent) {
block->addChild(
Factory.createNode(Node::Kind::ConcurrentFunctionType), Factory);
}
if (diffKind != MangledDifferentiabilityKind::NonDifferentiable) {
block->addChild(
Factory.createNode(
Node::Kind::DifferentiableFunctionType, (char)diffKind), Factory);
}
if (globalActorType) {
auto globalActorNode =
Factory.createNode(Node::Kind::GlobalActorFunctionType);
globalActorNode->addChild(globalActorType, Factory);
block->addChild(globalActorNode, Factory);
}
// Is there any need to handle isolated(any) function types here?
NodePointer in_node = Factory.createNode(Node::Kind::ArgumentTuple);
block->addChild(in_node, Factory);
in_node->addChild(in_args, Factory);
block->addChild(postProcessReturnTypeNode(out_args), Factory);
return block;
}
NodePointer demangleTypeImpl(unsigned depth) {
if (depth > OldDemangler::MaxDepth || !Mangled)
return nullptr;
char c = Mangled.next();
if (c == 'B') {
if (!Mangled)
return nullptr;
c = Mangled.next();
if (c == 'b')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.BridgeObject");
if (c == 'B')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.UnsafeValueBuffer");
if (c == 'f') {
Node::IndexType size;
if (demangleBuiltinSize(size, depth + 1)) {
return Factory.createNode(
Node::Kind::BuiltinTypeName,
std::move(DemanglerPrinter() << "Builtin.FPIEEE" << size).str());
}
}
if (c == 'i') {
Node::IndexType size;
if (demangleBuiltinSize(size, depth + 1)) {
return Factory.createNode(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Int" << size).str());
}
}
if (c == 'v') {
Node::IndexType elts;
if (demangleNatural(elts, depth + 1)) {
if (!Mangled.nextIf('B'))
return nullptr;
if (Mangled.nextIf('i')) {
Node::IndexType size;
if (!demangleBuiltinSize(size, depth + 1))
return nullptr;
return Factory.createNode(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
.str());
}
if (Mangled.nextIf('f')) {
Node::IndexType size;
if (!demangleBuiltinSize(size, depth + 1))
return nullptr;
return Factory.createNode(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xFPIEEE"
<< size).str());
}
if (Mangled.nextIf('p'))
return Factory.createNode(
Node::Kind::BuiltinTypeName,
(DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
.str());
}
}
if (c == 'O')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.UnknownObject");
if (c == 'o')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.NativeObject");
if (c == 'p')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.RawPointer");
if (c == 't')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.SILToken");
if (c == 'w')
return Factory.createNode(Node::Kind::BuiltinTypeName,
"Builtin.Word");
return nullptr;
}
if (c == 'a')
return demangleDeclarationName(Node::Kind::TypeAlias, depth + 1);
if (c == 'b') {
return demangleFunctionType(Node::Kind::ObjCBlock, depth + 1);
}
if (c == 'c') {
return demangleFunctionType(Node::Kind::CFunctionPointer, depth + 1);
}
if (c == 'D') {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer dynamicSelf = Factory.createNode(Node::Kind::DynamicSelf);
dynamicSelf->addChild(type, Factory);
return dynamicSelf;
}
if (c == 'E') {
if (!Mangled.nextIf('R'))
return nullptr;
if (!Mangled.nextIf('R'))
return nullptr;
return Factory.createNode(Node::Kind::ErrorType, std::string());
}
if (c == 'F') {
return demangleFunctionType(Node::Kind::FunctionType, depth + 1);
}
if (c == 'f') {
return demangleFunctionType(Node::Kind::UncurriedFunctionType, depth + 1);
}
if (c == 'G') {
return demangleBoundGenericType(depth + 1);
}
if (c == 'X') {
if (Mangled.nextIf('b')) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer boxType = Factory.createNode(Node::Kind::SILBoxType);
boxType->addChild(type, Factory);
return boxType;
}
if (Mangled.nextIf('B')) {
NodePointer signature = nullptr;
if (Mangled.nextIf('G')) {
signature = demangleGenericSignature(depth, /*pseudogeneric*/ false);
if (!signature)
return nullptr;
}
NodePointer layout = Factory.createNode(Node::Kind::SILBoxLayout);
while (!Mangled.nextIf('_')) {
Node::Kind kind;
if (Mangled.nextIf('m'))
kind = Node::Kind::SILBoxMutableField;
else if (Mangled.nextIf('i'))
kind = Node::Kind::SILBoxImmutableField;
else
return nullptr;
auto type = demangleType(depth + 1);
if (!type)
return nullptr;
auto field = Factory.createNode(kind);
field->addChild(type, Factory);
layout->addChild(field, Factory);
}
NodePointer genericArgs = nullptr;
if (signature) {
genericArgs = Factory.createNode(Node::Kind::TypeList);
while (!Mangled.nextIf('_')) {
auto type = demangleType(depth + 1);
if (!type)
return nullptr;
genericArgs->addChild(type, Factory);
}
}
NodePointer boxType =
Factory.createNode(Node::Kind::SILBoxTypeWithLayout);
boxType->addChild(layout, Factory);
if (signature) {
boxType->addChild(signature, Factory);
assert(genericArgs);
boxType->addChild(genericArgs, Factory);
}
return boxType;
}
}
if (c == 'K') {
return demangleFunctionType(Node::Kind::AutoClosureType, depth + 1);
}
if (c == 'M') {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer metatype = Factory.createNode(Node::Kind::Metatype);
metatype->addChild(type, Factory);
return metatype;
}
if (c == 'X') {
if (Mangled.nextIf('M')) {
NodePointer metatypeRepr = demangleMetatypeRepresentation(depth + 1);
if (!metatypeRepr) return nullptr;
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer metatype = Factory.createNode(Node::Kind::Metatype);
metatype->addChild(metatypeRepr, Factory);
metatype->addChild(type, Factory);
return metatype;
}
}
if (c == 'P') {
if (Mangled.nextIf('M')) {
NodePointer type = demangleType(depth + 1);
if (!type) return nullptr;
auto metatype = Factory.createNode(Node::Kind::ExistentialMetatype);
metatype->addChild(type, Factory);
return metatype;
}
return demangleProtocolList(depth + 1);
}
if (c == 'X') {
if (Mangled.nextIf('P')) {
if (Mangled.nextIf('M')) {
NodePointer metatypeRepr = demangleMetatypeRepresentation(depth + 1);
if (!metatypeRepr) return nullptr;
NodePointer type = demangleType(depth + 1);
if (!type) return nullptr;
auto metatype = Factory.createNode(Node::Kind::ExistentialMetatype);
metatype->addChild(metatypeRepr, Factory);
metatype->addChild(type, Factory);
return metatype;
}
return demangleProtocolList(depth + 1);
}
}
if (c == 'Q') {
if (Mangled.nextIf('u')) {
// Special mangling for opaque return type.
return Factory.createNode(Node::Kind::OpaqueReturnType);
}
if (Mangled.nextIf('U')) {
// Special mangling for opaque return type.
Node::IndexType ordinal;
if (!demangleIndex(ordinal, depth))
return nullptr;
auto result = Factory.createNode(Node::Kind::OpaqueReturnType);
result->addChild(
Factory.createNode(Node::Kind::OpaqueReturnTypeIndex, ordinal), Factory);
return result;
}
return demangleArchetypeType(depth + 1);
}
if (c == 'q') {
return demangleDependentType(depth + 1);
}
if (c == 'x') {
// Special mangling for the first generic param.
return getDependentGenericParamType(0, 0);
}
if (c == 'w') {
return demangleAssociatedTypeSimple(depth + 1);
}
if (c == 'W') {
return demangleAssociatedTypeCompound(depth + 1);
}
if (c == 'R') {
NodePointer inout = Factory.createNode(Node::Kind::InOut);
NodePointer type = demangleTypeImpl(depth + 1);
if (!type)
return nullptr;
inout->addChild(type, Factory);
return inout;
}
if (c == 'k') {
auto noDerivative = Factory.createNode(Node::Kind::NoDerivative);
auto type = demangleTypeImpl(depth + 1);
if (!type)
return nullptr;
noDerivative->addChild(type, Factory);
return noDerivative;
}
if (c == 'S') {
return demangleSubstitutionIndex(depth + 1);
}
if (c == 'T') {
return demangleTuple(IsVariadic::no, depth + 1);
}
if (c == 't') {
return demangleTuple(IsVariadic::yes, depth + 1);
}
if (c == 'u') {
NodePointer sig = demangleGenericSignature(depth + 1);
if (!sig) return nullptr;
NodePointer sub = demangleType(depth + 1);
if (!sub) return nullptr;
NodePointer dependentGenericType
= Factory.createNode(Node::Kind::DependentGenericType);
dependentGenericType->addChild(sig, Factory);
dependentGenericType->addChild(sub, Factory);
return dependentGenericType;
}
if (c == 'X') {
if (Mangled.nextIf('f')) {
return demangleFunctionType(Node::Kind::ThinFunctionType, depth + 1);
}
if (Mangled.nextIf('o')) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer unowned = Factory.createNode(Node::Kind::Unowned);
unowned->addChild(type, Factory);
return unowned;
}
if (Mangled.nextIf('u')) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer unowned = Factory.createNode(Node::Kind::Unmanaged);
unowned->addChild(type, Factory);
return unowned;
}
if (Mangled.nextIf('w')) {
NodePointer type = demangleType(depth + 1);
if (!type)
return nullptr;
NodePointer weak = Factory.createNode(Node::Kind::Weak);
weak->addChild(type, Factory);
return weak;
}
// type ::= 'XF' impl-function-type
if (Mangled.nextIf('F')) {
return demangleImplFunctionType(depth + 1);
}
return nullptr;
}
if (isStartOfNominalType(c))
return demangleDeclarationName(nominalTypeMarkerToNodeKind(c), depth + 1);
return nullptr;
}
bool demangleReabstractSignature(NodePointer signature, unsigned depth) {
if (Mangled.nextIf('G')) {
NodePointer generics = demangleGenericSignature(depth + 1);
if (!generics) return false;
signature->addChild(generics, Factory);
}
NodePointer srcType = demangleType(depth + 1);
if (!srcType) return false;
signature->addChild(srcType, Factory);
NodePointer destType = demangleType(depth + 1);
if (!destType) return false;
signature->addChild(destType, Factory);
return true;
}
// impl-function-type ::= impl-callee-convention impl-function-attribute*
// generics? '_' impl-parameter* '_' impl-result* '_'
// impl-function-attribute ::= 'Cb' // compatible with C block invocation function
// impl-function-attribute ::= 'Cc' // compatible with C global function
// impl-function-attribute ::= 'Cm' // compatible with Swift method
// impl-function-attribute ::= 'CO' // compatible with ObjC method
// impl-function-attribute ::= 'Cw' // compatible with protocol witness
// impl-function-attribute ::= 'G' // generic
NodePointer demangleImplFunctionType(unsigned depth) {
NodePointer type = Factory.createNode(Node::Kind::ImplFunctionType);
if (!demangleImplCalleeConvention(type, depth + 1))
return nullptr;
if (Mangled.nextIf('C')) {
if (Mangled.nextIf('b'))
addImplFunctionConvention(type, "block");
else if (Mangled.nextIf('c'))
addImplFunctionConvention(type, "c");
else if (Mangled.nextIf('m'))
addImplFunctionConvention(type, "method");
else if (Mangled.nextIf('O'))
addImplFunctionConvention(type, "objc_method");
else if (Mangled.nextIf('w'))
addImplFunctionConvention(type, "witness_method");
else
return nullptr;
}
if (Mangled.nextIf('h'))
addImplFunctionAttribute(type, "@Sendable");
if (Mangled.nextIf('H'))
addImplFunctionAttribute(type, "@async");
if (Mangled.nextIf('T'))
addImplFunctionAttribute(type, "sending-result");
// Enter a new generic context if this type is generic.
// FIXME: replace with std::optional, when we have it.
bool isPseudogeneric = false;
if (Mangled.nextIf('G') ||
(isPseudogeneric = Mangled.nextIf('g'))) {
NodePointer generics =
demangleGenericSignature(depth + 1, isPseudogeneric);
if (!generics)
return nullptr;
type->addChild(generics, Factory);
}
// Expect the attribute terminator.
if (!Mangled.nextIf('_'))
return nullptr;
// Demangle the parameters.
if (!demangleImplParameters(type, depth + 1))
return nullptr;
// Demangle the result type.
if (!demangleImplResults(type, depth + 1))
return nullptr;
return type;
}
enum class ImplConventionContext { Callee, Parameter, Result };
/// impl-convention ::= 'a' // direct, autoreleased
/// impl-convention ::= 'd' // direct, no ownership transfer
/// impl-convention ::= 'D' // direct, no ownership transfer,
/// // dependent on self
/// impl-convention ::= 'g' // direct, guaranteed
/// impl-convention ::= 'e' // direct, deallocating
/// impl-convention ::= 'i' // indirect, ownership transfer
/// impl-convention ::= 'l' // indirect, inout
/// impl-convention ::= 'o' // direct, ownership transfer
///
/// Returns an empty string otherwise.
StringRef demangleImplConvention(ImplConventionContext ctxt, unsigned depth) {
#define CASE(CHAR, FOR_CALLEE, FOR_PARAMETER, FOR_RESULT) \
if (Mangled.nextIf(CHAR)) { \
switch (ctxt) { \
case ImplConventionContext::Callee: return (FOR_CALLEE); \
case ImplConventionContext::Parameter: return (FOR_PARAMETER); \
case ImplConventionContext::Result: return (FOR_RESULT); \
} \
return StringRef(); \
}
auto Nothing = StringRef();
CASE('a', Nothing, Nothing, "@autoreleased")
CASE('d', "@callee_unowned", "@unowned", "@unowned")
CASE('D', Nothing, Nothing, "@unowned_inner_pointer")
CASE('g', "@callee_guaranteed", "@guaranteed", Nothing)
CASE('e', Nothing, "@deallocating", Nothing)
CASE('i', Nothing, "@in", "@out")
CASE('l', Nothing, "@inout", Nothing)
CASE('o', "@callee_owned", "@owned", "@owned")
return Nothing;
#undef CASE
}
// impl-callee-convention ::= 't'
// impl-callee-convention ::= impl-convention
bool demangleImplCalleeConvention(NodePointer type, unsigned depth) {
StringRef attr;
if (Mangled.nextIf('t')) {
attr = "@convention(thin)";
} else {
attr = demangleImplConvention(ImplConventionContext::Callee, depth + 1);
}
if (attr.empty()) {
return false;
}
type->addChild(Factory.createNode(Node::Kind::ImplConvention, attr), Factory);
return true;
}
void addImplFunctionAttribute(NodePointer parent, StringRef attr,
Node::Kind kind = Node::Kind::ImplFunctionAttribute) {
parent->addChild(Factory.createNode(kind, attr), Factory);
}
void addImplFunctionConvention(NodePointer parent, StringRef attr) {
auto attrNode = Factory.createNode(Node::Kind::ImplFunctionConvention);
attrNode->addChild(
Factory.createNode(Node::Kind::ImplFunctionConventionName, attr),
Factory);
parent->addChild(attrNode, Factory);
}
// impl-parameter ::= impl-convention type
bool demangleImplParameters(NodePointer parent, unsigned depth) {
while (!Mangled.nextIf('_')) {
auto input =
demangleImplParameterOrResult(Node::Kind::ImplParameter, depth + 1);
if (!input) return false;
parent->addChild(input, Factory);
}
return true;
}
// impl-result ::= impl-convention type
bool demangleImplResults(NodePointer parent, unsigned depth) {
while (!Mangled.nextIf('_')) {
auto res =
demangleImplParameterOrResult(Node::Kind::ImplResult, depth + 1);
if (!res) return false;
parent->addChild(res, Factory);
}
return true;
}
NodePointer demangleImplParameterOrResult(Node::Kind kind, unsigned depth) {
if (Mangled.nextIf('z')) {
// Only valid for a result.
if (kind != Node::Kind::ImplResult)
return nullptr;
kind = Node::Kind::ImplErrorResult;
}
ImplConventionContext ConvCtx;
if (kind == Node::Kind::ImplParameter) {
ConvCtx = ImplConventionContext::Parameter;
} else if (kind == Node::Kind::ImplResult
|| kind == Node::Kind::ImplErrorResult) {
ConvCtx = ImplConventionContext::Result;
} else {
return nullptr;
}
auto convention = demangleImplConvention(ConvCtx, depth + 1);
if (convention.empty()) return nullptr;
auto type = demangleType(depth + 1);
if (!type) return nullptr;
NodePointer node = Factory.createNode(kind);
node->addChild(Factory.createNode(Node::Kind::ImplConvention, convention),
Factory);
node->addChild(type, Factory);
return node;
}
};
} // end anonymous namespace
NodePointer
swift::Demangle::demangleOldSymbolAsNode(StringRef MangledName,
NodeFactory &Factory) {
OldDemangler demangler(MangledName, Factory);
return demangler.demangleTopLevel();
}