[libcxxabi] [lldb] [llvm] [WIP] [ItaniumDemangle] Add infrastructure to track location information of parts of a demangled function name (PR #133249)
Michael Buch via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 8 06:36:52 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/133249
>From 5183ff468fc31c754f1e26c792384f9c5fd9c19c 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] [llvm][ItaniumDemangle] Add function name location tracking
---
libcxxabi/src/demangle/ItaniumDemangle.h | 64 +++---
libcxxabi/src/demangle/Utility.h | 7 +
lldb/include/lldb/Core/Demangle.h | 90 ++++++++
lldb/source/Core/CMakeLists.txt | 1 +
lldb/source/Core/Demangle.cpp | 221 +++++++++++++++++++
lldb/unittests/Core/MangledTest.cpp | 143 ++++++++++++
llvm/include/llvm/Demangle/ItaniumDemangle.h | 64 +++---
llvm/include/llvm/Demangle/Utility.h | 7 +
8 files changed, 541 insertions(+), 56 deletions(-)
create mode 100644 lldb/include/lldb/Core/Demangle.h
create mode 100644 lldb/source/Core/Demangle.cpp
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3df41b5f4d7d0..89a24def830f2 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
}
void print(OutputBuffer &OB) const {
- printLeft(OB);
+ OB.printLeft(*this);
if (RHSComponentCache != Cache::No)
- printRight(OB);
+ OB.printRight(*this);
}
// Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
}
void printLeft(OutputBuffer &OB) const override {
- Child->printLeft(OB);
+ OB.printLeft(*Child);
printQuals(OB);
}
- void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+ void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
};
class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
void printLeft(OutputBuffer &OB) const override {
- Ty->printLeft(OB);
+ OB.printLeft(*Ty);
OB += Postfix;
}
};
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
std::string_view getBaseName() const override { return Base->getBaseName(); }
void printLeft(OutputBuffer &OB) const override {
- Base->printLeft(OB);
+ OB.printLeft(*Base);
OB += "[abi:";
OB += Tag;
OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
- Pointee->printLeft(OB);
+ OB.printLeft(*Pointee);
if (Pointee->hasArray(OB))
OB += " ";
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
OB += ")";
- Pointee->printRight(OB);
+ OB.printRight(*Pointee);
}
}
};
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
if (!Collapsed.second)
return;
- Collapsed.second->printLeft(OB);
+ OB.printLeft(*Collapsed.second);
if (Collapsed.second->hasArray(OB))
OB += " ";
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
return;
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
OB += ")";
- Collapsed.second->printRight(OB);
+ OB.printRight(*Collapsed.second);
}
};
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
}
void printLeft(OutputBuffer &OB) const override {
- MemberType->printLeft(OB);
+ OB.printLeft(*MemberType);
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += "(";
else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
void printRight(OutputBuffer &OB) const override {
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += ")";
- MemberType->printRight(OB);
+ OB.printRight(*MemberType);
}
};
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasArraySlow(OutputBuffer &) const override { return true; }
- void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+ void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
void printRight(OutputBuffer &OB) const override {
if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
if (Dimension)
Dimension->print(OB);
OB += "]";
- Base->printRight(OB);
+ OB.printRight(*Base);
}
bool printInitListAsType(OutputBuffer &OB,
@@ -851,7 +851,7 @@ class FunctionType final : public Node {
// by printing out the return types's left, then print our parameters, then
// finally print right of the return type.
void printLeft(OutputBuffer &OB) const override {
- Ret->printLeft(OB);
+ OB.printLeft(*Ret);
OB += " ";
}
@@ -859,7 +859,7 @@ class FunctionType final : public Node {
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
- Ret->printRight(OB);
+ OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@@ -964,6 +964,8 @@ class FunctionEncoding final : public Node {
FunctionRefQual getRefQual() const { return RefQual; }
NodeArray getParams() const { return Params; }
const Node *getReturnType() const { return Ret; }
+ const Node *getAttrs() const { return Attrs; }
+ const Node *getRequires() const { return Requires; }
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -972,10 +974,11 @@ class FunctionEncoding final : public Node {
void printLeft(OutputBuffer &OB) const override {
if (Ret) {
- Ret->printLeft(OB);
+ OB.printLeft(*Ret);
if (!Ret->hasRHSComponent(OB))
OB += " ";
}
+
Name->print(OB);
}
@@ -983,8 +986,9 @@ class FunctionEncoding final : public Node {
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+
if (Ret)
- Ret->printRight(OB);
+ OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@@ -1324,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
template<typename Fn> void match(Fn F) const { F(Name, Type); }
void printLeft(OutputBuffer &OB) const override {
- Type->printLeft(OB);
+ OB.printLeft(*Type);
if (!Type->hasRHSComponent(OB))
OB += " ";
}
void printRight(OutputBuffer &OB) const override {
Name->print(OB);
- Type->printRight(OB);
+ OB.printRight(*Type);
}
};
@@ -1376,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
template<typename Fn> void match(Fn F) const { F(Param); }
void printLeft(OutputBuffer &OB) const override {
- Param->printLeft(OB);
+ OB.printLeft(*Param);
OB += "...";
}
- void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+ void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
};
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1445,13 +1449,13 @@ class ParameterPack final : public Node {
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printLeft(OB);
+ OB.printLeft(*Data[Idx]);
}
void printRight(OutputBuffer &OB) const override {
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printRight(OB);
+ OB.printRight(*Data[Idx]);
}
};
@@ -1609,13 +1613,13 @@ struct ForwardTemplateReference : Node {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
- Ref->printLeft(OB);
+ OB.printLeft(*Ref);
}
void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
- Ref->printRight(OB);
+ OB.printRight(*Ref);
}
};
@@ -1767,7 +1771,7 @@ class DtorName : public Node {
void printLeft(OutputBuffer &OB) const override {
OB += "~";
- Base->printLeft(OB);
+ OB.printLeft(*Base);
}
};
@@ -2047,7 +2051,7 @@ class CastExpr : public Node {
{
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "<";
- To->printLeft(OB);
+ OB.printLeft(*To);
OB += ">";
}
OB.printOpen();
@@ -6176,6 +6180,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
Alloc>::AbstractManglingParser;
};
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
DEMANGLE_NAMESPACE_END
#if defined(__clang__)
diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h
index f1fad35d60d98..a38bef762dd57 100644
--- a/libcxxabi/src/demangle/Utility.h
+++ b/libcxxabi/src/demangle/Utility.h
@@ -27,6 +27,8 @@
DEMANGLE_NAMESPACE_BEGIN
+class Node;
+
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
@@ -79,10 +81,15 @@ class OutputBuffer {
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
+ virtual ~OutputBuffer() {}
+
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
}
+ virtual void printLeft(const Node &N);
+ virtual void printRight(const Node &N);
+
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
diff --git a/lldb/include/lldb/Core/Demangle.h b/lldb/include/lldb/Core/Demangle.h
new file mode 100644
index 0000000000000..27f0cacbdd48f
--- /dev/null
+++ b/lldb/include/lldb/Core/Demangle.h
@@ -0,0 +1,90 @@
+//===-- Demangle.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_DEMANGLE_H
+#define LLDB_CORE_DEMANGLE_H
+
+#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <cstddef>
+#include <utility>
+
+namespace lldb_private {
+
+struct TrackingOutputBuffer;
+
+// Stores information about parts of a demangled function name.
+struct 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;
+ bool shouldTrack(TrackingOutputBuffer &OB) const;
+ bool canFinalize(TrackingOutputBuffer &OB) const;
+ void updateBasenameEnd(TrackingOutputBuffer &OB);
+ void updateScopeStart(TrackingOutputBuffer &OB);
+ void updateScopeEnd(TrackingOutputBuffer &OB);
+ void finalizeArgumentEnd(TrackingOutputBuffer &OB);
+ void finalizeStart(TrackingOutputBuffer &OB);
+ void finalizeEnd(TrackingOutputBuffer &OB);
+ bool hasBasename() const;
+};
+
+struct TrackingOutputBuffer : public llvm::itanium_demangle::OutputBuffer {
+ using OutputBuffer::OutputBuffer;
+
+ FunctionNameInfo FunctionInfo;
+ unsigned FunctionPrintingDepth = 0;
+
+ [[nodiscard]] llvm::itanium_demangle::ScopedOverride<unsigned>
+ enterFunctionTypePrinting();
+
+ bool isPrintingTopLevelFunctionType() const;
+
+ void printLeft(const llvm::itanium_demangle::Node &N) override;
+ void printRight(const llvm::itanium_demangle::Node &N) override;
+
+private:
+ void printLeftImpl(const llvm::itanium_demangle::FunctionType &N);
+ void printRightImpl(const llvm::itanium_demangle::FunctionType &N);
+
+ void printLeftImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+ void printRightImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+
+ void printLeftImpl(const llvm::itanium_demangle::NestedName &N);
+ void printLeftImpl(const llvm::itanium_demangle::NameWithTemplateArgs &N);
+};
+} // namespace lldb_private
+
+#endif // LLDB_CORE_DEMANGLE_H
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index 0a08da0fec230..1882a3886174b 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -28,6 +28,7 @@ add_lldb_library(lldbCore
Debugger.cpp
DebuggerEvents.cpp
Declaration.cpp
+ Demangle.cpp
Disassembler.cpp
DumpDataExtractor.cpp
DumpRegisterValue.cpp
diff --git a/lldb/source/Core/Demangle.cpp b/lldb/source/Core/Demangle.cpp
new file mode 100644
index 0000000000000..122e006409816
--- /dev/null
+++ b/lldb/source/Core/Demangle.cpp
@@ -0,0 +1,221 @@
+//===-- Demangle.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Demangle.h"
+
+using namespace llvm::itanium_demangle;
+
+namespace lldb_private {
+
+bool FunctionNameInfo::startedPrintingArguments() const {
+ return ArgumentLocs.first > 0;
+}
+
+bool FunctionNameInfo::shouldTrack(TrackingOutputBuffer &OB) const {
+ if (!OB.isPrintingTopLevelFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (startedPrintingArguments())
+ return false;
+
+ return true;
+}
+
+bool FunctionNameInfo::canFinalize(TrackingOutputBuffer &OB) const {
+ if (!OB.isPrintingTopLevelFunctionType())
+ return false;
+
+ if (OB.isGtInsideTemplateArgs())
+ return false;
+
+ if (!startedPrintingArguments())
+ return false;
+
+ return true;
+}
+
+void FunctionNameInfo::updateBasenameEnd(TrackingOutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ BasenameLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeStart(TrackingOutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.first = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeEnd(TrackingOutputBuffer &OB) {
+ if (!shouldTrack(OB))
+ return;
+
+ ScopeLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeArgumentEnd(TrackingOutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeStart(TrackingOutputBuffer &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 FunctionNameInfo::finalizeEnd(TrackingOutputBuffer &OB) {
+ if (!canFinalize(OB))
+ return;
+
+ if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+ ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+ BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+}
+
+bool FunctionNameInfo::hasBasename() const {
+ return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
+}
+
+ScopedOverride<unsigned> TrackingOutputBuffer::enterFunctionTypePrinting() {
+ return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
+}
+
+bool TrackingOutputBuffer::isPrintingTopLevelFunctionType() const {
+ return FunctionPrintingDepth == 1;
+}
+
+void TrackingOutputBuffer::printLeft(const Node &N) {
+ switch (N.getKind()) {
+ case Node::KFunctionType:
+ printLeftImpl(static_cast<const FunctionType &>(N));
+ break;
+ case Node::KFunctionEncoding:
+ printLeftImpl(static_cast<const FunctionEncoding &>(N));
+ break;
+ case Node::KNestedName:
+ printLeftImpl(static_cast<const NestedName &>(N));
+ break;
+ case Node::KNameWithTemplateArgs:
+ printLeftImpl(static_cast<const NameWithTemplateArgs &>(N));
+ break;
+ default:
+ N.printLeft(*this);
+ }
+}
+
+void TrackingOutputBuffer::printRight(const Node &N) {
+ switch (N.getKind()) {
+ case Node::KFunctionType:
+ printRightImpl(static_cast<const FunctionType &>(N));
+ break;
+ case Node::KFunctionEncoding:
+ printRightImpl(static_cast<const FunctionEncoding &>(N));
+ break;
+ default:
+ N.printRight(*this);
+ }
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionType &N) {
+ auto Scoped = enterFunctionTypePrinting();
+ N.printLeft(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionType &N) {
+ auto Scoped = enterFunctionTypePrinting();
+ N.printRight(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionEncoding &N) {
+ auto Scoped = enterFunctionTypePrinting();
+
+ const Node *Ret = N.getReturnType();
+ if (Ret) {
+ printLeft(*Ret);
+ if (!Ret->hasRHSComponent(*this))
+ *this += " ";
+ }
+
+ FunctionInfo.updateScopeStart(*this);
+
+ N.getName()->print(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionEncoding &N) {
+ auto Scoped = enterFunctionTypePrinting();
+ FunctionInfo.finalizeStart(*this);
+
+ printOpen();
+ N.getParams().printWithComma(*this);
+ printClose();
+
+ FunctionInfo.finalizeArgumentEnd(*this);
+
+ const Node *Ret = N.getReturnType();
+
+ if (Ret)
+ printRight(*Ret);
+
+ auto CVQuals = N.getCVQuals();
+ auto RefQual = N.getRefQual();
+ auto *Attrs = N.getAttrs();
+ auto *Requires = N.getRequires();
+
+ if (CVQuals & QualConst)
+ *this += " const";
+ if (CVQuals & QualVolatile)
+ *this += " volatile";
+ if (CVQuals & QualRestrict)
+ *this += " restrict";
+ if (RefQual == FrefQualLValue)
+ *this += " &";
+ else if (RefQual == FrefQualRValue)
+ *this += " &&";
+ if (Attrs != nullptr)
+ Attrs->print(*this);
+ if (Requires != nullptr) {
+ *this += " requires ";
+ Requires->print(*this);
+ }
+
+ FunctionInfo.finalizeEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NestedName &N) {
+ N.Qual->print(*this);
+ *this += "::";
+ FunctionInfo.updateScopeEnd(*this);
+ N.Name->print(*this);
+ FunctionInfo.updateBasenameEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NameWithTemplateArgs &N) {
+ N.Name->print(*this);
+ FunctionInfo.updateBasenameEnd(*this);
+ N.TemplateArgs->print(*this);
+}
+
+} // namespace lldb_private
diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp
index a3760ba43b3c9..2f4e1755a4074 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -11,6 +11,7 @@
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/Demangle.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -319,3 +320,145 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
}
+
+struct DemanglingPartsTestCase {
+ const char *mangled;
+ FunctionNameInfo expected_info;
+ std::string_view basename;
+ std::string_view scope;
+ bool valid_basename = true;
+};
+
+DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+ // clang-format off
+ { "_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
+ { .BasenameLocs = {92, 98}, .ScopeLocs = {36, 92}, .ArgumentLocs = { 108, 158 } },
+ .basename = "method",
+ .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
+ },
+ { "_Z7getFuncIfEPFiiiET_",
+ { .BasenameLocs = {6, 13}, .ScopeLocs = {6, 6}, .ArgumentLocs = { 20, 27 } },
+ .basename = "getFunc",
+ .scope = ""
+ },
+ { "_ZN1f1b1c1gEv",
+ { .BasenameLocs = {9, 10}, .ScopeLocs = {0, 9}, .ArgumentLocs = { 10, 12 } },
+ .basename = "g",
+ .scope = "f::b::c::"
+ },
+ { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
+ { .BasenameLocs = {45, 48}, .ScopeLocs = {38, 45}, .ArgumentLocs = { 53, 58 } },
+ .basename = "fD1",
+ .scope = "test7::"
+ },
+ { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+ { .BasenameLocs = {61, 64}, .ScopeLocs = {54, 61}, .ArgumentLocs = { 69, 79 } },
+ .basename = "fD1",
+ .scope = "test7::"
+ },
+ { "_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+ { .BasenameLocs = {120, 123}, .ScopeLocs = {81, 120}, .ArgumentLocs = { 155, 168 } },
+ .basename = "fD1",
+ .scope = "test7<decltype(c)::d<decltype(c)::d>>::"
+ },
+ { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
+ { .BasenameLocs = {687, 692}, .ScopeLocs = {343, 687}, .ArgumentLocs = { 713, 1174 } },
+ .basename = "parse",
+ .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+ },
+ { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
+ { .BasenameLocs = {344, 354}, .ScopeLocs = {0, 344}, .ArgumentLocs = { 354, 370 } },
+ .basename = "basic_json",
+ .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+ },
+ { "_Z3fppIiEPFPFvvEiEf",
+ { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 25 } },
+ .basename = "fpp",
+ .scope = ""
+ },
+ { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
+ { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 25 } },
+ .basename = "fpp",
+ .scope = ""
+ },
+ { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
+ { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 25 } },
+ .basename = "fpp",
+ .scope = ""
+ },
+ { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
+ { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 79 } },
+ .basename = "fpp",
+ .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+ },
+ { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
+ { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 79 } },
+ .basename = "fpp",
+ .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+ },
+ { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
+ { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 79 } },
+ .basename = "fpp",
+ .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+ },
+ { "_ZTV11ImageLoader",
+ { .BasenameLocs = {0, 0}, .ScopeLocs = {0, 0}, .ArgumentLocs = { 0, 0 } },
+ .basename = "",
+ .scope = "",
+ .valid_basename = false
+ }
+ // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+ : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+namespace {
+class TestAllocator {
+ llvm::BumpPtrAllocator Alloc;
+
+public:
+ void reset() { Alloc.Reset(); }
+
+ template <typename T, typename... Args> T *makeNode(Args &&...args) {
+ return new (Alloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+ alignof(llvm::itanium_demangle::Node *));
+ }
+};
+} // namespace
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+ const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
+
+ llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
+ mangled, mangled + ::strlen(mangled));
+
+ const auto *Root = Parser.parse();
+
+ ASSERT_NE(nullptr, Root);
+
+ TrackingOutputBuffer OB;
+ Root->print(OB);
+ auto demangled = std::string_view(OB);
+
+ ASSERT_EQ(OB.FunctionInfo.hasBasename(), valid_basename);
+
+ EXPECT_EQ(OB.FunctionInfo.BasenameLocs, info.BasenameLocs);
+ EXPECT_EQ(OB.FunctionInfo.ScopeLocs, info.ScopeLocs);
+ EXPECT_EQ(OB.FunctionInfo.ArgumentLocs, info.ArgumentLocs);
+
+ auto get_part = [&](const std::pair<size_t, size_t> &loc) {
+ return demangled.substr(loc.first, loc.second - loc.first);
+ };
+
+ EXPECT_EQ(get_part(OB.FunctionInfo.BasenameLocs), basename);
+ EXPECT_EQ(get_part(OB.FunctionInfo.ScopeLocs), scope);
+}
+
+INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
+ ::testing::ValuesIn(g_demangling_parts_test_cases));
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index b0363c1a7a786..aab45f351e070 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
}
void print(OutputBuffer &OB) const {
- printLeft(OB);
+ OB.printLeft(*this);
if (RHSComponentCache != Cache::No)
- printRight(OB);
+ OB.printRight(*this);
}
// Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
}
void printLeft(OutputBuffer &OB) const override {
- Child->printLeft(OB);
+ OB.printLeft(*Child);
printQuals(OB);
}
- void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+ void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
};
class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
void printLeft(OutputBuffer &OB) const override {
- Ty->printLeft(OB);
+ OB.printLeft(*Ty);
OB += Postfix;
}
};
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
std::string_view getBaseName() const override { return Base->getBaseName(); }
void printLeft(OutputBuffer &OB) const override {
- Base->printLeft(OB);
+ OB.printLeft(*Base);
OB += "[abi:";
OB += Tag;
OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
- Pointee->printLeft(OB);
+ OB.printLeft(*Pointee);
if (Pointee->hasArray(OB))
OB += " ";
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
OB += ")";
- Pointee->printRight(OB);
+ OB.printRight(*Pointee);
}
}
};
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
if (!Collapsed.second)
return;
- Collapsed.second->printLeft(OB);
+ OB.printLeft(*Collapsed.second);
if (Collapsed.second->hasArray(OB))
OB += " ";
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
return;
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
OB += ")";
- Collapsed.second->printRight(OB);
+ OB.printRight(*Collapsed.second);
}
};
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
}
void printLeft(OutputBuffer &OB) const override {
- MemberType->printLeft(OB);
+ OB.printLeft(*MemberType);
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += "(";
else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
void printRight(OutputBuffer &OB) const override {
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
OB += ")";
- MemberType->printRight(OB);
+ OB.printRight(*MemberType);
}
};
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasArraySlow(OutputBuffer &) const override { return true; }
- void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+ void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
void printRight(OutputBuffer &OB) const override {
if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
if (Dimension)
Dimension->print(OB);
OB += "]";
- Base->printRight(OB);
+ OB.printRight(*Base);
}
bool printInitListAsType(OutputBuffer &OB,
@@ -851,7 +851,7 @@ class FunctionType final : public Node {
// by printing out the return types's left, then print our parameters, then
// finally print right of the return type.
void printLeft(OutputBuffer &OB) const override {
- Ret->printLeft(OB);
+ OB.printLeft(*Ret);
OB += " ";
}
@@ -859,7 +859,7 @@ class FunctionType final : public Node {
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
- Ret->printRight(OB);
+ OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@@ -964,6 +964,8 @@ class FunctionEncoding final : public Node {
FunctionRefQual getRefQual() const { return RefQual; }
NodeArray getParams() const { return Params; }
const Node *getReturnType() const { return Ret; }
+ const Node *getAttrs() const { return Attrs; }
+ const Node *getRequires() const { return Requires; }
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -972,10 +974,11 @@ class FunctionEncoding final : public Node {
void printLeft(OutputBuffer &OB) const override {
if (Ret) {
- Ret->printLeft(OB);
+ OB.printLeft(*Ret);
if (!Ret->hasRHSComponent(OB))
OB += " ";
}
+
Name->print(OB);
}
@@ -983,8 +986,9 @@ class FunctionEncoding final : public Node {
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+
if (Ret)
- Ret->printRight(OB);
+ OB.printRight(*Ret);
if (CVQuals & QualConst)
OB += " const";
@@ -1324,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
template<typename Fn> void match(Fn F) const { F(Name, Type); }
void printLeft(OutputBuffer &OB) const override {
- Type->printLeft(OB);
+ OB.printLeft(*Type);
if (!Type->hasRHSComponent(OB))
OB += " ";
}
void printRight(OutputBuffer &OB) const override {
Name->print(OB);
- Type->printRight(OB);
+ OB.printRight(*Type);
}
};
@@ -1376,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
template<typename Fn> void match(Fn F) const { F(Param); }
void printLeft(OutputBuffer &OB) const override {
- Param->printLeft(OB);
+ OB.printLeft(*Param);
OB += "...";
}
- void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+ void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
};
/// An unexpanded parameter pack (either in the expression or type context). If
@@ -1445,13 +1449,13 @@ class ParameterPack final : public Node {
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printLeft(OB);
+ OB.printLeft(*Data[Idx]);
}
void printRight(OutputBuffer &OB) const override {
initializePackExpansion(OB);
size_t Idx = OB.CurrentPackIndex;
if (Idx < Data.size())
- Data[Idx]->printRight(OB);
+ OB.printRight(*Data[Idx]);
}
};
@@ -1609,13 +1613,13 @@ struct ForwardTemplateReference : Node {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
- Ref->printLeft(OB);
+ OB.printLeft(*Ref);
}
void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
ScopedOverride<bool> SavePrinting(Printing, true);
- Ref->printRight(OB);
+ OB.printRight(*Ref);
}
};
@@ -1767,7 +1771,7 @@ class DtorName : public Node {
void printLeft(OutputBuffer &OB) const override {
OB += "~";
- Base->printLeft(OB);
+ OB.printLeft(*Base);
}
};
@@ -2047,7 +2051,7 @@ class CastExpr : public Node {
{
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "<";
- To->printLeft(OB);
+ OB.printLeft(*To);
OB += ">";
}
OB.printOpen();
@@ -6176,6 +6180,10 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
Alloc>::AbstractManglingParser;
};
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
DEMANGLE_NAMESPACE_END
#if defined(__clang__)
diff --git a/llvm/include/llvm/Demangle/Utility.h b/llvm/include/llvm/Demangle/Utility.h
index e893cceea2cdc..6a1bf6d0e6b63 100644
--- a/llvm/include/llvm/Demangle/Utility.h
+++ b/llvm/include/llvm/Demangle/Utility.h
@@ -27,6 +27,8 @@
DEMANGLE_NAMESPACE_BEGIN
+class Node;
+
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
@@ -79,10 +81,15 @@ class OutputBuffer {
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
+ virtual ~OutputBuffer() {}
+
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
}
+ virtual void printLeft(const Node &N);
+ virtual void printRight(const Node &N);
+
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
More information about the llvm-commits
mailing list