Author: Michael Buch
Date: 2025-04-25T10:04:27+01:00
New Revision: a2672250be871bdac18c1a955265a98704434218

URL: 
https://github.com/llvm/llvm-project/commit/a2672250be871bdac18c1a955265a98704434218
DIFF: 
https://github.com/llvm/llvm-project/commit/a2672250be871bdac18c1a955265a98704434218.diff

LOG: [lldb][Mangled] Retrieve and cache demangled name info (#131836)

Uses the `TrackingOutputBuffer` to populate the new member 
`Mangled::m_demangled_info`.

`m_demangled_info` is lazily popluated by `GetDemangledInfo`. To ensure 
`m_demangled` and `m_demangled_info` are in-sync we clear `m_demangled_info` 
anytime `m_demangled` is set/cleared.

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

Added: 
    

Modified: 
    lldb/include/lldb/Core/DemangledNameInfo.h
    lldb/include/lldb/Core/Mangled.h
    lldb/source/Core/DemangledNameInfo.cpp
    lldb/source/Core/Mangled.cpp
    lldb/unittests/Core/MangledTest.cpp
    llvm/include/llvm/Demangle/Demangle.h
    llvm/lib/Demangle/ItaniumDemangle.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/DemangledNameInfo.h 
b/lldb/include/lldb/Core/DemangledNameInfo.h
index 51cd152bf79d8..3926b45a96f3e 100644
--- a/lldb/include/lldb/Core/DemangledNameInfo.h
+++ b/lldb/include/lldb/Core/DemangledNameInfo.h
@@ -48,9 +48,20 @@ struct DemangledNameInfo {
   /// \endcode
   std::pair<size_t, size_t> ArgumentsRange;
 
+  /// Indicates the [start, end) of the function qualifiers
+  /// (e.g., CV-qualifiers, reference qualifiers, requires clauses).
+  ///
+  /// E.g.,
+  /// \code{.cpp}
+  ///    void foo::bar<int>::qux<float>(int) const &&
+  ///                                       ^        ^
+  ///                                     start     end
+  /// \endcode
+  std::pair<size_t, size_t> QualifiersRange;
+
   /// Returns \c true if this object holds a valid basename range.
   bool hasBasename() const {
-    return BasenameRange.first != BasenameRange.second &&
+    return BasenameRange.second > BasenameRange.first &&
            BasenameRange.second > 0;
   }
 
@@ -139,6 +150,8 @@ struct TrackingOutputBuffer : public 
llvm::itanium_demangle::OutputBuffer {
   void finalizeArgumentEnd();
   void finalizeStart();
   void finalizeEnd();
+  void finalizeQualifiersStart();
+  void finalizeQualifiersEnd();
 
   /// Helper used in the finalize APIs.
   bool canFinalize() const;

diff  --git a/lldb/include/lldb/Core/Mangled.h 
b/lldb/include/lldb/Core/Mangled.h
index 1dca1f0e2b139..eb9a58c568896 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,9 +135,15 @@ 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; }
+  void SetMangledName(ConstString name) {
+    m_mangled = name;
+    m_demangled_info.reset();
+  }
 
   /// Mangled name get accessor.
   ///
@@ -277,6 +284,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
@@ -290,6 +300,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/DemangledNameInfo.cpp 
b/lldb/source/Core/DemangledNameInfo.cpp
index 89757032409c2..54a06edc5ec1d 100644
--- a/lldb/source/Core/DemangledNameInfo.cpp
+++ b/lldb/source/Core/DemangledNameInfo.cpp
@@ -66,6 +66,20 @@ void TrackingOutputBuffer::finalizeArgumentEnd() {
   NameInfo.ArgumentsRange.second = getCurrentPosition();
 }
 
+void TrackingOutputBuffer::finalizeQualifiersStart() {
+  if (!canFinalize())
+    return;
+
+  NameInfo.QualifiersRange.first = getCurrentPosition();
+}
+
+void TrackingOutputBuffer::finalizeQualifiersEnd() {
+  if (!canFinalize())
+    return;
+
+  NameInfo.QualifiersRange.second = getCurrentPosition();
+}
+
 void TrackingOutputBuffer::finalizeStart() {
   if (!shouldTrack())
     return;
@@ -171,6 +185,8 @@ void TrackingOutputBuffer::printRightImpl(const 
FunctionEncoding &N) {
   if (Ret)
     printRight(*Ret);
 
+  finalizeQualifiersStart();
+
   auto CVQuals = N.getCVQuals();
   auto RefQual = N.getRefQual();
   auto *Attrs = N.getAttrs();
@@ -193,6 +209,7 @@ void TrackingOutputBuffer::printRightImpl(const 
FunctionEncoding &N) {
     Requires->print(*this);
   }
 
+  finalizeQualifiersEnd();
   finalizeEnd();
 }
 

diff  --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index b69be163ca233..ce4db4e0daa8b 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 (IsMangledName(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,26 @@ 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 +185,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 +285,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 +316,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 +478,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/lldb/unittests/Core/MangledTest.cpp 
b/lldb/unittests/Core/MangledTest.cpp
index b039299d032dd..e903cadd410f3 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -321,90 +321,197 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
 }
 
+TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
+  Mangled mangled;
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+
+  mangled.SetMangledName(ConstString("_Z3foov"));
+  ASSERT_TRUE(mangled);
+
+  auto info1 = mangled.GetDemangledInfo();
+  EXPECT_NE(info1, std::nullopt);
+  EXPECT_TRUE(info1->hasBasename());
+
+  mangled.SetMangledName(ConstString("_Z4funcv"));
+
+  // Should have re-calculated demangled-info since mangled name changed.
+  auto info2 = mangled.GetDemangledInfo();
+  ASSERT_NE(info2, std::nullopt);
+  EXPECT_TRUE(info2->hasBasename());
+
+  EXPECT_NE(info1.value(), info2.value());
+  EXPECT_EQ(mangled.GetDemangledName(), "func()");
+}
+
+TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
+  Mangled mangled("_Z3foov");
+  ASSERT_TRUE(mangled);
+
+  mangled.SetDemangledName(ConstString(""));
+
+  // Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
+  // of previously set mangled name.
+  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_EQ(mangled.GetDemangledName(), "foo()");
+}
+
+TEST(MangledTest, DemangledNameInfo_Clear) {
+  Mangled mangled("_Z3foov");
+  ASSERT_TRUE(mangled);
+  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+
+  mangled.Clear();
+
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+}
+
+TEST(MangledTest, DemangledNameInfo_SetValue) {
+  Mangled mangled("_Z4funcv");
+  ASSERT_TRUE(mangled);
+
+  auto demangled_func = mangled.GetDemangledInfo();
+
+  // SetValue(mangled) resets demangled-info
+  mangled.SetValue(ConstString("_Z3foov"));
+  auto demangled_foo = mangled.GetDemangledInfo();
+  EXPECT_NE(demangled_foo, std::nullopt);
+  EXPECT_NE(demangled_foo, demangled_func);
+
+  // SetValue(demangled) resets demangled-info
+  mangled.SetValue(ConstString("_Z4funcv"));
+  EXPECT_EQ(mangled.GetDemangledInfo(), demangled_func);
+
+  // SetValue(empty) resets demangled-info
+  mangled.SetValue(ConstString());
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+
+  // Demangling invalid mangled name will set demangled-info
+  // (without a valid basename).
+  mangled.SetValue(ConstString("_Zinvalid"));
+  ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
+}
+
 struct DemanglingPartsTestCase {
   const char *mangled;
   DemangledNameInfo expected_info;
   std::string_view basename;
   std::string_view scope;
+  std::string_view qualifiers;
   bool valid_basename = true;
 };
 
 DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
     // clang-format off
    { 
"_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
-     { .BasenameRange = {92, 98}, .ScopeRange = {36, 92}, .ArgumentsRange = { 
108, 158 } },
+     { .BasenameRange = {92, 98}, .ScopeRange = {36, 92}, .ArgumentsRange = { 
108, 158 },
+       .QualifiersRange = {158, 176} },
      .basename = "method",
-     .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
+     .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::",
+     .qualifiers = " const volatile &&"
    },
    { "_Z7getFuncIfEPFiiiET_",
-     { .BasenameRange = {6, 13}, .ScopeRange = {6, 6}, .ArgumentsRange = { 20, 
27 } },
+     { .BasenameRange = {6, 13}, .ScopeRange = {6, 6}, .ArgumentsRange = { 20, 
27 }, .QualifiersRange = {38, 38} },
      .basename = "getFunc",
-     .scope = ""
+     .scope = "",
+     .qualifiers = ""
    },
    { "_ZN1f1b1c1gEv",
-     { .BasenameRange = {9, 10}, .ScopeRange = {0, 9}, .ArgumentsRange = { 10, 
12 } },
+     { .BasenameRange = {9, 10}, .ScopeRange = {0, 9}, .ArgumentsRange = { 10, 
12 },
+       .QualifiersRange = {12, 12} },
      .basename = "g",
-     .scope = "f::b::c::"
+     .scope = "f::b::c::",
+     .qualifiers = ""
    },
    { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
-     { .BasenameRange = {45, 48}, .ScopeRange = {38, 45}, .ArgumentsRange = { 
53, 58 } },
+     { .BasenameRange = {45, 48}, .ScopeRange = {38, 45}, .ArgumentsRange = { 
53, 58 },
+       .QualifiersRange = {58, 58} },
      .basename = "fD1",
-     .scope = "test7::"
+     .scope = "test7::",
+     .qualifiers = ""
    },
    { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
-     { .BasenameRange = {61, 64}, .ScopeRange = {54, 61}, .ArgumentsRange = { 
69, 79 } },
+     { .BasenameRange = {61, 64}, .ScopeRange = {54, 61}, .ArgumentsRange = { 
69, 79 },
+       .QualifiersRange = {79, 79} },
      .basename = "fD1",
-     .scope = "test7::"
+     .scope = "test7::",
+     .qualifiers = ""
    },
    { 
"_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
-     { .BasenameRange = {120, 123}, .ScopeRange = {81, 120}, .ArgumentsRange = 
{ 155, 168 } },
+     { .BasenameRange = {120, 123}, .ScopeRange = {81, 120}, .ArgumentsRange = 
{ 155, 168 },
+       .QualifiersRange = {168, 168} },
      .basename = "fD1",
-     .scope = "test7<decltype(c)::d<decltype(c)::d>>::"
+     .scope = "test7<decltype(c)::d<decltype(c)::d>>::",
+     .qualifiers = ""
    },
    { 
"_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",
-     { .BasenameRange = {687, 692}, .ScopeRange = {343, 687}, .ArgumentsRange 
= { 713, 1174 } },
+     { .BasenameRange = {687, 692}, .ScopeRange = {343, 687}, .ArgumentsRange 
= { 713, 1174 },
+       .QualifiersRange = {1174, 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>::"
+     .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>::",
+     .qualifiers = ""
    },
    { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
-     { .BasenameRange = {344, 354}, .ScopeRange = {0, 344}, .ArgumentsRange = 
{ 354, 370 } },
+     { .BasenameRange = {344, 354}, .ScopeRange = {0, 344}, .ArgumentsRange = 
{ 354, 370 },
+       .QualifiersRange = {370, 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>::"
+     .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>::",
+     .qualifiers = ""
    },
    { "_Z3fppIiEPFPFvvEiEf",
-     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 } },
+     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 }, .QualifiersRange = {34,34} },
      .basename = "fpp",
-     .scope = ""
+     .scope = "",
+     .qualifiers = ""
    },
    { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
-     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 } },
+     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 },
+       .QualifiersRange = {43, 43} },
      .basename = "fpp",
