[lldb][CPlusPlusLanguage] Create public accessors for getting DemangledNameInfo components and use them in tests (#152134)

This way we make sure that the logic to reconstruct demangled names in
the tests is the same as the logic when reconstructing the actual
frame-format variable.

`DemangledNameInfo::SuffixRange` is currently the only one which we
can't test in the same way until we set it from inside the
`TrackingOutputBuffer`. I added TODOs to track this.
This commit is contained in:
Michael Buch 2025-08-05 18:12:22 +01:00 committed by GitHub
parent 3b2a1a5d9b
commit 406f61fd3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 162 additions and 55 deletions

View File

@ -172,6 +172,7 @@ GetItaniumDemangledStr(const char *M) {
TrackingOutputBuffer OB(demangled_cstr, demangled_size);
demangled_cstr = ipd.finishDemangle(&OB);
// TODO: we should set the SuffixRange inside the TrackingOutputBuffer.
OB.NameInfo.SuffixRange.first = OB.NameInfo.QualifiersRange.second;
OB.NameInfo.SuffixRange.second = std::string_view(OB).size();
info = std::move(OB.NameInfo);

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/ItaniumDemangle.h"
#include "lldb/Core/DemangledNameInfo.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
@ -271,8 +272,25 @@ GetDemangledBasename(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
return demangled_name.slice(info.BasenameRange.first,
info.BasenameRange.second);
return CPlusPlusLanguage::GetDemangledBasename(demangled_name, info);
}
llvm::StringRef
CPlusPlusLanguage::GetDemangledBasename(llvm::StringRef demangled,
const DemangledNameInfo &info) {
assert(info.hasBasename());
return demangled.slice(info.BasenameRange.first, info.BasenameRange.second);
}
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledTemplateArguments(
llvm::StringRef demangled, const DemangledNameInfo &info) {
if (!info.hasTemplateArguments())
return llvm::createStringError(
"Template arguments range for '%s' is invalid.", demangled.data());
return demangled.slice(info.TemplateArgumentsRange.first,
info.TemplateArgumentsRange.second);
}
static llvm::Expected<llvm::StringRef>
@ -283,12 +301,17 @@ GetDemangledTemplateArguments(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
if (!info.hasTemplateArguments())
return llvm::createStringError(
"Template arguments range for '%s' is invalid.", demangled_name.data());
return CPlusPlusLanguage::GetDemangledTemplateArguments(demangled_name, info);
}
return demangled_name.slice(info.TemplateArgumentsRange.first,
info.TemplateArgumentsRange.second);
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledReturnTypeLHS(llvm::StringRef demangled,
const DemangledNameInfo &info) {
if (info.ScopeRange.first >= demangled.size())
return llvm::createStringError(
"Scope range for '%s' LHS return type is invalid.", demangled.data());
return demangled.substr(0, info.ScopeRange.first);
}
static llvm::Expected<llvm::StringRef>
@ -299,12 +322,18 @@ GetDemangledReturnTypeLHS(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
if (info.ScopeRange.first >= demangled_name.size())
return llvm::createStringError(
"Scope range for '%s' LHS return type is invalid.",
demangled_name.data());
return CPlusPlusLanguage::GetDemangledReturnTypeLHS(demangled_name, info);
}
return demangled_name.substr(0, info.ScopeRange.first);
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledFunctionQualifiers(
llvm::StringRef demangled, const DemangledNameInfo &info) {
if (!info.hasQualifiers())
return llvm::createStringError("Qualifiers range for '%s' is invalid.",
demangled.data());
return demangled.slice(info.QualifiersRange.first,
info.QualifiersRange.second);
}
static llvm::Expected<llvm::StringRef>
@ -315,12 +344,20 @@ GetDemangledFunctionQualifiers(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
if (!info.hasQualifiers())
return llvm::createStringError("Qualifiers range for '%s' is invalid.",
demangled_name.data());
return CPlusPlusLanguage::GetDemangledFunctionQualifiers(demangled_name,
info);
}
return demangled_name.slice(info.QualifiersRange.first,
info.QualifiersRange.second);
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledReturnTypeRHS(llvm::StringRef demangled,
const DemangledNameInfo &info) {
if (info.QualifiersRange.first < info.ArgumentsRange.second)
return llvm::createStringError(
"Qualifiers range for '%s' RHS return type is invalid.",
demangled.data());
return demangled.slice(info.ArgumentsRange.second,
info.QualifiersRange.first);
}
static llvm::Expected<llvm::StringRef>
@ -331,13 +368,17 @@ GetDemangledReturnTypeRHS(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
if (info.QualifiersRange.first < info.ArgumentsRange.second)
return llvm::createStringError(
"Qualifiers range for '%s' RHS return type is invalid.",
demangled_name.data());
return CPlusPlusLanguage::GetDemangledReturnTypeRHS(demangled_name, info);
}
return demangled_name.slice(info.ArgumentsRange.second,
info.QualifiersRange.first);
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledScope(llvm::StringRef demangled,
const DemangledNameInfo &info) {
if (!info.hasScope())
return llvm::createStringError("Scope range for '%s' is invalid.",
demangled.data());
return demangled.slice(info.ScopeRange.first, info.ScopeRange.second);
}
static llvm::Expected<llvm::StringRef>
@ -348,15 +389,16 @@ GetDemangledScope(const SymbolContext &sc) {
auto [demangled_name, info] = *info_or_err;
if (!info.hasScope())
return llvm::createStringError("Scope range for '%s' is invalid.",
demangled_name.data());
return demangled_name.slice(info.ScopeRange.first, info.ScopeRange.second);
return CPlusPlusLanguage::GetDemangledScope(demangled_name, info);
}
/// Handles anything printed after the FunctionEncoding ItaniumDemangle
/// node. Most notably the DotSUffix node.
/// node. Most notably the DotSuffix node.
///
/// FIXME: the suffix should also have an associated
/// CPlusPlusLanguage::GetDemangledFunctionSuffix
/// once we start setting the `DemangledNameInfo::SuffixRange`
/// from inside the `TrackingOutputBuffer`.
static llvm::Expected<llvm::StringRef>
GetDemangledFunctionSuffix(const SymbolContext &sc) {
auto info_or_err = GetAndValidateInfo(sc);
@ -372,6 +414,16 @@ GetDemangledFunctionSuffix(const SymbolContext &sc) {
return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second);
}
llvm::Expected<llvm::StringRef>
CPlusPlusLanguage::GetDemangledFunctionArguments(
llvm::StringRef demangled, const DemangledNameInfo &info) {
if (!info.hasArguments())
return llvm::createStringError(
"Function arguments range for '%s' is invalid.", demangled.data());
return demangled.slice(info.ArgumentsRange.first, info.ArgumentsRange.second);
}
static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
assert(sc.symbol);
@ -382,13 +434,19 @@ static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
"frame-format variable: {0}");
return false;
}
auto [demangled_name, info] = *info_or_err;
if (!info.hasArguments())
auto args_or_err =
CPlusPlusLanguage::GetDemangledFunctionArguments(demangled_name, info);
if (!args_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), args_or_err.takeError(),
"Failed to handle ${{function.formatted-arguments}} "
"frame-format variable: {0}");
return false;
}
s << demangled_name.slice(info.ArgumentsRange.first,
info.ArgumentsRange.second);
s << *args_or_err;
return true;
}
@ -2261,7 +2319,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
FormatEntity::Entry::Type type, Stream &s) {
switch (type) {
case FormatEntity::Entry::Type::FunctionScope: {
auto scope_or_err = GetDemangledScope(sc);
auto scope_or_err = ::GetDemangledScope(sc);
if (!scope_or_err) {
LLDB_LOG_ERROR(
GetLog(LLDBLog::Language), scope_or_err.takeError(),
@ -2275,7 +2333,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
case FormatEntity::Entry::Type::FunctionBasename: {
auto name_or_err = GetDemangledBasename(sc);
auto name_or_err = ::GetDemangledBasename(sc);
if (!name_or_err) {
LLDB_LOG_ERROR(
GetLog(LLDBLog::Language), name_or_err.takeError(),
@ -2289,7 +2347,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
case FormatEntity::Entry::Type::FunctionTemplateArguments: {
auto template_args_or_err = GetDemangledTemplateArguments(sc);
auto template_args_or_err = ::GetDemangledTemplateArguments(sc);
if (!template_args_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language),
template_args_or_err.takeError(),
@ -2327,7 +2385,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
return true;
}
case FormatEntity::Entry::Type::FunctionReturnRight: {
auto return_rhs_or_err = GetDemangledReturnTypeRHS(sc);
auto return_rhs_or_err = ::GetDemangledReturnTypeRHS(sc);
if (!return_rhs_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_rhs_or_err.takeError(),
"Failed to handle ${{function.return-right}} frame-format "
@ -2340,7 +2398,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
return true;
}
case FormatEntity::Entry::Type::FunctionReturnLeft: {
auto return_lhs_or_err = GetDemangledReturnTypeLHS(sc);
auto return_lhs_or_err = ::GetDemangledReturnTypeLHS(sc);
if (!return_lhs_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_lhs_or_err.takeError(),
"Failed to handle ${{function.return-left}} frame-format "
@ -2353,7 +2411,7 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
return true;
}
case FormatEntity::Entry::Type::FunctionQualifiers: {
auto quals_or_err = GetDemangledFunctionQualifiers(sc);
auto quals_or_err = ::GetDemangledFunctionQualifiers(sc);
if (!quals_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), quals_or_err.takeError(),
"Failed to handle ${{function.qualifiers}} frame-format "

View File

@ -112,6 +112,32 @@ public:
static bool IsCPPMangledName(llvm::StringRef name);
static llvm::StringRef GetDemangledBasename(llvm::StringRef demangled,
const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledTemplateArguments(llvm::StringRef demangled,
const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeLHS(llvm::StringRef demangled,
const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledFunctionQualifiers(llvm::StringRef demangled,
const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledScope(llvm::StringRef demangled, const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeRHS(llvm::StringRef demangled,
const DemangledNameInfo &info);
static llvm::Expected<llvm::StringRef>
GetDemangledFunctionArguments(llvm::StringRef demangled,
const DemangledNameInfo &info);
// Extract C++ context and identifier from a string using heuristic matching
// (as opposed to
// CPlusPlusLanguage::CxxMethodName which has to have a fully qualified C++

View File

@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
#include "TestingSupport/SubsystemRAII.h"
@ -19,6 +20,7 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
@ -852,25 +854,45 @@ TEST_P(DemanglingInfoCorrectnessTestFixutre, Correctness) {
auto tracked_name = llvm::StringRef(*OB);
auto return_left = tracked_name.slice(0, OB->NameInfo.ScopeRange.first);
auto scope = tracked_name.slice(OB->NameInfo.ScopeRange.first,
OB->NameInfo.ScopeRange.second);
auto basename = tracked_name.slice(OB->NameInfo.BasenameRange.first,
OB->NameInfo.BasenameRange.second);
auto template_args = tracked_name.slice(OB->NameInfo.BasenameRange.second,
OB->NameInfo.ArgumentsRange.first);
auto args = tracked_name.slice(OB->NameInfo.ArgumentsRange.first,
OB->NameInfo.ArgumentsRange.second);
auto return_right = tracked_name.slice(OB->NameInfo.ArgumentsRange.second,
OB->NameInfo.QualifiersRange.first);
auto qualifiers = tracked_name.slice(OB->NameInfo.QualifiersRange.first,
OB->NameInfo.QualifiersRange.second);
std::string reconstructed_name;
auto return_left =
CPlusPlusLanguage::GetDemangledReturnTypeLHS(tracked_name, OB->NameInfo);
EXPECT_THAT_EXPECTED(return_left, llvm::Succeeded());
reconstructed_name += *return_left;
auto scope = CPlusPlusLanguage::GetDemangledScope(tracked_name, OB->NameInfo);
EXPECT_THAT_EXPECTED(scope, llvm::Succeeded());
reconstructed_name += *scope;
auto basename =
CPlusPlusLanguage::GetDemangledBasename(tracked_name, OB->NameInfo);
reconstructed_name += basename;
auto template_args = CPlusPlusLanguage::GetDemangledTemplateArguments(
tracked_name, OB->NameInfo);
EXPECT_THAT_EXPECTED(template_args, llvm::Succeeded());
reconstructed_name += *template_args;
auto args = CPlusPlusLanguage::GetDemangledFunctionArguments(tracked_name,
OB->NameInfo);
EXPECT_THAT_EXPECTED(args, llvm::Succeeded());
reconstructed_name += *args;
auto return_right =
CPlusPlusLanguage::GetDemangledReturnTypeRHS(tracked_name, OB->NameInfo);
EXPECT_THAT_EXPECTED(return_right, llvm::Succeeded());
reconstructed_name += *return_right;
auto qualifiers = CPlusPlusLanguage::GetDemangledFunctionQualifiers(
tracked_name, OB->NameInfo);
EXPECT_THAT_EXPECTED(qualifiers, llvm::Succeeded());
reconstructed_name += *qualifiers;
// TODO: should retrieve suffix using the plugin too.
auto suffix = tracked_name.slice(OB->NameInfo.QualifiersRange.second,
llvm::StringRef::npos);
auto reconstructed_name =
llvm::join_items("", return_left, scope, basename, template_args, args,
return_right, qualifiers, suffix);
reconstructed_name += suffix;
EXPECT_EQ(reconstructed_name, demangled);
}