[Lldb-commits] [libcxxabi] [lldb] [llvm] [WIP: DO NOT MERGE] [lldb][Format] Add option to highlight function names in backtraces (PR #131836)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Tue Mar 18 09:11:01 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/131836
>From 03a4172a3a4dae7d1ed45570fff66a89e792ca71 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 11 Mar 2025 08:57:13 +0000
Subject: [PATCH 1/4] [llvm][ItaniumDemangle] Add function name location
tracking
---
libcxxabi/src/demangle/ItaniumDemangle.h | 20 +++
libcxxabi/src/demangle/Utility.h | 163 ++++++++++++++++--
llvm/include/llvm/Demangle/ItaniumDemangle.h | 20 +++
llvm/include/llvm/Demangle/Utility.h | 163 ++++++++++++++++--
.../Demangle/ItaniumDemangleTest.cpp | 105 +++++++++++
5 files changed, 439 insertions(+), 32 deletions(-)
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3df41b5f4d7d0..d3cd1e4a405a6 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -851,11 +851,13 @@ 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 {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
Ret->printLeft(OB);
OB += " ";
}
void printRight(OutputBuffer &OB) const override {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
@@ -976,13 +978,26 @@ class FunctionEncoding final : public Node {
if (!Ret->hasRHSComponent(OB))
OB += " ";
}
+
+ // Nested FunctionEncoding parsing can happen with following productions:
+ // * <local-name>
+ // * <expr-primary>
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
+ OB.FunctionInfo.updateScopeStart(OB);
+
Name->print(OB);
}
void printRight(OutputBuffer &OB) const override {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
+ OB.FunctionInfo.finalizeStart(OB);
+
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+
+ OB.FunctionInfo.finalizeArgumentEnd(OB);
+
if (Ret)
Ret->printRight(OB);
@@ -1005,6 +1020,8 @@ class FunctionEncoding final : public Node {
OB += " requires ";
Requires->print(OB);
}
+
+ OB.FunctionInfo.finalizeEnd(OB);
}
};
@@ -1072,7 +1089,9 @@ struct NestedName : Node {
void printLeft(OutputBuffer &OB) const override {
Qual->print(OB);
OB += "::";
+ OB.FunctionInfo.updateScopeEnd(OB);
Name->print(OB);
+ OB.FunctionInfo.updateBasenameEnd(OB);
}
};
@@ -1633,6 +1652,7 @@ struct NameWithTemplateArgs : Node {
void printLeft(OutputBuffer &OB) const override {
Name->print(OB);
+ OB.FunctionInfo.updateBasenameEnd(OB);
TemplateArgs->print(OB);
}
};
diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h
index f1fad35d60d98..3bfdf8dff4526 100644
--- a/libcxxabi/src/demangle/Utility.h
+++ b/libcxxabi/src/demangle/Utility.h
@@ -27,6 +27,22 @@
DEMANGLE_NAMESPACE_BEGIN
+template <class T> class ScopedOverride {
+ T &Loc;
+ T Original;
+
+public:
+ ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+ ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+ Loc_ = std::move(NewVal);
+ }
+ ~ScopedOverride() { Loc = std::move(Original); }
+
+ ScopedOverride(const ScopedOverride &) = delete;
+ ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
@@ -83,6 +99,127 @@ class OutputBuffer {
return std::string_view(Buffer, CurrentPosition);
}
+ // Stores information about parts of a demangled function name.
+ struct FunctionNameInfo {
+ ///< 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 { return ArgumentLocs.first > 0; }
+
+ bool shouldTrack(OutputBuffer &OB) const {
+ if (OB.isPrintingNestedFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (startedPrintingArguments())
+ return false;
+
+ return true;
+ }
+
+ bool canFinalize(OutputBuffer &OB) const {
+ if (OB.isPrintingNestedFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (!startedPrintingArguments())
+ return false;
+
+ return true;
+ }
+
+ void updateBasenameEnd(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ BasenameLocs.second = OB.getCurrentPosition();
+ }
+
+ void updateScopeStart(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.first = OB.getCurrentPosition();
+ }
+
+ void updateScopeEnd(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.second = OB.getCurrentPosition();
+ }
+
+ void finalizeArgumentEnd(OutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+ }
+
+ void finalizeStart(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ OB.FunctionInfo.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.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+ DEMANGLE_ASSERT(!shouldTrack(OB), "");
+ DEMANGLE_ASSERT(canFinalize(OB), "");
+ }
+
+ void finalizeEnd(OutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+ ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+ BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+ }
+
+ ScopedOverride<unsigned> enterFunctionTypePrinting(OutputBuffer &OB) {
+ return {OB.FunctionPrintingDepth, OB.FunctionPrintingDepth + 1};
+ }
+
+ bool hasBasename() const {
+ return BasenameLocs.first != BasenameLocs.second &&
+ BasenameLocs.second > 0;
+ }
+ };
+
/// 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();
@@ -92,8 +229,18 @@ class OutputBuffer {
/// Use a counter so we can simply increment inside parentheses.
unsigned GtIsGt = 1;
+ ///< When a function type is being printed this value is incremented.
+ ///< When printing of the type is finished the value is decremented.
+ unsigned FunctionPrintingDepth = 0;
+
+ FunctionNameInfo FunctionInfo;
+
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
+ bool isPrintingNestedFunctionType() const {
+ return FunctionPrintingDepth != 1;
+ }
+
void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
@@ -182,22 +329,6 @@ class OutputBuffer {
size_t getBufferCapacity() const { return BufferCapacity; }
};
-template <class T> class ScopedOverride {
- T &Loc;
- T Original;
-
-public:
- ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
- ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
- Loc_ = std::move(NewVal);
- }
- ~ScopedOverride() { Loc = std::move(Original); }
-
- ScopedOverride(const ScopedOverride &) = delete;
- ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
DEMANGLE_NAMESPACE_END
#endif
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index b0363c1a7a786..4d8ee4484ce93 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -851,11 +851,13 @@ 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 {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
Ret->printLeft(OB);
OB += " ";
}
void printRight(OutputBuffer &OB) const override {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
@@ -976,13 +978,26 @@ class FunctionEncoding final : public Node {
if (!Ret->hasRHSComponent(OB))
OB += " ";
}
+
+ // Nested FunctionEncoding parsing can happen with following productions:
+ // * <local-name>
+ // * <expr-primary>
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
+ OB.FunctionInfo.updateScopeStart(OB);
+
Name->print(OB);
}
void printRight(OutputBuffer &OB) const override {
+ auto Scoped = OB.FunctionInfo.enterFunctionTypePrinting(OB);
+ OB.FunctionInfo.finalizeStart(OB);
+
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+
+ OB.FunctionInfo.finalizeArgumentEnd(OB);
+
if (Ret)
Ret->printRight(OB);
@@ -1005,6 +1020,8 @@ class FunctionEncoding final : public Node {
OB += " requires ";
Requires->print(OB);
}
+
+ OB.FunctionInfo.finalizeEnd(OB);
}
};
@@ -1072,7 +1089,9 @@ struct NestedName : Node {
void printLeft(OutputBuffer &OB) const override {
Qual->print(OB);
OB += "::";
+ OB.FunctionInfo.updateScopeEnd(OB);
Name->print(OB);
+ OB.FunctionInfo.updateBasenameEnd(OB);
}
};
@@ -1633,6 +1652,7 @@ struct NameWithTemplateArgs : Node {
void printLeft(OutputBuffer &OB) const override {
Name->print(OB);
+ OB.FunctionInfo.updateBasenameEnd(OB);
TemplateArgs->print(OB);
}
};
diff --git a/llvm/include/llvm/Demangle/Utility.h b/llvm/include/llvm/Demangle/Utility.h
index e893cceea2cdc..18adcabae5b2c 100644
--- a/llvm/include/llvm/Demangle/Utility.h
+++ b/llvm/include/llvm/Demangle/Utility.h
@@ -27,6 +27,22 @@
DEMANGLE_NAMESPACE_BEGIN
+template <class T> class ScopedOverride {
+ T &Loc;
+ T Original;
+
+public:
+ ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+ ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+ Loc_ = std::move(NewVal);
+ }
+ ~ScopedOverride() { Loc = std::move(Original); }
+
+ ScopedOverride(const ScopedOverride &) = delete;
+ ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
@@ -83,6 +99,127 @@ class OutputBuffer {
return std::string_view(Buffer, CurrentPosition);
}
+ // Stores information about parts of a demangled function name.
+ struct FunctionNameInfo {
+ ///< 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 { return ArgumentLocs.first > 0; }
+
+ bool shouldTrack(OutputBuffer &OB) const {
+ if (OB.isPrintingNestedFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (startedPrintingArguments())
+ return false;
+
+ return true;
+ }
+
+ bool canFinalize(OutputBuffer &OB) const {
+ if (OB.isPrintingNestedFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (!startedPrintingArguments())
+ return false;
+
+ return true;
+ }
+
+ void updateBasenameEnd(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ BasenameLocs.second = OB.getCurrentPosition();
+ }
+
+ void updateScopeStart(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.first = OB.getCurrentPosition();
+ }
+
+ void updateScopeEnd(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.second = OB.getCurrentPosition();
+ }
+
+ void finalizeArgumentEnd(OutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+ }
+
+ void finalizeStart(OutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ OB.FunctionInfo.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.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+ DEMANGLE_ASSERT(!shouldTrack(OB), "");
+ DEMANGLE_ASSERT(canFinalize(OB), "");
+ }
+
+ void finalizeEnd(OutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+ ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+ BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+ }
+
+ ScopedOverride<unsigned> enterFunctionTypePrinting(OutputBuffer &OB) {
+ return {OB.FunctionPrintingDepth, OB.FunctionPrintingDepth + 1};
+ }
+
+ bool hasBasename() const {
+ return BasenameLocs.first != BasenameLocs.second &&
+ BasenameLocs.second > 0;
+ }
+ };
+
/// 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();
@@ -92,8 +229,18 @@ class OutputBuffer {
/// Use a counter so we can simply increment inside parentheses.
unsigned GtIsGt = 1;
+ ///< When a function type is being printed this value is incremented.
+ ///< When printing of the type is finished the value is decremented.
+ unsigned FunctionPrintingDepth = 0;
+
+ FunctionNameInfo FunctionInfo;
+
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
+ bool isPrintingNestedFunctionType() const {
+ return FunctionPrintingDepth != 1;
+ }
+
void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
@@ -182,22 +329,6 @@ class OutputBuffer {
size_t getBufferCapacity() const { return BufferCapacity; }
};
-template <class T> class ScopedOverride {
- T &Loc;
- T Original;
-
-public:
- ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
- ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
- Loc_ = std::move(NewVal);
- }
- ~ScopedOverride() { Loc = std::move(Original); }
-
- ScopedOverride(const ScopedOverride &) = delete;
- ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
DEMANGLE_NAMESPACE_END
#endif
diff --git a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
index bc6ccc2e16e65..07c10aad11987 100644
--- a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
+++ b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
@@ -114,3 +114,108 @@ TEST(ItaniumDemangle, HalfType) {
ASSERT_NE(nullptr, Parser.parse());
EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16"));
}
+
+struct DemanglingPartsTestCase {
+ const char *mangled;
+ itanium_demangle::OutputBuffer::FunctionNameInfo expected_info;
+ llvm::StringRef basename;
+ llvm::StringRef scope;
+};
+
+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::"
+ },
+ { "_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>>::"
+ }
+ // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+ : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+ const auto &[mangled, info, basename, scope] = GetParam();
+
+ ManglingParser<TestAllocator> Parser(mangled, mangled + ::strlen(mangled));
+
+ const auto *Root = Parser.parse();
+
+ ASSERT_NE(nullptr, Root);
+
+ OutputBuffer OB;
+ Root->print(OB);
+ auto demangled = toString(OB);
+
+ ASSERT_TRUE(OB.FunctionInfo.hasBasename());
+
+ 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 02bc0b4f5fc2112018c9799f9ed5dbe2cc3f7032 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 10 Mar 2025 15:39:10 +0000
Subject: [PATCH 2/4] [lldb][Mangled] Add API to force re-demangling a Mangled
object
---
lldb/include/lldb/Core/Mangled.h | 6 ++++++
lldb/source/Core/Mangled.cpp | 11 ++++++++---
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
index 9ca28917ccffa..2abaa9a31d3f2 100644
--- a/lldb/include/lldb/Core/Mangled.h
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -276,6 +276,12 @@ class Mangled {
void Encode(DataEncoder &encoder, ConstStringTable &strtab) 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
+ ///< 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;
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 842c4ff646a67aa62c4b89f9da1a1ac2dafc74ae Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 18 Mar 2025 14:02:17 +0000
Subject: [PATCH 3/4] [lldb][Mangled] Retrieve and cache demangled name info
---
lldb/include/lldb/Core/Mangled.h | 10 ++++++++-
lldb/include/lldb/Symbol/Function.h | 2 ++
lldb/source/Core/Mangled.cpp | 32 +++++++++++++++++++++++----
lldb/source/Symbol/Function.cpp | 4 ++++
llvm/include/llvm/Demangle/Demangle.h | 1 +
llvm/lib/Demangle/ItaniumDemangle.cpp | 15 +++++++++++++
6 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/lldb/include/lldb/Core/Mangled.h b/lldb/include/lldb/Core/Mangled.h
index 2abaa9a31d3f2..b5f31b2072330 100644
--- a/lldb/include/lldb/Core/Mangled.h
+++ b/lldb/include/lldb/Core/Mangled.h
@@ -9,11 +9,12 @@
#ifndef LLDB_CORE_MANGLED_H
#define LLDB_CORE_MANGLED_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 "llvm/Demangle/Utility.h"
#include <cstddef>
#include <memory>
@@ -275,6 +276,10 @@ class Mangled {
/// table offsets in the cache data.
void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
+ using DemangledInfo = llvm::itanium_demangle::OutputBuffer::FunctionNameInfo;
+
+ const DemangledInfo &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 +293,9 @@ class Mangled {
///< Mutable so we can get it on demand with
///< a const version of this object.
mutable ConstString m_demangled;
+
+ // TODO: should this be an optional?
+ mutable DemangledInfo m_demangled_info;
};
Stream &operator<<(Stream &s, const Mangled &obj);
diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h
index ee3a8304fc5b3..30267b714e8ab 100644
--- a/lldb/include/lldb/Symbol/Function.h
+++ b/lldb/include/lldb/Symbol/Function.h
@@ -534,6 +534,8 @@ class Function : public UserID, public SymbolContextScope {
ConstString GetDisplayName() const;
+ Mangled::DemangledInfo GetDemangledInfo() const;
+
const Mangled &GetMangled() const { return m_mangled; }
/// Get the DeclContext for this function, if available.
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index db5aff40d34d3..c3504967f206a 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Demangle/Utility.h"
#include "llvm/Support/Compiler.h"
#include <mutex>
@@ -152,16 +153,21 @@ static char *GetMSVCDemangledStr(llvm::StringRef M) {
return demangled_cstr;
}
-static char *GetItaniumDemangledStr(const char *M) {
+static std::pair<char *, Mangled::DemangledInfo>
+GetItaniumDemangledStr(const char *M) {
char *demangled_cstr = nullptr;
+ Mangled::DemangledInfo info;
llvm::ItaniumPartialDemangler ipd;
bool err = ipd.partialDemangle(M);
if (!err) {
// Default buffer and size (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);
+
+ llvm::itanium_demangle::OutputBuffer OB(demangled_cstr, demangled_size);
+ demangled_cstr = ipd.finishDemangle(&OB, &demangled_size);
+ info = std::move(OB.FunctionInfo);
assert(demangled_cstr &&
"finishDemangle must always succeed if partialDemangle did");
@@ -174,9 +180,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 +280,16 @@ ConstString Mangled::GetDemangledName() const {
return GetDemangledNameImpl(/*force=*/false);
}
+const Mangled::DemangledInfo &Mangled::GetDemangledInfo() const {
+ // TODO: if setting m_demangled_info previously failed
+ // we still end up re-demangling. If m_demangled_info
+ // was an optional we could prevent that.
+ if (!m_demangled_info.hasBasename())
+ 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 +314,10 @@ ConstString Mangled::GetDemangledNameImpl(bool force) const {
demangled_name = GetMSVCDemangledStr(m_mangled);
break;
case eManglingSchemeItanium: {
- demangled_name = GetItaniumDemangledStr(m_mangled.GetCString());
+ std::pair<char *, Mangled::DemangledInfo> demangled =
+ GetItaniumDemangledStr(m_mangled.GetCString());
+ demangled_name = demangled.first;
+ m_demangled_info = std::move(demangled.second);
break;
}
case eManglingSchemeRustV0:
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
index c80f37ae68d9d..9a02d33f174c6 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);
}
+
+Mangled::DemangledInfo Function::GetDemangledInfo() const {
+ return m_mangled.GetDemangledInfo();
+}
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index 132e5088b5514..888ad60af34bf 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -92,6 +92,7 @@ struct ItaniumPartialDemangler {
/// Just print the entire mangled name into Buf. Buf and N behave like the
/// second and third parameters to __cxa_demangle.
char *finishDemangle(char *Buf, size_t *N) const;
+ char *finishDemangle(void *OB, size_t *N) const;
/// Get the base name of a function. This doesn't include trailing template
/// arguments, ie for "a::b<int>" this function returns "b".
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 5c21b06a1d095..544ab67faad45 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,13 @@ char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
return printNode(static_cast<Node *>(RootNode), Buf, N);
}
+char *ItaniumPartialDemangler::finishDemangle(void *OB, size_t *N) 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);
+}
+
bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
assert(RootNode != nullptr && "must call partialDemangle()");
if (!isFunction())
>From d262063e42750a8da6b93c6207ef63db3b10d413 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 18 Mar 2025 14:02:51 +0000
Subject: [PATCH 4/4] [lldb][Format] Add new function basename highlight option
to FormatEntity
---
lldb/include/lldb/Core/FormatEntity.h | 16 +++++
lldb/include/lldb/Target/Language.h | 9 +--
lldb/source/Core/FormatEntity.cpp | 67 ++++++++++++++++++-
.../Language/CPlusPlus/CPlusPlusLanguage.cpp | 45 ++++++++++++-
.../Language/CPlusPlus/CPlusPlusLanguage.h | 9 +--
lldb/source/Target/Language.cpp | 8 +--
6 files changed, 136 insertions(+), 18 deletions(-)
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/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..cf0f632912f25 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -178,7 +178,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 +208,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 Mangled::DemangledInfo &demangled_info,
+ const FormatEntity::Entry::HighlightSettings &settings) {
+ if (settings.kind == FormatEntity::Entry::HighlightSettings::Kind::None ||
+ !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 +1735,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
@@ -1738,7 +1775,9 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
args);
if (args.GetSize() > 0) {
- if (!PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args))
+ if (!PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args,
+ sc->function->GetDemangledInfo(),
+ settings))
return false;
} else {
s.PutCString(cstr);
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/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;
}
More information about the lldb-commits
mailing list