-     .scope = ""
+     .scope = "",
+     .qualifiers = ""
    },
    { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
-     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 } },
+     { .BasenameRange = {10, 13}, .ScopeRange = {10, 10}, .ArgumentsRange = { 
18, 25 },
+       .QualifiersRange = {108, 108} },
      .basename = "fpp",
-     .scope = ""
+     .scope = "",
+     .qualifiers = ""
    },
    { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
-     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 } },
+     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 },
+       .QualifiersRange = {88, 88} },
      .basename = "fpp",
-     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     .qualifiers = ""
    },
    { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
-     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 } },
+     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 },
+       .QualifiersRange = {97, 97} },
      .basename = "fpp",
-     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     .qualifiers = "",
    },
    { 
"_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
-     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 } },
+     { .BasenameRange = {64, 67}, .ScopeRange = {10, 64}, .ArgumentsRange = { 
72, 79 },
+       .QualifiersRange = {162, 162} },
      .basename = "fpp",
-     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     .qualifiers = "",
+   },
+   { "_ZNKO2ns3ns23Bar3fooIiEEPFPFNS0_3FooIiEEiENS3_IfEEEi",
+     { .BasenameRange = {37, 40}, .ScopeRange = {23, 37}, .ArgumentsRange = { 
45, 50 },
+       .QualifiersRange = {78, 87} },
+     .basename = "foo",
+     .scope = "ns::ns2::Bar::",
+     .qualifiers = " const &&",
    },
    { "_ZTV11ImageLoader",
-     { .BasenameRange = {0, 0}, .ScopeRange = {0, 0}, .ArgumentsRange = { 0, 0 
} },
+     { .BasenameRange = {0, 0}, .ScopeRange = {0, 0}, .ArgumentsRange = { 0, 0 
},
+       .QualifiersRange = {0, 0} },
      .basename = "",
      .scope = "",
+     .qualifiers = "",
      .valid_basename = false
    }
     // clang-format on
