Skip to content

Commit 215b9d7

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 215b9d7

File tree

6 files changed

+209
-75
lines changed

6 files changed

+209
-75
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -278,19 +278,17 @@ 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 {}
286+
// Print an initializer list of this type. Returns true if we printed a custom
287+
// representation, false if nothing has been printed and the default
288+
// representation should be used.
289+
virtual bool printInitListAsType(OutputBuffer &, const NodeArray &) const {
290+
return false;
291+
}
294292

295293
virtual std::string_view getBaseName() const { return {}; }
296294

@@ -300,6 +298,24 @@ class Node {
300298
#ifndef NDEBUG
301299
DEMANGLE_DUMP_METHOD void dump() const;
302300
#endif
301+
302+
private:
303+
friend class OutputBuffer;
304+
305+
// Print the "left" side of this Node into OutputBuffer.
306+
//
307+
// Note, should only be called from OutputBuffer implementations.
308+
// Call \ref OutputBuffer::printLeft instead.
309+
virtual void printLeft(OutputBuffer &) const = 0;
310+
311+
// Print the "right". This distinction is necessary to represent C++ types
312+
// that appear on the RHS of their subtype, such as arrays or functions.
313+
// Since most types don't have such a component, provide a default
314+
// implementation.
315+
//
316+
// Note, should only be called from OutputBuffer implementations.
317+
// Call \ref OutputBuffer::printRight instead.
318+
virtual void printRight(OutputBuffer &) const {}
303319
};
304320

305321
class NodeArray {
@@ -444,11 +460,11 @@ class QualType final : public Node {
444460
}
445461

446462
void printLeft(OutputBuffer &OB) const override {
447-
Child->printLeft(OB);
463+
OB.printLeft(*Child);
448464
printQuals(OB);
449465
}
450466

451-
void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
467+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
452468
};
453469

