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 <michaelbuc...@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(); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits