Skip to content

Commit af00dd9

Browse files
add new methods to the NodePrinter to enable range tracking possibilities when demangling a name
1 parent 2371e1f commit af00dd9

File tree

3 files changed

+274
-8
lines changed

3 files changed

+274
-8
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 203 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef SWIFT_DEMANGLING_DEMANGLE_H
2020
#define SWIFT_DEMANGLING_DEMANGLE_H
2121

22+
#include "swift/Demangling/Demangle.h"
2223
#include "swift/Demangling/Errors.h"
2324
#include "swift/Demangling/ManglingFlavor.h"
2425
#include "swift/Demangling/NamespaceMacros.h"
@@ -99,6 +100,7 @@ struct DemangleOptions {
99100

100101
class Node;
101102
using NodePointer = Node *;
103+
class NodePrinter;
102104

103105
enum class FunctionSigSpecializationParamKind : unsigned {
104106
// Option Flags use bits 0-5. This give us 6 bits implying 64 entries to
@@ -465,16 +467,26 @@ class Context {
465467
/// The lifetime of the returned node tree ends with the lifetime of the
466468
/// context or with a call of clear().
467469
NodePointer demangleTypeAsNode(llvm::StringRef MangledName);
468-
470+
469471
/// Demangle the given symbol and return the readable name.
470472
///
471473
/// \param MangledName The mangled symbol string, which start a mangling
472474
/// prefix: _T, _T0, $S, _$S.
473475
///
474476
/// \returns The demangled string.
475-
std::string demangleSymbolAsString(
476-
llvm::StringRef MangledName,
477-
const DemangleOptions &Options = DemangleOptions());
477+
std::string
478+
demangleSymbolAsString(llvm::StringRef MangledName,
479+
const DemangleOptions &Options = DemangleOptions());
480+
481+
/// Demangle the given symbol and store the result in the `printer`.
482+
///
483+
/// \param MangledName The mangled symbol string, which start a mangling
484+
/// prefix: _T, _T0, $S, _$S.
485+
/// \param printer The NodePrinter that will be used to demangle the symbol.
486+
///
487+
/// \returns The demangled string.
488+
void demangleSymbolAsString(llvm::StringRef MangledName,
489+
NodePrinter *printer);
478490

479491
/// Demangle the given type and return the readable name.
480492
///
@@ -533,6 +545,17 @@ std::string
533545
demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
534546
const DemangleOptions &options = DemangleOptions());
535547

548+
/// Standalone utility function to demangle the given symbol as string. The
549+
/// demangled string is stored in the `printer`.
550+
///
551+
/// If performance is an issue when demangling multiple symbols,
552+
/// `Context::demangleSymbolAsString` should be used instead.
553+
/// \param mangledName The mangled name string pointer.
554+
/// \param mangledNameLength The length of the mangledName string.
555+
/// \param printer The NodePrinter that will be used to demangle the symbol.
556+
void demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
557+
NodePrinter *printer);
558+
536559
/// Standalone utility function to demangle the given symbol as string.
537560
///
538561
/// If performance is an issue when demangling multiple symbols,
@@ -545,7 +568,7 @@ demangleSymbolAsString(const std::string &mangledName,
545568
return demangleSymbolAsString(mangledName.data(), mangledName.size(),
546569
options);
547570
}
548-
571+
549572
/// Standalone utility function to demangle the given symbol as string.
550573
///
551574
/// If performance is an issue when demangling multiple symbols,
@@ -559,6 +582,17 @@ demangleSymbolAsString(llvm::StringRef MangledName,
559582
MangledName.size(), Options);
560583
}
561584

