https://github.com/Michael137 updated 
https://github.com/llvm/llvm-project/pull/131836

>From 65aab6b727cc430a9e826c7eeda67259e041a462 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 7 Apr 2025 13:21:25 +0100
Subject: [PATCH 1/5] [ItaniumDemangle] Add printLeft/printRight APIs to
 OutputBuffer

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 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).
---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 64 +++++++++++---------
 libcxxabi/src/demangle/Utility.h             |  7 +++
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 64 +++++++++++---------
 llvm/include/llvm/Demangle/Utility.h         |  7 +++
 4 files changed, 86 insertions(+), 56 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h 
b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3df41b5f4d7d0..89a24def830f2 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
   }
 
   void print(OutputBuffer &OB) const {
-    printLeft(OB);
+    OB.printLeft(*this);
     if (RHSComponentCache != Cache::No)
-      printRight(OB);
+      OB.printRight(*this);
   }
 
   // Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Child->printLeft(OB);
+    OB.printLeft(*Child);
     printQuals(OB);
   }
 
-  void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
 };
 
 class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
   template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Ty->printLeft(OB);
+    OB.printLeft(*Ty);
     OB += Postfix;
   }
 };
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
   std::string_view getBaseName() const override { return Base->getBaseName(); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
     OB += "[abi:";
     OB += Tag;
     OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
     // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
     if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
-      Pointee->printLeft(OB);
+      OB.printLeft(*Pointee);
       if (Pointee->hasArray(OB))
         OB += " ";
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
         OB += ")";
-      Pointee->printRight(OB);
+      OB.printRight(*Pointee);
     }
   }
 };
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
     std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
     if (!Collapsed.second)
       return;
-    Collapsed.second->printLeft(OB);
+    OB.printLeft(*Collapsed.second);
     if (Collapsed.second->hasArray(OB))
       OB += " ";
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
       return;
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
       OB += ")";
-    Collapsed.second->printRight(OB);
+    OB.printRight(*Collapsed.second);
   }
 };
 
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    MemberType->printLeft(OB);
+    OB.printLeft(*MemberType);
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += "(";
     else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
   void printRight(OutputBuffer &OB) const override {
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += ")";
-    MemberType->printRight(OB);
+    OB.printRight(*MemberType);
   }
 };
 
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasArraySlow(OutputBuffer &) const override { return true; }
 
-  void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+  void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
 
   void printRight(OutputBuffer &OB) const override {
     if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
     if (Dimension)
       Dimension->print(OB);
     OB += "]";
-    Base->printRight(OB);
+    OB.printRight(*Base);
   }
 
   bool printInitListAsType(OutputBuffer &OB,
@@ -851,7 +851,7 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
-    Ret->printLeft(OB);
+    OB.printLeft(*Ret);
     OB += " ";
   }
 
@@ -859,7 +859,7 @@ class FunctionType final : public Node {
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
-    Ret->printRight(OB);
+    OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -964,6 +964,8 @@ class FunctionEncoding final : public Node {
   FunctionRefQual getRefQual() const { return RefQual; }
   NodeArray getParams() const { return Params; }
   const Node *getReturnType() const { return Ret; }
+  const Node *getAttrs() const { return Attrs; }
+  const Node *getRequires() const { return Requires; }
 
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -972,10 +974,11 @@ class FunctionEncoding final : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     if (Ret) {
-      Ret->printLeft(OB);
+      OB.printLeft(*Ret);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
+
     Name->print(OB);
   }
 
@@ -983,8 +986,9 @@ class FunctionEncoding final : public Node {
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
+
     if (Ret)
-      Ret->printRight(OB);
+      OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -1324,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Name, Type); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Type->printLeft(OB);
+    OB.printLeft(*Type);
     if (!Type->hasRHSComponent(OB))
       OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
     Name->print(OB);
-    Type->printRight(OB);
+    OB.printRight(*Type);
   }
 };
 
@@ -1376,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Param); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Param->printLeft(OB);
+    OB.printLeft(*Param);
     OB += "...";
   }
 
-  void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
 };
 
 /// An unexpanded parameter pack (either in the expression or type context). If
@@ -1445,13 +1449,13 @@ class ParameterPack final : public Node {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printLeft(OB);
+      OB.printLeft(*Data[Idx]);
   }
   void printRight(OutputBuffer &OB) const override {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printRight(OB);
+      OB.printRight(*Data[Idx]);
   }
 };
 
@@ -1609,13 +1613,13 @@ struct ForwardTemplateReference : Node {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printLeft(OB);
+    OB.printLeft(*Ref);
   }
   void printRight(OutputBuffer &OB) const override {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printRight(OB);
+    OB.printRight(*Ref);
   }
 };
 
@@ -1767,7 +1771,7 @@ class DtorName : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     OB += "~";
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
   }
 };
 
@@ -2047,7 +2051,7 @@ class CastExpr : public Node {
     {
       ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
       OB += "<";
-      To->printLeft(OB);
+      OB.printLeft(*To);
       OB += ">";
     }
     OB.printOpen();
@@ -6176,6 +6180,10 @@ struct ManglingParser : 
AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
                                Alloc>::AbstractManglingParser;
 };
 
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
 DEMANGLE_NAMESPACE_END
 
 #if defined(__clang__)
diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h
index f1fad35d60d98..a38bef762dd57 100644
--- a/libcxxabi/src/demangle/Utility.h
+++ b/libcxxabi/src/demangle/Utility.h
@@ -27,6 +27,8 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
+class Node;
+
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
 class OutputBuffer {
@@ -79,10 +81,15 @@ class OutputBuffer {
   OutputBuffer(const OutputBuffer &) = delete;
   OutputBuffer &operator=(const OutputBuffer &) = delete;
 
+  virtual ~OutputBuffer() {}
+
   operator std::string_view() const {
     return std::string_view(Buffer, CurrentPosition);
   }
 
+  virtual void printLeft(const Node &N);
+  virtual void printRight(const Node &N);
+
   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
   /// into the pack that we're currently printing.
   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h 
b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index b0363c1a7a786..aab45f351e070 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
   }
 
   void print(OutputBuffer &OB) const {
-    printLeft(OB);
+    OB.printLeft(*this);
     if (RHSComponentCache != Cache::No)
-      printRight(OB);
+      OB.printRight(*this);
   }
 
   // Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Child->printLeft(OB);
+    OB.printLeft(*Child);
     printQuals(OB);
   }
 
-  void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
 };
 
 class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
   template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Ty->printLeft(OB);
+    OB.printLeft(*Ty);
     OB += Postfix;
   }
 };
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
   std::string_view getBaseName() const override { return Base->getBaseName(); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
     OB += "[abi:";
     OB += Tag;
     OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
     // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
     if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
-      Pointee->printLeft(OB);
+      OB.printLeft(*Pointee);
       if (Pointee->hasArray(OB))
         OB += " ";
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
         OB += ")";
-      Pointee->printRight(OB);
+      OB.printRight(*Pointee);
     }
   }
 };
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
     std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
     if (!Collapsed.second)
       return;
