[llvm] a267225 - [lldb][Mangled] Retrieve and cache demangled name info (#131836)
Michael Buch via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 25 02:05:05 PDT 2025
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())
More information about the llvm-commits
mailing list