mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* Add UnsafeRawPointer type and API. As proposed in SE-0107: UnsafeRawPointer. https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md The fundamental difference between Unsafe[Mutable]RawPointer and Unsafe[Mutable]Pointer<Pointee> is simply that the former is used for "untyped" memory access, and the later is used for "typed" memory access. Let's refer to these as "raw pointers" and "typed pointers". Because operations on raw pointers access untyped memory, the compiler cannot make assumptions about the underlying type of memory and must be conservative. With operations on typed pointers, the compiler may make strict assumptions about the type of the underlying memory, which allows more aggressive optimization. Memory can only be accessed by a typed pointer when it is currently bound to the Pointee type. Memory can be bound to type `T` via: - `UnsafePointer<T>.allocate(capacity: n)` - `UnsafePointer<Pointee>.withMemoryRebound(to: T.self, capacity: n) {...}` - `UnsafeMutableRawPointer.initializeMemory(as: T.self, at: i, count: n, to: x)` - `UnsafeMutableRawPointer.initializeMemory(as: T.self, from: p, count: n)` - `UnsafeMutableRawPointer.moveInitializeMemory(as: T.self, from: p, count: n)` - `UnsafeMutableRawPointer.bindMemory(to: T.self, capacity: n)` Mangle UnsafeRawPointer as predefined substitution 'Sv' for Swift void pointer ([urp] are taken). * UnsafeRawPointer minor improvements. Incorporate Dmitri's feedback. Properly use a _memmove helper. Add load/storeBytes alignment precondition checks. Reword comments. Demangler tests. * Fix name mangling test cases. * Fix bind_memory specialization.
3730 lines
116 KiB
C++
3730 lines
116 KiB
C++
//===--- Demangle.cpp - Swift Name Demangling -----------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements declaration name demangling in Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Demangle.h"
|
|
#include "swift/Basic/Fallthrough.h"
|
|
#include "swift/Strings.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/Punycode.h"
|
|
#include "swift/Basic/UUID.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <functional>
|
|
#include <vector>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
using namespace swift;
|
|
using namespace Demangle;
|
|
|
|
[[noreturn]]
|
|
static void unreachable(const char *Message) {
|
|
fprintf(stderr, "fatal error: %s\n", Message);
|
|
std::abort();
|
|
}
|
|
|
|
DemanglerPrinter &DemanglerPrinter::operator<<(unsigned long long n) & {
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%llu", n);
|
|
Stream.append(buffer);
|
|
return *this;
|
|
}
|
|
DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & {
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%lld",n);
|
|
Stream.append(buffer);
|
|
return *this;
|
|
}
|
|
|
|
namespace {
|
|
struct QuotedString {
|
|
std::string Value;
|
|
|
|
explicit QuotedString(std::string Value) : Value(Value) {}
|
|
};
|
|
} // end anonymous namespace.
|
|
|
|
static DemanglerPrinter &operator<<(DemanglerPrinter &printer,
|
|
const QuotedString &QS) {
|
|
printer << '"';
|
|
for (auto C : QS.Value) {
|
|
switch (C) {
|
|
case '\\': printer << "\\\\"; break;
|
|
case '\t': printer << "\\t"; break;
|
|
case '\n': printer << "\\n"; break;
|
|
case '\r': printer << "\\r"; break;
|
|
case '"': printer << "\\\""; break;
|
|
case '\'': printer << '\''; break; // no need to escape these
|
|
case '\0': printer << "\\0"; break;
|
|
default:
|
|
auto c = static_cast<char>(C);
|
|
// Other ASCII control characters should get escaped.
|
|
if (c < 0x20 || c == 0x7F) {
|
|
static const char Hexdigit[] = {
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
printer << "\\x" << Hexdigit[c >> 4] << Hexdigit[c & 0xF];
|
|
} else {
|
|
printer << c;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
printer << '"';
|
|
return printer;
|
|
}
|
|
|
|
Node::~Node() {
|
|
switch (NodePayloadKind) {
|
|
case PayloadKind::None: return;
|
|
case PayloadKind::Index: return;
|
|
case PayloadKind::Text: TextPayload.~basic_string(); return;
|
|
}
|
|
unreachable("bad payload kind");
|
|
}
|
|
|
|
namespace {
|
|
struct FindPtr {
|
|
FindPtr(Node *v) : Target(v) {}
|
|
bool operator()(NodePointer sp) const {
|
|
return sp.get() == 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;
|
|
}
|
|
|
|
static std::string archetypeName(Node::IndexType index,
|
|
Node::IndexType depth) {
|
|
DemanglerPrinter name;
|
|
do {
|
|
name << (char)('A' + (index % 26));
|
|
index /= 26;
|
|
} while (index);
|
|
if (depth != 0)
|
|
name << depth;
|
|
return std::move(name).str();
|
|
}
|
|
|
|
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() { return Text.front(); }
|
|
|
|
/// Claim and return the next character. Asserts that there is at
|
|
/// least one remaining character.
|
|
char next() {
|
|
char c = peek();
|
|
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.startswith(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) {
|
|
llvm::Optional<char> c2;
|
|
while (!isEmpty() && (c2 = peek()).getValue() != c) {
|
|
result.push_back(c2.getValue());
|
|
advanceOffset(1);
|
|
}
|
|
return c2.hasValue() && c2.getValue() == c;
|
|
}
|
|
};
|
|
|
|
static StringRef toString(Directness d) {
|
|
switch (d) {
|
|
case Directness::Direct:
|
|
return "direct";
|
|
case Directness::Indirect:
|
|
return "indirect";
|
|
}
|
|
unreachable("bad directness");
|
|
}
|
|
|
|
static StringRef toString(ValueWitnessKind k) {
|
|
switch (k) {
|
|
case ValueWitnessKind::AllocateBuffer:
|
|
return "allocateBuffer";
|
|
case ValueWitnessKind::AssignWithCopy:
|
|
return "assignWithCopy";
|
|
case ValueWitnessKind::AssignWithTake:
|
|
return "assignWithTake";
|
|
case ValueWitnessKind::DeallocateBuffer:
|
|
return "deallocateBuffer";
|
|
case ValueWitnessKind::Destroy:
|
|
return "destroy";
|
|
case ValueWitnessKind::DestroyBuffer:
|
|
return "destroyBuffer";
|
|
case ValueWitnessKind::InitializeBufferWithCopyOfBuffer:
|
|
return "initializeBufferWithCopyOfBuffer";
|
|
case ValueWitnessKind::InitializeBufferWithCopy:
|
|
return "initializeBufferWithCopy";
|
|
case ValueWitnessKind::InitializeWithCopy:
|
|
return "initializeWithCopy";
|
|
case ValueWitnessKind::InitializeBufferWithTake:
|
|
return "initializeBufferWithTake";
|
|
case ValueWitnessKind::InitializeWithTake:
|
|
return "initializeWithTake";
|
|
case ValueWitnessKind::ProjectBuffer:
|
|
return "projectBuffer";
|
|
case ValueWitnessKind::InitializeBufferWithTakeOfBuffer:
|
|
return "initializeBufferWithTakeOfBuffer";
|
|
case ValueWitnessKind::DestroyArray:
|
|
return "destroyArray";
|
|
case ValueWitnessKind::InitializeArrayWithCopy:
|
|
return "initializeArrayWithCopy";
|
|
case ValueWitnessKind::InitializeArrayWithTakeFrontToBack:
|
|
return "initializeArrayWithTakeFrontToBack";
|
|
case ValueWitnessKind::InitializeArrayWithTakeBackToFront:
|
|
return "initializeArrayWithTakeBackToFront";
|
|
case ValueWitnessKind::StoreExtraInhabitant:
|
|
return "storeExtraInhabitant";
|
|
case ValueWitnessKind::GetExtraInhabitantIndex:
|
|
return "getExtraInhabitantIndex";
|
|
case ValueWitnessKind::GetEnumTag:
|
|
return "getEnumTag";
|
|
case ValueWitnessKind::DestructiveProjectEnumData:
|
|
return "destructiveProjectEnumData";
|
|
}
|
|
unreachable("bad value witness kind");
|
|
}
|
|
|
|
/// The main class for parsing a demangling tree out of a mangled string.
|
|
class Demangler {
|
|
std::vector<NodePointer> Substitutions;
|
|
NameSource Mangled;
|
|
public:
|
|
Demangler(llvm::StringRef mangled) : Mangled(mangled) {}
|
|
|
|
/// Try to demangle a child node of the given kind. If that fails,
|
|
/// return; otherwise add it to the parent.
|
|
#define DEMANGLE_CHILD_OR_RETURN(PARENT, CHILD_KIND) do { \
|
|
auto _node = demangle##CHILD_KIND(); \
|
|
if (!_node) return nullptr; \
|
|
(PARENT)->addChild(std::move(_node)); \
|
|
} while (false)
|
|
|
|
/// Try to demangle a child node of the given kind. If that fails,
|
|
/// return; otherwise add it to the parent.
|
|
#define DEMANGLE_CHILD_AS_NODE_OR_RETURN(PARENT, CHILD_KIND) do { \
|
|
auto _kind = demangle##CHILD_KIND(); \
|
|
if (!_kind.hasValue()) return nullptr; \
|
|
(PARENT)->addChild(NodeFactory::create(Node::Kind::CHILD_KIND, \
|
|
unsigned(*_kind))); \
|
|
} while (false)
|
|
|
|
/// Attempt to demangle the source string. The root node will
|
|
/// always be a Global. Extra characters at the end will be
|
|
/// tolerated (and included as a Suffix node as a child of the
|
|
/// Global).
|
|
///
|
|
/// \return true if the mangling succeeded
|
|
NodePointer demangleTopLevel() {
|
|
if (!Mangled.nextIf("_T"))
|
|
return nullptr;
|
|
|
|
NodePointer topLevel = NodeFactory::create(Node::Kind::Global);
|
|
|
|
// First demangle any specialization prefixes.
|
|
if (Mangled.nextIf("TS")) {
|
|
do {
|
|
DEMANGLE_CHILD_OR_RETURN(topLevel, SpecializedAttribute);
|
|
|
|
// The Substitution header does not share state with the rest
|
|
// of the mangling.
|
|
Substitutions.clear();
|
|
} while (Mangled.nextIf("_TTS"));
|
|
|
|
// Then check that we have a global.
|
|
if (!Mangled.nextIf("_T"))
|
|
return nullptr;
|
|
|
|
} else if (Mangled.nextIf("To")) {
|
|
topLevel->addChild(NodeFactory::create(Node::Kind::ObjCAttribute));
|
|
} else if (Mangled.nextIf("TO")) {
|
|
topLevel->addChild(NodeFactory::create(Node::Kind::NonObjCAttribute));
|
|
} else if (Mangled.nextIf("TD")) {
|
|
topLevel->addChild(NodeFactory::create(Node::Kind::DynamicAttribute));
|
|
} else if (Mangled.nextIf("Td")) {
|
|
topLevel->addChild(NodeFactory::create(
|
|
Node::Kind::DirectMethodReferenceAttribute));
|
|
} else if (Mangled.nextIf("TV")) {
|
|
topLevel->addChild(NodeFactory::create(Node::Kind::VTableAttribute));
|
|
}
|
|
|
|
DEMANGLE_CHILD_OR_RETURN(topLevel, Global);
|
|
|
|
// Add a suffix node if there's anything left unmangled.
|
|
if (!Mangled.isEmpty()) {
|
|
topLevel->addChild(NodeFactory::create(Node::Kind::Suffix,
|
|
Mangled.getString()));
|
|
}
|
|
|
|
return topLevel;
|
|
}
|
|
|
|
NodePointer demangleTypeName() {
|
|
return demangleType();
|
|
}
|
|
|
|
private:
|
|
enum class IsVariadic {
|
|
yes = true, no = false
|
|
};
|
|
|
|
Optional<Directness> demangleDirectness() {
|
|
if (Mangled.nextIf('d'))
|
|
return Directness::Direct;
|
|
if (Mangled.nextIf('i'))
|
|
return Directness::Indirect;
|
|
return None;
|
|
}
|
|
|
|
bool demangleNatural(Node::IndexType &num) {
|
|
if (!Mangled)
|
|
return false;
|
|
char c = Mangled.next();
|
|
if (c < '0' || c > '9')
|
|
return false;
|
|
num = (c - '0');
|
|
while (true) {
|
|
if (!Mangled) {
|
|
return true;
|
|
}
|
|
c = Mangled.peek();
|
|
if (c < '0' || c > '9') {
|
|
return true;
|
|
} else {
|
|
num = (10 * num) + (c - '0');
|
|
}
|
|
Mangled.next();
|
|
}
|
|
}
|
|
|
|
bool demangleBuiltinSize(Node::IndexType &num) {
|
|
if (!demangleNatural(num))
|
|
return false;
|
|
if (Mangled.nextIf('_'))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
Optional<ValueWitnessKind> demangleValueWitnessKind() {
|
|
if (!Mangled)
|
|
return None;
|
|
char c1 = Mangled.next();
|
|
if (!Mangled)
|
|
return None;
|
|
char c2 = Mangled.next();
|
|
if (c1 == 'a' && c2 == 'l')
|
|
return ValueWitnessKind::AllocateBuffer;
|
|
if (c1 == 'c' && c2 == 'a')
|
|
return ValueWitnessKind::AssignWithCopy;
|
|
if (c1 == 't' && c2 == 'a')
|
|
return ValueWitnessKind::AssignWithTake;
|
|
if (c1 == 'd' && c2 == 'e')
|
|
return ValueWitnessKind::DeallocateBuffer;
|
|
if (c1 == 'x' && c2 == 'x')
|
|
return ValueWitnessKind::Destroy;
|
|
if (c1 == 'X' && c2 == 'X')
|
|
return ValueWitnessKind::DestroyBuffer;
|
|
if (c1 == 'C' && c2 == 'P')
|
|
return ValueWitnessKind::InitializeBufferWithCopyOfBuffer;
|
|
if (c1 == 'C' && c2 == 'p')
|
|
return ValueWitnessKind::InitializeBufferWithCopy;
|
|
if (c1 == 'c' && c2 == 'p')
|
|
return ValueWitnessKind::InitializeWithCopy;
|
|
if (c1 == 'C' && c2 == 'c')
|
|
return ValueWitnessKind::InitializeArrayWithCopy;
|
|
if (c1 == 'T' && c2 == 'K')
|
|
return ValueWitnessKind::InitializeBufferWithTakeOfBuffer;
|
|
if (c1 == 'T' && c2 == 'k')
|
|
return ValueWitnessKind::InitializeBufferWithTake;
|
|
if (c1 == 't' && c2 == 'k')
|
|
return ValueWitnessKind::InitializeWithTake;
|
|
if (c1 == 'T' && c2 == 't')
|
|
return ValueWitnessKind::InitializeArrayWithTakeFrontToBack;
|
|
if (c1 == 't' && c2 == 'T')
|
|
return ValueWitnessKind::InitializeArrayWithTakeBackToFront;
|
|
if (c1 == 'p' && c2 == 'r')
|
|
return ValueWitnessKind::ProjectBuffer;
|
|
if (c1 == 'X' && c2 == 'x')
|
|
return ValueWitnessKind::DestroyArray;
|
|
if (c1 == 'x' && c2 == 's')
|
|
return ValueWitnessKind::StoreExtraInhabitant;
|
|
if (c1 == 'x' && c2 == 'g')
|
|
return ValueWitnessKind::GetExtraInhabitantIndex;
|
|
if (c1 == 'u' && c2 == 'g')
|
|
return ValueWitnessKind::GetEnumTag;
|
|
if (c1 == 'u' && c2 == 'p')
|
|
return ValueWitnessKind::DestructiveProjectEnumData;
|
|
return None;
|
|
}
|
|
|
|
NodePointer demangleGlobal() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
|
|
// Type metadata.
|
|
if (Mangled.nextIf('M')) {
|
|
if (Mangled.nextIf('P')) {
|
|
auto pattern =
|
|
NodeFactory::create(Node::Kind::GenericTypeMetadataPattern);
|
|
DEMANGLE_CHILD_OR_RETURN(pattern, Type);
|
|
return pattern;
|
|
}
|
|
if (Mangled.nextIf('a')) {
|
|
auto accessor =
|
|
NodeFactory::create(Node::Kind::TypeMetadataAccessFunction);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('L')) {
|
|
auto cache = NodeFactory::create(Node::Kind::TypeMetadataLazyCache);
|
|
DEMANGLE_CHILD_OR_RETURN(cache, Type);
|
|
return cache;
|
|
}
|
|
if (Mangled.nextIf('m')) {
|
|
auto metaclass = NodeFactory::create(Node::Kind::Metaclass);
|
|
DEMANGLE_CHILD_OR_RETURN(metaclass, Type);
|
|
return metaclass;
|
|
}
|
|
if (Mangled.nextIf('n')) {
|
|
auto nominalType =
|
|
NodeFactory::create(Node::Kind::NominalTypeDescriptor);
|
|
DEMANGLE_CHILD_OR_RETURN(nominalType, Type);
|
|
return nominalType;
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
auto metadata = NodeFactory::create(Node::Kind::FullTypeMetadata);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, Type);
|
|
return metadata;
|
|
}
|
|
if (Mangled.nextIf('p')) {
|
|
auto metadata = NodeFactory::create(Node::Kind::ProtocolDescriptor);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, ProtocolName);
|
|
return metadata;
|
|
}
|
|
auto metadata = NodeFactory::create(Node::Kind::TypeMetadata);
|
|
DEMANGLE_CHILD_OR_RETURN(metadata, Type);
|
|
return metadata;
|
|
}
|
|
|
|
// Partial application thunks.
|
|
if (Mangled.nextIf('P')) {
|
|
if (!Mangled.nextIf('A')) return nullptr;
|
|
Node::Kind kind = Node::Kind::PartialApplyForwarder;
|
|
if (Mangled.nextIf('o'))
|
|
kind = Node::Kind::PartialApplyObjCForwarder;
|
|
auto forwarder = NodeFactory::create(kind);
|
|
if (Mangled.nextIf("__T"))
|
|
DEMANGLE_CHILD_OR_RETURN(forwarder, Global);
|
|
return forwarder;
|
|
}
|
|
|
|
// Top-level types, for various consumers.
|
|
if (Mangled.nextIf('t')) {
|
|
auto type = NodeFactory::create(Node::Kind::TypeMangling);
|
|
DEMANGLE_CHILD_OR_RETURN(type, Type);
|
|
return type;
|
|
}
|
|
|
|
// Value witnesses.
|
|
if (Mangled.nextIf('w')) {
|
|
Optional<ValueWitnessKind> w = demangleValueWitnessKind();
|
|
if (!w.hasValue())
|
|
return nullptr;
|
|
auto witness =
|
|
NodeFactory::create(Node::Kind::ValueWitness, unsigned(w.getValue()));
|
|
DEMANGLE_CHILD_OR_RETURN(witness, Type);
|
|
return witness;
|
|
}
|
|
|
|
// Offsets, value witness tables, and protocol witnesses.
|
|
if (Mangled.nextIf('W')) {
|
|
if (Mangled.nextIf('V')) {
|
|
auto witnessTable = NodeFactory::create(Node::Kind::ValueWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, Type);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('o')) {
|
|
auto witnessTableOffset =
|
|
NodeFactory::create(Node::Kind::WitnessTableOffset);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTableOffset, Entity);
|
|
return witnessTableOffset;
|
|
}
|
|
if (Mangled.nextIf('v')) {
|
|
auto fieldOffset = NodeFactory::create(Node::Kind::FieldOffset);
|
|
DEMANGLE_CHILD_AS_NODE_OR_RETURN(fieldOffset, Directness);
|
|
DEMANGLE_CHILD_OR_RETURN(fieldOffset, Entity);
|
|
return fieldOffset;
|
|
}
|
|
if (Mangled.nextIf('P')) {
|
|
auto witnessTable =
|
|
NodeFactory::create(Node::Kind::ProtocolWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('G')) {
|
|
auto witnessTable =
|
|
NodeFactory::create(Node::Kind::GenericProtocolWitnessTable);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('I')) {
|
|
auto witnessTable = NodeFactory::create(
|
|
Node::Kind::GenericProtocolWitnessTableInstantiationFunction);
|
|
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
|
|
return witnessTable;
|
|
}
|
|
if (Mangled.nextIf('l')) {
|
|
auto accessor =
|
|
NodeFactory::create(Node::Kind::LazyProtocolWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('L')) {
|
|
auto accessor =
|
|
NodeFactory::create(Node::Kind::LazyProtocolWitnessTableCacheVariable);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, Type);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('a')) {
|
|
auto tableTemplate =
|
|
NodeFactory::create(Node::Kind::ProtocolWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance);
|
|
return tableTemplate;
|
|
}
|
|
if (Mangled.nextIf('t')) {
|
|
auto accessor = NodeFactory::create(
|
|
Node::Kind::AssociatedTypeMetadataAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
|
|
return accessor;
|
|
}
|
|
if (Mangled.nextIf('T')) {
|
|
auto accessor = NodeFactory::create(
|
|
Node::Kind::AssociatedTypeWitnessTableAccessor);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
|
|
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName);
|
|
return accessor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Other thunks.
|
|
if (Mangled.nextIf('T')) {
|
|
if (Mangled.nextIf('R')) {
|
|
auto thunk = NodeFactory::create(Node::Kind::ReabstractionThunkHelper);
|
|
if (!demangleReabstractSignature(thunk))
|
|
return nullptr;
|
|
return thunk;
|
|
}
|
|
if (Mangled.nextIf('r')) {
|
|
auto thunk = NodeFactory::create(Node::Kind::ReabstractionThunk);
|
|
if (!demangleReabstractSignature(thunk))
|
|
return nullptr;
|
|
return thunk;
|
|
}
|
|
if (Mangled.nextIf('W')) {
|
|
NodePointer thunk = NodeFactory::create(Node::Kind::ProtocolWitness);
|
|
DEMANGLE_CHILD_OR_RETURN(thunk, ProtocolConformance);
|
|
// The entity is mangled in its own generic context.
|
|
DEMANGLE_CHILD_OR_RETURN(thunk, Entity);
|
|
return thunk;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Everything else is just an entity.
|
|
return demangleEntity();
|
|
}
|
|
|
|
NodePointer demangleGenericSpecialization(NodePointer specialization) {
|
|
while (!Mangled.nextIf('_')) {
|
|
// Otherwise, we have another parameter. Demangle the type.
|
|
NodePointer param = NodeFactory::create(Node::Kind::GenericSpecializationParam);
|
|
DEMANGLE_CHILD_OR_RETURN(param, Type);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Add the parameter to our specialization list.
|
|
specialization->addChild(param);
|
|
}
|
|
|
|
return specialization;
|
|
}
|
|
|
|
/// TODO: This is an atrocity. Come up with a shorter name.
|
|
#define FUNCSIGSPEC_CREATE_PARAM_KIND(kind) \
|
|
NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParamKind, \
|
|
unsigned(FunctionSigSpecializationParamKind::kind))
|
|
#define FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(payload) \
|
|
NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParamPayload, \
|
|
payload)
|
|
|
|
bool demangleFuncSigSpecializationConstantProp(NodePointer parent) {
|
|
// 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();
|
|
if (!name || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFunction));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf('g')) {
|
|
NodePointer name = demangleIdentifier();
|
|
if (!name || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropGlobal));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf('i')) {
|
|
std::string Str;
|
|
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropInteger));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str));
|
|
return true;
|
|
}
|
|
|
|
if (Mangled.nextIf("fl")) {
|
|
std::string Str;
|
|
if (!Mangled.readUntil('_', Str) || !Mangled.nextIf('_'))
|
|
return false;
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropFloat));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(Str));
|
|
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();
|
|
if (!str || !Mangled.nextIf('_'))
|
|
return false;
|
|
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ConstantPropString));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(encodingStr));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(str->getText()));
|
|
return true;
|
|
}
|
|
|
|
unreachable("Unknown constant prop specialization");
|
|
}
|
|
|
|
bool demangleFuncSigSpecializationClosureProp(NodePointer parent) {
|
|
// 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();
|
|
if (!name) {
|
|
return false;
|
|
}
|
|
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_KIND(ClosureProp));
|
|
parent->addChild(FUNCSIGSPEC_CREATE_PARAM_PAYLOAD(name->getText()));
|
|
|
|
// Then demangle types until we fail.
|
|
NodePointer type;
|
|
while (Mangled.peek() != '_' && (type = demangleType())) {
|
|
parent->addChild(type);
|
|
}
|
|
|
|
// Eat last '_'
|
|
if (!Mangled.nextIf('_'))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
NodePointer
|
|
demangleFunctionSignatureSpecialization(NodePointer specialization) {
|
|
unsigned paramCount = 0;
|
|
|
|
// Until we hit the last '_' in our specialization info...
|
|
while (!Mangled.nextIf('_')) {
|
|
// Create the parameter.
|
|
NodePointer param =
|
|
NodeFactory::create(Node::Kind::FunctionSignatureSpecializationParam,
|
|
paramCount);
|
|
|
|
// First handle options.
|
|
if (Mangled.nextIf("n_")) {
|
|
// Leave the parameter empty.
|
|
} else if (Mangled.nextIf("cp")) {
|
|
if (!demangleFuncSigSpecializationConstantProp(param))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf("cl")) {
|
|
if (!demangleFuncSigSpecializationClosureProp(param))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf("i_")) {
|
|
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToValue);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result);
|
|
} else if (Mangled.nextIf("k_")) {
|
|
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToStack);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result);
|
|
} 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('s')) {
|
|
Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
|
|
}
|
|
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
|
|
if (!Value)
|
|
return nullptr;
|
|
|
|
auto result = NodeFactory::create(
|
|
Node::Kind::FunctionSignatureSpecializationParamKind, Value);
|
|
if (!result)
|
|
return nullptr;
|
|
param->addChild(result);
|
|
}
|
|
|
|
specialization->addChild(param);
|
|
paramCount++;
|
|
}
|
|
|
|
return specialization;
|
|
}
|
|
|
|
#undef FUNCSIGSPEC_CREATE_PARAM_KIND
|
|
#undef FUNCSIGSPEC_CREATE_PARAM_PAYLOAD
|
|
|
|
NodePointer demangleSpecializedAttribute() {
|
|
bool isNotReAbstracted = false;
|
|
if (Mangled.nextIf("g") || (isNotReAbstracted = Mangled.nextIf("r"))) {
|
|
auto spec = NodeFactory::create(isNotReAbstracted ?
|
|
Node::Kind::GenericSpecializationNotReAbstracted :
|
|
Node::Kind::GenericSpecialization);
|
|
|
|
// Create a node if the specialization is externally inlineable.
|
|
if (Mangled.nextIf("q")) {
|
|
auto kind = Node::Kind::SpecializationIsFragile;
|
|
spec->addChild(NodeFactory::create(kind));
|
|
}
|
|
|
|
// Create a node for the pass id.
|
|
spec->addChild(NodeFactory::create(Node::Kind::SpecializationPassID,
|
|
unsigned(Mangled.next() - 48)));
|
|
|
|
// And then mangle the generic specialization.
|
|
return demangleGenericSpecialization(spec);
|
|
}
|
|
if (Mangled.nextIf("f")) {
|
|
auto spec =
|
|
NodeFactory::create(Node::Kind::FunctionSignatureSpecialization);
|
|
|
|
// Create a node if the specialization is externally inlineable.
|
|
if (Mangled.nextIf("q")) {
|
|
auto kind = Node::Kind::SpecializationIsFragile;
|
|
spec->addChild(NodeFactory::create(kind));
|
|
}
|
|
|
|
// Add the pass id.
|
|
spec->addChild(NodeFactory::create(Node::Kind::SpecializationPassID,
|
|
unsigned(Mangled.next() - 48)));
|
|
|
|
// Then perform the function signature specialization.
|
|
return demangleFunctionSignatureSpecialization(spec);
|
|
}
|
|
|
|
// We don't know how to handle this specialization.
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleDeclName() {
|
|
// decl-name ::= local-decl-name
|
|
// local-decl-name ::= 'L' index identifier
|
|
if (Mangled.nextIf('L')) {
|
|
NodePointer discriminator = demangleIndexAsNode();
|
|
if (!discriminator) return nullptr;
|
|
|
|
NodePointer name = demangleIdentifier();
|
|
if (!name) return nullptr;
|
|
|
|
NodePointer localName = NodeFactory::create(Node::Kind::LocalDeclName);
|
|
localName->addChild(std::move(discriminator));
|
|
localName->addChild(std::move(name));
|
|
return localName;
|
|
|
|
} else if (Mangled.nextIf('P')) {
|
|
NodePointer discriminator = demangleIdentifier();
|
|
if (!discriminator) return nullptr;
|
|
|
|
NodePointer name = demangleIdentifier();
|
|
if (!name) return nullptr;
|
|
|
|
auto privateName = NodeFactory::create(Node::Kind::PrivateDeclName);
|
|
privateName->addChildren(std::move(discriminator), std::move(name));
|
|
return privateName;
|
|
}
|
|
|
|
// decl-name ::= identifier
|
|
return demangleIdentifier();
|
|
}
|
|
|
|
NodePointer demangleIdentifier(Optional<Node::Kind> kind = None) {
|
|
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.hasValue()) 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.hasValue()) kind = Node::Kind::Identifier;
|
|
|
|
Node::IndexType length;
|
|
if (!demangleNatural(length))
|
|
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 NodeFactory::create(*kind, identifier);
|
|
}
|
|
|
|
bool demangleIndex(Node::IndexType &natural) {
|
|
if (Mangled.nextIf('_')) {
|
|
natural = 0;
|
|
return true;
|
|
}
|
|
if (demangleNatural(natural)) {
|
|
if (!Mangled.nextIf('_'))
|
|
return false;
|
|
natural++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Demangle an <index> and package it as a node of some kind.
|
|
NodePointer demangleIndexAsNode(Node::Kind kind = Node::Kind::Number) {
|
|
Node::IndexType index;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
return NodeFactory::create(kind, index);
|
|
}
|
|
|
|
NodePointer createSwiftType(Node::Kind typeKind, StringRef name) {
|
|
NodePointer type = NodeFactory::create(typeKind);
|
|
type->addChild(NodeFactory::create(Node::Kind::Module, STDLIB_NAME));
|
|
type->addChild(NodeFactory::create(Node::Kind::Identifier, name));
|
|
return type;
|
|
}
|
|
|
|
/// Demangle a <substitution>, given that we've already consumed the 'S'.
|
|
NodePointer demangleSubstitutionIndex() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
if (Mangled.nextIf('o'))
|
|
return NodeFactory::create(Node::Kind::Module, MANGLING_MODULE_OBJC);
|
|
if (Mangled.nextIf('C'))
|
|
return NodeFactory::create(Node::Kind::Module, MANGLING_MODULE_C);
|
|
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))
|
|
return nullptr;
|
|
if (index_sub >= Substitutions.size())
|
|
return nullptr;
|
|
return Substitutions[index_sub];
|
|
}
|
|
|
|
NodePointer demangleModule() {
|
|
if (Mangled.nextIf('s')) {
|
|
return NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
|
|
}
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer module = demangleSubstitutionIndex();
|
|
if (!module)
|
|
return nullptr;
|
|
if (module->getKind() != Node::Kind::Module)
|
|
return nullptr;
|
|
return module;
|
|
}
|
|
|
|
NodePointer module = demangleIdentifier(Node::Kind::Module);
|
|
if (!module) return nullptr;
|
|
Substitutions.push_back(module);
|
|
return module;
|
|
}
|
|
|
|
NodePointer demangleDeclarationName(Node::Kind kind) {
|
|
NodePointer context = demangleContext();
|
|
if (!context) return nullptr;
|
|
|
|
auto name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
|
|
auto decl = NodeFactory::create(kind);
|
|
decl->addChild(context);
|
|
decl->addChild(name);
|
|
Substitutions.push_back(decl);
|
|
return decl;
|
|
}
|
|
|
|
NodePointer demangleProtocolName() {
|
|
NodePointer proto = demangleProtocolNameImpl();
|
|
if (!proto) return nullptr;
|
|
|
|
NodePointer type = NodeFactory::create(Node::Kind::Type);
|
|
type->addChild(proto);
|
|
return type;
|
|
}
|
|
|
|
NodePointer demangleProtocolNameGivenContext(NodePointer context) {
|
|
NodePointer name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
|
|
auto proto = NodeFactory::create(Node::Kind::Protocol);
|
|
proto->addChild(std::move(context));
|
|
proto->addChild(std::move(name));
|
|
Substitutions.push_back(proto);
|
|
return proto;
|
|
}
|
|
|
|
NodePointer demangleProtocolNameImpl() {
|
|
// 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();
|
|
if (!sub) return nullptr;
|
|
if (sub->getKind() == Node::Kind::Protocol)
|
|
return sub;
|
|
|
|
if (sub->getKind() != Node::Kind::Module)
|
|
return nullptr;
|
|
|
|
return demangleProtocolNameGivenContext(sub);
|
|
}
|
|
|
|
if (Mangled.nextIf('s')) {
|
|
NodePointer stdlib = NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
|
|
|
|
return demangleProtocolNameGivenContext(stdlib);
|
|
}
|
|
|
|
return demangleDeclarationName(Node::Kind::Protocol);
|
|
}
|
|
|
|
NodePointer demangleNominalType() {
|
|
if (Mangled.nextIf('S'))
|
|
return demangleSubstitutionIndex();
|
|
if (Mangled.nextIf('V'))
|
|
return demangleDeclarationName(Node::Kind::Structure);
|
|
if (Mangled.nextIf('O'))
|
|
return demangleDeclarationName(Node::Kind::Enum);
|
|
if (Mangled.nextIf('C'))
|
|
return demangleDeclarationName(Node::Kind::Class);
|
|
if (Mangled.nextIf('P'))
|
|
return demangleDeclarationName(Node::Kind::Protocol);
|
|
return nullptr;
|
|
}
|
|
|
|
NodePointer demangleBoundGenericArgs(NodePointer nominalType) {
|
|
// Generic arguments for the outermost type come first.
|
|
NodePointer parentOrModule = nominalType->getChild(0);
|
|
if (parentOrModule->getKind() != Node::Kind::Module) {
|
|
parentOrModule = demangleBoundGenericArgs(parentOrModule);
|
|
|
|
// Rebuild this type with the new parent type, which may have
|
|
// had its generic arguments applied.
|
|
NodePointer result = NodeFactory::create(nominalType->getKind());
|
|
result->addChild(parentOrModule);
|
|
result->addChild(nominalType->getChild(1));
|
|
|
|
nominalType = result;
|
|
}
|
|
|
|
NodePointer args = NodeFactory::create(Node::Kind::TypeList);
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
args->addChild(type);
|
|
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 = NodeFactory::create(Node::Kind::Type);
|
|
unboundType->addChild(nominalType);
|
|
|
|
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 = NodeFactory::create(kind);
|
|
result->addChild(unboundType);
|
|
result->addChild(args);
|
|
return result;
|
|
}
|
|
|
|
NodePointer demangleBoundGenericType() {
|
|
// bound-generic-type ::= 'G' nominal-type (args+ '_')+
|
|
//
|
|
// Each level of nominal type nesting has its own list of arguments.
|
|
|
|
NodePointer nominalType = demangleNominalType();
|
|
if (!nominalType)
|
|
return nullptr;
|
|
|
|
return demangleBoundGenericArgs(nominalType);
|
|
}
|
|
|
|
NodePointer demangleContext() {
|
|
// 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 = NodeFactory::create(Node::Kind::Extension);
|
|
NodePointer def_module = demangleModule();
|
|
if (!def_module) return nullptr;
|
|
NodePointer type = demangleContext();
|
|
if (!type) return nullptr;
|
|
ext->addChild(def_module);
|
|
ext->addChild(type);
|
|
return ext;
|
|
}
|
|
if (Mangled.nextIf('e')) {
|
|
NodePointer ext = NodeFactory::create(Node::Kind::Extension);
|
|
NodePointer def_module = demangleModule();
|
|
if (!def_module) return nullptr;
|
|
NodePointer sig = demangleGenericSignature();
|
|
// 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();
|
|
if (!type) return nullptr;
|
|
|
|
ext->addChild(def_module);
|
|
ext->addChild(type);
|
|
ext->addChild(sig);
|
|
return ext;
|
|
}
|
|
if (Mangled.nextIf('S'))
|
|
return demangleSubstitutionIndex();
|
|
if (Mangled.nextIf('s'))
|
|
return NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
|
|
if (Mangled.nextIf('G'))
|
|
return demangleBoundGenericType();
|
|
if (isStartOfEntity(Mangled.peek()))
|
|
return demangleEntity();
|
|
return demangleModule();
|
|
}
|
|
|
|
NodePointer demangleProtocolList() {
|
|
NodePointer proto_list = NodeFactory::create(Node::Kind::ProtocolList);
|
|
NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
|
|
proto_list->addChild(type_list);
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer proto = demangleProtocolName();
|
|
if (!proto)
|
|
return nullptr;
|
|
type_list->addChild(std::move(proto));
|
|
}
|
|
return proto_list;
|
|
}
|
|
|
|
NodePointer demangleProtocolConformance() {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer protocol = demangleProtocolName();
|
|
if (!protocol)
|
|
return nullptr;
|
|
NodePointer context = demangleContext();
|
|
if (!context)
|
|
return nullptr;
|
|
NodePointer proto_conformance =
|
|
NodeFactory::create(Node::Kind::ProtocolConformance);
|
|
proto_conformance->addChild(type);
|
|
proto_conformance->addChild(protocol);
|
|
proto_conformance->addChild(context);
|
|
return proto_conformance;
|
|
}
|
|
|
|
// entity ::= entity-kind context entity-name
|
|
// entity ::= nominal-type
|
|
NodePointer demangleEntity() {
|
|
// 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();
|
|
}
|
|
|
|
NodePointer context = demangleContext();
|
|
if (!context) return nullptr;
|
|
|
|
// entity-name
|
|
Node::Kind entityKind;
|
|
bool hasType = true;
|
|
NodePointer name;
|
|
if (Mangled.nextIf('D')) {
|
|
entityKind = Node::Kind::Deallocator;
|
|
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')) {
|
|
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();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('l')) {
|
|
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();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('g')) {
|
|
entityKind = Node::Kind::Getter;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('G')) {
|
|
entityKind = Node::Kind::GlobalGetter;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('s')) {
|
|
entityKind = Node::Kind::Setter;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('m')) {
|
|
entityKind = Node::Kind::MaterializeForSet;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('w')) {
|
|
entityKind = Node::Kind::WillSet;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('W')) {
|
|
entityKind = Node::Kind::DidSet;
|
|
name = demangleDeclName();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('U')) {
|
|
entityKind = Node::Kind::ExplicitClosure;
|
|
name = demangleIndexAsNode();
|
|
if (!name) return nullptr;
|
|
} else if (Mangled.nextIf('u')) {
|
|
entityKind = Node::Kind::ImplicitClosure;
|
|
name = demangleIndexAsNode();
|
|
if (!name) return nullptr;
|
|
} else if (entityBasicKind == Node::Kind::Initializer) {
|
|
// entity-name ::= 'A' index
|
|
if (Mangled.nextIf('A')) {
|
|
entityKind = Node::Kind::DefaultArgumentInitializer;
|
|
name = demangleIndexAsNode();
|
|
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();
|
|
if (!name) return nullptr;
|
|
}
|
|
|
|
NodePointer entity = NodeFactory::create(entityKind);
|
|
entity->addChild(context);
|
|
|
|
if (name) entity->addChild(name);
|
|
|
|
if (hasType) {
|
|
auto type = demangleType();
|
|
if (!type) return nullptr;
|
|
entity->addChild(type);
|
|
}
|
|
|
|
if (isStatic) {
|
|
auto staticNode = NodeFactory::create(Node::Kind::Static);
|
|
staticNode->addChild(entity);
|
|
return staticNode;
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
NodePointer demangleArchetypeRef(Node::IndexType depth, Node::IndexType i) {
|
|
// FIXME: Name won't match demangled context generic signatures correctly.
|
|
auto ref = NodeFactory::create(Node::Kind::ArchetypeRef,
|
|
archetypeName(i, depth));
|
|
ref->addChild(NodeFactory::create(Node::Kind::Index, depth));
|
|
ref->addChild(NodeFactory::create(Node::Kind::Index, i));
|
|
return ref;
|
|
}
|
|
|
|
NodePointer getDependentGenericParamType(unsigned depth, unsigned index) {
|
|
DemanglerPrinter PrintName;
|
|
PrintName << archetypeName(index, depth);
|
|
|
|
auto paramTy = NodeFactory::create(Node::Kind::DependentGenericParamType,
|
|
std::move(PrintName).str());
|
|
paramTy->addChild(NodeFactory::create(Node::Kind::Index, depth));
|
|
paramTy->addChild(NodeFactory::create(Node::Kind::Index, index));
|
|
|
|
return paramTy;
|
|
}
|
|
|
|
NodePointer demangleGenericParamIndex() {
|
|
Node::IndexType depth, index;
|
|
|
|
if (Mangled.nextIf('d')) {
|
|
if (!demangleIndex(depth))
|
|
return nullptr;
|
|
depth += 1;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
} else if (Mangled.nextIf('x')) {
|
|
depth = 0;
|
|
index = 0;
|
|
} else {
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
depth = 0;
|
|
index += 1;
|
|
}
|
|
return getDependentGenericParamType(depth, index);
|
|
}
|
|
|
|
NodePointer demangleDependentMemberTypeName(NodePointer base) {
|
|
assert(base->getKind() == Node::Kind::Type
|
|
&& "base should be a type");
|
|
NodePointer assocTy;
|
|
|
|
if (Mangled.nextIf('S')) {
|
|
assocTy = demangleSubstitutionIndex();
|
|
if (assocTy->getKind() != Node::Kind::DependentAssociatedTypeRef)
|
|
return nullptr;
|
|
} else {
|
|
NodePointer protocol = nullptr;
|
|
if (Mangled.nextIf('P')) {
|
|
protocol = demangleProtocolName();
|
|
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.
|
|
assocTy = demangleIdentifier(Node::Kind::DependentAssociatedTypeRef);
|
|
if (!assocTy) return nullptr;
|
|
if (protocol)
|
|
assocTy->addChild(protocol);
|
|
|
|
Substitutions.push_back(assocTy);
|
|
}
|
|
|
|
NodePointer depTy = NodeFactory::create(Node::Kind::DependentMemberType);
|
|
depTy->addChild(base);
|
|
depTy->addChild(assocTy);
|
|
return depTy;
|
|
}
|
|
|
|
NodePointer demangleAssociatedTypeSimple() {
|
|
// Demangle the base type.
|
|
auto base = demangleGenericParamIndex();
|
|
if (!base)
|
|
return nullptr;
|
|
|
|
NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
|
|
nodeType->addChild(base);
|
|
|
|
// Demangle the associated type name.
|
|
return demangleDependentMemberTypeName(nodeType);
|
|
}
|
|
|
|
NodePointer demangleAssociatedTypeCompound() {
|
|
// Demangle the base type.
|
|
auto base = demangleGenericParamIndex();
|
|
if (!base)
|
|
return nullptr;
|
|
|
|
// Demangle the associated type chain.
|
|
while (!Mangled.nextIf('_')) {
|
|
NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
|
|
nodeType->addChild(base);
|
|
|
|
base = demangleDependentMemberTypeName(nodeType);
|
|
if (!base)
|
|
return nullptr;
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
NodePointer demangleDependentType() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
|
|
// A dependent member type begins with a non-index, non-'d' character.
|
|
auto c = Mangled.peek();
|
|
if (c != 'd' && c != '_' && !isDigit(c)) {
|
|
NodePointer baseType = demangleType();
|
|
if (!baseType) return nullptr;
|
|
return demangleDependentMemberTypeName(baseType);
|
|
}
|
|
|
|
// Otherwise, we have a generic parameter.
|
|
return demangleGenericParamIndex();
|
|
}
|
|
|
|
NodePointer demangleConstrainedTypeImpl() {
|
|
// 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();
|
|
}
|
|
if (Mangled.nextIf('W')) {
|
|
return demangleAssociatedTypeCompound();
|
|
}
|
|
return demangleGenericParamIndex();
|
|
}
|
|
|
|
NodePointer demangleConstrainedType() {
|
|
auto type = demangleConstrainedTypeImpl();
|
|
if (!type)
|
|
return nullptr;
|
|
|
|
NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
|
|
nodeType->addChild(type);
|
|
return nodeType;
|
|
}
|
|
|
|
NodePointer demangleGenericSignature(bool isPseudogeneric = false) {
|
|
auto sig =
|
|
NodeFactory::create(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 =
|
|
NodeFactory::create(Node::Kind::DependentGenericParamCount, count);
|
|
sig->addChild(countNode);
|
|
};
|
|
|
|
while (Mangled.peek() != 'R' && Mangled.peek() != 'r') {
|
|
if (Mangled.nextIf('z')) {
|
|
count = 0;
|
|
} else if (demangleIndex(count)) {
|
|
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();
|
|
if (!reqt) return nullptr;
|
|
sig->addChild(reqt);
|
|
}
|
|
|
|
return sig;
|
|
}
|
|
|
|
NodePointer demangleMetatypeRepresentation() {
|
|
if (Mangled.nextIf('t'))
|
|
return NodeFactory::create(Node::Kind::MetatypeRepresentation, "@thin");
|
|
|
|
if (Mangled.nextIf('T'))
|
|
return NodeFactory::create(Node::Kind::MetatypeRepresentation, "@thick");
|
|
|
|
if (Mangled.nextIf('o'))
|
|
return NodeFactory::create(Node::Kind::MetatypeRepresentation,
|
|
"@objc_metatype");
|
|
|
|
unreachable("Unhandled metatype representation");
|
|
}
|
|
|
|
NodePointer demangleGenericRequirement() {
|
|
NodePointer constrainedType = demangleConstrainedType();
|
|
if (!constrainedType)
|
|
return nullptr;
|
|
if (Mangled.nextIf('z')) {
|
|
NodePointer second = demangleType();
|
|
if (!second) return nullptr;
|
|
auto reqt = NodeFactory::create(
|
|
Node::Kind::DependentGenericSameTypeRequirement);
|
|
reqt->addChild(constrainedType);
|
|
reqt->addChild(second);
|
|
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;
|
|
|
|
auto next = Mangled.peek();
|
|
|
|
if (next == 'C') {
|
|
constraint = demangleType();
|
|
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;
|
|
Mangled.next();
|
|
NodePointer sub = demangleSubstitutionIndex();
|
|
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);
|
|
if (!typeName)
|
|
return nullptr;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
constraint = NodeFactory::create(Node::Kind::Type);
|
|
constraint->addChild(typeName);
|
|
} else {
|
|
constraint = demangleProtocolName();
|
|
if (!constraint)
|
|
return nullptr;
|
|
}
|
|
auto reqt = NodeFactory::create(
|
|
Node::Kind::DependentGenericConformanceRequirement);
|
|
reqt->addChild(constrainedType);
|
|
reqt->addChild(constraint);
|
|
return reqt;
|
|
}
|
|
|
|
NodePointer demangleArchetypeType() {
|
|
auto makeSelfType = [&](NodePointer proto) -> NodePointer {
|
|
auto selfType = NodeFactory::create(Node::Kind::SelfTypeRef);
|
|
selfType->addChild(proto);
|
|
Substitutions.push_back(selfType);
|
|
return selfType;
|
|
};
|
|
|
|
auto makeAssociatedType = [&](NodePointer root) -> NodePointer {
|
|
NodePointer name = demangleIdentifier();
|
|
if (!name) return nullptr;
|
|
auto assocType = NodeFactory::create(Node::Kind::AssociatedTypeRef);
|
|
assocType->addChild(root);
|
|
assocType->addChild(name);
|
|
Substitutions.push_back(assocType);
|
|
return assocType;
|
|
};
|
|
|
|
if (Mangled.nextIf('P')) {
|
|
NodePointer proto = demangleProtocolName();
|
|
if (!proto) return nullptr;
|
|
return makeSelfType(proto);
|
|
}
|
|
|
|
if (Mangled.nextIf('Q')) {
|
|
NodePointer root = demangleArchetypeType();
|
|
if (!root) return nullptr;
|
|
return makeAssociatedType(root);
|
|
}
|
|
if (Mangled.nextIf('S')) {
|
|
NodePointer sub = demangleSubstitutionIndex();
|
|
if (!sub) return nullptr;
|
|
if (sub->getKind() == Node::Kind::Protocol)
|
|
return makeSelfType(sub);
|
|
else
|
|
return makeAssociatedType(sub);
|
|
}
|
|
if (Mangled.nextIf('s')) {
|
|
NodePointer stdlib = NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
|
|
return makeAssociatedType(stdlib);
|
|
}
|
|
if (Mangled.nextIf('d')) {
|
|
Node::IndexType depth, index;
|
|
if (!demangleIndex(depth))
|
|
return nullptr;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
return demangleArchetypeRef(depth + 1, index);
|
|
}
|
|
if (Mangled.nextIf('q')) {
|
|
NodePointer index = demangleIndexAsNode();
|
|
if (!index)
|
|
return nullptr;
|
|
NodePointer decl_ctx = NodeFactory::create(Node::Kind::DeclContext);
|
|
NodePointer ctx = demangleContext();
|
|
if (!ctx)
|
|
return nullptr;
|
|
decl_ctx->addChild(ctx);
|
|
auto qual_atype = NodeFactory::create(Node::Kind::QualifiedArchetype);
|
|
qual_atype->addChild(index);
|
|
qual_atype->addChild(decl_ctx);
|
|
return qual_atype;
|
|
}
|
|
Node::IndexType index;
|
|
if (!demangleIndex(index))
|
|
return nullptr;
|
|
return demangleArchetypeRef(0, index);
|
|
}
|
|
|
|
NodePointer demangleTuple(IsVariadic isV) {
|
|
NodePointer tuple = NodeFactory::create(
|
|
isV == IsVariadic::yes ? Node::Kind::VariadicTuple
|
|
: Node::Kind::NonVariadicTuple);
|
|
while (!Mangled.nextIf('_')) {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
NodePointer elt = NodeFactory::create(Node::Kind::TupleElement);
|
|
|
|
if (isStartOfIdentifier(Mangled.peek())) {
|
|
NodePointer label = demangleIdentifier(Node::Kind::TupleElementName);
|
|
if (!label)
|
|
return nullptr;
|
|
elt->addChild(label);
|
|
}
|
|
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
elt->addChild(type);
|
|
|
|
tuple->addChild(elt);
|
|
}
|
|
return tuple;
|
|
}
|
|
|
|
NodePointer postProcessReturnTypeNode (NodePointer out_args) {
|
|
NodePointer out_node = NodeFactory::create(Node::Kind::ReturnType);
|
|
out_node->addChild(out_args);
|
|
return out_node;
|
|
}
|
|
|
|
NodePointer demangleType() {
|
|
NodePointer type = demangleTypeImpl();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer nodeType = NodeFactory::create(Node::Kind::Type);
|
|
nodeType->addChild(type);
|
|
return nodeType;
|
|
}
|
|
|
|
NodePointer demangleFunctionType(Node::Kind kind) {
|
|
bool throws = false;
|
|
if (Mangled &&
|
|
Mangled.nextIf('z')) {
|
|
throws = true;
|
|
}
|
|
NodePointer in_args = demangleType();
|
|
if (!in_args)
|
|
return nullptr;
|
|
NodePointer out_args = demangleType();
|
|
if (!out_args)
|
|
return nullptr;
|
|
NodePointer block = NodeFactory::create(kind);
|
|
|
|
if (throws) {
|
|
block->addChild(NodeFactory::create(Node::Kind::ThrowsAnnotation));
|
|
}
|
|
|
|
NodePointer in_node = NodeFactory::create(Node::Kind::ArgumentTuple);
|
|
block->addChild(in_node);
|
|
in_node->addChild(in_args);
|
|
block->addChild(postProcessReturnTypeNode(out_args));
|
|
return block;
|
|
}
|
|
|
|
NodePointer demangleTypeImpl() {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
char c = Mangled.next();
|
|
if (c == 'B') {
|
|
if (!Mangled)
|
|
return nullptr;
|
|
c = Mangled.next();
|
|
if (c == 'b')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.BridgeObject");
|
|
if (c == 'B')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.UnsafeValueBuffer");
|
|
if (c == 'f') {
|
|
Node::IndexType size;
|
|
if (demangleBuiltinSize(size)) {
|
|
return NodeFactory::create(
|
|
Node::Kind::BuiltinTypeName,
|
|
std::move(DemanglerPrinter() << "Builtin.Float" << size).str());
|
|
}
|
|
}
|
|
if (c == 'i') {
|
|
Node::IndexType size;
|
|
if (demangleBuiltinSize(size)) {
|
|
return NodeFactory::create(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Int" << size).str());
|
|
}
|
|
}
|
|
if (c == 'v') {
|
|
Node::IndexType elts;
|
|
if (demangleNatural(elts)) {
|
|
if (!Mangled.nextIf('B'))
|
|
return nullptr;
|
|
if (Mangled.nextIf('i')) {
|
|
Node::IndexType size;
|
|
if (!demangleBuiltinSize(size))
|
|
return nullptr;
|
|
return NodeFactory::create(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xInt" << size)
|
|
.str());
|
|
}
|
|
if (Mangled.nextIf('f')) {
|
|
Node::IndexType size;
|
|
if (!demangleBuiltinSize(size))
|
|
return nullptr;
|
|
return NodeFactory::create(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xFloat"
|
|
<< size).str());
|
|
}
|
|
if (Mangled.nextIf('p'))
|
|
return NodeFactory::create(
|
|
Node::Kind::BuiltinTypeName,
|
|
(DemanglerPrinter() << "Builtin.Vec" << elts << "xRawPointer")
|
|
.str());
|
|
}
|
|
}
|
|
if (c == 'O')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.UnknownObject");
|
|
if (c == 'o')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.NativeObject");
|
|
if (c == 'p')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.RawPointer");
|
|
if (c == 'w')
|
|
return NodeFactory::create(Node::Kind::BuiltinTypeName,
|
|
"Builtin.Word");
|
|
return nullptr;
|
|
}
|
|
if (c == 'a')
|
|
return demangleDeclarationName(Node::Kind::TypeAlias);
|
|
|
|
if (c == 'b') {
|
|
return demangleFunctionType(Node::Kind::ObjCBlock);
|
|
}
|
|
if (c == 'c') {
|
|
return demangleFunctionType(Node::Kind::CFunctionPointer);
|
|
}
|
|
if (c == 'D') {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
|
|
NodePointer dynamicSelf = NodeFactory::create(Node::Kind::DynamicSelf);
|
|
dynamicSelf->addChild(type);
|
|
return dynamicSelf;
|
|
}
|
|
if (c == 'E') {
|
|
if (!Mangled.nextIf('R'))
|
|
return nullptr;
|
|
if (!Mangled.nextIf('R'))
|
|
return nullptr;
|
|
return NodeFactory::create(Node::Kind::ErrorType, std::string());
|
|
}
|
|
if (c == 'F') {
|
|
return demangleFunctionType(Node::Kind::FunctionType);
|
|
}
|
|
if (c == 'f') {
|
|
return demangleFunctionType(Node::Kind::UncurriedFunctionType);
|
|
}
|
|
if (c == 'G') {
|
|
return demangleBoundGenericType();
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('b')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer boxType = NodeFactory::create(Node::Kind::SILBoxType);
|
|
boxType->addChild(type);
|
|
return boxType;
|
|
}
|
|
}
|
|
if (c == 'K') {
|
|
return demangleFunctionType(Node::Kind::AutoClosureType);
|
|
}
|
|
if (c == 'M') {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer metatype = NodeFactory::create(Node::Kind::Metatype);
|
|
metatype->addChild(type);
|
|
return metatype;
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer metatypeRepr = demangleMetatypeRepresentation();
|
|
if (!metatypeRepr) return nullptr;
|
|
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer metatype = NodeFactory::create(Node::Kind::Metatype);
|
|
metatype->addChild(metatypeRepr);
|
|
metatype->addChild(type);
|
|
return metatype;
|
|
}
|
|
}
|
|
if (c == 'P') {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer type = demangleType();
|
|
if (!type) return nullptr;
|
|
auto metatype = NodeFactory::create(Node::Kind::ExistentialMetatype);
|
|
metatype->addChild(type);
|
|
return metatype;
|
|
}
|
|
|
|
return demangleProtocolList();
|
|
}
|
|
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('P')) {
|
|
if (Mangled.nextIf('M')) {
|
|
NodePointer metatypeRepr = demangleMetatypeRepresentation();
|
|
if (!metatypeRepr) return nullptr;
|
|
|
|
NodePointer type = demangleType();
|
|
if (!type) return nullptr;
|
|
|
|
auto metatype = NodeFactory::create(Node::Kind::ExistentialMetatype);
|
|
metatype->addChild(metatypeRepr);
|
|
metatype->addChild(type);
|
|
return metatype;
|
|
}
|
|
|
|
return demangleProtocolList();
|
|
}
|
|
}
|
|
if (c == 'Q') {
|
|
return demangleArchetypeType();
|
|
}
|
|
if (c == 'q') {
|
|
return demangleDependentType();
|
|
}
|
|
if (c == 'x') {
|
|
// Special mangling for the first generic param.
|
|
return getDependentGenericParamType(0, 0);
|
|
}
|
|
if (c == 'w') {
|
|
return demangleAssociatedTypeSimple();
|
|
}
|
|
if (c == 'W') {
|
|
return demangleAssociatedTypeCompound();
|
|
}
|
|
if (c == 'R') {
|
|
NodePointer inout = NodeFactory::create(Node::Kind::InOut);
|
|
NodePointer type = demangleTypeImpl();
|
|
if (!type)
|
|
return nullptr;
|
|
inout->addChild(type);
|
|
return inout;
|
|
}
|
|
if (c == 'S') {
|
|
return demangleSubstitutionIndex();
|
|
}
|
|
if (c == 'T') {
|
|
return demangleTuple(IsVariadic::no);
|
|
}
|
|
if (c == 't') {
|
|
return demangleTuple(IsVariadic::yes);
|
|
}
|
|
if (c == 'u') {
|
|
NodePointer sig = demangleGenericSignature();
|
|
if (!sig) return nullptr;
|
|
NodePointer sub = demangleType();
|
|
if (!sub) return nullptr;
|
|
NodePointer dependentGenericType
|
|
= NodeFactory::create(Node::Kind::DependentGenericType);
|
|
dependentGenericType->addChild(sig);
|
|
dependentGenericType->addChild(sub);
|
|
return dependentGenericType;
|
|
}
|
|
if (c == 'X') {
|
|
if (Mangled.nextIf('f')) {
|
|
return demangleFunctionType(Node::Kind::ThinFunctionType);
|
|
}
|
|
if (Mangled.nextIf('o')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = NodeFactory::create(Node::Kind::Unowned);
|
|
unowned->addChild(type);
|
|
return unowned;
|
|
}
|
|
if (Mangled.nextIf('u')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer unowned = NodeFactory::create(Node::Kind::Unmanaged);
|
|
unowned->addChild(type);
|
|
return unowned;
|
|
}
|
|
if (Mangled.nextIf('w')) {
|
|
NodePointer type = demangleType();
|
|
if (!type)
|
|
return nullptr;
|
|
NodePointer weak = NodeFactory::create(Node::Kind::Weak);
|
|
weak->addChild(type);
|
|
return weak;
|
|
}
|
|
|
|
// type ::= 'XF' impl-function-type
|
|
if (Mangled.nextIf('F')) {
|
|
return demangleImplFunctionType();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
if (isStartOfNominalType(c))
|
|
return demangleDeclarationName(nominalTypeMarkerToNodeKind(c));
|
|
return nullptr;
|
|
}
|
|
|
|
bool demangleReabstractSignature(NodePointer signature) {
|
|
if (Mangled.nextIf('G')) {
|
|
NodePointer generics = demangleGenericSignature();
|
|
if (!generics) return false;
|
|
signature->addChild(std::move(generics));
|
|
}
|
|
|
|
NodePointer srcType = demangleType();
|
|
if (!srcType) return false;
|
|
signature->addChild(std::move(srcType));
|
|
|
|
NodePointer destType = demangleType();
|
|
if (!destType) return false;
|
|
signature->addChild(std::move(destType));
|
|
|
|
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 ::= 'N' // noreturn
|
|
// impl-function-attribute ::= 'G' // generic
|
|
NodePointer demangleImplFunctionType() {
|
|
NodePointer type = NodeFactory::create(Node::Kind::ImplFunctionType);
|
|
|
|
if (!demangleImplCalleeConvention(type))
|
|
return nullptr;
|
|
|
|
if (Mangled.nextIf('C')) {
|
|
if (Mangled.nextIf('b'))
|
|
addImplFunctionAttribute(type, "@convention(block)");
|
|
else if (Mangled.nextIf('c'))
|
|
addImplFunctionAttribute(type, "@convention(c)");
|
|
else if (Mangled.nextIf('m'))
|
|
addImplFunctionAttribute(type, "@convention(method)");
|
|
else if (Mangled.nextIf('O'))
|
|
addImplFunctionAttribute(type, "@convention(objc_method)");
|
|
else if (Mangled.nextIf('w'))
|
|
addImplFunctionAttribute(type, "@convention(witness_method)");
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Mangled.nextIf('N'))
|
|
addImplFunctionAttribute(type, "@noreturn");
|
|
|
|
// 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(isPseudogeneric);
|
|
if (!generics)
|
|
return nullptr;
|
|
type->addChild(generics);
|
|
}
|
|
|
|
// Expect the attribute terminator.
|
|
if (!Mangled.nextIf('_'))
|
|
return nullptr;
|
|
|
|
// Demangle the parameters.
|
|
if (!demangleImplParameters(type))
|
|
return nullptr;
|
|
|
|
// Demangle the result type.
|
|
if (!demangleImplResults(type))
|
|
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) {
|
|
#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); \
|
|
} \
|
|
unreachable("bad context"); \
|
|
}
|
|
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) {
|
|
StringRef attr;
|
|
if (Mangled.nextIf('t')) {
|
|
attr = "@convention(thin)";
|
|
} else {
|
|
attr = demangleImplConvention(ImplConventionContext::Callee);
|
|
}
|
|
if (attr.empty()) {
|
|
return false;
|
|
}
|
|
type->addChild(NodeFactory::create(Node::Kind::ImplConvention, attr));
|
|
return true;
|
|
}
|
|
|
|
void addImplFunctionAttribute(NodePointer parent, StringRef attr,
|
|
Node::Kind kind = Node::Kind::ImplFunctionAttribute) {
|
|
parent->addChild(NodeFactory::create(kind, attr));
|
|
}
|
|
|
|
// impl-parameter ::= impl-convention type
|
|
bool demangleImplParameters(NodePointer parent) {
|
|
while (!Mangled.nextIf('_')) {
|
|
auto input = demangleImplParameterOrResult(Node::Kind::ImplParameter);
|
|
if (!input) return false;
|
|
parent->addChild(input);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// impl-result ::= impl-convention type
|
|
bool demangleImplResults(NodePointer parent) {
|
|
while (!Mangled.nextIf('_')) {
|
|
auto res = demangleImplParameterOrResult(Node::Kind::ImplResult);
|
|
if (!res) return false;
|
|
parent->addChild(res);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
NodePointer demangleImplParameterOrResult(Node::Kind kind) {
|
|
if (Mangled.nextIf('z')) {
|
|
// Only valid for a result.
|
|
if (kind != Node::Kind::ImplResult)
|
|
return nullptr;
|
|
kind = Node::Kind::ImplErrorResult;
|
|
}
|
|
|
|
auto getContext = [](Node::Kind kind) -> ImplConventionContext {
|
|
if (kind == Node::Kind::ImplParameter)
|
|
return ImplConventionContext::Parameter;
|
|
else if (kind == Node::Kind::ImplResult
|
|
|| kind == Node::Kind::ImplErrorResult)
|
|
return ImplConventionContext::Result;
|
|
else
|
|
unreachable("unexpected node kind");
|
|
};
|
|
|
|
auto convention = demangleImplConvention(getContext(kind));
|
|
if (convention.empty()) return nullptr;
|
|
auto type = demangleType();
|
|
if (!type) return nullptr;
|
|
|
|
NodePointer node = NodeFactory::create(kind);
|
|
node->addChild(NodeFactory::create(Node::Kind::ImplConvention,
|
|
convention));
|
|
node->addChild(type);
|
|
|
|
return node;
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
NodePointer
|
|
swift::Demangle::demangleSymbolAsNode(const char *MangledName,
|
|
size_t MangledNameLength,
|
|
const DemangleOptions &Options) {
|
|
Demangler demangler(StringRef(MangledName, MangledNameLength));
|
|
return demangler.demangleTopLevel();
|
|
}
|
|
|
|
NodePointer
|
|
swift::Demangle::demangleTypeAsNode(const char *MangledName,
|
|
size_t MangledNameLength,
|
|
const DemangleOptions &Options) {
|
|
Demangler demangler(StringRef(MangledName, MangledNameLength));
|
|
return demangler.demangleTypeName();
|
|
}
|
|
|
|
namespace {
|
|
class NodePrinter {
|
|
private:
|
|
DemanglerPrinter Printer;
|
|
DemangleOptions Options;
|
|
|
|
public:
|
|
NodePrinter(DemangleOptions options) : Options(options) {}
|
|
|
|
std::string printRoot(NodePointer root) {
|
|
print(root);
|
|
return std::move(Printer).str();
|
|
}
|
|
|
|
private:
|
|
void printChildren(Node::iterator begin,
|
|
Node::iterator end,
|
|
const char *sep = nullptr) {
|
|
for (; begin != end;) {
|
|
print(*begin);
|
|
++begin;
|
|
if (sep && begin != end)
|
|
Printer << sep;
|
|
}
|
|
}
|
|
|
|
void printChildren(NodePointer pointer, const char *sep = nullptr) {
|
|
if (!pointer)
|
|
return;
|
|
Node::iterator begin = pointer->begin(), end = pointer->end();
|
|
printChildren(begin, end, sep);
|
|
}
|
|
|
|
NodePointer getFirstChildOfKind(NodePointer pointer, Node::Kind kind) {
|
|
if (!pointer)
|
|
return nullptr;
|
|
for (NodePointer &child : *pointer) {
|
|
if (child && child->getKind() == kind)
|
|
return child;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void printBoundGenericNoSugar(NodePointer pointer) {
|
|
if (pointer->getNumChildren() < 2)
|
|
return;
|
|
NodePointer typelist = pointer->getChild(1);
|
|
print(pointer->getChild(0));
|
|
Printer << "<";
|
|
printChildren(typelist, ", ");
|
|
Printer << ">";
|
|
}
|
|
|
|
static bool isSwiftModule(NodePointer node) {
|
|
return (node->getKind() == Node::Kind::Module &&
|
|
node->getText() == STDLIB_NAME);
|
|
}
|
|
|
|
static bool isDebuggerGeneratedModule(NodePointer node) {
|
|
return (node->getKind() == Node::Kind::Module &&
|
|
0 == node->getText().find(LLDB_EXPRESSIONS_MODULE_NAME_PREFIX));
|
|
}
|
|
|
|
static bool isIdentifier(NodePointer node, StringRef desired) {
|
|
return (node->getKind() == Node::Kind::Identifier &&
|
|
node->getText() == desired);
|
|
}
|
|
|
|
enum class SugarType {
|
|
None,
|
|
Optional,
|
|
ImplicitlyUnwrappedOptional,
|
|
Array,
|
|
Dictionary
|
|
};
|
|
|
|
/// Determine whether this is a "simple" type, from the type-simple
|
|
/// production.
|
|
bool isSimpleType(NodePointer pointer) {
|
|
switch (pointer->getKind()) {
|
|
case Node::Kind::Archetype:
|
|
case Node::Kind::ArchetypeRef:
|
|
case Node::Kind::AssociatedType:
|
|
case Node::Kind::AssociatedTypeRef:
|
|
case Node::Kind::BoundGenericClass:
|
|
case Node::Kind::BoundGenericEnum:
|
|
case Node::Kind::BoundGenericStructure:
|
|
case Node::Kind::BuiltinTypeName:
|
|
case Node::Kind::Class:
|
|
case Node::Kind::DependentGenericType:
|
|
case Node::Kind::DependentMemberType:
|
|
case Node::Kind::DependentGenericParamType:
|
|
case Node::Kind::DynamicSelf:
|
|
case Node::Kind::Enum:
|
|
case Node::Kind::ErrorType:
|
|
case Node::Kind::ExistentialMetatype:
|
|
case Node::Kind::Metatype:
|
|
case Node::Kind::MetatypeRepresentation:
|
|
case Node::Kind::Module:
|
|
case Node::Kind::NonVariadicTuple:
|
|
case Node::Kind::Protocol:
|
|
case Node::Kind::QualifiedArchetype:
|
|
case Node::Kind::ReturnType:
|
|
case Node::Kind::SelfTypeRef:
|
|
case Node::Kind::SILBoxType:
|
|
case Node::Kind::Structure:
|
|
case Node::Kind::TupleElementName:
|
|
case Node::Kind::Type:
|
|
case Node::Kind::TypeAlias:
|
|
case Node::Kind::TypeList:
|
|
case Node::Kind::VariadicTuple:
|
|
return true;
|
|
|
|
case Node::Kind::Allocator:
|
|
case Node::Kind::ArgumentTuple:
|
|
case Node::Kind::AssociatedTypeMetadataAccessor:
|
|
case Node::Kind::AssociatedTypeWitnessTableAccessor:
|
|
case Node::Kind::AutoClosureType:
|
|
case Node::Kind::CFunctionPointer:
|
|
case Node::Kind::Constructor:
|
|
case Node::Kind::Deallocator:
|
|
case Node::Kind::DeclContext:
|
|
case Node::Kind::DefaultArgumentInitializer:
|
|
case Node::Kind::DependentAssociatedTypeRef:
|
|
case Node::Kind::DependentGenericSignature:
|
|
case Node::Kind::DependentGenericParamCount:
|
|
case Node::Kind::DependentGenericConformanceRequirement:
|
|
case Node::Kind::DependentGenericSameTypeRequirement:
|
|
case Node::Kind::DependentPseudogenericSignature:
|
|
case Node::Kind::Destructor:
|
|
case Node::Kind::DidSet:
|
|
case Node::Kind::DirectMethodReferenceAttribute:
|
|
case Node::Kind::Directness:
|
|
case Node::Kind::DynamicAttribute:
|
|
case Node::Kind::ExplicitClosure:
|
|
case Node::Kind::Extension:
|
|
case Node::Kind::FieldOffset:
|
|
case Node::Kind::FullTypeMetadata:
|
|
case Node::Kind::Function:
|
|
case Node::Kind::FunctionSignatureSpecialization:
|
|
case Node::Kind::FunctionSignatureSpecializationParam:
|
|
case Node::Kind::FunctionSignatureSpecializationParamKind:
|
|
case Node::Kind::FunctionSignatureSpecializationParamPayload:
|
|
case Node::Kind::FunctionType:
|
|
case Node::Kind::GenericProtocolWitnessTable:
|
|
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
|
|
case Node::Kind::GenericSpecialization:
|
|
case Node::Kind::GenericSpecializationNotReAbstracted:
|
|
case Node::Kind::GenericSpecializationParam:
|
|
case Node::Kind::GenericTypeMetadataPattern:
|
|
case Node::Kind::Getter:
|
|
case Node::Kind::Global:
|
|
case Node::Kind::GlobalGetter:
|
|
case Node::Kind::Identifier:
|
|
case Node::Kind::Index:
|
|
case Node::Kind::IVarInitializer:
|
|
case Node::Kind::IVarDestroyer:
|
|
case Node::Kind::ImplConvention:
|
|
case Node::Kind::ImplFunctionAttribute:
|
|
case Node::Kind::ImplFunctionType:
|
|
case Node::Kind::ImplicitClosure:
|
|
case Node::Kind::ImplParameter:
|
|
case Node::Kind::ImplResult:
|
|
case Node::Kind::ImplErrorResult:
|
|
case Node::Kind::InOut:
|
|
case Node::Kind::InfixOperator:
|
|
case Node::Kind::Initializer:
|
|
case Node::Kind::LazyProtocolWitnessTableAccessor:
|
|
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
|
|
case Node::Kind::LocalDeclName:
|
|
case Node::Kind::PrivateDeclName:
|
|
case Node::Kind::MaterializeForSet:
|
|
case Node::Kind::Metaclass:
|
|
case Node::Kind::NativeOwningAddressor:
|
|
case Node::Kind::NativeOwningMutableAddressor:
|
|
case Node::Kind::NativePinningAddressor:
|
|
case Node::Kind::NativePinningMutableAddressor:
|
|
case Node::Kind::NominalTypeDescriptor:
|
|
case Node::Kind::NonObjCAttribute:
|
|
case Node::Kind::Number:
|
|
case Node::Kind::ObjCAttribute:
|
|
case Node::Kind::ObjCBlock:
|
|
case Node::Kind::OwningAddressor:
|
|
case Node::Kind::OwningMutableAddressor:
|
|
case Node::Kind::PartialApplyForwarder:
|
|
case Node::Kind::PartialApplyObjCForwarder:
|
|
case Node::Kind::PostfixOperator:
|
|
case Node::Kind::PrefixOperator:
|
|
case Node::Kind::ProtocolConformance:
|
|
case Node::Kind::ProtocolDescriptor:
|
|
case Node::Kind::ProtocolList:
|
|
case Node::Kind::ProtocolWitness:
|
|
case Node::Kind::ProtocolWitnessTable:
|
|
case Node::Kind::ProtocolWitnessTableAccessor:
|
|
case Node::Kind::ReabstractionThunk:
|
|
case Node::Kind::ReabstractionThunkHelper:
|
|
case Node::Kind::Setter:
|
|
case Node::Kind::SpecializationIsFragile:
|
|
case Node::Kind::SpecializationPassID:
|
|
case Node::Kind::Static:
|
|
case Node::Kind::Subscript:
|
|
case Node::Kind::Suffix:
|
|
case Node::Kind::ThinFunctionType:
|
|
case Node::Kind::TupleElement:
|
|
case Node::Kind::TypeMangling:
|
|
case Node::Kind::TypeMetadata:
|
|
case Node::Kind::TypeMetadataAccessFunction:
|
|
case Node::Kind::TypeMetadataLazyCache:
|
|
case Node::Kind::UncurriedFunctionType:
|
|
case Node::Kind::Unmanaged:
|
|
case Node::Kind::Unowned:
|
|
case Node::Kind::UnsafeAddressor:
|
|
case Node::Kind::UnsafeMutableAddressor:
|
|
case Node::Kind::ValueWitness:
|
|
case Node::Kind::ValueWitnessTable:
|
|
case Node::Kind::Variable:
|
|
case Node::Kind::VTableAttribute:
|
|
case Node::Kind::Weak:
|
|
case Node::Kind::WillSet:
|
|
case Node::Kind::WitnessTableOffset:
|
|
case Node::Kind::ThrowsAnnotation:
|
|
return false;
|
|
}
|
|
unreachable("bad node kind");
|
|
}
|
|
|
|
SugarType findSugar(NodePointer pointer) {
|
|
if (pointer->getNumChildren() == 1 &&
|
|
pointer->getKind() == Node::Kind::Type)
|
|
return findSugar(pointer->getChild(0));
|
|
|
|
if (pointer->getNumChildren() != 2)
|
|
return SugarType::None;
|
|
|
|
if (pointer->getKind() != Node::Kind::BoundGenericEnum &&
|
|
pointer->getKind() != Node::Kind::BoundGenericStructure)
|
|
return SugarType::None;
|
|
|
|
auto unboundType = pointer->getChild(0)->getChild(0); // drill through Type
|
|
auto typeArgs = pointer->getChild(1);
|
|
|
|
if (pointer->getKind() == Node::Kind::BoundGenericEnum) {
|
|
// Swift.Optional
|
|
if (isIdentifier(unboundType->getChild(1), "Optional") &&
|
|
typeArgs->getNumChildren() == 1 &&
|
|
isSwiftModule(unboundType->getChild(0))) {
|
|
return SugarType::Optional;
|
|
}
|
|
|
|
// Swift.ImplicitlyUnwrappedOptional
|
|
if (isIdentifier(unboundType->getChild(1),
|
|
"ImplicitlyUnwrappedOptional") &&
|
|
typeArgs->getNumChildren() == 1 &&
|
|
isSwiftModule(unboundType->getChild(0))) {
|
|
return SugarType::ImplicitlyUnwrappedOptional;
|
|
}
|
|
|
|
return SugarType::None;
|
|
}
|
|
|
|
assert(pointer->getKind() == Node::Kind::BoundGenericStructure);
|
|
|
|
// Array
|
|
if (isIdentifier(unboundType->getChild(1), "Array") &&
|
|
typeArgs->getNumChildren() == 1 &&
|
|
isSwiftModule(unboundType->getChild(0))) {
|
|
return SugarType::Array;
|
|
}
|
|
|
|
// Dictionary
|
|
if (isIdentifier(unboundType->getChild(1), "Dictionary") &&
|
|
typeArgs->getNumChildren() == 2 &&
|
|
isSwiftModule(unboundType->getChild(0))) {
|
|
return SugarType::Dictionary;
|
|
}
|
|
|
|
return SugarType::None;
|
|
}
|
|
|
|
void printBoundGeneric(NodePointer pointer) {
|
|
if (pointer->getNumChildren() < 2)
|
|
return;
|
|
if (pointer->getNumChildren() != 2) {
|
|
printBoundGenericNoSugar(pointer);
|
|
return;
|
|
}
|
|
|
|
if (!Options.SynthesizeSugarOnTypes ||
|
|
pointer->getKind() == Node::Kind::BoundGenericClass)
|
|
{
|
|
// no sugar here
|
|
printBoundGenericNoSugar(pointer);
|
|
return;
|
|
}
|
|
|
|
SugarType sugarType = findSugar(pointer);
|
|
|
|
switch (sugarType) {
|
|
case SugarType::None:
|
|
printBoundGenericNoSugar(pointer);
|
|
break;
|
|
case SugarType::Optional:
|
|
case SugarType::ImplicitlyUnwrappedOptional: {
|
|
NodePointer type = pointer->getChild(1)->getChild(0);
|
|
bool needs_parens = !isSimpleType(type);
|
|
if (needs_parens)
|
|
Printer << "(";
|
|
print(type);
|
|
if (needs_parens)
|
|
Printer << ")";
|
|
Printer << (sugarType == SugarType::Optional ? "?" : "!");
|
|
break;
|
|
}
|
|
case SugarType::Array: {
|
|
NodePointer type = pointer->getChild(1)->getChild(0);
|
|
Printer << "[";
|
|
print(type);
|
|
Printer << "]";
|
|
break;
|
|
}
|
|
case SugarType::Dictionary: {
|
|
NodePointer keyType = pointer->getChild(1)->getChild(0);
|
|
NodePointer valueType = pointer->getChild(1)->getChild(1);
|
|
Printer << "[";
|
|
print(keyType);
|
|
Printer << " : ";
|
|
print(valueType);
|
|
Printer << "]";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void printSimplifiedEntityType(NodePointer context, NodePointer entityType);
|
|
|
|
void printFunctionType(NodePointer node) {
|
|
assert(node->getNumChildren() == 2 || node->getNumChildren() == 3);
|
|
unsigned startIndex = 0;
|
|
bool throws = false;
|
|
if (node->getNumChildren() == 3) {
|
|
assert(node->getChild(0)->getKind() == Node::Kind::ThrowsAnnotation);
|
|
startIndex++;
|
|
throws = true;
|
|
}
|
|
print(node->getChild(startIndex));
|
|
if (throws) Printer << " throws";
|
|
print(node->getChild(startIndex+1));
|
|
}
|
|
|
|
void printImplFunctionType(NodePointer fn) {
|
|
enum State { Attrs, Inputs, Results } curState = Attrs;
|
|
auto transitionTo = [&](State newState) {
|
|
assert(newState >= curState);
|
|
for (; curState != newState; curState = State(curState + 1)) {
|
|
switch (curState) {
|
|
case Attrs: Printer << '('; continue;
|
|
case Inputs: Printer << ") -> ("; continue;
|
|
case Results: unreachable("no state after Results");
|
|
}
|
|
unreachable("bad state");
|
|
}
|
|
};
|
|
|
|
for (auto &child : *fn) {
|
|
if (child->getKind() == Node::Kind::ImplParameter) {
|
|
if (curState == Inputs) Printer << ", ";
|
|
transitionTo(Inputs);
|
|
print(child);
|
|
} else if (child->getKind() == Node::Kind::ImplResult
|
|
|| child->getKind() == Node::Kind::ImplErrorResult) {
|
|
if (curState == Results) Printer << ", ";
|
|
transitionTo(Results);
|
|
print(child);
|
|
} else {
|
|
assert(curState == Attrs);
|
|
print(child);
|
|
Printer << ' ';
|
|
}
|
|
}
|
|
transitionTo(Results);
|
|
Printer << ')';
|
|
}
|
|
|
|
void printContext(NodePointer context) {
|
|
// TODO: parenthesize local contexts?
|
|
if (Options.DisplayDebuggerGeneratedModule ||
|
|
!isDebuggerGeneratedModule(context))
|
|
{
|
|
print(context, /*asContext*/ true);
|
|
if (context->getKind() == Node::Kind::Module && !Options.DisplayModuleNames)
|
|
return;
|
|
Printer << '.';
|
|
}
|
|
}
|
|
|
|
void print(NodePointer pointer, bool asContext = false, bool suppressType = false);
|
|
|
|
unsigned printFunctionSigSpecializationParam(NodePointer pointer,
|
|
unsigned Idx);
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
static bool isExistentialType(NodePointer node) {
|
|
assert(node->getKind() == Node::Kind::Type);
|
|
node = node->getChild(0);
|
|
return (node->getKind() == Node::Kind::ExistentialMetatype ||
|
|
node->getKind() == Node::Kind::ProtocolList);
|
|
}
|
|
|
|
/// Print the relevant parameters and return the new index.
|
|
unsigned NodePrinter::printFunctionSigSpecializationParam(NodePointer pointer,
|
|
unsigned Idx) {
|
|
NodePointer firstChild = pointer->getChild(Idx);
|
|
unsigned V = firstChild->getIndex();
|
|
auto K = FunctionSigSpecializationParamKind(V);
|
|
switch (K) {
|
|
case FunctionSigSpecializationParamKind::BoxToValue:
|
|
case FunctionSigSpecializationParamKind::BoxToStack:
|
|
print(pointer->getChild(Idx++));
|
|
return Idx;
|
|
case FunctionSigSpecializationParamKind::ConstantPropFunction:
|
|
case FunctionSigSpecializationParamKind::ConstantPropGlobal: {
|
|
Printer << "[";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << " : ";
|
|
const auto &text = pointer->getChild(Idx++)->getText();
|
|
std::string demangledName = demangleSymbolAsString(text);
|
|
if (demangledName.empty()) {
|
|
Printer << text;
|
|
} else {
|
|
Printer << demangledName;
|
|
}
|
|
Printer << "]";
|
|
return Idx;
|
|
}
|
|
case FunctionSigSpecializationParamKind::ConstantPropInteger:
|
|
case FunctionSigSpecializationParamKind::ConstantPropFloat:
|
|
Printer << "[";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << " : ";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << "]";
|
|
return Idx;
|
|
case FunctionSigSpecializationParamKind::ConstantPropString:
|
|
Printer << "[";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << " : ";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << "'";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << "'";
|
|
Printer << "]";
|
|
return Idx;
|
|
case FunctionSigSpecializationParamKind::ClosureProp:
|
|
Printer << "[";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << " : ";
|
|
print(pointer->getChild(Idx++));
|
|
Printer << ", Argument Types : [";
|
|
for (unsigned e = pointer->getNumChildren(); Idx < e;) {
|
|
NodePointer child = pointer->getChild(Idx);
|
|
// Until we no longer have a type node, keep demangling.
|
|
if (child->getKind() != Node::Kind::Type)
|
|
break;
|
|
print(child);
|
|
++Idx;
|
|
|
|
// If we are not done, print the ", ".
|
|
if (Idx < e && pointer->getChild(Idx)->hasText())
|
|
Printer << ", ";
|
|
}
|
|
Printer << "]";
|
|
return Idx;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
assert(
|
|
((V & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) ||
|
|
(V & unsigned(FunctionSigSpecializationParamKind::SROA)) ||
|
|
(V & unsigned(FunctionSigSpecializationParamKind::Dead))) &&
|
|
"Invalid OptionSet");
|
|
print(pointer->getChild(Idx++));
|
|
return Idx;
|
|
}
|
|
|
|
static bool isClassType(NodePointer pointer) {
|
|
return pointer->getKind() == Node::Kind::Class;
|
|
}
|
|
|
|
static bool useColonForEntityType(NodePointer entity, NodePointer type) {
|
|
switch (entity->getKind()) {
|
|
case Node::Kind::Variable:
|
|
case Node::Kind::Initializer:
|
|
case Node::Kind::DefaultArgumentInitializer:
|
|
case Node::Kind::IVarInitializer:
|
|
case Node::Kind::Class:
|
|
case Node::Kind::Structure:
|
|
case Node::Kind::Enum:
|
|
case Node::Kind::Protocol:
|
|
case Node::Kind::TypeAlias:
|
|
case Node::Kind::OwningAddressor:
|
|
case Node::Kind::OwningMutableAddressor:
|
|
case Node::Kind::NativeOwningAddressor:
|
|
case Node::Kind::NativeOwningMutableAddressor:
|
|
case Node::Kind::NativePinningAddressor:
|
|
case Node::Kind::NativePinningMutableAddressor:
|
|
case Node::Kind::UnsafeAddressor:
|
|
case Node::Kind::UnsafeMutableAddressor:
|
|
case Node::Kind::GlobalGetter:
|
|
case Node::Kind::Getter:
|
|
case Node::Kind::Setter:
|
|
case Node::Kind::MaterializeForSet:
|
|
case Node::Kind::WillSet:
|
|
case Node::Kind::DidSet:
|
|
return true;
|
|
|
|
case Node::Kind::Subscript:
|
|
case Node::Kind::Function:
|
|
case Node::Kind::ExplicitClosure:
|
|
case Node::Kind::ImplicitClosure:
|
|
case Node::Kind::Allocator:
|
|
case Node::Kind::Constructor:
|
|
case Node::Kind::Destructor:
|
|
case Node::Kind::Deallocator:
|
|
case Node::Kind::IVarDestroyer: {
|
|
// We expect to see a function type here, but if we don't, use the colon.
|
|
type = type->getChild(0);
|
|
while (type->getKind() == Node::Kind::DependentGenericType)
|
|
type = type->getChild(1)->getChild(0);
|
|
return (type->getKind() != Node::Kind::FunctionType &&
|
|
type->getKind() != Node::Kind::UncurriedFunctionType &&
|
|
type->getKind() != Node::Kind::CFunctionPointer &&
|
|
type->getKind() != Node::Kind::ThinFunctionType);
|
|
}
|
|
|
|
default:
|
|
unreachable("not an entity");
|
|
}
|
|
}
|
|
|
|
static bool isMethodContext(const NodePointer &context) {
|
|
switch (context->getKind()) {
|
|
case Node::Kind::Structure:
|
|
case Node::Kind::Enum:
|
|
case Node::Kind::Class:
|
|
case Node::Kind::Protocol:
|
|
case Node::Kind::Extension:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Perform any desired type simplifications for an entity in Simplified mode.
|
|
void NodePrinter::printSimplifiedEntityType(NodePointer context,
|
|
NodePointer entityType) {
|
|
// Only do anything special to methods.
|
|
if (!isMethodContext(context)) return print(entityType);
|
|
|
|
// Strip off a single level of uncurried function type.
|
|
NodePointer type = entityType;
|
|
assert(type->getKind() == Node::Kind::Type);
|
|
type = type->getChild(0);
|
|
|
|
NodePointer generics;
|
|
if (type->getKind() == Node::Kind::DependentGenericType) {
|
|
generics = type->getChild(0);
|
|
type = type->getChild(1)->getChild(0);
|
|
}
|
|
|
|
print(entityType);
|
|
}
|
|
|
|
void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) {
|
|
// Common code for handling entities.
|
|
auto printEntity = [&](bool hasName, bool hasType, StringRef extraName) {
|
|
if (Options.QualifyEntities)
|
|
printContext(pointer->getChild(0));
|
|
|
|
bool printType = (hasType && !suppressType);
|
|
bool useParens = (printType && asContext);
|
|
|
|
if (useParens) Printer << '(';
|
|
|
|
if (hasName) print(pointer->getChild(1));
|
|
Printer << extraName;
|
|
|
|
if (printType) {
|
|
NodePointer type = pointer->getChild(1 + unsigned(hasName));
|
|
if (useColonForEntityType(pointer, type)) {
|
|
if (Options.DisplayEntityTypes) {
|
|
Printer << " : ";
|
|
print(type);
|
|
}
|
|
} else if (!Options.DisplayEntityTypes) {
|
|
printSimplifiedEntityType(pointer->getChild(0), type);
|
|
} else {
|
|
Printer << " ";
|
|
print(type);
|
|
}
|
|
}
|
|
|
|
if (useParens) Printer << ')';
|
|
};
|
|
|
|
Node::Kind kind = pointer->getKind();
|
|
switch (kind) {
|
|
case Node::Kind::Static:
|
|
Printer << "static ";
|
|
print(pointer->getChild(0), asContext, suppressType);
|
|
return;
|
|
case Node::Kind::Directness:
|
|
Printer << toString(Directness(pointer->getIndex())) << " ";
|
|
return;
|
|
case Node::Kind::Extension:
|
|
assert((pointer->getNumChildren() == 2 || pointer->getNumChildren() == 3)
|
|
&& "Extension expects 2 or 3 children.");
|
|
if (Options.QualifyEntities && Options.DisplayExtensionContexts) {
|
|
Printer << "(extension in ";
|
|
// Print the module where extension is defined.
|
|
print(pointer->getChild(0), true);
|
|
Printer << "):";
|
|
}
|
|
print(pointer->getChild(1), asContext);
|
|
if (pointer->getNumChildren() == 3)
|
|
print(pointer->getChild(2), true);
|
|
return;
|
|
case Node::Kind::Variable:
|
|
case Node::Kind::Function:
|
|
case Node::Kind::Subscript:
|
|
printEntity(true, true, "");
|
|
return;
|
|
case Node::Kind::ExplicitClosure:
|
|
case Node::Kind::ImplicitClosure: {
|
|
auto index = pointer->getChild(1)->getIndex();
|
|
DemanglerPrinter printName;
|
|
printName << '(';
|
|
if (pointer->getKind() == Node::Kind::ImplicitClosure)
|
|
printName << "implicit ";
|
|
printName << "closure #" << (index + 1) << ")";
|
|
printEntity(false, false, std::move(printName).str());
|
|
return;
|
|
}
|
|
case Node::Kind::Global:
|
|
printChildren(pointer);
|
|
return;
|
|
case Node::Kind::Suffix:
|
|
if (!Options.DisplayUnmangledSuffix) return;
|
|
Printer << " with unmangled suffix " << QuotedString(pointer->getText());
|
|
return;
|
|
case Node::Kind::Initializer:
|
|
printEntity(false, false, "(variable initialization expression)");
|
|
return;
|
|
case Node::Kind::DefaultArgumentInitializer: {
|
|
auto index = pointer->getChild(1);
|
|
DemanglerPrinter strPrinter;
|
|
strPrinter << "(default argument " << index->getIndex() << ")";
|
|
printEntity(false, false, std::move(strPrinter).str());
|
|
return;
|
|
}
|
|
case Node::Kind::DeclContext:
|
|
print(pointer->getChild(0), asContext);
|
|
return;
|
|
case Node::Kind::Type:
|
|
print(pointer->getChild(0), asContext);
|
|
return;
|
|
case Node::Kind::TypeMangling:
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::Class:
|
|
case Node::Kind::Structure:
|
|
case Node::Kind::Enum:
|
|
case Node::Kind::Protocol:
|
|
case Node::Kind::TypeAlias:
|
|
printEntity(true, false, "");
|
|
return;
|
|
case Node::Kind::LocalDeclName:
|
|
Printer << '(';
|
|
print(pointer->getChild(1));
|
|
Printer << " #" << (pointer->getChild(0)->getIndex() + 1) << ')';
|
|
return;
|
|
case Node::Kind::PrivateDeclName:
|
|
if (Options.ShowPrivateDiscriminators)
|
|
Printer << '(';
|
|
|
|
print(pointer->getChild(1));
|
|
|
|
if (Options.ShowPrivateDiscriminators)
|
|
Printer << " in " << pointer->getChild(0)->getText() << ')';
|
|
return;
|
|
case Node::Kind::Module:
|
|
if (Options.DisplayModuleNames)
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::Identifier:
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::Index:
|
|
Printer << pointer->getIndex();
|
|
return;
|
|
case Node::Kind::AutoClosureType:
|
|
Printer << "@autoclosure ";
|
|
printFunctionType(pointer);
|
|
return;
|
|
case Node::Kind::ThinFunctionType:
|
|
Printer << "@convention(thin) ";
|
|
printFunctionType(pointer);
|
|
return;
|
|
case Node::Kind::FunctionType:
|
|
case Node::Kind::UncurriedFunctionType:
|
|
printFunctionType(pointer);
|
|
return;
|
|
case Node::Kind::ArgumentTuple: {
|
|
bool need_parens = false;
|
|
if (pointer->getNumChildren() > 1)
|
|
need_parens = true;
|
|
else {
|
|
if (!pointer->hasChildren())
|
|
need_parens = true;
|
|
else {
|
|
Node::Kind child0_kind = pointer->getChild(0)->getChild(0)->getKind();
|
|
if (child0_kind != Node::Kind::VariadicTuple &&
|
|
child0_kind != Node::Kind::NonVariadicTuple)
|
|
need_parens = true;
|
|
}
|
|
}
|
|
if (need_parens)
|
|
Printer << "(";
|
|
printChildren(pointer);
|
|
if (need_parens)
|
|
Printer << ")";
|
|
return;
|
|
}
|
|
case Node::Kind::NonVariadicTuple:
|
|
case Node::Kind::VariadicTuple: {
|
|
Printer << "(";
|
|
printChildren(pointer, ", ");
|
|
if (pointer->getKind() == Node::Kind::VariadicTuple)
|
|
Printer << "...";
|
|
Printer << ")";
|
|
return;
|
|
}
|
|
case Node::Kind::TupleElement:
|
|
if (pointer->getNumChildren() == 1) {
|
|
NodePointer type = pointer->getChild(0);
|
|
print(type);
|
|
} else if (pointer->getNumChildren() == 2) {
|
|
NodePointer id = pointer->getChild(0);
|
|
NodePointer type = pointer->getChild(1);
|
|
print(id);
|
|
print(type);
|
|
}
|
|
return;
|
|
case Node::Kind::TupleElementName:
|
|
Printer << pointer->getText() << " : ";
|
|
return;
|
|
case Node::Kind::ReturnType:
|
|
if (pointer->getNumChildren() == 0)
|
|
Printer << " -> " << pointer->getText();
|
|
else {
|
|
Printer << " -> ";
|
|
printChildren(pointer);
|
|
}
|
|
return;
|
|
case Node::Kind::Weak:
|
|
Printer << "weak ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::Unowned:
|
|
Printer << "unowned ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::Unmanaged:
|
|
Printer << "unowned(unsafe) ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::InOut:
|
|
Printer << "inout ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::NonObjCAttribute:
|
|
Printer << "@nonobjc ";
|
|
return;
|
|
case Node::Kind::ObjCAttribute:
|
|
Printer << "@objc ";
|
|
return;
|
|
case Node::Kind::DirectMethodReferenceAttribute:
|
|
Printer << "super ";
|
|
return;
|
|
case Node::Kind::DynamicAttribute:
|
|
Printer << "dynamic ";
|
|
return;
|
|
case Node::Kind::VTableAttribute:
|
|
Printer << "override ";
|
|
return;
|
|
case Node::Kind::FunctionSignatureSpecialization:
|
|
case Node::Kind::GenericSpecialization:
|
|
case Node::Kind::GenericSpecializationNotReAbstracted: {
|
|
if (!Options.DisplayGenericSpecializations) {
|
|
Printer << "specialized ";
|
|
return;
|
|
}
|
|
if (pointer->getKind() == Node::Kind::FunctionSignatureSpecialization) {
|
|
Printer << "function signature specialization <";
|
|
} else if (pointer->getKind() == Node::Kind::GenericSpecialization) {
|
|
Printer << "generic specialization <";
|
|
} else {
|
|
Printer << "generic not re-abstracted specialization <";
|
|
}
|
|
bool hasPrevious = false;
|
|
for (unsigned i = 0, e = pointer->getNumChildren(); i < e; ++i) {
|
|
auto child = pointer->getChild(i);
|
|
|
|
switch (pointer->getChild(i)->getKind()) {
|
|
case Node::Kind::SpecializationPassID:
|
|
// We skip the SpecializationPassID since it does not contain any
|
|
// information that is useful to our users.
|
|
continue;
|
|
|
|
case Node::Kind::SpecializationIsFragile:
|
|
break;
|
|
|
|
default:
|
|
// Ignore empty specializations.
|
|
if (!pointer->getChild(i)->hasChildren())
|
|
continue;
|
|
}
|
|
|
|
if (hasPrevious)
|
|
Printer << ", ";
|
|
print(pointer->getChild(i));
|
|
hasPrevious = true;
|
|
}
|
|
Printer << "> of ";
|
|
return;
|
|
}
|
|
case Node::Kind::SpecializationIsFragile:
|
|
Printer << "preserving fragile attribute";
|
|
return;
|
|
case Node::Kind::GenericSpecializationParam:
|
|
print(pointer->getChild(0));
|
|
for (unsigned i = 1, e = pointer->getNumChildren(); i < e; ++i) {
|
|
if (i == 1)
|
|
Printer << " with ";
|
|
else
|
|
Printer << " and ";
|
|
print(pointer->getChild(i));
|
|
}
|
|
return;
|
|
case Node::Kind::FunctionSignatureSpecializationParam: {
|
|
uint64_t argNum = pointer->getIndex();
|
|
|
|
Printer << "Arg[" << argNum << "] = ";
|
|
|
|
unsigned Idx = printFunctionSigSpecializationParam(pointer, 0);
|
|
|
|
for (unsigned e = pointer->getNumChildren(); Idx < e;) {
|
|
Printer << " and ";
|
|
Idx = printFunctionSigSpecializationParam(pointer, Idx);
|
|
}
|
|
|
|
return;
|
|
}
|
|
case Node::Kind::FunctionSignatureSpecializationParamPayload: {
|
|
std::string demangledName = demangleSymbolAsString(pointer->getText());
|
|
if (demangledName.empty()) {
|
|
Printer << pointer->getText();
|
|
} else {
|
|
Printer << demangledName;
|
|
}
|
|
return;
|
|
}
|
|
case Node::Kind::FunctionSignatureSpecializationParamKind: {
|
|
uint64_t raw = pointer->getIndex();
|
|
|
|
bool printedOptionSet = false;
|
|
if (raw & uint64_t(FunctionSigSpecializationParamKind::Dead)) {
|
|
printedOptionSet = true;
|
|
Printer << "Dead";
|
|
}
|
|
|
|
if (raw & uint64_t(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) {
|
|
if (printedOptionSet)
|
|
Printer << " and ";
|
|
printedOptionSet = true;
|
|
Printer << "Owned To Guaranteed";
|
|
}
|
|
|
|
if (raw & uint64_t(FunctionSigSpecializationParamKind::SROA)) {
|
|
if (printedOptionSet)
|
|
Printer << " and ";
|
|
Printer << "Exploded";
|
|
return;
|
|
}
|
|
|
|
if (printedOptionSet)
|
|
return;
|
|
|
|
switch (FunctionSigSpecializationParamKind(raw)) {
|
|
case FunctionSigSpecializationParamKind::BoxToValue:
|
|
Printer << "Value Promoted from Box";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::BoxToStack:
|
|
Printer << "Stack Promoted from Box";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ConstantPropFunction:
|
|
Printer << "Constant Propagated Function";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ConstantPropGlobal:
|
|
Printer << "Constant Propagated Global";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ConstantPropInteger:
|
|
Printer << "Constant Propagated Integer";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ConstantPropFloat:
|
|
Printer << "Constant Propagated Float";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ConstantPropString:
|
|
Printer << "Constant Propagated String";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::ClosureProp:
|
|
Printer << "Closure Propagated";
|
|
break;
|
|
case FunctionSigSpecializationParamKind::Dead:
|
|
case FunctionSigSpecializationParamKind::OwnedToGuaranteed:
|
|
case FunctionSigSpecializationParamKind::SROA:
|
|
unreachable("option sets should have been handled earlier");
|
|
}
|
|
return;
|
|
}
|
|
case Node::Kind::SpecializationPassID:
|
|
Printer << pointer->getIndex();
|
|
return;
|
|
case Node::Kind::BuiltinTypeName:
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::Number:
|
|
Printer << pointer->getIndex();
|
|
return;
|
|
case Node::Kind::InfixOperator:
|
|
Printer << pointer->getText() << " infix";
|
|
return;
|
|
case Node::Kind::PrefixOperator:
|
|
Printer << pointer->getText() << " prefix";
|
|
return;
|
|
case Node::Kind::PostfixOperator:
|
|
Printer << pointer->getText() << " postfix";
|
|
return;
|
|
case Node::Kind::LazyProtocolWitnessTableAccessor:
|
|
Printer << "lazy protocol witness table accessor for type ";
|
|
print(pointer->getChild(0));
|
|
Printer << " and conformance ";
|
|
print(pointer->getChild(1));
|
|
return;
|
|
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
|
|
Printer << "lazy protocol witness table cache variable for type ";
|
|
print(pointer->getChild(0));
|
|
Printer << " and conformance ";
|
|
print(pointer->getChild(1));
|
|
return;
|
|
case Node::Kind::ProtocolWitnessTableAccessor:
|
|
Printer << "protocol witness table accessor for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::ProtocolWitnessTable:
|
|
Printer << "protocol witness table for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::GenericProtocolWitnessTable:
|
|
Printer << "generic protocol witness table for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
|
|
Printer << "instantiation function for generic protocol witness table for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::ProtocolWitness: {
|
|
Printer << "protocol witness for ";
|
|
print(pointer->getChild(1));
|
|
Printer << " in conformance ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
}
|
|
case Node::Kind::PartialApplyForwarder:
|
|
if (Options.ShortenPartialApply)
|
|
Printer << "partial apply";
|
|
else
|
|
Printer << "partial apply forwarder";
|
|
|
|
if (pointer->hasChildren()) {
|
|
Printer << " for ";
|
|
print(pointer->getFirstChild());
|
|
}
|
|
return;
|
|
case Node::Kind::PartialApplyObjCForwarder:
|
|
if (Options.ShortenPartialApply)
|
|
Printer << "partial apply";
|
|
else
|
|
Printer << "partial apply ObjC forwarder";
|
|
|
|
if (pointer->hasChildren()) {
|
|
Printer << " for ";
|
|
print(pointer->getFirstChild());
|
|
}
|
|
return;
|
|
case Node::Kind::FieldOffset: {
|
|
print(pointer->getChild(0)); // directness
|
|
Printer << "field offset for ";
|
|
auto entity = pointer->getChild(1);
|
|
print(entity, /*asContext*/ false,
|
|
/*suppressType*/ !Options.DisplayTypeOfIVarFieldOffset);
|
|
return;
|
|
}
|
|
case Node::Kind::ReabstractionThunk:
|
|
case Node::Kind::ReabstractionThunkHelper: {
|
|
if (Options.ShortenThunk) {
|
|
Printer << "thunk";
|
|
return;
|
|
}
|
|
Printer << "reabstraction thunk ";
|
|
if (pointer->getKind() == Node::Kind::ReabstractionThunkHelper)
|
|
Printer << "helper ";
|
|
auto generics = getFirstChildOfKind(pointer, Node::Kind::DependentGenericSignature);
|
|
assert(pointer->getNumChildren() == 2 + unsigned(generics != nullptr));
|
|
if (generics) {
|
|
print(generics);
|
|
Printer << " ";
|
|
}
|
|
Printer << "from ";
|
|
print(pointer->getChild(pointer->getNumChildren() - 2));
|
|
Printer << " to ";
|
|
print(pointer->getChild(pointer->getNumChildren() - 1));
|
|
return;
|
|
}
|
|
case Node::Kind::GenericTypeMetadataPattern:
|
|
Printer << "generic type metadata pattern for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::Metaclass:
|
|
Printer << "metaclass for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::ProtocolDescriptor:
|
|
Printer << "protocol descriptor for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::FullTypeMetadata:
|
|
Printer << "full type metadata for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::TypeMetadata:
|
|
Printer << "type metadata for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::TypeMetadataAccessFunction:
|
|
Printer << "type metadata accessor for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::TypeMetadataLazyCache:
|
|
Printer << "lazy cache variable for type metadata for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::AssociatedTypeMetadataAccessor:
|
|
Printer << "associated type metadata accessor for ";
|
|
print(pointer->getChild(1));
|
|
Printer << " in ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::AssociatedTypeWitnessTableAccessor:
|
|
Printer << "associated type witness table accessor for ";
|
|
print(pointer->getChild(1));
|
|
Printer << " : ";
|
|
print(pointer->getChild(2));
|
|
Printer << " in ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::NominalTypeDescriptor:
|
|
Printer << "nominal type descriptor for ";
|
|
print(pointer->getChild(0));
|
|
return;
|
|
case Node::Kind::ValueWitness:
|
|
Printer << toString(ValueWitnessKind(pointer->getIndex()));
|
|
if (Options.ShortenValueWitness) Printer << " for ";
|
|
else Printer << " value witness for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::ValueWitnessTable:
|
|
Printer << "value witness table for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::WitnessTableOffset:
|
|
Printer << "witness table offset for ";
|
|
print(pointer->getFirstChild());
|
|
return;
|
|
case Node::Kind::BoundGenericClass:
|
|
case Node::Kind::BoundGenericStructure:
|
|
case Node::Kind::BoundGenericEnum:
|
|
printBoundGeneric(pointer);
|
|
return;
|
|
case Node::Kind::DynamicSelf:
|
|
Printer << "Self";
|
|
return;
|
|
case Node::Kind::CFunctionPointer: {
|
|
Printer << "@convention(c) ";
|
|
printFunctionType(pointer);
|
|
return;
|
|
}
|
|
case Node::Kind::ObjCBlock: {
|
|
Printer << "@convention(block) ";
|
|
printFunctionType(pointer);
|
|
return;
|
|
}
|
|
case Node::Kind::SILBoxType: {
|
|
Printer << "@box ";
|
|
NodePointer type = pointer->getChild(0);
|
|
print(type);
|
|
return;
|
|
}
|
|
case Node::Kind::Metatype: {
|
|
unsigned Idx = 0;
|
|
if (pointer->getNumChildren() == 2) {
|
|
NodePointer repr = pointer->getChild(Idx);
|
|
print(repr);
|
|
Printer << " ";
|
|
Idx++;
|
|
}
|
|
NodePointer type = pointer->getChild(Idx);
|
|
print(type);
|
|
if (isExistentialType(type)) {
|
|
Printer << ".Protocol";
|
|
} else {
|
|
Printer << ".Type";
|
|
}
|
|
return;
|
|
}
|
|
case Node::Kind::ExistentialMetatype: {
|
|
unsigned Idx = 0;
|
|
if (pointer->getNumChildren() == 2) {
|
|
NodePointer repr = pointer->getChild(Idx);
|
|
print(repr);
|
|
Printer << " ";
|
|
Idx++;
|
|
}
|
|
|
|
NodePointer type = pointer->getChild(Idx);
|
|
print(type);
|
|
Printer << ".Type";
|
|
return;
|
|
}
|
|
case Node::Kind::MetatypeRepresentation: {
|
|
Printer << pointer->getText();
|
|
return;
|
|
}
|
|
case Node::Kind::ArchetypeRef:
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::AssociatedTypeRef:
|
|
print(pointer->getChild(0));
|
|
Printer << '.' << pointer->getChild(1)->getText();
|
|
return;
|
|
case Node::Kind::SelfTypeRef:
|
|
print(pointer->getChild(0));
|
|
Printer << ".Self";
|
|
return;
|
|
case Node::Kind::ProtocolList: {
|
|
NodePointer type_list = pointer->getChild(0);
|
|
if (!type_list)
|
|
return;
|
|
if (type_list->getNumChildren() == 0)
|
|
Printer << "Any";
|
|
else
|
|
printChildren(type_list, " & ");
|
|
return;
|
|
}
|
|
case Node::Kind::Archetype: {
|
|
Printer << pointer->getText();
|
|
if (pointer->hasChildren()) {
|
|
Printer << " : ";
|
|
print(pointer->getChild(0));
|
|
}
|
|
return;
|
|
}
|
|
case Node::Kind::AssociatedType:
|
|
// Don't print for now.
|
|
return;
|
|
case Node::Kind::QualifiedArchetype: {
|
|
if (Options.ShortenArchetype) {
|
|
Printer << "(archetype)";
|
|
return;
|
|
}
|
|
if (pointer->getNumChildren() < 2)
|
|
return;
|
|
NodePointer number = pointer->getChild(0);
|
|
NodePointer decl_ctx = pointer->getChild(1);
|
|
Printer << "(archetype " << number->getIndex() << " of ";
|
|
print(decl_ctx);
|
|
Printer << ")";
|
|
return;
|
|
}
|
|
case Node::Kind::OwningAddressor:
|
|
printEntity(true, true, ".owningAddressor");
|
|
return;
|
|
case Node::Kind::OwningMutableAddressor:
|
|
printEntity(true, true, ".owningMutableAddressor");
|
|
return;
|
|
case Node::Kind::NativeOwningAddressor:
|
|
printEntity(true, true, ".nativeOwningAddressor");
|
|
return;
|
|
case Node::Kind::NativeOwningMutableAddressor:
|
|
printEntity(true, true, ".nativeOwningMutableAddressor");
|
|
return;
|
|
case Node::Kind::NativePinningAddressor:
|
|
printEntity(true, true, ".nativePinningAddressor");
|
|
return;
|
|
case Node::Kind::NativePinningMutableAddressor:
|
|
printEntity(true, true, ".nativePinningMutableAddressor");
|
|
return;
|
|
case Node::Kind::UnsafeAddressor:
|
|
printEntity(true, true, ".unsafeAddressor");
|
|
return;
|
|
case Node::Kind::UnsafeMutableAddressor:
|
|
printEntity(true, true, ".unsafeMutableAddressor");
|
|
return;
|
|
case Node::Kind::GlobalGetter:
|
|
printEntity(true, true, ".getter");
|
|
return;
|
|
case Node::Kind::Getter:
|
|
printEntity(true, true, ".getter");
|
|
return;
|
|
case Node::Kind::Setter:
|
|
printEntity(true, true, ".setter");
|
|
return;
|
|
case Node::Kind::MaterializeForSet:
|
|
printEntity(true, true, ".materializeForSet");
|
|
return;
|
|
case Node::Kind::WillSet:
|
|
printEntity(true, true, ".willset");
|
|
return;
|
|
case Node::Kind::DidSet:
|
|
printEntity(true, true, ".didset");
|
|
return;
|
|
case Node::Kind::Allocator:
|
|
printEntity(false, true,
|
|
isClassType(pointer->getChild(0))
|
|
? "__allocating_init" : "init");
|
|
return;
|
|
case Node::Kind::Constructor:
|
|
printEntity(false, true, "init");
|
|
return;
|
|
case Node::Kind::Destructor:
|
|
printEntity(false, false, "deinit");
|
|
return;
|
|
case Node::Kind::Deallocator:
|
|
printEntity(false, false,
|
|
isClassType(pointer->getChild(0))
|
|
? "__deallocating_deinit" : "deinit");
|
|
return;
|
|
case Node::Kind::IVarInitializer:
|
|
printEntity(false, false, "__ivar_initializer");
|
|
return;
|
|
case Node::Kind::IVarDestroyer:
|
|
printEntity(false, false, "__ivar_destroyer");
|
|
return;
|
|
case Node::Kind::ProtocolConformance: {
|
|
NodePointer child0 = pointer->getChild(0);
|
|
NodePointer child1 = pointer->getChild(1);
|
|
NodePointer child2 = pointer->getChild(2);
|
|
print(child0);
|
|
if (Options.DisplayProtocolConformances) {
|
|
Printer << " : ";
|
|
print(child1);
|
|
Printer << " in ";
|
|
print(child2);
|
|
}
|
|
return;
|
|
}
|
|
case Node::Kind::TypeList:
|
|
printChildren(pointer);
|
|
return;
|
|
case Node::Kind::ImplConvention:
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::ImplFunctionAttribute:
|
|
Printer << pointer->getText();
|
|
return;
|
|
case Node::Kind::ImplErrorResult:
|
|
Printer << "@error ";
|
|
SWIFT_FALLTHROUGH;
|
|
case Node::Kind::ImplParameter:
|
|
case Node::Kind::ImplResult:
|
|
printChildren(pointer, " ");
|
|
return;
|
|
case Node::Kind::ImplFunctionType:
|
|
printImplFunctionType(pointer);
|
|
return;
|
|
case Node::Kind::ErrorType:
|
|
Printer << "<ERROR TYPE>";
|
|
return;
|
|
|
|
case Node::Kind::DependentPseudogenericSignature:
|
|
case Node::Kind::DependentGenericSignature: {
|
|
Printer << '<';
|
|
|
|
unsigned depth = 0;
|
|
unsigned numChildren = pointer->getNumChildren();
|
|
for (;
|
|
depth < numChildren
|
|
&& pointer->getChild(depth)->getKind()
|
|
== Node::Kind::DependentGenericParamCount;
|
|
++depth) {
|
|
if (depth != 0)
|
|
Printer << "><";
|
|
|
|
unsigned count = pointer->getChild(depth)->getIndex();
|
|
for (unsigned index = 0; index < count; ++index) {
|
|
if (index != 0)
|
|
Printer << ", ";
|
|
// FIXME: Depth won't match when a generic signature applies to a
|
|
// method in generic type context.
|
|
Printer << archetypeName(index, depth);
|
|
}
|
|
}
|
|
|
|
if (depth != numChildren) {
|
|
if (!Options.DisplayWhereClauses) {
|
|
Printer << " where ...";
|
|
} else {
|
|
Printer << " where ";
|
|
for (unsigned i = depth; i < numChildren; ++i) {
|
|
if (i > depth)
|
|
Printer << ", ";
|
|
print(pointer->getChild(i));
|
|
}
|
|
}
|
|
}
|
|
Printer << '>';
|
|
return;
|
|
}
|
|
case Node::Kind::DependentGenericParamCount:
|
|
unreachable("should be printed as a child of a "
|
|
"DependentGenericSignature");
|
|
case Node::Kind::DependentGenericConformanceRequirement: {
|
|
NodePointer type = pointer->getChild(0);
|
|
NodePointer reqt = pointer->getChild(1);
|
|
print(type);
|
|
Printer << ": ";
|
|
print(reqt);
|
|
return;
|
|
}
|
|
case Node::Kind::DependentGenericSameTypeRequirement: {
|
|
NodePointer fst = pointer->getChild(0);
|
|
NodePointer snd = pointer->getChild(1);
|
|
|
|
print(fst);
|
|
Printer << " == ";
|
|
print(snd);
|
|
return;
|
|
}
|
|
case Node::Kind::DependentGenericParamType: {
|
|
Printer << pointer->getText();
|
|
return;
|
|
}
|
|
case Node::Kind::DependentGenericType: {
|
|
NodePointer sig = pointer->getChild(0);
|
|
NodePointer depTy = pointer->getChild(1);
|
|
print(sig);
|
|
Printer << ' ';
|
|
print(depTy);
|
|
return;
|
|
}
|
|
case Node::Kind::DependentMemberType: {
|
|
NodePointer base = pointer->getChild(0);
|
|
print(base);
|
|
Printer << '.';
|
|
NodePointer assocTy = pointer->getChild(1);
|
|
print(assocTy);
|
|
return;
|
|
}
|
|
case Node::Kind::DependentAssociatedTypeRef: {
|
|
Printer << pointer->getText();
|
|
return;
|
|
}
|
|
case Node::Kind::ThrowsAnnotation: {
|
|
Printer<< " throws ";
|
|
return;
|
|
}
|
|
}
|
|
unreachable("bad node kind!");
|
|
}
|
|
|
|
std::string Demangle::nodeToString(NodePointer root,
|
|
const DemangleOptions &options) {
|
|
if (!root)
|
|
return "";
|
|
|
|
return NodePrinter(options).printRoot(root);
|
|
}
|
|
|
|
std::string Demangle::demangleSymbolAsString(const char *MangledName,
|
|
size_t MangledNameLength,
|
|
const DemangleOptions &Options) {
|
|
auto mangled = StringRef(MangledName, MangledNameLength);
|
|
auto root = demangleSymbolAsNode(MangledName, MangledNameLength, Options);
|
|
if (!root) return mangled.str();
|
|
|
|
std::string demangling = nodeToString(std::move(root), Options);
|
|
if (demangling.empty())
|
|
return mangled.str();
|
|
return demangling;
|
|
}
|
|
|
|
std::string Demangle::demangleTypeAsString(const char *MangledName,
|
|
size_t MangledNameLength,
|
|
const DemangleOptions &Options) {
|
|
auto mangled = StringRef(MangledName, MangledNameLength);
|
|
auto root = demangleTypeAsNode(MangledName, MangledNameLength, Options);
|
|
if (!root) return mangled.str();
|
|
|
|
std::string demangling = nodeToString(std::move(root), Options);
|
|
if (demangling.empty())
|
|
return mangled.str();
|
|
return demangling;
|
|
}
|
|
|
|
|
|
|