Skip to content

Commit 1072d08

Browse files
committed
[ItaniumDemangle] Add customizable printLeft/printRight APIs to OutputBuffer (llvm#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. (cherry picked from commit 889dad7)
1 parent d2ebe63 commit 1072d08

File tree

6 files changed

+197
-77
lines changed

6 files changed

+197
-77
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,11 @@ class Node {
278278
}
279279

280280
void print(OutputBuffer &OB) const {
281-
printLeft(OB);
281+
OB.printLeft(*this);
282282
if (RHSComponentCache != Cache::No)
283-
printRight(OB);
283+
OB.printRight(*this);
284284
}
285285

286-
// Print the "left" side of this Node into OutputBuffer.
287-
virtual void printLeft(OutputBuffer &) const = 0;
288-
289-
// Print the "right". This distinction is necessary to represent C++ types
290-
// that appear on the RHS of their subtype, such as arrays or functions.
291-
// Since most types don't have such a component, provide a default
292-
// implementation.
293-
virtual void printRight(OutputBuffer &) const {}
294-
295286
virtual std::string_view getBaseName() const { return {}; }
296287

297288
// Silence compiler warnings, this dtor will never be called.
@@ -300,6 +291,24 @@ class Node {
300291
#ifndef NDEBUG
301292
DEMANGLE_DUMP_METHOD void dump() const;
302293
#endif
294+
295+
private:
296+
friend class OutputBuffer;
297+
298+
// Print the "left" side of this Node into OutputBuffer.
299+
//
300+
// Note, should only be called from OutputBuffer implementations.
301+
// Call \ref OutputBuffer::printLeft instead.
302+
virtual void printLeft(OutputBuffer &) const = 0;
303+
304+
// Print the "right". This distinction is necessary to represent C++ types
305+
// that appear on the RHS of their subtype, such as arrays or functions.
306+
// Since most types don't have such a component, provide a default
307+
// implementation.
308+
//
309+
// Note, should only be called from OutputBuffer implementations.
310+
// Call \ref OutputBuffer::printRight instead.
311+
virtual void printRight(OutputBuffer &) const {}
303312
};
304313

305314
class NodeArray {
@@ -444,11 +453,11 @@ class QualType final : public Node {
444453
}
445454

446455
void printLeft(OutputBuffer &OB) const override {
447-
Child->printLeft(OB);
456+
OB.printLeft(*Child);
448457
printQuals(OB);
449458
}
450459

451-
void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
460+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
452461
};
453462

454463
class ConversionOperatorType final : public Node {
@@ -477,7 +486,7 @@ class PostfixQualifiedType final : public Node {
477486
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
478487

479488
void printLeft(OutputBuffer &OB) const override {
480-
Ty->printLeft(OB);
489+
OB.printLeft(*Ty);
481490
OB += Postfix;
482491
}
483492
};
@@ -563,7 +572,7 @@ struct AbiTagAttr : Node {
563572
std::string_view getBaseName() const override { return Base->getBaseName(); }
564573

565574
void printLeft(OutputBuffer &OB) const override {
566-
Base->printLeft(OB);
575+
OB.printLeft(*Base);
567576
OB += "[abi:";
568577
OB += Tag;
569578
OB += "]";
@@ -630,7 +639,7 @@ class PointerType final : public Node {
630639
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
631640
if (Pointee->getKind() != KObjCProtoName ||
632641
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
633-
Pointee->printLeft(OB);
642+
OB.printLeft(*Pointee);
634643
if (Pointee->hasArray(OB))
635644
OB += " ";
636645
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -649,7 +658,7 @@ class PointerType final : public Node {
649658
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
650659
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
651660
OB += ")";
652-
Pointee->printRight(OB);
661+
OB.printRight(*Pointee);
653662
}
654663
}
655664
};
@@ -715,7 +724,7 @@ class ReferenceType : public Node {
715724
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
716725
if (!Collapsed.second)
717726
return;
718-
Collapsed.second->printLeft(OB);
727+
OB.printLeft(*Collapsed.second);
719728
if (Collapsed.second->hasArray(OB))
720729
OB += " ";
721730
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -732,7 +741,7 @@ class ReferenceType : public Node {
732741
return;
733742
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
734743
OB += ")";
735-
Collapsed.second->printRight(OB);
744+
OB.printRight(*Collapsed.second);
736745
}
737746
};
738747

@@ -752,7 +761,7 @@ class PointerToMemberType final : public Node {
752761
}
753762

754763
void printLeft(OutputBuffer &OB) const override {
755-
MemberType->printLeft(OB);
764+
OB.printLeft(*MemberType);
756765
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
757766
OB += "(";
758767
else
@@ -764,7 +773,7 @@ class PointerToMemberType final : public Node {
764773
void printRight(OutputBuffer &OB) const override {
765774
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
766775
OB += ")";
767-
MemberType->printRight(OB);
776+
OB.printRight(*MemberType);
768777
}
769778
};
770779

@@ -784,7 +793,7 @@ class ArrayType final : public Node {
784793
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
785794
bool hasArraySlow(OutputBuffer &) const override { return true; }
786795

787-
void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
796+
void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
788797

789798
void printRight(OutputBuffer &OB) const override {
790799
if (OB.back() != ']')
@@ -793,7 +802,7 @@ class ArrayType final : public Node {
793802
if (Dimension)
794803
Dimension->print(OB);
795804
OB += "]";
796-
Base->printRight(OB);
805+
OB.printRight(*Base);
797806
}
798807
};
799808

@@ -828,15 +837,15 @@ class FunctionType final : public Node {
828837
// by printing out the return types's left, then print our parameters, then
829838
// finally print right of the return type.
830839
void printLeft(OutputBuffer &OB) const override {
831-
Ret->printLeft(OB);
840+
OB.printLeft(*Ret);
832841
OB += " ";
833842
}
834843

835844
void printRight(OutputBuffer &OB) const override {
836845
OB.printOpen();
837846
Params.printWithComma(OB);
838847
OB.printClose();
839-
Ret->printRight(OB);
848+
OB.printRight(*Ret);
840849

841850
if (CVQuals & QualConst)
842851
OB += " const";
@@ -941,6 +950,8 @@ class FunctionEncoding final : public Node {
941950
FunctionRefQual getRefQual() const { return RefQual; }
942951
NodeArray getParams() const { return Params; }
943952
const Node *getReturnType() const { return Ret; }
953+
const Node *getAttrs() const { return Attrs; }
954+
const Node *getRequires() const { return Requires; }
944955

945956
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
946957
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -949,19 +960,21 @@ class FunctionEncoding final : public Node {
949960

950961
void printLeft(OutputBuffer &OB) const override {
951962
if (Ret) {
952-
Ret->printLeft(OB);
963+
OB.printLeft(*Ret);
953964
if (!Ret->hasRHSComponent(OB))
954965
OB += " ";
955966
}
967+
956968
Name->print(OB);
957969
}
958970

959971
void printRight(OutputBuffer &OB) const override {
960972
OB.printOpen();
961973
Params.printWithComma(OB);
962974
OB.printClose();
975+
963976
if (Ret)
964-
Ret->printRight(OB);
977+
OB.printRight(*Ret);
965978

966979
if (CVQuals & QualConst)
967980
OB += " const";
@@ -1301,14 +1314,14 @@ class NonTypeTemplateParamDecl final : public Node {
13011314
template<typename Fn> void match(Fn F) const { F(Name, Type); }
13021315

13031316
void printLeft(OutputBuffer &OB) const override {
1304-
Type->printLeft(OB);
1317+
OB.printLeft(*Type);
13051318
if (!Type->hasRHSComponent(OB))
13061319
OB += " ";
13071320
}
13081321

13091322
void printRight(OutputBuffer &OB) const override {
13101323
Name->print(OB);
1311-
Type->printRight(OB);
1324+
OB.printRight(*Type);
13121325
}
13131326
};
13141327

@@ -1353,11 +1366,11 @@ class TemplateParamPackDecl final : public Node {
13531366
template<typename Fn> void match(Fn F) const { F(Param); }
13541367

13551368
void printLeft(OutputBuffer &OB) const override {
1356-
Param->printLeft(OB);
1369+
OB.printLeft(*Param);
13571370
OB += "...";
13581371
}
13591372

1360-
void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
1373+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
13611374
};
13621375

13631376
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1424,13 +1437,13 @@ class ParameterPack final : public Node {
14241437
initializePackExpansion(OB);
14251438
size_t Idx = OB.CurrentPackIndex;
14261439
if (Idx < Data.size())
1427-
Data[Idx]->printLeft(OB);
1440+
OB.printLeft(*Data[Idx]);
14281441
}
14291442
void printRight(OutputBuffer &OB) const override {
14301443
initializePackExpansion(OB);
14311444
size_t Idx = OB.CurrentPackIndex;
14321445
if (Idx < Data.size())
1433-
Data[Idx]->printRight(OB);
1446+
OB.printRight(*Data[Idx]);
14341447
}
14351448
};
14361449

@@ -1588,13 +1601,13 @@ struct ForwardTemplateReference : Node {
15881601
if (Printing)
15891602
return;
15901603
ScopedOverride<bool> SavePrinting(Printing, true);
1591-
Ref->printLeft(OB);
1604+
OB.printLeft(*Ref);
15921605
}
15931606
void printRight(OutputBuffer &OB) const override {
15941607
if (Printing)
15951608
return;
15961609
ScopedOverride<bool> SavePrinting(Printing, true);
1597-
Ref->printRight(OB);
1610+
OB.printRight(*Ref);
15981611
}
15991612
};
16001613

@@ -1746,7 +1759,7 @@ class DtorName : public Node {
17461759

17471760
void printLeft(OutputBuffer &OB) const override {
17481761
OB += "~";
1749-
Base->printLeft(OB);
1762+
OB.printLeft(*Base);
17501763
}
17511764
};
17521765

@@ -2026,7 +2039,7 @@ class CastExpr : public Node {
20262039
{
20272040
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
20282041
OB += "<";
2029-
To->printLeft(OB);
2042+
OB.printLeft(*To);
20302043
OB += ">";
20312044
}
20322045
OB.printOpen();
@@ -5946,6 +5959,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
59465959
Alloc>::AbstractManglingParser;
59475960
};
59485961

5962+
inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
5963+
5964+
inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
5965+
59495966
DEMANGLE_NAMESPACE_END
59505967

59515968
#ifdef _LIBCXXABI_COMPILER_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)