diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h --- a/lldb/include/lldb/Core/FormatEntity.h +++ b/lldb/include/lldb/Core/FormatEntity.h @@ -241,6 +241,17 @@ llvm::StringRef elements, llvm::StringRef element_format); + /// For each variable in 'args' this function writes the variable + /// name and it's pretty-printed value representation to 'out_stream' + /// in following format: + /// + /// \verbatim + /// name_1=repr_1, name_2=repr_2 ... + /// \endverbatim + static void PrettyPrintFunctionArguments(Stream &out_stream, + VariableList const &args, + ExecutionContextScope *exe_scope); + protected: static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, uint32_t depth); diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -1039,6 +1039,71 @@ return (::strncmp(var_name_begin, var, strlen(var)) == 0); } +/// Parses the basename out of a demangled function name +/// that may include function arguments. Supports +/// template functions. +/// +/// Returns pointers to the opening and closing parenthesis of +/// `full_name`. Can return nullptr for either parenthesis if +/// none is exists. +static std::pair +ParseBaseName(char const *full_name) { + const char *open_paren = strchr(full_name, '('); + const char *close_paren = nullptr; + const char *generic = strchr(full_name, '<'); + // 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; + } + + if (open_paren) { + if (IsToken(open_paren, "(anonymous namespace)")) { + open_paren = strchr(open_paren + strlen("(anonymous namespace)"), '('); + if (open_paren) + close_paren = strchr(open_paren, ')'); + } else + close_paren = strchr(open_paren, ')'); + } + + return {open_paren, close_paren}; +} + +/// Writes out the function name in 'full_name' to 'out_stream' +/// but replaces each argument type with the variable name +/// and the corresponding pretty-printed value +static void PrettyPrintFunctionNameWithArgs(Stream &out_stream, + char const *full_name, + ExecutionContextScope *exe_scope, + VariableList const &args) { + auto [open_paren, close_paren] = ParseBaseName(full_name); + if (open_paren) + out_stream.Write(full_name, open_paren - full_name + 1); + else { + out_stream.PutCString(full_name); + out_stream.PutChar('('); + } + + FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope); + + if (close_paren) + out_stream.PutCString(close_paren); + else + out_stream.PutChar(')'); +} + bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s, const SymbolContext *sc, const ExecutionContext *exe_ctx, @@ -1645,100 +1710,7 @@ variable_list_sp->AppendVariablesWithScope( eValueTypeVariableArgument, args); if (args.GetSize() > 0) { - 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; - } - if (open_paren) { - if (IsToken(open_paren, "(anonymous namespace)")) { - open_paren = - strchr(open_paren + strlen("(anonymous namespace)"), '('); - if (open_paren) - close_paren = strchr(open_paren, ')'); - } else - close_paren = strchr(open_paren, ')'); - } - - if (open_paren) - s.Write(cstr, open_paren - cstr + 1); - else { - s.PutCString(cstr); - 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)); - StreamString ss; - llvm::StringRef var_representation; - const char *var_name = var_value_sp->GetName().GetCString(); - if (var_value_sp->GetCompilerType().IsValid()) { - if (exe_scope && 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)) { - static StringSummaryFormat format( - TypeSummaryImpl::Flags() - .SetHideItemNames(false) - .SetShowMembersOneLiner(true), - ""); - format.FormatObject(var_value_sp.get(), buffer, - TypeSummaryOptions()); - var_representation = buffer; - } else - var_value_sp->DumpPrintableRepresentation( - ss, - ValueObject::ValueObjectRepresentationStyle:: - eValueObjectRepresentationStyleSummary, - eFormatDefault, - ValueObject::PrintableRepresentationSpecialCases::eAllow, - false); - } - - if (!ss.GetString().empty()) - var_representation = ss.GetString(); - if (arg_idx > 0) - s.PutCString(", "); - if (var_value_sp->GetError().Success()) { - if (!var_representation.empty()) - s.Printf("%s=%s", var_name, var_representation.str().c_str()); - else - s.Printf("%s=%s at %s", var_name, - var_value_sp->GetTypeName().GetCString(), - var_value_sp->GetLocationAsCString()); - } else - s.Printf("%s=", var_name); - } - - if (close_paren) - s.PutCString(close_paren); - else - s.PutChar(')'); - + PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args); } else { s.PutCString(cstr); } @@ -2447,3 +2419,55 @@ request.AddCompletions(new_matches); } } + +void FormatEntity::PrettyPrintFunctionArguments( + Stream &out_stream, VariableList const &args, + ExecutionContextScope *exe_scope) { + 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)); + StreamString ss; + llvm::StringRef var_representation; + const char *var_name = var_value_sp->GetName().GetCString(); + if (var_value_sp->GetCompilerType().IsValid()) { + if (exe_scope && 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)) { + static StringSummaryFormat format(TypeSummaryImpl::Flags() + .SetHideItemNames(false) + .SetShowMembersOneLiner(true), + ""); + format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); + var_representation = buffer; + } else + var_value_sp->DumpPrintableRepresentation( + ss, + ValueObject::ValueObjectRepresentationStyle:: + eValueObjectRepresentationStyleSummary, + eFormatDefault, + ValueObject::PrintableRepresentationSpecialCases::eAllow, false); + } + + if (!ss.GetString().empty()) + var_representation = ss.GetString(); + if (arg_idx > 0) + out_stream.PutCString(", "); + if (var_value_sp->GetError().Success()) { + if (!var_representation.empty()) + out_stream.Printf("%s=%s", var_name, var_representation.str().c_str()); + else + out_stream.Printf("%s=%s at %s", var_name, + var_value_sp->GetTypeName().GetCString(), + var_value_sp->GetLocationAsCString()); + } else + out_stream.Printf("%s=", var_name); + } +}