Skip to content

Commit 889dad7

Browse files
authored
[ItaniumDemangle] Add customizable printLeft/printRight APIs to OutputBuffer (#133249)
This patch includes the necessary changes for the LLDB feature proposed in https://discourse.llvm.org/t/rfc-lldb-highlighting-function-names-in-lldb-backtraces/85309. The TL;DR is that we want to track where certain parts of a demangled name begin/end so we can highlight them in backtraces. We introduce a new `printLeft`/`printRight` API on `OutputBuffer` that a client (in our case LLDB) can implement to track state while printing the demangle tree. This requires redirecting all calls to to `printLeft`/`printRight` to the `OutputBuffer`. One quirk with the new API is that `Utility.h` would now depend on `ItaniumDemangle.h` and vice-versa. To keep these files header-only I made the definitions `inline` and implement the new APIs in `ItaniumDemangle.h` (so the definition of `Node` is available to them). Also introduces `notifyInsertion`/`notifyDeletion` APIs that a client can override to respond to cases where the `OutputBuffer` changes arbitrary parts of the name.
1 parent 7119b0c commit 889dad7

File tree

6 files changed

+196
-77
lines changed

6 files changed

+196
-77
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -283,20 +283,11 @@ class Node {
283283
}
284284

285285
void print(OutputBuffer &OB) const {
286-
printLeft(OB);
286+
OB.printLeft(*this);
287287
if (RHSComponentCache != Cache::No)
288-
printRight(OB);
288+
OB.printRight(*this);
289289
}
290290

291-
// Print the "left" side of this Node into OutputBuffer.
292-
virtual void printLeft(OutputBuffer &) const = 0;
293-
294-
// Print the "right". This distinction is necessary to represent C++ types
295-
// that appear on the RHS of their subtype, such as arrays or functions.
296-
// Since most types don't have such a component, provide a default
297-
// implementation.
298-
virtual void printRight(OutputBuffer &) const {}
299-
300291
// Print an initializer list of this type. Returns true if we printed a custom
301292
// representation, false if nothing has been printed and the default
302293
// representation should be used.
@@ -312,6 +303,24 @@ class Node {
312303
#ifndef NDEBUG
313304
DEMANGLE_DUMP_METHOD void dump() const;
314305
#endif
306+
307+
private:
308+
friend class OutputBuffer;
309+
310+
// Print the "left" side of this Node into OutputBuffer.
311+
//
312+
// Note, should only be called from OutputBuffer implementations.
313+
// Call \ref OutputBuffer::printLeft instead.
314+
virtual void printLeft(OutputBuffer &) const = 0;
315+
316+
// Print the "right". This distinction is necessary to represent C++ types
317+
// that appear on the RHS of their subtype, such as arrays or functions.
318+
// Since most types don't have such a component, provide a default
319+
// implementation.
320+
//
321+
// Note, should only be called from OutputBuffer implementations.
322+
// Call \ref OutputBuffer::printRight instead.
323+
virtual void printRight(OutputBuffer &) const {}
315324
};
316325

317326
class NodeArray {
@@ -460,11 +469,11 @@ class QualType final : public Node {
460469
}
461470

462471
void printLeft(OutputBuffer &OB) const override {
463-
Child->printLeft(OB);
472+
OB.printLeft(*Child);
464473
printQuals(OB);
465474
}
466475

467-
void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
476+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
468477
};
469478

470479
class ConversionOperatorType final : public Node {
@@ -493,7 +502,7 @@ class PostfixQualifiedType final : public Node {
493502
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
494503

495504
void printLeft(OutputBuffer &OB) const override {
496-
Ty->printLeft(OB);
505+
OB.printLeft(*Ty);
497506
OB += Postfix;
498507
}
499508
};
@@ -579,7 +588,7 @@ struct AbiTagAttr : Node {
579588
std::string_view getBaseName() const override { return Base->getBaseName(); }
580589

581590
void printLeft(OutputBuffer &OB) const override {
582-
Base->printLeft(OB);
591+
OB.printLeft(*Base);
583592
OB += "[abi:";
584593
OB += Tag;
585594
OB += "]";
@@ -646,7 +655,7 @@ class PointerType final : public Node {
646655
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
647656
if (Pointee->getKind() != KObjCProtoName ||
648657
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
649-
Pointee->printLeft(OB);
658+
OB.printLeft(*Pointee);
650659
if (Pointee->hasArray(OB))
651660
OB += " ";
652661
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -665,7 +674,7 @@ class PointerType final : public Node {
665674
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
666675
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
667676
OB += ")";
668-
Pointee->printRight(OB);
677+
OB.printRight(*Pointee);
669678
}
670679
}
671680
};
@@ -731,7 +740,7 @@ class ReferenceType : public Node {
731740
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
732741
if (!Collapsed.second)
733742
return;
734-
Collapsed.second->printLeft(OB);
743+
OB.printLeft(*Collapsed.second);
735744
if (Collapsed.second->hasArray(OB))
736745
OB += " ";
737746
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -748,7 +757,7 @@ class ReferenceType : public Node {
748757
return;
749758
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
750759
OB += ")";
751-
Collapsed.second->printRight(OB);
760+
OB.printRight(*Collapsed.second);
752761
}
753762
};
754763

@@ -768,7 +777,7 @@ class PointerToMemberType final : public Node {
768777
}
769778

770779
void printLeft(OutputBuffer &OB) const override {
771-
MemberType->printLeft(OB);
780+
OB.printLeft(*MemberType);
772781
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
773782
OB += "(";
774783
else
@@ -780,7 +789,7 @@ class PointerToMemberType final : public Node {
780789
void printRight(OutputBuffer &OB) const override {
781790
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
782791
OB += ")";
783-
MemberType->printRight(OB);
792+
OB.printRight(*MemberType);
784793
}
785794
};
786795

@@ -800,7 +809,7 @@ class ArrayType final : public Node {
800809
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
801810
bool hasArraySlow(OutputBuffer &) const override { return true; }
802811

803-
void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
812+
void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
804813

805814
void printRight(OutputBuffer &OB) const override {
806815
if (OB.back() != ']')
@@ -809,7 +818,7 @@ class ArrayType final : public Node {
809818
if (Dimension)
810819
Dimension->print(OB);
811820
OB += "]";
812-
Base->printRight(OB);
821+
OB.printRight(*Base);
813822
}
814823

815824
bool printInitListAsType(OutputBuffer &OB,
@@ -853,15 +862,15 @@ class FunctionType final : public Node {
853862
// by printing out the return types's left, then print our parameters, then
854863
// finally print right of the return type.
855864
void printLeft(OutputBuffer &OB) const override {
856-
Ret->printLeft(OB);
865+
OB.printLeft(*Ret);
857866
OB += " ";
858867
}
859868

860869
void printRight(OutputBuffer &OB) const override {
861870
OB.printOpen();
862871
Params.printWithComma(OB);
863872
OB.printClose();
864-
Ret->printRight(OB);
873+
OB.printRight(*Ret);
865874

866875
if (CVQuals & QualConst)
867876
OB += " const";
@@ -966,6 +975,8 @@ class FunctionEncoding final : public Node {
966975
FunctionRefQual getRefQual() const { return RefQual; }
967976
NodeArray getParams() const { return Params; }
968977
const Node *getReturnType() const { return Ret; }
978+
const Node *getAttrs() const { return Attrs; }
979+
const Node *getRequires() const { return Requires; }
969980

970981
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
971982
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -974,19 +985,21 @@ class FunctionEncoding final : public Node {
974985

975986
void printLeft(OutputBuffer &OB) const override {
976987
if (Ret) {
977-
Ret->printLeft(OB);
988+
OB.printLeft(*Ret);
978989
if (!Ret->hasRHSComponent(OB))
979990
OB += " ";
980991
}
992+
981993
Name->print(OB);
982994
}
983995

984996
void printRight(OutputBuffer &OB) const override {
985997
OB.printOpen();
986998
Params.printWithComma(OB);
987999
OB.printClose();
1000+
9881001
if (Ret)
989-
Ret->printRight(OB);
1002+
OB.printRight(*Ret);
9901003

9911004
if (CVQuals & QualConst)
9921005
OB += " const";
@@ -1326,14 +1339,14 @@ class NonTypeTemplateParamDecl final : public Node {
13261339
template<typename Fn> void match(Fn F) const { F(Name, Type); }
13271340

13281341
void printLeft(OutputBuffer &OB) const override {
1329-
Type->printLeft(OB);
1342+
OB.printLeft(*Type);
13301343
if (!Type->hasRHSComponent(OB))
13311344
OB += " ";
13321345
}
13331346

13341347
void printRight(OutputBuffer &OB) const override {
13351348
Name->print(OB);
1336-
Type->printRight(OB);
1349+
OB.printRight(*Type);
13371350
}
13381351
};
13391352

@@ -1378,11 +1391,11 @@ class TemplateParamPackDecl final : public Node {
13781391
template<typename Fn> void match(Fn F) const { F(Param); }
13791392

13801393
void printLeft(OutputBuffer &OB) const override {
1381-
Param->printLeft(OB);
1394+
OB.printLeft(*Param);
13821395
OB += "...";
13831396
}
13841397

1385-
void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
1398+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
13861399
};
13871400

13881401
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1447,13 +1460,13 @@ class ParameterPack final : public Node {
14471460
initializePackExpansion(OB);
14481461
size_t Idx = OB.CurrentPackIndex;
14491462
if (Idx < Data.size())
1450-
Data[Idx]->printLeft(OB);
1463+
OB.printLeft(*Data[Idx]);
14511464
}
14521465
void printRight(OutputBuffer &OB) const override {
14531466
initializePackExpansion(OB);
14541467
size_t Idx = OB.CurrentPackIndex;
14551468
if (Idx < Data.size())
1456-
Data[Idx]->printRight(OB);
1469+
OB.printRight(*Data[Idx]);
14571470
}
14581471
};
14591472

@@ -1611,13 +1624,13 @@ struct ForwardTemplateReference : Node {
16111624
if (Printing)
16121625
return;
16131626
ScopedOverride<bool> SavePrinting(Printing, true);
1614-
Ref->printLeft(OB);
1627+
OB.printLeft(*Ref);
16151628
}
16161629
void printRight(OutputBuffer &OB) const override {
16171630
if (Printing)
16181631
return;
16191632
ScopedOverride<bool> SavePrinting(Printing, true);
1620-
Ref->printRight(OB);
1633+
OB.printRight(*Ref);
16211634
}
16221635
};
16231636

@@ -1769,7 +1782,7 @@ class DtorName : public Node {
17691782

17701783
void printLeft(OutputBuffer &OB) const override {
17711784
OB += "~";
1772-
Base->printLeft(OB);
1785+
OB.printLeft(*Base);
17731786
}
17741787
};
17751788

@@ -2049,7 +2062,7 @@ class CastExpr : public Node {
20492062
{
20502063
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
20512064
OB += "<";
2052-
To->printLeft(OB);
2065+
OB.printLeft(*To);
20532066
OB += ">";
20542067
}
20552068
OB.printOpen();
@@ -6180,6 +6193,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
61806193
Alloc>::AbstractManglingParser;
61816194
};
61826195

6196+
inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
6197+
6198+
inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
6199+
61836200
DEMANGLE_NAMESPACE_END
61846201

61856202
#if defined(__clang__)

libcxxabi/src/demangle/Utility.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
DEMANGLE_NAMESPACE_BEGIN
2929

30+
class Node;
31+
3032
// Stream that AST nodes write their string representation into after the AST
3133
// has been parsed.
3234
class OutputBuffer {
@@ -79,10 +81,24 @@ class OutputBuffer {
7981
OutputBuffer(const OutputBuffer &) = delete;
8082
OutputBuffer &operator=(const OutputBuffer &) = delete;
8183

84+
virtual ~OutputBuffer() {}
85+
8286
operator std::string_view() const {
8387
return std::string_view(Buffer, CurrentPosition);
8488
}
8589

90+
/// Called by the demangler when printing the demangle tree. By
91+
/// default calls into \c Node::print{Left|Right} but can be overriden
92+
/// by clients to track additional state when printing the demangled name.
93+
virtual void printLeft(const Node &N);
94+
virtual void printRight(const Node &N);
95+
96+
/// Called when we write to this object anywhere other than the end.
97+
virtual void notifyInsertion(size_t /*Position*/, size_t /*Count*/) {}
98+
99+
/// Called when we make the \c CurrentPosition of this object smaller.
100+
virtual void notifyDeletion(size_t /*OldPos*/, size_t /*NewPos*/) {}
101+
86102
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
87103
/// into the pack that we're currently printing.
88104
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
@@ -126,6 +142,8 @@ class OutputBuffer {
126142
std::memcpy(Buffer, &*R.begin(), Size);
127143
CurrentPosition += Size;
128144

145+
notifyInsertion(/*Position=*/0, /*Count=*/Size);
146+
129147
return *this;
130148
}
131149

@@ -161,14 +179,20 @@ class OutputBuffer {
161179
DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
162180
if (N == 0)
163181
return;
182+
164183
grow(N);
165184
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
166185
std::memcpy(Buffer + Pos, S, N);
167186
CurrentPosition += N;
187+
188+
notifyInsertion(Pos, N);
168189
}
169190

170191
size_t getCurrentPosition() const { return CurrentPosition; }
171-
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
192+
void setCurrentPosition(size_t NewPos) {
193+
notifyDeletion(CurrentPosition, NewPos);
194+
CurrentPosition = NewPos;
195+
}
172196

173197
char back() const {
174198
DEMANGLE_ASSERT(CurrentPosition, "");

0 commit comments

Comments
 (0)