Skip to content

Commit c95ffe3

Browse files
add range tracking when demangling a name
1 parent acb53d2 commit c95ffe3

File tree

3 files changed

+1043
-865
lines changed

3 files changed

+1043
-865
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 225 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
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"
26+
#include "swift/Strings.h"
2527
#include "llvm/ADT/StringRef.h"
2628
#include "llvm/Support/Compiler.h"
2729

@@ -99,6 +101,7 @@ struct DemangleOptions {
99101

100102
class Node;
101103
using NodePointer = Node *;
104+
class NodePrinter;
102105

103106
enum class FunctionSigSpecializationParamKind : unsigned {
104107
// Option Flags use bits 0-5. This give us 6 bits implying 64 entries to
@@ -234,6 +237,18 @@ class Node {
234237
public:
235238
Kind getKind() const { return NodeKind; }
236239

240+
bool shouldTrackNameRange() const {
241+
switch (getKind()) {
242+
case Kind::Function:
243+
case Kind::Constructor:
244+
case Kind::Allocator:
245+
case Kind::ExplicitClosure:
246+
return true;
247+
default:
248+
return false;
249+
}
250+
}
251+
237252
bool isSimilarTo(const Node *other) const {
238253
if (NodeKind != other->NodeKind
239254
|| NodePayloadKind != other->NodePayloadKind)
@@ -417,6 +432,10 @@ bool isOldFunctionTypeMangling(llvm::StringRef mangledName);
417432

418433
class Demangler;
419434

435+
class DemanglerPrinter;
436+
437+
class TrackingDemanglerPrinter;
438+
420439
/// The demangler context.
421440
///
422441
/// It owns the allocated nodes which are created during demangling.
@@ -465,16 +484,26 @@ class Context {
465484
/// The lifetime of the returned node tree ends with the lifetime of the
466485
/// context or with a call of clear().
467486
NodePointer demangleTypeAsNode(llvm::StringRef MangledName);
468-
487+
469488
/// Demangle the given symbol and return the readable name.
470489
///
471490
/// \param MangledName The mangled symbol string, which start a mangling
472491
/// prefix: _T, _T0, $S, _$S.
473492
///
474493
/// \returns The demangled string.
475-
std::string demangleSymbolAsString(
476-
llvm::StringRef MangledName,
477-
const DemangleOptions &Options = DemangleOptions());
494+
std::string
495+
demangleSymbolAsString(llvm::StringRef MangledName,
496+
const DemangleOptions &Options = DemangleOptions());
497+
498+
/// Demangle the given symbol.
499+
///
500+
/// \param MangledName The mangled symbol string, which start a mangling
501+
/// prefix: _T, _T0, $S, _$S.
502+
/// \param printer The NodePrinter that will be used to demangle the symbol.
503+
///
504+
/// \returns The demangled string.
505+
void demangleSymbolAsString(llvm::StringRef MangledName,
506+
NodePrinter *printer);
478507

479508
/// Demangle the given type and return the readable name.
480509
///
@@ -533,6 +562,18 @@ std::string
533562
demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
534563
const DemangleOptions &options = DemangleOptions());
535564

565+
/// Standalone utility function to demangle the given symbol as string.
566+
///
567+
/// If performance is an issue when demangling multiple symbols,
568+
/// Context::demangleSymbolAsString should be used instead.
569+
/// \param mangledName The mangled name string pointer.
570+
/// \param mangledNameLength The length of the mangledName string.
571+
/// \param printer The NodePrinter that will be used to demangle the symbol.
572+
///
573+
/// \returns The demangled string.
574+
void demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
575+
NodePrinter *printer);
576+
536577
/// Standalone utility function to demangle the given symbol as string.
537578
///
538579
/// If performance is an issue when demangling multiple symbols,
@@ -545,7 +586,7 @@ demangleSymbolAsString(const std::string &mangledName,
545586
return demangleSymbolAsString(mangledName.data(), mangledName.size(),
546587
options);
547588
}
548-
589+
549590
/// Standalone utility function to demangle the given symbol as string.
550591
///
551592
/// If performance is an issue when demangling multiple symbols,
@@ -555,8 +596,20 @@ demangleSymbolAsString(const std::string &mangledName,
555596
inline std::string
556597
demangleSymbolAsString(llvm::StringRef MangledName,
557598
const DemangleOptions &Options = DemangleOptions()) {
558-
return demangleSymbolAsString(MangledName.data(),
559-
MangledName.size(), Options);
599+
return demangleSymbolAsString(MangledName.data(), MangledName.size(),
600+
Options);
601+
}
602+
603+
/// Standalone utility function to demangle the given symbol as string.
604+
///
605+
/// If performance is an issue when demangling multiple symbols,
606+
/// Context::demangleSymbolAsString should be used instead.
607+
/// \param MangledName The mangled name string.
608+
///
609+
/// \returns The demangled string.
610+
inline void demangleSymbolAsString(llvm::StringRef MangledName,
611+
NodePrinter *printer) {
612+
demangleSymbolAsString(MangledName.data(), MangledName.size(), printer);
560613
}
561614

562615
/// Standalone utility function to demangle the given type as string.
@@ -732,6 +785,15 @@ ManglingErrorOr<const char *> mangleNodeAsObjcCString(NodePointer node,
732785
std::string nodeToString(NodePointer Root,
733786
const DemangleOptions &Options = DemangleOptions());
734787

788+
/// Transform the node structure to a string.
789+
///
790+
/// \endcode
791+
///
792+
/// \param Root A pointer to a parse tree generated by the demangler.
793+
/// \param Printer A NodePrinter used to pretty print the demangled Node.
794+
///
795+
void nodeToString(NodePointer Root, NodePrinter *Printer);
796+
735797
/// Transforms a mangled key path accessor thunk helper
736798
/// into the identfier/subscript that would be used to invoke it in swift code.
737799
std::string keyPathSourceString(const char *MangledName,
@@ -777,11 +839,14 @@ class DemanglerPrinter {
777839

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

842+
size_t getStreamLength() { return Stream.length(); }
843+
780844
/// Shrinks the buffer.
781845
void resetSize(size_t toPos) {
782846
assert(toPos <= Stream.size());
783847
Stream.resize(toPos);
784848
}
849+
785850
private:
786851
std::string Stream;
787852
};
@@ -818,6 +883,159 @@ std::string mangledNameForTypeMetadataAccessor(
818883
llvm::StringRef moduleName, llvm::StringRef typeName, Node::Kind typeKind,
819884
Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default);
820885

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

0 commit comments

Comments
 (0)