@@ -433,7 +540,8 @@ class TestAllocator {
 } // namespace
 
 TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
-  const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
+  const auto &[mangled, info, basename, scope, qualifiers, valid_basename] =
+      GetParam();
 
   llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
       mangled, mangled + ::strlen(mangled));
@@ -451,6 +559,7 @@ TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
   EXPECT_EQ(OB.NameInfo.BasenameRange, info.BasenameRange);
   EXPECT_EQ(OB.NameInfo.ScopeRange, info.ScopeRange);
   EXPECT_EQ(OB.NameInfo.ArgumentsRange, info.ArgumentsRange);
+  EXPECT_EQ(OB.NameInfo.QualifiersRange, info.QualifiersRange);
 
   auto get_part = [&](const std::pair<size_t, size_t> &loc) {
     return demangled.substr(loc.first, loc.second - loc.first);
@@ -458,6 +567,7 @@ TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
 
   EXPECT_EQ(get_part(OB.NameInfo.BasenameRange), basename);
   EXPECT_EQ(get_part(OB.NameInfo.ScopeRange), scope);
+  EXPECT_EQ(get_part(OB.NameInfo.QualifiersRange), qualifiers);
 }
 
 INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,

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..1009cc91ca12a 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -411,9 +411,7 @@ bool ItaniumPartialDemangler::partialDemangle(const char 
*MangledName) {
   RootNode = Parser->parse();
   return RootNode == nullptr;
 }
-
-static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
-  OutputBuffer OB(Buf, N);
+static char *printNode(const Node *RootNode, OutputBuffer &OB, size_t *N) {
   RootNode->print(OB);
   OB += '\0';
   if (N != nullptr)
@@ -421,6 +419,11 @@ static char *printNode(const Node *RootNode, char *Buf, 
size_t *N) {
   return OB.getBuffer();
 }
 
+static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
+  OutputBuffer OB(Buf, N);
+  return printNode(RootNode, OB, N);
+}
+
 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const 
{
   if (!isFunction())
     return nullptr;
@@ -540,6 +543,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())


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

Reply via email to