585+
/// Standalone utility function to demangle the given symbol as string. The
586+
/// result is stored in the `printer`.
587+
///
588+
/// If performance is an issue when demangling multiple symbols,
589+
/// Context::demangleSymbolAsString should be used instead.
590+
/// \param MangledName The mangled name string.
591+
inline void demangleSymbolAsString(llvm::StringRef MangledName,
592+
NodePrinter *printer) {
593+
demangleSymbolAsString(MangledName.data(), MangledName.size(), printer);
594+
}
595+
562596
/// Standalone utility function to demangle the given type as string.
563597
///
564598
/// If performance is an issue when demangling multiple symbols,
@@ -725,13 +759,19 @@ ManglingErrorOr<const char *> mangleNodeAsObjcCString(NodePointer node,
725759
/// \endcode
726760
///
727761
/// \param Root A pointer to a parse tree generated by the demangler.
728-
/// \param Options An object encapsulating options to use to perform this demangling.
762+
/// \param Options An object encapsulating options to use to perform this
763+
/// demangling.
729764
///
730765
/// \returns A string representing the demangled name.
731-
///
732766
std::string nodeToString(NodePointer Root,
733767
const DemangleOptions &Options = DemangleOptions());
734768

769+
/// Transform the node structure to a string, which is stored in the `Printer`.
770+
///
771+
/// \param Root A pointer to a parse tree generated by the demangler.
772+
/// \param Printer A NodePrinter used to pretty print the demangled Node.
773+
void nodeToString(NodePointer Root, NodePrinter *Printer);
774+
735775
/// Transforms a mangled key path accessor thunk helper
736776
/// into the identfier/subscript that would be used to invoke it in swift code.
737777
std::string keyPathSourceString(const char *MangledName,
@@ -777,11 +817,14 @@ class DemanglerPrinter {
777817

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

820+
size_t getStreamLength() { return Stream.length(); }
821+
780822
/// Shrinks the buffer.
781823
void resetSize(size_t toPos) {
782824
assert(toPos <= Stream.size());
783825
Stream.resize(toPos);
784826
}
827+
785828
private:
786829
std::string Stream;
787830
};
@@ -818,6 +861,159 @@ std::string mangledNameForTypeMetadataAccessor(
818861
llvm::StringRef moduleName, llvm::StringRef typeName, Node::Kind typeKind,
819862
Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default);
820863

864+
/// Base class for printing a Swift demangled node tree.
865+
///
866+
/// NodePrinter is used to convert demangled Swift symbol nodes into
867+
/// human-readable string representations. It handles formatting, indentation,
868+
/// and Swift-specific syntax.
869+
///
870+
/// The virtual methods in this class are meant to be overriden to allow
871+
/// external consumers (e.g lldb) to track the ranges of components of the
872+
/// demangled name.
873+
class NodePrinter {
874+
protected:
875+
DemanglerPrinter Printer;
876+
DemangleOptions Options;
877+
bool SpecializationPrefixPrinted = false;
878+
bool isValid = true;
879+
880+
public:
881+
NodePrinter(DemangleOptions options) : Options(options) {}
882+
883+
virtual ~NodePrinter() = default;
884+
885+
void printRoot(NodePointer root) {
886+
isValid = true;
887+
print(root, 0);
888+
}
889+
890+
std::string takeString() {
891+
if (isValid)
892+
return std::move(Printer).str();
893+
return "";
894+
}
895+
896+
protected:
897+
static const unsigned MaxDepth = 768;
898+
899+
size_t getStreamLength() { return Printer.getStreamLength(); }
900+
901+
/// Called when the node tree in valid.
902+
///
903+
/// The demangler already catches most error cases and mostly produces valid
904+
/// node trees. But some cases are difficult to catch in the demangler and
905+
/// instead the NodePrinter bails.
906+
void setInvalid() { isValid = false; }
907+
908+
void printChildren(Node::iterator begin, Node::iterator end, unsigned depth,
909+
const char *sep = nullptr);
910+
911+
void printChildren(NodePointer Node, unsigned depth,
912+
const char *sep = nullptr);
913+
914+
NodePointer getFirstChildOfKind(NodePointer Node, Node::Kind kind);
915+
916+
void printBoundGenericNoSugar(NodePointer Node, unsigned depth);
917+
918+
void printOptionalIndex(NodePointer node);
919+
920+
static bool isSwiftModule(NodePointer node) {
921+
return (node->getKind() == Node::Kind::Module &&
922+
node->getText() == STDLIB_NAME);
923+
}
924+
925+
static bool isIdentifier(NodePointer node, StringRef desired) {
926+
return (node->getKind() == Node::Kind::Identifier &&
927+
node->getText() == desired);
928+
}
929+
930+
bool printContext(NodePointer Context);
931+
932+
enum class SugarType {
933+
None,
934+
Optional,
935+
ImplicitlyUnwrappedOptional,
936+
Array,
937+
Dictionary
938+
};
939+
940+
enum class TypePrinting { NoType, WithColon, FunctionStyle };
941+
942+
/// Determine whether this is a "simple" type, from the type-simple
943+
/// production.
944+
bool isSimpleType(NodePointer Node);
945+
946+
void printWithParens(NodePointer type, unsigned depth);
947+
948+
SugarType findSugar(NodePointer Node);
949+
950+
void printBoundGeneric(NodePointer Node, unsigned depth);
951+
952+
NodePointer getChildIf(NodePointer Node, Node::Kind Kind);
953+
954+
virtual void printFunctionParameters(NodePointer LabelList,
955+
NodePointer ParameterType,
956+
unsigned depth, bool showTypes);
957+
958+
void printFunctionType(NodePointer LabelList, NodePointer node,
959+
unsigned depth);
960+
961+
void printImplFunctionType(NodePointer fn, unsigned depth);
962+
963+
void printGenericSignature(NodePointer Node, unsigned depth);
964+
965+
void printFunctionSigSpecializationParams(NodePointer Node, unsigned depth);
966+
967+
void printSpecializationPrefix(NodePointer node, StringRef Description,
968+
unsigned depth,
969+
StringRef ParamPrefix = StringRef());
970+
971+
/// The main big print function.
972+
NodePointer print(NodePointer Node, unsigned depth,
973+
bool asPrefixContext = false);
974+
975+
NodePointer printAbstractStorage(NodePointer Node, unsigned depth,
976+
bool asPrefixContent, StringRef ExtraName);
977+
978+
/// Utility function to print entities.
979+
///
980+
/// \param Entity The entity node to print
981+
/// \param depth The depth in the print() call tree.
982+
/// \param asPrefixContext Should the entity printed as a context which as a
983+
/// prefix to another entity, e.g. the Abc in Abc.def()
984+
/// \param TypePr How should the type of the entity be printed, if at all.
985+
/// E.g. with a colon for properties or as a function type.
986+
/// \param hasName Does the entity has a name, e.g. a function in contrast to
987+
/// an initializer.
988+
/// \param ExtraName An extra name added to the entity name (if any).
989+
/// \param ExtraIndex An extra index added to the entity name (if any),
990+
/// e.g. closure #1
991+
/// \param OverwriteName If non-empty, print this name instead of the one
992+
/// provided by the node. Gets printed even if hasName is false.
993+
/// \return If a non-null node is returned it's a context which must be
994+
/// printed in postfix-form after the entity: "<entity> in <context>".
995+
NodePointer printEntity(NodePointer Entity, unsigned depth,
996+
bool asPrefixContext, TypePrinting TypePr,
997+
bool hasName, StringRef ExtraName = "",
998+
int ExtraIndex = -1, StringRef OverwriteName = "");
999+
1000+
virtual void printFunctionName(bool hasName, llvm::StringRef &OverwriteName,
1001+
llvm::StringRef &ExtraName, bool MultiWordName,
1002+
int &ExtraIndex,
1003+
swift::Demangle::NodePointer Entity,
1004+
unsigned int depth);
1005+
1006+
/// Print the type of an entity.
1007+
///
1008+
/// \param Entity The entity.
1009+
/// \param type The type of the entity.
1010+
/// \param genericFunctionTypeList If not null, the generic argument types
1011+
/// which is printed in the generic signature.
1012+
/// \param depth The depth in the print() call tree.
1013+
void printEntityType(NodePointer Entity, NodePointer type,
1014+
NodePointer genericFunctionTypeList, unsigned depth);
1015+
};
1016+
8211017
SWIFT_END_INLINE_NAMESPACE
8221018
} // end namespace Demangle
8231019
} // end namespace swift