454470
class ConversionOperatorType final : public Node {
@@ -477,7 +493,7 @@ class PostfixQualifiedType final : public Node {
477493
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
478494

479495
void printLeft(OutputBuffer &OB) const override {
480-
Ty->printLeft(OB);
496+
OB.printLeft(*Ty);
481497
OB += Postfix;
482498
}
483499
};
@@ -563,7 +579,7 @@ struct AbiTagAttr : Node {
563579
std::string_view getBaseName() const override { return Base->getBaseName(); }
564580

565581
void printLeft(OutputBuffer &OB) const override {
566-
Base->printLeft(OB);
582+
OB.printLeft(*Base);
567583
OB += "[abi:";
568584
OB += Tag;
569585
OB += "]";
@@ -630,7 +646,7 @@ class PointerType final : public Node {
630646
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
631647
if (Pointee->getKind() != KObjCProtoName ||
632648
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
633-
Pointee->printLeft(OB);
649+
OB.printLeft(*Pointee);
634650
if (Pointee->hasArray(OB))
635651
OB += " ";
636652
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -649,7 +665,7 @@ class PointerType final : public Node {
649665
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
650666
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
651667
OB += ")";
652-
Pointee->printRight(OB);
668+
OB.printRight(*Pointee);
653669
}
654670
}
655671
};
@@ -715,7 +731,7 @@ class ReferenceType : public Node {
715731
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
716732
if (!Collapsed.second)
717733
return;
718-
Collapsed.second->printLeft(OB);
734+
OB.printLeft(*Collapsed.second);
719735
if (Collapsed.second->hasArray(OB))
720736
OB += " ";
721737
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -732,7 +748,7 @@ class ReferenceType : public Node {
732748
return;
733749
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
734750
OB += ")";
735-
Collapsed.second->printRight(OB);
751+
OB.printRight(*Collapsed.second);
736752
}
737753
};
738754

@@ -752,7 +768,7 @@ class PointerToMemberType final : public Node {
752768
}
753769

754770
void printLeft(OutputBuffer &OB) const override {
755-
MemberType->printLeft(OB);
771+
OB.printLeft(*MemberType);
756772
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
757773
OB += "(";
758774
else
@@ -764,7 +780,7 @@ class PointerToMemberType final : public Node {
764780
void printRight(OutputBuffer &OB) const override {
765781
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
766782
OB += ")";
767-
MemberType->printRight(OB);
783+
OB.printRight(*MemberType);
768784
}
769785
};
770786

@@ -784,7 +800,7 @@ class ArrayType final : public Node {
784800
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
785801
bool hasArraySlow(OutputBuffer &) const override { return true; }
786802

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

789805
void printRight(OutputBuffer &OB) const override {
790806
if (OB.back() != ']')
@@ -793,7 +809,7 @@ class ArrayType final : public Node {
793809
if (Dimension)
794810
Dimension->print(OB);
795811
OB += "]";
796-
Base->printRight(OB);
812+
OB.printRight(*Base);
797813
}
798814
};
799815

@@ -828,15 +844,15 @@ class FunctionType final : public Node {
828844
// by printing out the return types's left, then print our parameters, then
829845
// finally print right of the return type.
830846
void printLeft(OutputBuffer &OB) const override {
831-
Ret->printLeft(OB);
847+
OB.printLeft(*Ret);
832848
OB += " ";
833849
}
834850

835851
void printRight(OutputBuffer &OB) const override {
836852
OB.printOpen();
837853
Params.printWithComma(OB);
838854
OB.printClose();
839-
Ret->printRight(OB);
855+
OB.printRight(*Ret);
840856

841857
if (CVQuals & QualConst)
842858
OB += " const";
@@ -941,6 +957,8 @@ class FunctionEncoding final : public Node {
941957
FunctionRefQual getRefQual() const { return RefQual; }
942958
NodeArray getParams() const { return Params; }
943959
const Node *getReturnType() const { return Ret; }
960+
const Node *getAttrs() const { return Attrs; }
961+
const Node *getRequires() const { return Requires; }
944962

945963
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
946964
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -949,19 +967,21 @@ class FunctionEncoding final : public Node {
949967

950968
void printLeft(OutputBuffer &OB) const override {
951969
if (Ret) {
952-
Ret->printLeft(OB);
970+
OB.printLeft(*Ret);
953971
if (!Ret->hasRHSComponent(OB))
954972
OB += " ";
955973
}
974+
956975
Name->print(OB);
957976
}
958977

959978
void printRight(OutputBuffer &OB) const override {
960979
OB.printOpen();
961980
Params.printWithComma(OB);
962981
OB.printClose();
982+
963983
if (Ret)
964-
Ret->printRight(OB);
984+
OB.printRight(*Ret);
965985

966986
if (CVQuals & QualConst)
967987
OB += " const";
@@ -1301,14 +1321,14 @@ class NonTypeTemplateParamDecl final : public Node {
13011321
template<typename Fn> void match(Fn F) const { F(Name, Type); }
13021322

13031323
void printLeft(OutputBuffer &OB) const override {
1304-
Type->printLeft(OB);
1324+
OB.printLeft(*Type);
13051325
if (!Type->hasRHSComponent(OB))
13061326
OB += " ";
13071327
}
13081328

13091329
void printRight(OutputBuffer &OB) const override {
13101330
Name->print(OB);
1311-
Type->printRight(OB);
1331+
OB.printRight(*Type);
13121332
}
13131333
};
13141334

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

13551375
void printLeft(OutputBuffer &OB) const override {
1356-
Param->printLeft(OB);
1376+
OB.printLeft(*Param);
13571377
OB += "...";
13581378
}
13591379

1360-
void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
1380+
void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
13611381
};
13621382

13631383
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1424,13 +1444,13 @@ class ParameterPack final : public Node {
14241444
initializePackExpansion(OB);
14251445
size_t Idx = OB.CurrentPackIndex;
14261446
if (Idx < Data.size())
1427-
Data[Idx]->printLeft(OB);
1447+
OB.printLeft(*Data[Idx]);
14281448
}
14291449
void printRight(OutputBuffer &OB) const override {
14301450
initializePackExpansion(OB);
14311451
size_t Idx = OB.CurrentPackIndex;
14321452
if (Idx < Data.size())
1433-
Data[Idx]->printRight(OB);
1453+
OB.printRight(*Data[Idx]);
14341454
}
14351455
};
14361456

@@ -1588,13 +1608,13 @@ struct ForwardTemplateReference : Node {
15881608
if (Printing)
15891609
return;
15901610
ScopedOverride<bool> SavePrinting(Printing, true);
1591-
Ref->printLeft(OB);
1611+
OB.printLeft(*Ref);
15921612
}
15931613
void printRight(OutputBuffer &OB) const override {
15941614
if (Printing)
15951615
return;
15961616
ScopedOverride<bool> SavePrinting(Printing, true);
1597-
Ref->printRight(OB);
1617+
OB.printRight(*Ref);
15981618
}
15991619
};
16001620

@@ -1746,7 +1766,7 @@ class DtorName : public Node {
17461766

17471767
void printLeft(OutputBuffer &OB) const override {
17481768
OB += "~";
1749-
Base->printLeft(OB);
1769+
OB.printLeft(*Base);
17501770
}
17511771
};
17521772

@@ -2026,7 +2046,7 @@ class CastExpr : public Node {
20262046
{
20272047
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
20282048
OB += "<";
2029-
To->printLeft(OB);
2049+
OB.printLeft(*To);
20302050
OB += ">";
20312051
}
20322052
OB.printOpen();
@@ -5946,6 +5966,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
59465966
Alloc>::AbstractManglingParser;
59475967
};
59485968

5969+
inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
5970+
5971+
inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
5972+
59495973
DEMANGLE_NAMESPACE_END
59505974

59515975
#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)