diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp index 620b4033d4f97..721bb5a54d0d2 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp @@ -1719,17 +1719,10 @@ bool SwiftLanguage::GetFunctionDisplayName( return true; } case Language::FunctionNameRepresentation::eNameWithArgs: { - if (!sc.function) - return false; - if (sc.function->GetLanguage() != eLanguageTypeSwift) - return false; - std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString( - sc.function->GetMangled().GetMangledName().GetStringRef(), - SwiftLanguageRuntime::eSimplified, &sc, exe_ctx); + std::string display_name = GetFunctionName(sc, exe_ctx); if (display_name.empty()) return false; - ExecutionContextScope *exe_scope = - exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; + s << display_name; const InlineFunctionInfo *inline_info = NULL; VariableListSP variable_list_sp; bool get_function_vars = true; @@ -1749,109 +1742,131 @@ bool SwiftLanguage::GetFunctionDisplayName( sc.function->GetBlock(true).GetBlockVariableList(true); } - if (inline_info) { - s << display_name; - s.PutCString(" [inlined] "); - display_name = inline_info->GetName().GetString(); - } - VariableList args; if (variable_list_sp) variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args); - if (args.GetSize() == 0) { - s << display_name; - return true; - } - const char *cstr = display_name.data(); - const char *open_paren = strchr(cstr, '('); - const char *close_paren = nullptr; - const char *generic = strchr(cstr, '<'); - // If before the arguments list begins there is a template sign - // then scan to the end of the generic args before you try to find - // the arguments list. - if (generic && open_paren && generic < open_paren) { - int generic_depth = 1; - ++generic; - for (; *generic && generic_depth > 0; generic++) { - if (*generic == '<') - generic_depth++; - if (*generic == '>') - generic_depth--; - } - if (*generic) - open_paren = strchr(generic, '('); - else - open_paren = nullptr; + + s << GetFunctionDisplayArgs(sc, args, exe_ctx); + return true; } - if (open_paren) { - close_paren = strchr(open_paren, ')'); } + return false; +} - if (open_paren) - s.Write(cstr, open_paren - cstr + 1); - else { - s << display_name; - s.PutChar('('); +std::string SwiftLanguage::GetFunctionName(const SymbolContext &sc, + const ExecutionContext *exe_ctx) { + if (!sc.function) + return {}; + if (sc.function->GetLanguage() != eLanguageTypeSwift) + return {}; + std::string name = SwiftLanguageRuntime::DemangleSymbolAsString( + sc.function->GetMangled().GetMangledName().GetStringRef(), + SwiftLanguageRuntime::eSimplified, &sc, exe_ctx); + if (name.empty()) + return {}; + size_t open_paren = name.find('('); + size_t generic = name.find('<'); + size_t name_end = std::min(open_paren, generic); + if (name_end == std::string::npos) + return name; + return name.substr(0, name_end); +} + +std::string SwiftLanguage::GetFunctionDisplayArgs( + const SymbolContext &sc, VariableList &args, + const lldb_private::ExecutionContext *exe_ctx) { + ExecutionContextScope *exe_scope = + exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; + std::string name = SwiftLanguageRuntime::DemangleSymbolAsString( + sc.function->GetMangled().GetMangledName().GetStringRef(), + SwiftLanguageRuntime::eSimplified, &sc, exe_ctx); + lldb_private::StreamString s; + const char *cstr = name.data(); + const char *open_paren = strchr(cstr, '('); + const char *close_paren = nullptr; + const char *generic = strchr(cstr, '<'); + // If before the arguments list begins there is a template sign + // then scan to the end of the generic args before you try to find + // the arguments list. + const char *generic_start = generic; + if (generic && open_paren && generic < open_paren) { + int generic_depth = 1; + ++generic; + for (; *generic && generic_depth > 0; generic++) { + if (*generic == '<') + generic_depth++; + if (*generic == '>') + generic_depth--; } - const size_t num_args = args.GetSize(); - for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { - std::string buffer; - - VariableSP var_sp(args.GetVariableAtIndex(arg_idx)); - ValueObjectSP var_value_sp( - ValueObjectVariable::Create(exe_scope, var_sp)); - if (!var_sp || !var_value_sp || var_sp->IsArtificial()) - continue; - StreamString ss; - const char *var_representation = nullptr; - const char *var_name = var_value_sp->GetName().GetCString(); - if (var_value_sp->GetCompilerType().IsValid()) { - if (var_value_sp && exe_scope->CalculateTarget()) - var_value_sp = var_value_sp->GetQualifiedRepresentationIfAvailable( - exe_scope->CalculateTarget() - ->TargetProperties::GetPreferDynamicValue(), - exe_scope->CalculateTarget() - ->TargetProperties::GetEnableSyntheticValue()); - if (var_value_sp->GetCompilerType().IsAggregateType() && - DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) { - static StringSummaryFormat format(TypeSummaryImpl::Flags() - .SetHideItemNames(false) - .SetShowMembersOneLiner(true), - ""); - format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); - var_representation = buffer.c_str(); - } else - var_value_sp->DumpPrintableRepresentation( - ss, - ValueObject::ValueObjectRepresentationStyle:: - eValueObjectRepresentationStyleSummary, - eFormatDefault, - ValueObject::PrintableRepresentationSpecialCases::eAllow, false); - } - if (ss.GetData() && ss.GetSize()) - var_representation = ss.GetData(); - if (arg_idx > 0) - s.PutCString(", "); - if (var_value_sp->GetError().Success()) { - if (var_representation) - s.Printf("%s=%s", var_name, var_representation); - else - s.Printf("%s=%s at %s", var_name, - var_value_sp->GetTypeName().GetCString(), - var_value_sp->GetLocationAsCString()); + if (*generic) + open_paren = strchr(generic, '('); + else + open_paren = nullptr; + } + if (open_paren) { + close_paren = strchr(open_paren, ')'); + } + + if (generic_start && generic_start < open_paren) + s.Write(generic_start, open_paren - generic_start); + s.PutChar('('); + + const size_t num_args = args.GetSize(); + for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { + std::string buffer; + + VariableSP var_sp(args.GetVariableAtIndex(arg_idx)); + ValueObjectSP var_value_sp(ValueObjectVariable::Create(exe_scope, var_sp)); + if (!var_sp || !var_value_sp || var_sp->IsArtificial()) + continue; + StreamString ss; + const char *var_representation = nullptr; + const char *var_name = var_value_sp->GetName().GetCString(); + if (var_value_sp->GetCompilerType().IsValid()) { + if (var_value_sp && exe_scope->CalculateTarget()) + var_value_sp = var_value_sp->GetQualifiedRepresentationIfAvailable( + exe_scope->CalculateTarget() + ->TargetProperties::GetPreferDynamicValue(), + exe_scope->CalculateTarget() + ->TargetProperties::GetEnableSyntheticValue()); + if (var_value_sp->GetCompilerType().IsAggregateType() && + DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) { + static StringSummaryFormat format(TypeSummaryImpl::Flags() + .SetHideItemNames(false) + .SetShowMembersOneLiner(true), + ""); + format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); + var_representation = buffer.c_str(); } else - s.Printf("%s=", var_name); + var_value_sp->DumpPrintableRepresentation( + ss, + ValueObject::ValueObjectRepresentationStyle:: + eValueObjectRepresentationStyleSummary, + eFormatDefault, + ValueObject::PrintableRepresentationSpecialCases::eAllow, false); } - - if (close_paren) - s.PutCString(close_paren); - else - s.PutChar(')'); - } - return true; + if (ss.GetData() && ss.GetSize()) + var_representation = ss.GetData(); + if (arg_idx > 0) + s.PutCString(", "); + if (var_value_sp->GetError().Success()) { + if (var_representation) + s.Printf("%s=%s", var_name, var_representation); + else + s.Printf("%s=%s at %s", var_name, + var_value_sp->GetTypeName().GetCString(), + var_value_sp->GetLocationAsCString()); + } else + s.Printf("%s=", var_name); } - return false; + + if (close_paren) + s.PutCString(close_paren); + else + s.PutChar(')'); + + return s.GetString().str(); } void SwiftLanguage::GetExceptionResolverDescription(bool catch_on, diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.h b/lldb/source/Plugins/Language/Swift/SwiftLanguage.h index c93743f595661..353dab75284a8 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.h +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.h @@ -69,6 +69,37 @@ class SwiftLanguage : public Language { FunctionNameRepresentation representation, Stream &s) override; + /// Returns the name of function up to the first generic or opening + /// parenthesis. + /// + /// The following function will have the name "foo": + /// \code{.swift} + /// func foo(bar: T) {} + /// \endcode + /// + /// \param sc The associated SymbolContext. + /// \param exe_ctx The associated ExecutionContext. + /// \returns The name of a function as an std::string. + std::string GetFunctionName(const SymbolContext &sc, + const ExecutionContext *exe_ctx); + + /// Returns the arguments of a function call with its generics if any. + /// + /// Calling GetFunctionDisplayArgs on the following function call will return + /// "(bar=1)" + /// \code{.swift} + /// func foo(bar: T) {} + /// foo(1) + /// \endcode + /// + /// \param sc The associated SymbolContext. + /// \param args The VariableList that are passed to the function. + /// \param exe_ctx The associated ExecutionContext. + /// \returns The generics and arguments of a function call as an std::string. + std::string + GetFunctionDisplayArgs(const SymbolContext &sc, VariableList &args, + const lldb_private::ExecutionContext *exe_ctx); + void GetExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s) override; diff --git a/lldb/test/Shell/Swift/function-name-backtrace.test b/lldb/test/Shell/Swift/function-name-backtrace.test new file mode 100644 index 0000000000000..2cac540b08156 --- /dev/null +++ b/lldb/test/Shell/Swift/function-name-backtrace.test @@ -0,0 +1,52 @@ +# XFAIL: target-windows + +# Test Swift function name printing in backtraces. + +# RUN: split-file %s %t +# RUN: %target-swiftc -g %t/main.swift -o %t.out +# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \ +# RUN: | FileCheck %s + +#--- main.swift +func foo() async -> Int { + return await try! bar(a: 1, b: 1) +} + +var res = { + (index: Int) -> Int in + return index + 10 +}(1) + +fileprivate func bar(a: Int, b: Int) async throws -> Int { + var baz = Baz(baz: 1) + return res + a + b + Foo.foo_(a: baz) +} + +struct Foo { + let foo: Int + static func foo_(a: T) -> Int { + var a_ = a as! Baz + return a_.qux(a: 1) + } +} + +struct Baz { + var baz: Int + mutating func qux(a: T) -> Int { + baz += 1 + return baz + } +} + +await foo() + +#--- commands.input +b qux + +run +bt + +# CHECK: `Baz.qux(a=1) +# CHECK: `static Foo.foo_(a=(baz = 1)) +# CHECK: `bar(a=1, b=1) +# CHECK: `foo() \ No newline at end of file