-    Collapsed.second->printLeft(OB);
+    OB.printLeft(*Collapsed.second);
     if (Collapsed.second->hasArray(OB))
       OB += " ";
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
       return;
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
       OB += ")";
-    Collapsed.second->printRight(OB);
+    OB.printRight(*Collapsed.second);
   }
 };
 
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    MemberType->printLeft(OB);
+    OB.printLeft(*MemberType);
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += "(";
     else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
   void printRight(OutputBuffer &OB) const override {
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += ")";
-    MemberType->printRight(OB);
+    OB.printRight(*MemberType);
   }
 };
 
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasArraySlow(OutputBuffer &) const override { return true; }
 
-  void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+  void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
 
   void printRight(OutputBuffer &OB) const override {
     if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
     if (Dimension)
       Dimension->print(OB);
     OB += "]";
-    Base->printRight(OB);
+    OB.printRight(*Base);
   }
 
   bool printInitListAsType(OutputBuffer &OB,
@@ -851,7 +851,7 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
-    Ret->printLeft(OB);
+    OB.printLeft(*Ret);
     OB += " ";
   }
 
@@ -859,7 +859,7 @@ class FunctionType final : public Node {
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
-    Ret->printRight(OB);
+    OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -964,6 +964,8 @@ class FunctionEncoding final : public Node {
   FunctionRefQual getRefQual() const { return RefQual; }
   NodeArray getParams() const { return Params; }
   const Node *getReturnType() const { return Ret; }
+  const Node *getAttrs() const { return Attrs; }
+  const Node *getRequires() const { return Requires; }
 
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -972,10 +974,11 @@ class FunctionEncoding final : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     if (Ret) {
-      Ret->printLeft(OB);
+      OB.printLeft(*Ret);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
+
     Name->print(OB);
   }
 
@@ -983,8 +986,9 @@ class FunctionEncoding final : public Node {
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
+
     if (Ret)
-      Ret->printRight(OB);
+      OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -1324,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Name, Type); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Type->printLeft(OB);
+    OB.printLeft(*Type);
     if (!Type->hasRHSComponent(OB))
       OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
     Name->print(OB);
-    Type->printRight(OB);
+    OB.printRight(*Type);
   }
 };
 
@@ -1376,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Param); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Param->printLeft(OB);
+    OB.printLeft(*Param);
     OB += "...";
   }
 
-  void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
 };
 
 /// An unexpanded parameter pack (either in the expression or type context). If
@@ -1445,13 +1449,13 @@ class ParameterPack final : public Node {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printLeft(OB);
+      OB.printLeft(*Data[Idx]);
   }
   void printRight(OutputBuffer &OB) const override {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printRight(OB);
+      OB.printRight(*Data[Idx]);
   }
 };
 
@@ -1609,13 +1613,13 @@ struct ForwardTemplateReference : Node {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printLeft(OB);
+    OB.printLeft(*Ref);
   }
   void printRight(OutputBuffer &OB) const override {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printRight(OB);
+    OB.printRight(*Ref);
   }
 };
 
@@ -1767,7 +1771,7 @@ class DtorName : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     OB += "~";
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
   }
 };
 
@@ -2047,7 +2051,7 @@ class CastExpr : public Node {
     {
       ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
       OB += "<";
-      To->printLeft(OB);
+      OB.printLeft(*To);
       OB += ">";
     }
     OB.printOpen();
@@ -6176,6 +6180,10 @@ struct ManglingParser : 
AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
                                Alloc>::AbstractManglingParser;
 };
 
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
 DEMANGLE_NAMESPACE_END
 
 #if defined(__clang__)
