diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h b/lldb/include/lldb/Core/DemangledNameInfo.h index a2f3fde90c611..9f567232dc50f 100644 --- a/lldb/include/lldb/Core/DemangledNameInfo.h +++ b/lldb/include/lldb/Core/DemangledNameInfo.h @@ -71,27 +71,28 @@ struct DemangledNameInfo { /// Returns \c true if this object holds a valid basename range. bool hasBasename() const { + // A function always has a name. return BasenameRange.second > BasenameRange.first; } /// Returns \c true if this object holds a valid scope range. - bool hasScope() const { return ScopeRange.second > ScopeRange.first; } + bool hasScope() const { return ScopeRange.second >= ScopeRange.first; } /// Returns \c true if this object holds a valid arguments range. bool hasArguments() const { - return ArgumentsRange.second > ArgumentsRange.first; + return ArgumentsRange.second >= ArgumentsRange.first; } /// Returns \c true if this object holds a valid qualifiers range. bool hasQualifiers() const { - return QualifiersRange.second > QualifiersRange.first; + return QualifiersRange.second >= QualifiersRange.first; } /// Returns \c true if this object holds a valid prefix range. - bool hasPrefix() const { return PrefixRange.second > PrefixRange.first; } + bool hasPrefix() const { return PrefixRange.second >= PrefixRange.first; } /// Returns \c true if this object holds a valid suffix range. - bool hasSuffix() const { return SuffixRange.second > SuffixRange.first; } + bool hasSuffix() const { return SuffixRange.second >= SuffixRange.first; } }; /// An OutputBuffer which keeps a record of where certain parts of a diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 0f18abb47591d..7ae2e141a63e0 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -236,199 +236,158 @@ static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream, return true; } -static std::optional -GetDemangledBasename(const SymbolContext &sc) { +static llvm::Expected> +GetAndValidateInfo(const SymbolContext &sc) { Mangled mangled = sc.GetPossiblyInlinedFunctionName(); if (!mangled) - return std::nullopt; + return llvm::createStringError("Function does not have a mangled name."); auto demangled_name = mangled.GetDemangledName().GetStringRef(); if (demangled_name.empty()) - return std::nullopt; + return llvm::createStringError( + "Function '%s' does not have a demangled name.", + mangled.GetMangledName().AsCString("")); const std::optional &info = mangled.GetDemangledInfo(); if (!info) - return std::nullopt; + return llvm::createStringError( + "Function '%s' does not have demangled info.", demangled_name.data()); // Function without a basename is nonsense. if (!info->hasBasename()) - return std::nullopt; + return llvm::createStringError( + "DemangledInfo for '%s does not have basename range.", + demangled_name.data()); - return demangled_name.slice(info->BasenameRange.first, - info->BasenameRange.second); + return std::make_pair(demangled_name, *info); } -static std::optional -GetDemangledTemplateArguments(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; +static llvm::Expected +GetDemangledBasename(const SymbolContext &sc) { + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; + return demangled_name.slice(info.BasenameRange.first, + info.BasenameRange.second); +} - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; +static llvm::Expected +GetDemangledTemplateArguments(const SymbolContext &sc) { + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); + + auto [demangled_name, info] = *info_or_err; - if (info->ArgumentsRange.first < info->BasenameRange.second) - return std::nullopt; + if (info.ArgumentsRange.first < info.BasenameRange.second) + return llvm::createStringError("Arguments range for '%s' is invalid.", + demangled_name.data()); - return demangled_name.slice(info->BasenameRange.second, - info->ArgumentsRange.first); + return demangled_name.slice(info.BasenameRange.second, + info.ArgumentsRange.first); } -static std::optional +static llvm::Expected GetDemangledReturnTypeLHS(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; + if (info.ScopeRange.first >= demangled_name.size()) + return llvm::createStringError( + "Scope range for '%s' LHS return type is invalid.", + demangled_name.data()); - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; - - if (info->ScopeRange.first >= demangled_name.size()) - return std::nullopt; - - return demangled_name.substr(0, info->ScopeRange.first); + return demangled_name.substr(0, info.ScopeRange.first); } -static std::optional +static llvm::Expected GetDemangledFunctionQualifiers(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; - - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; + if (!info.hasQualifiers()) + return llvm::createStringError("Qualifiers range for '%s' is invalid.", + demangled_name.data()); - if (info->QualifiersRange.second < info->QualifiersRange.first) - return std::nullopt; - - return demangled_name.slice(info->QualifiersRange.first, - info->QualifiersRange.second); + return demangled_name.slice(info.QualifiersRange.first, + info.QualifiersRange.second); } -static std::optional +static llvm::Expected GetDemangledReturnTypeRHS(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; - - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; + if (info.QualifiersRange.first < info.ArgumentsRange.second) + return llvm::createStringError( + "Qualifiers range for '%s' RHS return type is invalid.", + demangled_name.data()); - if (info->QualifiersRange.first < info->ArgumentsRange.second) - return std::nullopt; - - return demangled_name.slice(info->ArgumentsRange.second, - info->QualifiersRange.first); + return demangled_name.slice(info.ArgumentsRange.second, + info.QualifiersRange.first); } -static std::optional +static llvm::Expected GetDemangledScope(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; - - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; - - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - if (info->ScopeRange.second < info->ScopeRange.first) - return std::nullopt; + 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 demangled_name.slice(info.ScopeRange.first, info.ScopeRange.second); } /// Handles anything printed after the FunctionEncoding ItaniumDemangle /// node. Most notably the DotSUffix node. -static std::optional +static llvm::Expected GetDemangledFunctionSuffix(const SymbolContext &sc) { - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return std::nullopt; - - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return std::nullopt; + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) + return info_or_err.takeError(); - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return std::nullopt; + auto [demangled_name, info] = *info_or_err; - // Function without a basename is nonsense. - if (!info->hasBasename()) - return std::nullopt; + if (!info.hasSuffix()) + return llvm::createStringError("Suffix range for '%s' is invalid.", + demangled_name.data()); - return demangled_name.slice(info->SuffixRange.first, - info->SuffixRange.second); + return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second); } static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) { assert(sc.symbol); - Mangled mangled = sc.GetPossiblyInlinedFunctionName(); - if (!mangled) - return false; - - auto demangled_name = mangled.GetDemangledName().GetStringRef(); - if (demangled_name.empty()) - return false; - - const std::optional &info = mangled.GetDemangledInfo(); - if (!info) - return false; - - // Function without a basename is nonsense. - if (!info->hasBasename()) + auto info_or_err = GetAndValidateInfo(sc); + if (!info_or_err) { + LLDB_LOG_ERROR( + GetLog(LLDBLog::Language), info_or_err.takeError(), + "Failed to handle ${{function.basename}} frame-format variable: {0}"); return false; + } + auto [demangled_name, info] = *info_or_err; - if (info->ArgumentsRange.second < info->ArgumentsRange.first) + if (!info.hasArguments()) return false; - s << demangled_name.slice(info->ArgumentsRange.first, - info->ArgumentsRange.second); + s << demangled_name.slice(info.ArgumentsRange.first, + info.ArgumentsRange.second); return true; } @@ -1954,32 +1913,44 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable( FormatEntity::Entry::Type type, Stream &s) { switch (type) { case FormatEntity::Entry::Type::FunctionScope: { - std::optional scope = GetDemangledScope(sc); - if (!scope) + auto scope_or_err = GetDemangledScope(sc); + if (!scope_or_err) { + LLDB_LOG_ERROR( + GetLog(LLDBLog::Language), scope_or_err.takeError(), + "Failed to handle ${{function.scope}} frame-format variable: {0}"); return false; + } - s << *scope; + s << *scope_or_err; return true; } case FormatEntity::Entry::Type::FunctionBasename: { - std::optional name = GetDemangledBasename(sc); - if (!name) + auto name_or_err = GetDemangledBasename(sc); + if (!name_or_err) { + LLDB_LOG_ERROR( + GetLog(LLDBLog::Language), name_or_err.takeError(), + "Failed to handle ${{function.basename}} frame-format variable: {0}"); return false; + } - s << *name; + s << *name_or_err; return true; } case FormatEntity::Entry::Type::FunctionTemplateArguments: { - std::optional template_args = - GetDemangledTemplateArguments(sc); - if (!template_args) + auto template_args_or_err = GetDemangledTemplateArguments(sc); + if (!template_args_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Language), + template_args_or_err.takeError(), + "Failed to handle ${{function.template-arguments}} " + "frame-format variable: {0}"); return false; + } - s << *template_args; + s << *template_args_or_err; return true; } @@ -2008,38 +1979,54 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable( return true; } case FormatEntity::Entry::Type::FunctionReturnRight: { - std::optional return_rhs = GetDemangledReturnTypeRHS(sc); - if (!return_rhs) + 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 " + "variable: {0}"); return false; + } - s << *return_rhs; + s << *return_rhs_or_err; return true; } case FormatEntity::Entry::Type::FunctionReturnLeft: { - std::optional return_lhs = GetDemangledReturnTypeLHS(sc); - if (!return_lhs) + 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 " + "variable: {0}"); return false; + } - s << *return_lhs; + s << *return_lhs_or_err; return true; } case FormatEntity::Entry::Type::FunctionQualifiers: { - std::optional quals = GetDemangledFunctionQualifiers(sc); - if (!quals) + 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 " + "variable: {0}"); return false; + } - s << *quals; + s << *quals_or_err; return true; } case FormatEntity::Entry::Type::FunctionSuffix: { - std::optional suffix = GetDemangledFunctionSuffix(sc); - if (!suffix) + auto suffix_or_err = GetDemangledFunctionSuffix(sc); + if (!suffix_or_err) { + LLDB_LOG_ERROR( + GetLog(LLDBLog::Language), suffix_or_err.takeError(), + "Failed to handle ${{function.suffix}} frame-format variable: {0}"); return false; + } - s << *suffix; + s << *suffix_or_err; return true; } diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp index 5994d6072481b..4bda657047541 100644 --- a/lldb/unittests/Core/MangledTest.cpp +++ b/lldb/unittests/Core/MangledTest.cpp @@ -648,43 +648,43 @@ struct DemangledNameInfoTestCase { DemangledNameInfoTestCase g_demangled_name_info_test_cases[] = { // clang-format off { - { /*.BasenameRange=*/{0, 10}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{0, 0}, - /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} + { /*.BasenameRange=*/{0, 10}, /*.ScopeRange=*/{1, 0}, /*.ArgumentsRange=*/{1, 0}, + /*.QualifiersRange=*/{1, 0}, /*.PrefixRange=*/{1, 0}, /*.SuffixRange=*/{1, 0} }, /*valid_basename=*/true, /*valid_scope=*/false, /*valid_arguments=*/false, /*valid_qualifiers=*/false, /*valid_prefix=*/false, /*valid_suffix=*/false, }, { - { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 10}, /*.ArgumentsRange=*/{0, 0}, - /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} + { /*.BasenameRange=*/{1, 0}, /*.ScopeRange=*/{0, 10}, /*.ArgumentsRange=*/{1, 0}, + /*.QualifiersRange=*/{1, 0}, /*.PrefixRange=*/{1, 0}, /*.SuffixRange=*/{1, 0} }, /*valid_basename=*/false, /*valid_scope=*/true, /*valid_arguments=*/false, /*valid_qualifiers=*/false, /*valid_prefix=*/false, /*valid_suffix=*/false, }, { - { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{0, 10}, - /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} + { /*.BasenameRange=*/{1, 0}, /*.ScopeRange=*/{1, 0}, /*.ArgumentsRange=*/{0, 10}, + /*.QualifiersRange=*/{1, 0}, /*.PrefixRange=*/{1, 0}, /*.SuffixRange=*/{1, 0} }, /*valid_basename=*/false, /*valid_scope=*/false, /*valid_arguments=*/true, /*valid_qualifiers=*/false, /*valid_prefix=*/false, /*valid_suffix=*/false, }, { - { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{0, 0}, - /*.QualifiersRange=*/{0, 10}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} + { /*.BasenameRange=*/{1, 0}, /*.ScopeRange=*/{1, 0}, /*.ArgumentsRange=*/{1, 0}, + /*.QualifiersRange=*/{0, 10}, /*.PrefixRange=*/{1, 0}, /*.SuffixRange=*/{1, 0} }, /*valid_basename=*/false, /*valid_scope=*/false, /*valid_arguments=*/false, /*valid_qualifiers=*/true, /*valid_prefix=*/false, /*valid_suffix=*/false, }, { - { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{0, 0}, - /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 10}, /*.SuffixRange=*/{0, 0} + { /*.BasenameRange=*/{1, 0}, /*.ScopeRange=*/{1, 0}, /*.ArgumentsRange=*/{1, 0}, + /*.QualifiersRange=*/{1, 0}, /*.PrefixRange=*/{0, 10}, /*.SuffixRange=*/{1, 0} }, /*valid_basename=*/false, /*valid_scope=*/false, /*valid_arguments=*/false, /*valid_qualifiers=*/false, /*valid_prefix=*/true, /*valid_suffix=*/false, }, { - { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{0, 0}, - /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 10} + { /*.BasenameRange=*/{1, 0}, /*.ScopeRange=*/{1, 0}, /*.ArgumentsRange=*/{1, 0}, + /*.QualifiersRange=*/{1, 0}, /*.PrefixRange=*/{1, 0}, /*.SuffixRange=*/{0, 10} }, /*valid_basename=*/false, /*valid_scope=*/false, /*valid_arguments=*/false, /*valid_qualifiers=*/false, /*valid_prefix=*/false, /*valid_suffix=*/true,