lib/Demangling/Context.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ std::string Context::demangleSymbolAsString(llvm::StringRef MangledName,
6666
return demangling;
6767
}
6868

69+
void Context::demangleSymbolAsString(llvm::StringRef MangledName,
70+
NodePrinter *printer) {
71+
NodePointer root = demangleSymbolAsNode(MangledName);
72+
nodeToString(root, printer);
73+
}
74+
6975
std::string Context::demangleTypeAsString(llvm::StringRef MangledName,
7076
const DemangleOptions &Options) {
7177
NodePointer root = demangleTypeAsNode(MangledName);
@@ -275,6 +281,13 @@ std::string demangleSymbolAsString(const char *MangledName,
275281
Options);
276282
}
277283

284+
void demangleSymbolAsString(const char *MangledName, size_t MangledNameLength,
285+
NodePrinter *printer) {
286+
Context Ctx;
287+
return Ctx.demangleSymbolAsString(StringRef(MangledName, MangledNameLength),
288+
printer);
289+
}
290+
278291
std::string demangleTypeAsString(const char *MangledName,
279292
size_t MangledNameLength,
280293
const DemangleOptions &Options) {

lib/Demangling/NodePrinter.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3666,6 +3666,43 @@ NodePointer NodePrinter::printEntity(NodePointer Entity, unsigned depth,
36663666
return PostfixContext;
36673667
}
36683668

3669+
void NodePrinter::printFunctionName(bool hasName,
3670+
llvm::StringRef &OverwriteName,
3671+
llvm::StringRef &ExtraName,
3672+
bool MultiWordName, int &ExtraIndex,
3673+
swift::Demangle::NodePointer Entity,
3674+
unsigned int depth) {
3675+
if (hasName || !OverwriteName.empty()) {
3676+
if (!ExtraName.empty() && MultiWordName) {
3677+
Printer << ExtraName;
3678+
if (ExtraIndex >= 0)
3679+
Printer << ExtraIndex;
3680+
3681+
Printer << " of ";
3682+
ExtraName = "";
3683+
ExtraIndex = -1;
3684+
}
3685+
size_t CurrentPos = Printer.getStringRef().size();
3686+
if (!OverwriteName.empty()) {
3687+
Printer << OverwriteName;
3688+
} else {
3689+
auto Name = Entity->getChild(1);
3690+
if (Name->getKind() != Node::Kind::PrivateDeclName)
3691+
print(Name, depth + 1);
3692+
3693+
if (auto PrivateName = getChildIf(Entity, Node::Kind::PrivateDeclName))
3694+
print(PrivateName, depth + 1);
3695+
}
3696+
if (Printer.getStringRef().size() != CurrentPos && !ExtraName.empty())
3697+
Printer << '.';
3698+
}
3699+
if (!ExtraName.empty()) {
3700+
Printer << ExtraName;
3701+
if (ExtraIndex >= 0)
3702+
Printer << ExtraIndex;
3703+
}
3704+
}
3705+
36693706
void NodePrinter::printEntityType(NodePointer Entity, NodePointer type,
36703707
NodePointer genericFunctionTypeList,
36713708
unsigned depth) {
@@ -3844,12 +3881,32 @@ std::string Demangle::keyPathSourceString(const char *MangledName,
38443881
return invalid;
38453882
}
38463883

3884+
/// Converts a demangled node to a string.
3885+
///
3886+
/// \param root The root of the AST to demangle.
3887+
/// @param options The `DemangleOptions` which will be used to create the
3888+
/// NodePrinter.
3889+
///
3890+
/// \return The demangled node as a string.
38473891
std::string Demangle::nodeToString(NodePointer root,
38483892
const DemangleOptions &options) {
38493893
if (!root)
38503894
return "";
38513895

3852-
return NodePrinter(options).printRoot(root);
3896+
NodePrinter printer = NodePrinter(options);
3897+
nodeToString(root, &printer);
3898+
return printer.takeString();
3899+
}
3900+
3901+
/// Converts a demangled node to a string, which is stored in the `printer`.
3902+
///
3903+
/// \param root The root of the AST to demangle.
3904+
/// @param printer The `NodePrinter` which will be used to print the AST to a
3905+
/// string.
3906+
void Demangle::nodeToString(NodePointer root, NodePrinter *printer) {
3907+
if (!root)
3908+
return;
3909+
printer->printRoot(root);
38533910
}
38543911

38553912
#endif

0 commit comments

Comments
 (0)