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