Skip to content

Commit e180d8b

Browse files
Merge pull request #82479 from charles-zablit/charles-zablit/add-new-demangling-methods-to-6.2
🍒 [demangling] add new methods to the NodePrinter to enable range tracking possibilities when demangling a name
2 parents ea734e2 + e1a1609 commit e180d8b

File tree

3 files changed

+1018
-867
lines changed

3 files changed

+1018
-867
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 192 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
@@ -465,16 +468,26 @@ class Context {
465468
/// The lifetime of the returned node tree ends with the lifetime of the
466469
/// context or with a call of clear().
467470
NodePointer demangleTypeAsNode(llvm::StringRef MangledName);
468-
471+
469472
/// Demangle the given symbol and return the readable name.
470473
///
471474
/// \param MangledName The mangled symbol string, which start a mangling
472475
/// prefix: _T, _T0, $S, _$S.
473476
///
474477
/// \returns The demangled string.
475-
std::string demangleSymbolAsString(
476-
llvm::StringRef MangledName,
477-
const DemangleOptions &Options = DemangleOptions());
478+
std::string
479+
demangleSymbolAsString(llvm::StringRef MangledName,
480+
const DemangleOptions &Options = DemangleOptions());
481+
482+
/// Demangle the given symbol and store the result in the `printer`.
483+
///
484+
/// \param MangledName The mangled symbol string, which start a mangling
485+
/// prefix: _T, _T0, $S, _$S.
486+
/// \param Printer The NodePrinter that will be used to demangle the symbol.
487+
///
488+
/// \returns The demangled string.
489+
void demangleSymbolAsString(llvm::StringRef MangledName,
490+
NodePrinter &Printer);
478491

479492
/// Demangle the given type and return the readable name.
480493
///
@@ -533,6 +546,16 @@ std::string
533546
demangleSymbolAsString(const char *mangledName, size_t mangledNameLength,
534547
const DemangleOptions &options = DemangleOptions());
535548

549+
/// Standalone utility function to demangle the given symbol as string. The
550+
/// demangled string is stored in the `printer`.
551+
///
552+
/// If performance is an issue when demangling multiple symbols,
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 llvm::StringRef mangledName,
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,
@@ -725,13 +748,19 @@ ManglingErrorOr<const char *> mangleNodeAsObjcCString(NodePointer node,
725748
/// \endcode
726749
///
727750
/// \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.
751+
/// \param Options An object encapsulating options to use to perform this
752+
/// demangling.
729753
///
730754
/// \returns A string representing the demangled name.
731-
///
732755
std::string nodeToString(NodePointer Root,
733756
const DemangleOptions &Options = DemangleOptions());
734757

758+
/// Transform the node structure to a string, which is stored in the `Printer`.
759+
///
760+
/// \param Root A pointer to a parse tree generated by the demangler.
761+
/// \param Printer A NodePrinter used to pretty print the demangled Node.
762+
void nodeToString(NodePointer Root, NodePrinter &Printer);
763+
735764
/// Transforms a mangled key path accessor thunk helper
736765
/// into the identfier/subscript that would be used to invoke it in swift code.
737766
std::string keyPathSourceString(const char *MangledName,
@@ -777,11 +806,14 @@ class DemanglerPrinter {
777806

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

809+
size_t getStreamLength() { return Stream.length(); }
810+
780811
/// Shrinks the buffer.
781812
void resetSize(size_t toPos) {
782813
assert(toPos <= Stream.size());
783814
Stream.resize(toPos);
784815
}
816+
785817
private:
786818
std::string Stream;
787819
};
@@ -818,6 +850,159 @@ std::string mangledNameForTypeMetadataAccessor(
818850
llvm::StringRef moduleName, llvm::StringRef typeName, Node::Kind typeKind,
819851
Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default);
820852

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

lib/Demangling/Context.cpp

Lines changed: 6 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);

0 commit comments

Comments
 (0)