diff --git a/llvm/include/llvm/Demangle/Utility.h 
b/llvm/include/llvm/Demangle/Utility.h
index e893cceea2cdc..6a1bf6d0e6b63 100644
--- a/llvm/include/llvm/Demangle/Utility.h
+++ b/llvm/include/llvm/Demangle/Utility.h
@@ -27,6 +27,8 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
+class Node;
+
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
 class OutputBuffer {
@@ -79,10 +81,15 @@ class OutputBuffer {
   OutputBuffer(const OutputBuffer &) = delete;
   OutputBuffer &operator=(const OutputBuffer &) = delete;
 
+  virtual ~OutputBuffer() {}
+
   operator std::string_view() const {
     return std::string_view(Buffer, CurrentPosition);
   }
 
+  virtual void printLeft(const Node &N);
+  virtual void printRight(const Node &N);
+
   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
   /// into the pack that we're currently printing.
   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();

>From de8272d2364c291d017ed05fca0f3f3706a46f96 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 7 Apr 2025 13:22:27 +0100
Subject: [PATCH 2/5] [lldb] Implement TrackingOutputBuffer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch implements a new `TrackingOutputBuffer` which tracks where the 
scope/basename/arguments begin and end in the demangled string.

The idea that a function name can be decomposed into <scope, base, arguments>. 
The assumption is that given the ranges of those three elements and the 
demangled name, LLDB will be able to to reconstruct the full demangled name. 
The tracking of those ranges is pretty simple. We don’t ever deal with nesting, 
so whenever we recurse into a template argument list or another function type, 
we just stop tracking any positions. Once we recursed out of those, and are 
back to printing the top-level function name, we continue tracking the 
positions.

We introduce a new structure `FunctionNameInfo` that holds all this information 
and is stored in the new `TrackingOutputBuffer` class.

Tests are in `ItaniumDemangleTest.cpp`.
---
 lldb/include/lldb/Core/DemangledNameInfo.h |  90 +++++++++
 lldb/source/Core/CMakeLists.txt            |   1 +
 lldb/source/Core/DemangledNameInfo.cpp     | 221 +++++++++++++++++++++
 lldb/unittests/Core/MangledTest.cpp        | 143 +++++++++++++
 4 files changed, 455 insertions(+)
 create mode 100644 lldb/include/lldb/Core/DemangledNameInfo.h
 create mode 100644 lldb/source/Core/DemangledNameInfo.cpp

diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h 
b/lldb/include/lldb/Core/DemangledNameInfo.h
new file mode 100644
index 0000000000000..6c2de1700b188
--- /dev/null
+++ b/lldb/include/lldb/Core/DemangledNameInfo.h
@@ -0,0 +1,90 @@
+//===-- DemangledNameInfo.h -------------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_DEMANGLEDNAMEINFO_H
+#define LLDB_CORE_DEMANGLEDNAMEINFO_H
+
+#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <cstddef>
+#include <utility>
+
+namespace lldb_private {
+
+struct TrackingOutputBuffer;
+
+// Stores information about parts of a demangled function name.
+struct DemangledNameInfo {
+  /// A [start, end) pair for the function basename.
+  /// The basename is the name without scope qualifiers
+  /// and without template parameters. E.g.,
+  /// \code{.cpp}
+  ///    void foo::bar<int>::someFunc<float>(int) const &&
+  ///                        ^       ^
+  ///                      start    end
+  /// \endcode
+  std::pair<size_t, size_t> BasenameLocs;
+
+  /// A [start, end) pair for the function scope qualifiers.
+  /// E.g., for
+  /// \code{.cpp}
+  ///    void foo::bar<int>::qux<float>(int) const &&
+  ///         ^              ^
+  ///       start           end
+  /// \endcode
+  std::pair<size_t, size_t> ScopeLocs;
+
+  /// Indicates the [start, end) of the function argument lits.
+  /// E.g.,
+  /// \code{.cpp}
+  ///    int (*getFunc<float>(float, double))(int, int)
+  ///                        ^              ^
+  ///                      start           end
+  /// \endcode
+  std::pair<size_t, size_t> ArgumentLocs;
+
+  bool startedPrintingArguments() const;
+  bool shouldTrack(TrackingOutputBuffer &OB) const;
+  bool canFinalize(TrackingOutputBuffer &OB) const;
+  void updateBasenameEnd(TrackingOutputBuffer &OB);
+  void updateScopeStart(TrackingOutputBuffer &OB);
+  void updateScopeEnd(TrackingOutputBuffer &OB);
+  void finalizeArgumentEnd(TrackingOutputBuffer &OB);
+  void finalizeStart(TrackingOutputBuffer &OB);
+  void finalizeEnd(TrackingOutputBuffer &OB);
+  bool hasBasename() const;
+};
+
+struct TrackingOutputBuffer : public llvm::itanium_demangle::OutputBuffer {
+  using OutputBuffer::OutputBuffer;
+
+  DemangledNameInfo NameInfo;
+  unsigned FunctionPrintingDepth = 0;
+
+  [[nodiscard]] llvm::itanium_demangle::ScopedOverride<unsigned>
+  enterFunctionTypePrinting();
+
+  bool isPrintingTopLevelFunctionType() const;
+
+  void printLeft(const llvm::itanium_demangle::Node &N) override;
+  void printRight(const llvm::itanium_demangle::Node &N) override;
+
+private:
+  void printLeftImpl(const llvm::itanium_demangle::FunctionType &N);
+  void printRightImpl(const llvm::itanium_demangle::FunctionType &N);
+
+  void printLeftImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+  void printRightImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+
+  void printLeftImpl(const llvm::itanium_demangle::NestedName &N);
+  void printLeftImpl(const llvm::itanium_demangle::NameWithTemplateArgs &N);
+};
+} // namespace lldb_private
+
+#endif // LLDB_CORE_DEMANGLEDNAMEINFO_H
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index d5d8a9d5088fc..cab46c400f451 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -28,6 +28,7 @@ add_lldb_library(lldbCore
   Debugger.cpp
   DebuggerEvents.cpp
   Declaration.cpp
+  DemangledNameInfo.cpp
   Disassembler.cpp
   DumpDataExtractor.cpp
   DumpRegisterValue.cpp
diff --git a/lldb/source/Core/DemangledNameInfo.cpp 
b/lldb/source/Core/DemangledNameInfo.cpp
new file mode 100644
index 0000000000000..5d09ea1397f7e
--- /dev/null
+++ b/lldb/source/Core/DemangledNameInfo.cpp
@@ -0,0 +1,221 @@
+//===-- DemangledNameInfo.cpp 
---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DemangledNameInfo.h"
+
+using namespace llvm::itanium_demangle;
+
+namespace lldb_private {
+
+bool DemangledNameInfo::startedPrintingArguments() const {
+  return ArgumentLocs.first > 0;
+}
+
+bool DemangledNameInfo::shouldTrack(TrackingOutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+bool DemangledNameInfo::canFinalize(TrackingOutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (!startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+void DemangledNameInfo::updateBasenameEnd(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  BasenameLocs.second = OB.getCurrentPosition();
+}
+
+void DemangledNameInfo::updateScopeStart(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.first = OB.getCurrentPosition();
+}
+
+void DemangledNameInfo::updateScopeEnd(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.second = OB.getCurrentPosition();
+}
+
+void DemangledNameInfo::finalizeArgumentEnd(TrackingOutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  OB.NameInfo.ArgumentLocs.second = OB.getCurrentPosition();
+}
+
+void DemangledNameInfo::finalizeStart(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  OB.NameInfo.ArgumentLocs.first = OB.getCurrentPosition();
+
+  // If nothing has set the end of the basename yet (for example when
+  // printing templates), then the beginning of the arguments is the end of
+  // the basename.
+  if (BasenameLocs.second == 0)
+    OB.NameInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+  DEMANGLE_ASSERT(!shouldTrack(OB), "");
+  DEMANGLE_ASSERT(canFinalize(OB), "");
+}
+
+void DemangledNameInfo::finalizeEnd(TrackingOutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  if (ScopeLocs.first > OB.NameInfo.ScopeLocs.second)
+    ScopeLocs.second = OB.NameInfo.ScopeLocs.first;
+  BasenameLocs.first = OB.NameInfo.ScopeLocs.second;
+}
+
+bool DemangledNameInfo::hasBasename() const {
+  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
+}
+
+ScopedOverride<unsigned> TrackingOutputBuffer::enterFunctionTypePrinting() {
+  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
+}
+
+bool TrackingOutputBuffer::isPrintingTopLevelFunctionType() const {
+  return FunctionPrintingDepth == 1;
+}
+
+void TrackingOutputBuffer::printLeft(const Node &N) {
+  switch (N.getKind()) {
+  case Node::KFunctionType:
+    printLeftImpl(static_cast<const FunctionType &>(N));
+    break;
+  case Node::KFunctionEncoding:
+    printLeftImpl(static_cast<const FunctionEncoding &>(N));
+    break;
+  case Node::KNestedName:
+    printLeftImpl(static_cast<const NestedName &>(N));
+    break;
+  case Node::KNameWithTemplateArgs:
+    printLeftImpl(static_cast<const NameWithTemplateArgs &>(N));
+    break;
+  default:
+    N.printLeft(*this);
+  }
+}
+
+void TrackingOutputBuffer::printRight(const Node &N) {
+  switch (N.getKind()) {
+  case Node::KFunctionType:
+    printRightImpl(static_cast<const FunctionType &>(N));
+    break;
+  case Node::KFunctionEncoding:
+    printRightImpl(static_cast<const FunctionEncoding &>(N));
+    break;
+  default:
+    N.printRight(*this);
+  }
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionType &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  N.printLeft(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionType &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  N.printRight(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionEncoding &N) {
+  auto Scoped = enterFunctionTypePrinting();
+
+  const Node *Ret = N.getReturnType();
+  if (Ret) {
+    printLeft(*Ret);
+    if (!Ret->hasRHSComponent(*this))
+      *this += " ";
+  }
+
+  NameInfo.updateScopeStart(*this);
+
+  N.getName()->print(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionEncoding &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  NameInfo.finalizeStart(*this);
+
+  printOpen();
+  N.getParams().printWithComma(*this);
+  printClose();
+
+  NameInfo.finalizeArgumentEnd(*this);
+
+  const Node *Ret = N.getReturnType();
+
+  if (Ret)
+    printRight(*Ret);
+
+  auto CVQuals = N.getCVQuals();
+  auto RefQual = N.getRefQual();
+  auto *Attrs = N.getAttrs();
+  auto *Requires = N.getRequires();
+
+  if (CVQuals & QualConst)
+    *this += " const";
+  if (CVQuals & QualVolatile)
+    *this += " volatile";
+  if (CVQuals & QualRestrict)
+    *this += " restrict";
+  if (RefQual == FrefQualLValue)
+    *this += " &";
+  else if (RefQual == FrefQualRValue)
+    *this += " &&";
+  if (Attrs != nullptr)
+    Attrs->print(*this);
+  if (Requires != nullptr) {
+    *this += " requires ";
+    Requires->print(*this);
+  }
+
+  NameInfo.finalizeEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NestedName &N) {
+  N.Qual->print(*this);
+  *this += "::";
+  NameInfo.updateScopeEnd(*this);
+  N.Name->print(*this);
+  NameInfo.updateBasenameEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NameWithTemplateArgs &N) {
+  N.Name->print(*this);
+  NameInfo.updateBasenameEnd(*this);
+  N.TemplateArgs->print(*this);
+}
+
+} // namespace lldb_private
diff --git a/lldb/unittests/Core/MangledTest.cpp 
b/lldb/unittests/Core/MangledTest.cpp
index a3760ba43b3c9..f8e9a026057cc 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -11,6 +11,7 @@
 #include "TestingSupport/SubsystemRAII.h"
 #include "TestingSupport/TestUtilities.h"
 
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/Mangled.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
@@ -319,3 +320,145 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
 }
+
+struct DemanglingPartsTestCase {
+  const char *mangled;
+  DemangledNameInfo expected_info;
+  std::string_view basename;
+  std::string_view scope;
+  bool valid_basename = true;
+};
+
+DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+    // clang-format off
+   { 
"_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
+     { .BasenameLocs = {92, 98}, .ScopeLocs = {36, 92}, .ArgumentLocs = { 108, 
158 } },
+     .basename = "method",
+     .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
+   },
+   { "_Z7getFuncIfEPFiiiET_",
+     { .BasenameLocs = {6, 13}, .ScopeLocs = {6, 6}, .ArgumentLocs = { 20, 27 
} },
+     .basename = "getFunc",
+     .scope = ""
+   },
+   { "_ZN1f1b1c1gEv",
+     { .BasenameLocs = {9, 10}, .ScopeLocs = {0, 9}, .ArgumentLocs = { 10, 12 
} },
+     .basename = "g",
+     .scope = "f::b::c::"
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
+     { .BasenameLocs = {45, 48}, .ScopeLocs = {38, 45}, .ArgumentLocs = { 53, 
58 } },
+     .basename = "fD1",
+     .scope = "test7::"
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { .BasenameLocs = {61, 64}, .ScopeLocs = {54, 61}, .ArgumentLocs = { 69, 
79 } },
+     .basename = "fD1",
+     .scope = "test7::"
+   },
+   { 
"_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { .BasenameLocs = {120, 123}, .ScopeLocs = {81, 120}, .ArgumentLocs = { 
155, 168 } },
+     .basename = "fD1",
+     .scope = "test7<decltype(c)::d<decltype(c)::d>>::"
+   },
+   { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
+     { .BasenameLocs = {687, 692}, .ScopeLocs = {343, 687}, .ArgumentLocs = { 
713, 1174 } },
+     .basename = "parse",
+     .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+   },
+   { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
+     { .BasenameLocs = {344, 354}, .ScopeLocs = {0, 344}, .ArgumentLocs = { 
354, 370 } },
+     .basename = "basic_json",
+     .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+   },
+   { "_Z3fppIiEPFPFvvEiEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { 
"_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { "_ZTV11ImageLoader",
+     { .BasenameLocs = {0, 0}, .ScopeLocs = {0, 0}, .ArgumentLocs = { 0, 0 } },
+     .basename = "",
+     .scope = "",
+     .valid_basename = false
+   }
+    // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+namespace {
+class TestAllocator {
+  llvm::BumpPtrAllocator Alloc;
+
+public:
+  void reset() { Alloc.Reset(); }
+
+  template <typename T, typename... Args> T *makeNode(Args &&...args) {
+    return new (Alloc.Allocate(sizeof(T), alignof(T)))
+        T(std::forward<Args>(args)...);
+  }
+
+  void *allocateNodeArray(size_t sz) {
+    return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+                          alignof(llvm::itanium_demangle::Node *));
+  }
+};
+} // namespace
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+  const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
+
+  llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
+      mangled, mangled + ::strlen(mangled));
+
+  const auto *Root = Parser.parse();
+
+  ASSERT_NE(nullptr, Root);
+
+  TrackingOutputBuffer OB;
+  Root->print(OB);
+  auto demangled = std::string_view(OB);
+
+  ASSERT_EQ(OB.FunctionInfo.hasBasename(), valid_basename);
+
+  EXPECT_EQ(OB.FunctionInfo.BasenameLocs, info.BasenameLocs);
+  EXPECT_EQ(OB.FunctionInfo.ScopeLocs, info.ScopeLocs);
+  EXPECT_EQ(OB.FunctionInfo.ArgumentLocs, info.ArgumentLocs);
+
+  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
+    return demangled.substr(loc.first, loc.second - loc.first);
+  };
+
+  EXPECT_EQ(get_part(OB.FunctionInfo.BasenameLocs), basename);
+  EXPECT_EQ(get_part(OB.FunctionInfo.ScopeLocs), scope);
+}
+
+INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
+                         ::testing::ValuesIn(g_demangling_parts_test_cases));

