Skip to content

[Demangling] Add name and parameters range tracking when demangling a name #81511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 100 additions & 12 deletions include/swift/Demangling/Demangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef SWIFT_DEMANGLING_DEMANGLE_H
#define SWIFT_DEMANGLING_DEMANGLE_H

#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/Errors.h"
#include "swift/Demangling/ManglingFlavor.h"
#include "swift/Demangling/NamespaceMacros.h"
Expand Down Expand Up @@ -234,6 +235,18 @@ class Node {
public:
Kind getKind() const { return NodeKind; }

bool shouldTrackNameRange() const {
switch (getKind()) {
case Kind::Function:
case Kind::Constructor:
case Kind::Allocator:
case Kind::ExplicitClosure:
return true;
default:
return false;
}
}

bool isSimilarTo(const Node *other) const {
if (NodeKind != other->NodeKind
|| NodePayloadKind != other->NodePayloadKind)
Expand Down Expand Up @@ -417,6 +430,10 @@ bool isOldFunctionTypeMangling(llvm::StringRef mangledName);

class Demangler;

class DemanglerPrinter;

class TrackingDemanglerPrinter;

/// The demangler context.
///
/// It owns the allocated nodes which are created during demangling.
Expand Down Expand Up @@ -472,9 +489,10 @@ class Context {
/// prefix: _T, _T0, $S, _$S.
///
/// \returns The demangled string.
std::string demangleSymbolAsString(
llvm::StringRef MangledName,
const DemangleOptions &Options = DemangleOptions());
std::string
demangleSymbolAsString(llvm::StringRef MangledName,
const DemangleOptions &Options = DemangleOptions(),
DemanglerPrinter *printer = nullptr);

/// Demangle the given type and return the readable name.
///
Expand Down Expand Up @@ -531,7 +549,8 @@ class Context {
/// \returns The demangled string.
std::string
demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
const DemangleOptions &options = DemangleOptions());
const DemangleOptions &options = DemangleOptions(),
DemanglerPrinter *printer = nullptr);

/// Standalone utility function to demangle the given symbol as string.
///
Expand All @@ -541,11 +560,12 @@ demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
/// \returns The demangled string.
inline std::string
demangleSymbolAsString(const std::string &mangledName,
const DemangleOptions &options = DemangleOptions()) {
return demangleSymbolAsString(mangledName.data(), mangledName.size(),
options);
const DemangleOptions &options = DemangleOptions(),
DemanglerPrinter *printer = nullptr) {
return demangleSymbolAsString(mangledName.data(), mangledName.size(), options,
printer);
}

/// Standalone utility function to demangle the given symbol as string.
///
/// If performance is an issue when demangling multiple symbols,
Expand All @@ -554,9 +574,10 @@ demangleSymbolAsString(const std::string &mangledName,
/// \returns The demangled string.
inline std::string
demangleSymbolAsString(llvm::StringRef MangledName,
const DemangleOptions &Options = DemangleOptions()) {
return demangleSymbolAsString(MangledName.data(),
MangledName.size(), Options);
const DemangleOptions &Options = DemangleOptions(),
DemanglerPrinter *printer = nullptr) {
return demangleSymbolAsString(MangledName.data(), MangledName.size(), Options,
printer);
}

/// Standalone utility function to demangle the given type as string.
Expand Down Expand Up @@ -730,7 +751,8 @@ ManglingErrorOr<const char *> mangleNodeAsObjcCString(NodePointer node,
/// \returns A string representing the demangled name.
///
std::string nodeToString(NodePointer Root,
const DemangleOptions &Options = DemangleOptions());
const DemangleOptions &Options = DemangleOptions(),
DemanglerPrinter *printer = nullptr);

/// Transforms a mangled key path accessor thunk helper
/// into the identfier/subscript that would be used to invoke it in swift code.
Expand Down Expand Up @@ -777,15 +799,81 @@ class DemanglerPrinter {

llvm::StringRef getStringRef() const { return Stream; }

size_t getStreamLength() { return Stream.length(); }

/// Shrinks the buffer.
void resetSize(size_t toPos) {
assert(toPos <= Stream.size());
Stream.resize(toPos);
}

/// Mark the start of the name of a function.
virtual void startName() {}

/// Mark the end of the name of a function.
virtual void endName() {}

/// Mark the start of the parameters of a function.
///
/// \param depth Current depth of the parameters that are being printed.
virtual void startParameters(unsigned depth) {}

/// Mark the end of the parameters of a function.
///
/// \param depth Current depth of the parameters that are being printed.
virtual void endParameters(unsigned depth) {}

virtual ~DemanglerPrinter() {}

private:
std::string Stream;
};

/// A class for printing to a std::string while tracking ranges.
class TrackingDemanglerPrinter : public swift::Demangle::DemanglerPrinter {
public:
size_t getNameStart() { return baseNameRange.first; }
size_t getNameEnd() { return baseNameRange.second; }
size_t getParametersStart() { return parametersRange.first; }
size_t getParametersEnd() { return parametersRange.second; }
bool hasBaseName() { return baseNameRange.first < baseNameRange.second; }
bool hasParameters() {
return parametersRange.first < parametersRange.second;
}

void startName() override {
if (!hasBaseName())
baseNameRange.first = getStreamLength();
}

void endName() override {
if (!hasBaseName())
baseNameRange.second = getStreamLength();
}

void startParameters(unsigned depth) override {
if (parametersDepth || !hasBaseName() || hasParameters()) {
return;
}
parametersRange.first = getStreamLength();
parametersDepth = depth;
}

void endParameters(unsigned depth) override {
if (!parametersDepth || *parametersDepth != depth || hasParameters()) {
return;
}
parametersRange.second = getStreamLength();
}

private:
std::pair<size_t, size_t> baseNameRange;

std::pair<size_t, size_t> parametersRange;

std::optional<unsigned> parametersDepth;
};

/// Returns a the node kind \p k as string.
const char *getNodeKindString(swift::Demangle::Node::Kind k);

Expand Down
10 changes: 6 additions & 4 deletions lib/Demangling/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ NodePointer Context::demangleTypeAsNode(llvm::StringRef MangledName) {
#if SWIFT_STDLIB_HAS_TYPE_PRINTING

std::string Context::demangleSymbolAsString(llvm::StringRef MangledName,
const DemangleOptions &Options) {
const DemangleOptions &Options,
DemanglerPrinter *printer) {
NodePointer root = demangleSymbolAsNode(MangledName);
if (!root) return MangledName.str();

std::string demangling = nodeToString(root, Options);
std::string demangling = nodeToString(root, Options, printer);
if (demangling.empty())
return MangledName.str();
return demangling;
Expand Down Expand Up @@ -269,10 +270,11 @@ std::string Context::getModuleName(llvm::StringRef mangledName) {

std::string demangleSymbolAsString(const char *MangledName,
size_t MangledNameLength,
const DemangleOptions &Options) {
const DemangleOptions &Options,
DemanglerPrinter *printer) {
Context Ctx;
return Ctx.demangleSymbolAsString(StringRef(MangledName, MangledNameLength),
Options);
Options, printer);
}

std::string demangleTypeAsString(const char *MangledName,
Expand Down
25 changes: 20 additions & 5 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,19 @@ static StringRef toString(ValueWitnessKind k) {

class NodePrinter {
private:
DemanglerPrinter Printer;
std::unique_ptr<DemanglerPrinter> PrinterStorage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having two separate members feels a bit weird. Could we just make Printer a std::unique_ptr<DemanglerPrinter>? And take a std::unique_ptr<DemanglerPrinter> in the constructor? And if it's nullptr we just make_unique

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It didn't feel right yes. I initially wanted to pass an std::optional, but couldn't because it wouldn't allow me to pass in a child class. I will give it another go with your suggestion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I managed to get it to a good state. I decided to use a template instead of changing all the Printer << ... calls to (*Printer) << .... I found out about decltype on this SO thread: https://stackoverflow.com/questions/18815221/what-is-decltype-and-how-is-it-used

DemanglerPrinter &Printer;
DemangleOptions Options;
bool SpecializationPrefixPrinted = false;
bool isValid = true;

public:
NodePrinter(DemangleOptions options) : Options(options) {}
NodePrinter(DemangleOptions options, DemanglerPrinter *printer = nullptr)
: PrinterStorage(),
Printer(printer
? *printer
: *(PrinterStorage = std::make_unique<DemanglerPrinter>())),
Options(options) {}

std::string printRoot(NodePointer root) {
isValid = true;
Expand Down Expand Up @@ -802,6 +808,7 @@ class NodePrinter {
return;
}

Printer.startParameters(depth);
NodePointer Parameters = ParameterType->getFirstChild();
assert(Parameters->getKind() == Node::Kind::Type);
Parameters = Parameters->getFirstChild();
Expand All @@ -814,6 +821,7 @@ class NodePrinter {
} else {
Printer << "(_:)";
}
Printer.endParameters(depth);
return;
}

Expand Down Expand Up @@ -853,6 +861,7 @@ class NodePrinter {
},
[&]() { Printer << (showTypes ? ", " : ""); });
Printer << ')';
Printer.endParameters(depth);
}

void printFunctionType(NodePointer LabelList, NodePointer node,
Expand Down Expand Up @@ -3576,7 +3585,9 @@ NodePointer NodePrinter::printEntity(NodePointer Entity, unsigned depth,
Printer << '.';
}
}

if (Entity->shouldTrackNameRange()) {
Printer.startName();
}
if (hasName || !OverwriteName.empty()) {
if (!ExtraName.empty() && MultiWordName) {
Printer << ExtraName;
Expand Down Expand Up @@ -3606,6 +3617,9 @@ NodePointer NodePrinter::printEntity(NodePointer Entity, unsigned depth,
if (ExtraIndex >= 0)
Printer << ExtraIndex;
}
if (Entity->shouldTrackNameRange()) {
Printer.endName();
}
if (TypePr != TypePrinting::NoType) {
NodePointer type = getChildIf(Entity, Node::Kind::Type);
assert(type && "malformed entity");
Expand Down Expand Up @@ -3836,11 +3850,12 @@ std::string Demangle::keyPathSourceString(const char *MangledName,
}

std::string Demangle::nodeToString(NodePointer root,
const DemangleOptions &options) {
const DemangleOptions &options,
DemanglerPrinter *printer) {
if (!root)
return "";

return NodePrinter(options).printRoot(root);
return NodePrinter(options, printer).printRoot(root);
}

#endif
Loading