>From fc779ae3ce346bf4c8a3a52b3c24a98cd9e6f8ef Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 10 Mar 2025 15:39:10 +0000
Subject: [PATCH 3/5] [lldb][Mangled] Add API to force re-demangling a Mangled
 object

Add version of GetDemangledName that will force re-demangling. This is required 
because LLDB will SetDemangledName without going through the demangler. So we 
need a way to force demangling to set the m_demangled_info member when we need 
it.
---
 lldb/include/lldb/Core/Mangled.h |  8 +++++++-
 lldb/source/Core/Mangled.cpp     | 11 ++++++++---
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
index 9ca28917ccffa..12a69f25b2187 100644
--- a/lldb/include/lldb/Core/Mangled.h
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -276,7 +276,13 @@ class Mangled {
   void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
 
 private:
-  ///< The mangled version of the name.
+  /// If \c force is \c false, this function will re-use the previously
+  /// demangled name (if any). If \c force is \c true (or the mangled name
+  /// on this object was not previously demangled), demangle and cache the
+  /// name.
+  ConstString GetDemangledNameImpl(bool force) const;
+
+  /// The mangled version of the name.
   ConstString m_mangled;
 
   ///< Mutable so we can get it on demand with
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index ddaaedea04183..db5aff40d34d3 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -265,19 +265,24 @@ bool Mangled::GetRichManglingInfo(RichManglingContext 
&context,
   llvm_unreachable("Fully covered switch above!");
 }
 
+ConstString Mangled::GetDemangledName() const {
+  return GetDemangledNameImpl(/*force=*/false);
+}
+
 // Generate the demangled name on demand using this accessor. Code in this
 // class will need to use this accessor if it wishes to decode the demangled
 // name. The result is cached and will be kept until a new string value is
 // supplied to this object, or until the end of the object's lifetime.
-ConstString Mangled::GetDemangledName() const {
+ConstString Mangled::GetDemangledNameImpl(bool force) const {
   if (!m_mangled)
     return m_demangled;
 
   // Re-use previously demangled names.
-  if (!m_demangled.IsNull())
+  if (!force && !m_demangled.IsNull())
     return m_demangled;
 
-  if (m_mangled.GetMangledCounterpart(m_demangled) && !m_demangled.IsNull())
+  if (!force && m_mangled.GetMangledCounterpart(m_demangled) &&
+      !m_demangled.IsNull())
     return m_demangled;
 
   // We didn't already mangle this name, demangle it and if all goes well

>From 6f0498521ac59754797bd21f2d140ba7aa6829af Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 7 Apr 2025 13:54:27 +0100
Subject: [PATCH 4/5] [lldb][Mangled] Retrieve and cache demangled name info

Uses the `TrackingOutputBuffer` to populate `Mangled::m_demangled_info`.
---
 lldb/include/lldb/Core/Mangled.h      | 15 ++++++++--
 lldb/source/Core/Mangled.cpp          | 40 ++++++++++++++++++++++-----
 llvm/include/llvm/Demangle/Demangle.h |  7 +++++
 llvm/lib/Demangle/ItaniumDemangle.cpp | 16 +++++++++++
 4 files changed, 69 insertions(+), 9 deletions(-)

diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
index 12a69f25b2187..3297c23bfe320 100644
--- a/lldb/include/lldb/Core/Mangled.h
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -9,10 +9,11 @@
 #ifndef LLDB_CORE_MANGLED_H
 #define LLDB_CORE_MANGLED_H
 
+#include "lldb/Core/DemangledNameInfo.h"
+#include "lldb/Utility/ConstString.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-types.h"
-#include "lldb/Utility/ConstString.h"
 #include "llvm/ADT/StringRef.h"
 
 #include <cstddef>
@@ -134,7 +135,10 @@ class Mangled {
   ///     A const reference to the display demangled name string object.
   ConstString GetDisplayDemangledName() const;
 
-  void SetDemangledName(ConstString name) { m_demangled = name; }
+  void SetDemangledName(ConstString name) {
+    m_demangled = name;
+    m_demangled_info.reset();
+  }
 
   void SetMangledName(ConstString name) { m_mangled = name; }
 
@@ -275,6 +279,9 @@ class Mangled {
   ///   table offsets in the cache data.
   void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
 
+  /// Retrieve \c DemangledNameInfo of the demangled name held by this object.
+  const std::optional<DemangledNameInfo> &GetDemangledInfo() const;
+
 private:
   /// If \c force is \c false, this function will re-use the previously
   /// demangled name (if any). If \c force is \c true (or the mangled name
@@ -288,6 +295,10 @@ class Mangled {
   ///< Mutable so we can get it on demand with
   ///< a const version of this object.
   mutable ConstString m_demangled;
+
+  /// If available, holds information about where in \c m_demangled certain
+  /// parts of the name (e.g., basename, arguments, etc.) begin and end.
+  mutable std::optional<DemangledNameInfo> m_demangled_info = std::nullopt;
 };
 
 Stream &operator<<(Stream &s, const Mangled &obj);
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index db5aff40d34d3..2971181524060 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -9,6 +9,7 @@
 #include "lldb/Core/Mangled.h"
 
 #include "lldb/Core/DataFileCache.h"
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/RichManglingContext.h"
 #include "lldb/Target/Language.h"
 #include "lldb/Utility/ConstString.h"
@@ -111,6 +112,7 @@ Mangled::operator bool() const { return m_mangled || 
m_demangled; }
 void Mangled::Clear() {
   m_mangled.Clear();
   m_demangled.Clear();
+  m_demangled_info.reset();
 }
 
 // Compare the string values.
@@ -124,13 +126,16 @@ void Mangled::SetValue(ConstString name) {
     if (cstring_is_mangled(name.GetStringRef())) {
       m_demangled.Clear();
       m_mangled = name;
+      m_demangled_info.reset();
     } else {
       m_demangled = name;
       m_mangled.Clear();
+      m_demangled_info.reset();
     }
   } else {
     m_demangled.Clear();
     m_mangled.Clear();
+    m_demangled_info.reset();
   }
 }
 
@@ -152,20 +157,25 @@ static char *GetMSVCDemangledStr(llvm::StringRef M) {
   return demangled_cstr;
 }
 
-static char *GetItaniumDemangledStr(const char *M) {
+static std::pair<char *, DemangledNameInfo>
+GetItaniumDemangledStr(const char *M) {
   char *demangled_cstr = nullptr;
 
+  DemangledNameInfo info;
   llvm::ItaniumPartialDemangler ipd;
   bool err = ipd.partialDemangle(M);
   if (!err) {
-    // Default buffer and size (will realloc in case it's too small).
+    // Default buffer and size (OutputBuffer will realloc in case it's too 
small).
     size_t demangled_size = 80;
-    demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
-    demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
+    demangled_cstr = static_cast<char *>(std::malloc(80));
+
+    TrackingOutputBuffer OB(demangled_cstr, demangled_size);
+    demangled_cstr = ipd.finishDemangle(&OB);
+    info = std::move(OB.NameInfo);
 
     assert(demangled_cstr &&
            "finishDemangle must always succeed if partialDemangle did");
-    assert(demangled_cstr[demangled_size - 1] == '\0' &&
+    assert(demangled_cstr[OB.getCurrentPosition() - 1] == '\0' &&
            "Expected demangled_size to return length including trailing null");
   }
 
@@ -174,9 +184,14 @@ static char *GetItaniumDemangledStr(const char *M) {
       LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
     else
       LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);
+
+    if (!info.hasBasename())
+      LLDB_LOGF(log,
+                "demangled itanium: %s -> error: failed to retrieve name info",
+                M);
   }
 
-  return demangled_cstr;
+  return {demangled_cstr, std::move(info)};
 }
 
 static char *GetRustV0DemangledStr(llvm::StringRef M) {
@@ -269,6 +284,13 @@ ConstString Mangled::GetDemangledName() const {
   return GetDemangledNameImpl(/*force=*/false);
 }
 
+std::optional<DemangledNameInfo> const &Mangled::GetDemangledInfo() const {
+  if (!m_demangled_info)
+    GetDemangledNameImpl(/*force=*/true);
+
+  return m_demangled_info;
+}
+
 // Generate the demangled name on demand using this accessor. Code in this
 // class will need to use this accessor if it wishes to decode the demangled
 // name. The result is cached and will be kept until a new string value is
@@ -293,7 +315,10 @@ ConstString Mangled::GetDemangledNameImpl(bool force) 
const {
     demangled_name = GetMSVCDemangledStr(m_mangled);
     break;
   case eManglingSchemeItanium: {
-    demangled_name = GetItaniumDemangledStr(m_mangled.GetCString());
+    std::pair<char *, DemangledNameInfo> demangled =
+        GetItaniumDemangledStr(m_mangled.GetCString());
+    demangled_name = demangled.first;
+    m_demangled_info.emplace(std::move(demangled.second));
     break;
   }
   case eManglingSchemeRustV0:
@@ -452,6 +477,7 @@ bool Mangled::Decode(const DataExtractor &data, 
lldb::offset_t *offset_ptr,
                      const StringTableReader &strtab) {
   m_mangled.Clear();
   m_demangled.Clear();
+  m_demangled_info.reset();
   MangledEncoding encoding = (MangledEncoding)data.GetU8(offset_ptr);
   switch (encoding) {
     case Empty:
diff --git a/llvm/include/llvm/Demangle/Demangle.h 
b/llvm/include/llvm/Demangle/Demangle.h
index 132e5088b5514..21e7457b6336f 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -93,6 +93,13 @@ struct ItaniumPartialDemangler {
   /// second and third parameters to __cxa_demangle.
   char *finishDemangle(char *Buf, size_t *N) const;
 
+  /// See \ref finishDemangle
+  ///
+  /// \param[in] OB A llvm::itanium_demangle::OutputBuffer that the demangled
+  /// name will be printed into.
+  ///
+  char *finishDemangle(void *OB) const;
+
   /// Get the base name of a function. This doesn't include trailing template
   /// arguments, ie for "a::b<int>" this function returns "b".
   char *getFunctionBaseName(char *Buf, size_t *N) const;
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp 
b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 5c21b06a1d095..8277bd78de543 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -421,6 +421,14 @@ static char *printNode(const Node *RootNode, char *Buf, 
size_t *N) {
   return OB.getBuffer();
 }
 
+static char *printNode(const Node *RootNode, OutputBuffer &OB, size_t *N) {
+  RootNode->print(OB);
+  OB += '\0';
+  if (N != nullptr)
+    *N = OB.getCurrentPosition();
+  return OB.getBuffer();
+}
+
 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const 
{
   if (!isFunction())
     return nullptr;
@@ -540,6 +548,14 @@ char *ItaniumPartialDemangler::finishDemangle(char *Buf, 
size_t *N) const {
   return printNode(static_cast<Node *>(RootNode), Buf, N);
 }
 
+char *ItaniumPartialDemangler::finishDemangle(void *OB) const {
+  assert(RootNode != nullptr && "must call partialDemangle()");
+  assert(OB != nullptr && "valid OutputBuffer argument required");
+  return printNode(static_cast<Node *>(RootNode),
+                   *static_cast<OutputBuffer *>(OB),
+                   /*N=*/nullptr);
+}
+
 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
   assert(RootNode != nullptr && "must call partialDemangle()");
   if (!isFunction())

>From a8ae83c1deeefe01a4fafc70eb87125fd565109a Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Tue, 18 Mar 2025 14:02:51 +0000
Subject: [PATCH 5/5] [lldb][Format] Add new function basename highlight option
 to FormatEntity

---
 lldb/include/lldb/Core/FormatEntity.h         | 16 +++++
 lldb/include/lldb/Symbol/Function.h           |  3 +
 lldb/include/lldb/Target/Language.h           |  9 +--
 lldb/source/Core/FormatEntity.cpp             | 67 ++++++++++++++++++-
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  | 53 ++++++++++++---
 .../Language/CPlusPlus/CPlusPlusLanguage.h    |  9 +--
 lldb/source/Symbol/Function.cpp               |  4 ++
 lldb/source/Target/Language.cpp               |  8 +--
 .../Settings/TestFrameFormatHighlight.test    | 55 +++++++++++++++
 9 files changed, 200 insertions(+), 24 deletions(-)
 create mode 100644 lldb/test/Shell/Settings/TestFrameFormatHighlight.test

diff --git a/lldb/include/lldb/Core/FormatEntity.h 
b/lldb/include/lldb/Core/FormatEntity.h
index c9d5af1f31673..1f94da8a36aa1 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -197,6 +197,21 @@ struct Entry {
     return true;
   }
 
+  struct HighlightSettings {
+    std::string prefix;
+    std::string suffix;
+
+    enum class Kind : uint8_t {
+      ///< Don't highlight.
+      None,
+
+      ///< Highlight function basename
+      ///< (i.e., name without Scope and
+      ///< without template arguments).
+      Basename,
+    } kind = Kind::None;
+  };
+
   std::string string;
   std::string printf_format;
   std::vector<Entry> children;
@@ -204,6 +219,7 @@ struct Entry {
   lldb::Format fmt = lldb::eFormatDefault;
   lldb::addr_t number = 0;
   bool deref = false;
+  HighlightSettings highlight;
 };
 
 bool Format(const Entry &entry, Stream &s, const SymbolContext *sc,
diff --git a/lldb/include/lldb/Symbol/Function.h 
b/lldb/include/lldb/Symbol/Function.h
index ee3a8304fc5b3..0a51b7ae051d3 100644
--- a/lldb/include/lldb/Symbol/Function.h
+++ b/lldb/include/lldb/Symbol/Function.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Core/AddressRange.h"
 #include "lldb/Core/Declaration.h"
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/Mangled.h"
 #include "lldb/Expression/DWARFExpressionList.h"
 #include "lldb/Symbol/Block.h"
@@ -534,6 +535,8 @@ class Function : public UserID, public SymbolContextScope {
 
   ConstString GetDisplayName() const;
 
+  const std::optional<DemangledNameInfo> &GetDemangledInfo() const;
+
   const Mangled &GetMangled() const { return m_mangled; }
 
   /// Get the DeclContext for this function, if available.
diff --git a/lldb/include/lldb/Target/Language.h 
b/lldb/include/lldb/Target/Language.h
index b699a90aff8e4..088aa1a964ec7 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -268,10 +268,11 @@ class Language : public PluginInterface {
   // the reference has never been assigned
   virtual bool IsUninitializedReference(ValueObject &valobj);
 
-  virtual bool GetFunctionDisplayName(const SymbolContext *sc,
-                                      const ExecutionContext *exe_ctx,
-                                      FunctionNameRepresentation 
representation,
-                                      Stream &s);
+  virtual bool
+  GetFunctionDisplayName(const SymbolContext *sc,
+                         const ExecutionContext *exe_ctx,
+                         FunctionNameRepresentation representation, Stream &s,
+                         const FormatEntity::Entry::HighlightSettings &);
 
   virtual ConstString
   GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
diff --git a/lldb/source/Core/FormatEntity.cpp 
b/lldb/source/Core/FormatEntity.cpp
index 7fe22994d7f7e..17311cecf01ec 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -1654,7 +1654,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
 
     if (language_plugin)
       language_plugin_handled = language_plugin->GetFunctionDisplayName(
-          sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
+          sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss,
+          entry.highlight);
 
     if (language_plugin_handled) {
       s << ss.GetString();
@@ -1690,7 +1691,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
     if (language_plugin)
       language_plugin_handled = language_plugin->GetFunctionDisplayName(
           sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
-          ss);
+          ss, entry.highlight);
 
     if (language_plugin_handled) {
       s << ss.GetString();
@@ -1724,7 +1725,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
 
     if (language_plugin)
       language_plugin_handled = language_plugin->GetFunctionDisplayName(
-          sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, 
ss);
+          sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss,
+          entry.highlight);
 
     if (language_plugin_handled) {
       s << ss.GetString();
@@ -2046,6 +2048,54 @@ static const Definition *FindEntry(const llvm::StringRef 
&format_str,
   return parent;
 }
 
+static llvm::Expected<Entry::HighlightSettings>
+ParseHighlightSettings(const Entry &entry) {
+  // FIXME: support other function.name-XXX types as well
+  if (entry.type != Entry::Type::FunctionNameWithArgs)
+    return llvm::createStringError(
+        "The 'highlight_basename' format can only be used on "
+        "${function.name-with-args}");
+
+  llvm::StringRef format = entry.printf_format;
+  if (!format.consume_front("highlight_"))
+    return llvm::createStringError(
+        "Expected 'highlight_' prefix not found in: %s.",
+        entry.printf_format.c_str());
+
+  Entry::HighlightSettings settings;
+  if (format.consume_front("basename")) {
+    settings.kind = Entry::HighlightSettings::Kind::Basename;
+  } else {
+    return llvm::createStringError(
+        "Unsupported highlight kind detected in: %s. "
+        "Currently supported: basename",
+        entry.printf_format.c_str());
+  }
+
+  llvm::SmallVector<llvm::StringRef, 1> matches;
+  // TODO: support ${ansi.XXX} syntax. ExtractVariableInfo needs
+  // to be adjusted to support nested '{}'.
+  llvm::Regex color_pattern{R"(^\(([a-z\.]+)\)$)"};
+  if (!color_pattern.match(format, &matches))
+    return llvm::createStringError("Couldn't find valid color variable in: %s. 
"
+                                   "Expected format: (ansi.some-color)",
+                                   entry.printf_format.c_str());
+
+  assert(matches.size() == 2);
+
+  std::string color_format = ("${" + matches[1] + "}").str();
+  std::string terminal_code = ansi::FormatAnsiTerminalCodes(color_format);
+  if (terminal_code.empty())
+    return llvm::createStringError("Invalid color variable '%s' found in: %s",
+                                   color_format.c_str(),
+                                   entry.printf_format.c_str());
+
+  settings.prefix = std::move(terminal_code);
+  settings.suffix = ansi::FormatAnsiTerminalCodes("${ansi.normal}");
+
+  return settings;
+}
+
 static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
                             uint32_t depth) {
   Status error;
@@ -2201,6 +2251,7 @@ static Status ParseInternal(llvm::StringRef &format, 
Entry &parent_entry,
         if (error.Fail())
           return error;
         bool verify_is_thread_id = false;
+        bool parse_highlight_settings = false;
         Entry entry;
         if (!variable_format.empty()) {
           entry.printf_format = variable_format.str();
@@ -2266,6 +2317,8 @@ static Status ParseInternal(llvm::StringRef &format, 
Entry &parent_entry,
                 clear_printf = true;
               } else if (entry.printf_format == "tid") {
                 verify_is_thread_id = true;
+              } else if (entry.printf_format.find("highlight_") == 0) {
+                parse_highlight_settings = true;
               } else {
                 error = Status::FromErrorStringWithFormat(
                     "invalid format: '%s'", entry.printf_format.c_str());
@@ -2307,6 +2360,14 @@ static Status ParseInternal(llvm::StringRef &format, 
Entry &parent_entry,
                 "the 'tid' format can only be used on "
                 "${thread.id} and ${thread.protocol_id}");
           }
+        } else if (parse_highlight_settings) {
+          auto highlight_or_err = ParseHighlightSettings(entry);
+          if (highlight_or_err) {
+            entry.highlight = std::move(*highlight_or_err);
+            entry.printf_format.clear();
+          } else {
+            error = Status::FromError(highlight_or_err.takeError());
+          }
         }
 
         switch (entry.type) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 4b045d12ad494..820bc48dc1fdf 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -19,6 +19,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Demangle/ItaniumDemangle.h"
 
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/Mangled.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
@@ -178,7 +179,7 @@ static bool IsTrivialBasename(const llvm::StringRef 
&basename) {
 /// but replaces each argument type with the variable name
 /// and the corresponding pretty-printed value
 static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
-                                            char const *full_name,
+                                            llvm::StringRef full_name,
                                             ExecutionContextScope *exe_scope,
                                             VariableList const &args) {
   CPlusPlusLanguage::MethodName cpp_method{ConstString(full_name)};
@@ -208,6 +209,42 @@ static bool PrettyPrintFunctionNameWithArgs(Stream 
&out_stream,
   return true;
 }
 
+static bool PrettyPrintFunctionNameWithArgs(
+    Stream &out_stream, llvm::StringRef full_name,
+    ExecutionContextScope *exe_scope, VariableList const &args,
+    const std::optional<DemangledNameInfo> &demangled_info,
+    const FormatEntity::Entry::HighlightSettings &settings) {
+  if (settings.kind == FormatEntity::Entry::HighlightSettings::Kind::None ||
+      !demangled_info || !demangled_info->hasBasename())
+    return PrettyPrintFunctionNameWithArgs(out_stream, full_name, exe_scope,
+                                           args);
+
+  auto [base_start, base_end] = demangled_info->BasenameLocs;
+
+  // Dump anything before the basename.
+  out_stream.PutCString(full_name.substr(0, base_start));
+
+  // Highlight the basename.
+  out_stream.PutCString(settings.prefix);
+  out_stream.PutCString(full_name.substr(base_start, base_end - base_start));
+  out_stream.PutCString(settings.suffix);
+
+  // Dump anything between the basename and the argument list.
+  if (demangled_info->ArgumentLocs.first > base_end)
+    out_stream.PutCString(full_name.substr(
+        base_end, demangled_info->ArgumentLocs.first - base_end));
+
+  // Dump arguments.
+  out_stream.PutChar('(');
+  FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
+  out_stream.PutChar(')');
+
+  // Dump anything after the argument list.
+  out_stream.PutCString(full_name.substr(demangled_info->ArgumentLocs.second));
+
+  return true;
+}
+
 bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
   // This method tries to parse simple method definitions which are presumably
   // most comman in user programs. Definitions that can be parsed by this
@@ -1699,7 +1736,8 @@ bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef 
file_path) const {
 
 bool CPlusPlusLanguage::GetFunctionDisplayName(
     const SymbolContext *sc, const ExecutionContext *exe_ctx,
-    FunctionNameRepresentation representation, Stream &s) {
+    FunctionNameRepresentation representation, Stream &s,
+    const FormatEntity::Entry::HighlightSettings &settings) {
   switch (representation) {
   case FunctionNameRepresentation::eNameWithArgs: {
     // Print the function name with arguments in it
@@ -1737,13 +1775,10 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
         if (variable_list_sp)
           
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
                                                      args);
-        if (args.GetSize() > 0) {
-          if (!PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args))
-            return false;
-        } else {
-          s.PutCString(cstr);
-        }
-        return true;
+
+        return PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args,
+                                               
sc->function->GetDemangledInfo(),
+                                               settings);
       }
     } else if (sc->symbol) {
       const char *cstr = sc->symbol->GetName().AsCString(nullptr);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 623d481bf117f..593432ba19dc2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -15,6 +15,7 @@
 #include "llvm/ADT/StringRef.h"
 
 #include "Plugins/Language/ClangCommon/ClangHighlighter.h"
+#include "lldb/Core/FormatEntity.h"
 #include "lldb/Target/Language.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/lldb-private.h"
@@ -138,10 +139,10 @@ class CPlusPlusLanguage : public Language {
   ConstString
   GetDemangledFunctionNameWithoutArguments(Mangled mangled) const override;
 
-  bool GetFunctionDisplayName(const SymbolContext *sc,
-                              const ExecutionContext *exe_ctx,
-                              FunctionNameRepresentation representation,
-                              Stream &s) override;
+  bool GetFunctionDisplayName(
+      const SymbolContext *sc, const ExecutionContext *exe_ctx,
+      FunctionNameRepresentation representation, Stream &s,
+      const FormatEntity::Entry::HighlightSettings &) override;
 
   static bool IsCPPMangledName(llvm::StringRef name);
 
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
index c80f37ae68d9d..c32463b77a30c 100644
--- a/lldb/source/Symbol/Function.cpp
+++ b/lldb/source/Symbol/Function.cpp
@@ -729,3 +729,7 @@ ConstString Function::GetName() const {
 ConstString Function::GetNameNoArguments() const {
   return m_mangled.GetName(Mangled::ePreferDemangledWithoutArguments);
 }
+
+const std::optional<DemangledNameInfo> &Function::GetDemangledInfo() const {
+  return m_mangled.GetDemangledInfo();
+}
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index a75894ffa4b3b..e01165ee875f5 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -510,10 +510,10 @@ bool Language::IsNilReference(ValueObject &valobj) { 
return false; }
 
 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
 
-bool Language::GetFunctionDisplayName(const SymbolContext *sc,
-                                      const ExecutionContext *exe_ctx,
-                                      FunctionNameRepresentation 
representation,
-                                      Stream &s) {
+bool Language::GetFunctionDisplayName(
+    const SymbolContext *sc, const ExecutionContext *exe_ctx,
+    FunctionNameRepresentation representation, Stream &s,
+    const FormatEntity::Entry::HighlightSettings &) {
   return false;
 }
 
diff --git a/lldb/test/Shell/Settings/TestFrameFormatHighlight.test 
b/lldb/test/Shell/Settings/TestFrameFormatHighlight.test
new file mode 100644
index 0000000000000..1ca9a7ed9fc81
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatHighlight.test
@@ -0,0 +1,55 @@
+# UNSUPPORTED: system-windows
+# Test highlighting of function basenames.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 | FileCheck %s 
--check-prefix=CHECK-COLOR
+
+#--- main.cpp
+namespace ns {
+template<typename T>
+struct Bar {
+  template<typename K>
+  T bar(K k) const & { return 1.0f; }
+};
+
+template<typename T>
+struct Foo {
+  template<typename K>
+  void foo() const volatile && {
+    Bar<float> b;
+    b.bar(b);
+  }
+};
+
+template<typename T>
+T func() {
+  ns::Foo<int>{}.foo<int>();
+  return T{};
+}
+} // namespace ns
+
+int main() {
+  ns::func<ns::Foo<int>>();
+  return 0;
+}
+
+#--- commands.input
+settings set use-color true
+settings set -f frame-format "frame 
${function.name-with-args:%highlight_basename(ansi.fg.cyan)}\n"
+break set -n bar
+
+run
+bt
+# CHECK-COLOR: frame float 
ns::Bar<float>::bar<ns::Bar<float>>(this={{.*}}, k=Bar<float> @ 
{{.*}}) const &
+# CHECK-COLOR: frame void ns::Foo<int>::foo<int>(this={{.*}}) const 
volatile &&
+# CHECK-COLOR: frame ns::Foo<int> ns::func<ns::Foo<int>>()
+# CHECK-COLOR: frame main
+
+settings set -f frame-format "frame 
${function.name-with-args:%highlight_basename(ansi.bg.green)}\n"
+bt
+
+# CHECK-COLOR: frame float 
ns::Bar<float>::bar<ns::Bar<float>>(this={{.*}}, k=Bar<float> @ 
{{.*}}) const &
+# CHECK-COLOR: frame void ns::Foo<int>::foo<int>(this={{.*}}) const 
volatile &&
+# CHECK-COLOR: frame ns::Foo<int> ns::func<ns::Foo<int>>()
+# CHECK-COLOR: frame main

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to