Skip to content

Commit 0c777e5

Browse files
committed
[lldb] Print ValueObject when GetObjectDescription fails (llvm#152417)
This fixes a few bugs, effectively through a fallback to `p` when `po` fails. The motivating bug this fixes is when an error within the compiler causes `po` to fail. Previously when that happened, only its value (typically an object's address) was printed – and problematically, no compiler diagnostics were shown. With this change, compiler diagnostics are shown, _and_ the object is fully printed (ie `p`). Another bug this fixes is when `po` is used on a type that doesn't provide an object description (such as a struct). Again, the normal `ValueObject` printing is used. Additionally, this also improves how lldb handles an object description method that fails in some way. Now an error will be shown (it wasn't before), and the value will be printed normally. (cherry picked from commit ae7e1b8)
1 parent 5cf5979 commit 0c777e5

File tree

15 files changed

+154
-78
lines changed

15 files changed

+154
-78
lines changed

lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ class DumpValueObjectOptions {
8181

8282
DumpValueObjectOptions &SetShowLocation(bool show = false);
8383

84-
DumpValueObjectOptions &SetUseObjectiveC(bool use = false);
84+
DumpValueObjectOptions &DisableObjectDescription();
85+
86+
DumpValueObjectOptions &SetUseObjectDescription(bool use = false);
8587

8688
DumpValueObjectOptions &SetShowSummary(bool show = true);
8789

@@ -148,13 +150,14 @@ class DumpValueObjectOptions {
148150
ChildPrintingDecider m_child_printing_decider;
149151
PointerAsArraySettings m_pointer_as_array;
150152
unsigned m_expand_ptr_type_flags = 0;
153+
// The following flags commonly default to false.
151154
bool m_use_synthetic : 1;
152155
bool m_scope_already_checked : 1;
153156
bool m_flat_output : 1;
154157
bool m_ignore_cap : 1;
155158
bool m_show_types : 1;
156159
bool m_show_location : 1;
157-
bool m_use_objc : 1;
160+
bool m_use_object_desc : 1;
158161
bool m_hide_root_type : 1;
159162
bool m_hide_root_name : 1;
160163
bool m_hide_name : 1;

lldb/include/lldb/DataFormatters/ValueObjectPrinter.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ class ValueObjectPrinter {
7575

7676
void SetupMostSpecializedValue();
7777

78-
llvm::Expected<std::string> GetDescriptionForDisplay();
79-
8078
const char *GetRootNameForDisplay();
8179

8280
bool ShouldPrintValueObject();
@@ -108,8 +106,7 @@ class ValueObjectPrinter {
108106

109107
bool PrintValueAndSummaryIfNeeded(bool &value_printed, bool &summary_printed);
110108

111-
llvm::Error PrintObjectDescriptionIfNeeded(bool value_printed,
112-
bool summary_printed);
109+
void PrintObjectDescriptionIfNeeded(std::optional<std::string> object_desc);
113110

114111
bool
115112
ShouldPrintChildren(DumpValueObjectOptions::PointerDepth &curr_ptr_depth);
@@ -141,6 +138,7 @@ class ValueObjectPrinter {
141138

142139
private:
143140
bool ShouldShowName() const;
141+
bool ShouldPrintObjectDescription();
144142

145143
ValueObject &m_orig_valobj;
146144
/// Cache the current "most specialized" value. Don't use this

lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class OptionGroupValueObjectDisplay : public OptionGroup {
3131

3232
bool AnyOptionWasSet() const {
3333
return show_types || no_summary_depth != 0 || show_location ||
34-
flat_output || use_objc || max_depth != UINT32_MAX ||
34+
flat_output || use_object_desc || max_depth != UINT32_MAX ||
3535
ptr_depth != 0 || !use_synth || be_raw || ignore_cap ||
3636
run_validator;
3737
}
@@ -42,7 +42,7 @@ class OptionGroupValueObjectDisplay : public OptionGroup {
4242
lldb::Format format = lldb::eFormatDefault,
4343
lldb::TypeSummaryImplSP summary_sp = lldb::TypeSummaryImplSP());
4444

45-
bool show_types : 1, show_location : 1, flat_output : 1, use_objc : 1,
45+
bool show_types : 1, show_location : 1, flat_output : 1, use_object_desc : 1,
4646
use_synth : 1, be_raw : 1, ignore_cap : 1, run_validator : 1,
4747
max_depth_is_default : 1;
4848

lldb/source/Commands/CommandObjectDWIMPrint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
9292
dump_options.SetHideRootName(suppress_result)
9393
.SetExpandPointerTypeFlags(lldb::eTypeIsObjC);
9494

95-
bool is_po = m_varobj_options.use_objc;
95+
bool is_po = m_varobj_options.use_object_desc;
9696

9797
StackFrame *frame = m_exe_ctx.GetFramePtr();
9898

lldb/source/Commands/CommandObjectExpression.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ EvaluateExpressionOptions
220220
CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
221221
const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
222222
EvaluateExpressionOptions options;
223-
options.SetCoerceToId(display_opts.use_objc);
223+
options.SetCoerceToId(display_opts.use_object_desc);
224224
options.SetUnwindOnError(unwind_on_error);
225225
options.SetIgnoreBreakpoints(ignore_breakpoints);
226226
options.SetKeepInMemory(true);
@@ -263,11 +263,11 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
263263
bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
264264
const OptionGroupValueObjectDisplay &display_opts) const {
265265
// Explicitly disabling persistent results takes precedence over the
266-
// m_verbosity/use_objc logic.
266+
// m_verbosity/use_object_desc logic.
267267
if (suppress_persistent_result != eLazyBoolCalculate)
268268
return suppress_persistent_result == eLazyBoolYes;
269269

270-
return display_opts.use_objc &&
270+
return display_opts.use_object_desc &&
271271
m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
272272
}
273273

@@ -356,7 +356,7 @@ Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
356356

357357
void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
358358
EvaluateExpressionOptions options;
359-
options.SetCoerceToId(m_varobj_options.use_objc);
359+
options.SetCoerceToId(m_varobj_options.use_object_desc);
360360
options.SetLanguage(m_command_options.language);
361361
options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
362362
options.SetAutoApplyFixIts(false);

lldb/source/DataFormatters/DumpValueObjectOptions.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ DumpValueObjectOptions::DumpValueObjectOptions()
1919
m_decl_printing_helper(), m_child_printing_decider(),
2020
m_pointer_as_array(), m_use_synthetic(true),
2121
m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
22-
m_show_types(false), m_show_location(false), m_use_objc(false),
22+
m_show_types(false), m_show_location(false), m_use_object_desc(false),
2323
m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
2424
m_hide_value(false), m_run_validator(false),
2525
m_use_type_display_name(true), m_allow_oneliner_mode(true),
@@ -67,8 +67,19 @@ DumpValueObjectOptions &DumpValueObjectOptions::SetShowLocation(bool show) {
6767
return *this;
6868
}
6969

70-
DumpValueObjectOptions &DumpValueObjectOptions::SetUseObjectiveC(bool use) {
71-
m_use_objc = use;
70+
DumpValueObjectOptions &DumpValueObjectOptions::DisableObjectDescription() {
71+
// Reset these options to their default values.
72+
SetUseObjectDescription(false);
73+
SetHideRootType(false);
74+
SetHideName(false);
75+
SetHideValue(false);
76+
SetShowSummary(true);
77+
return *this;
78+
}
79+
80+
DumpValueObjectOptions &
81+
DumpValueObjectOptions::SetUseObjectDescription(bool use) {
82+
m_use_object_desc = use;
7283
return *this;
7384
}
7485

lldb/source/DataFormatters/ValueObjectPrinter.cpp

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#include "lldb/Target/Target.h"
1515
#include "lldb/Utility/Stream.h"
1616
#include "lldb/ValueObject/ValueObject.h"
17+
#include "llvm/Support/Error.h"
1718
#include "llvm/Support/MathExtras.h"
1819
#include <cstdint>
20+
#include <optional>
1921

2022
using namespace lldb;
2123
using namespace lldb_private;
@@ -69,6 +71,18 @@ void ValueObjectPrinter::Init(
6971
SetupMostSpecializedValue();
7072
}
7173

74+
static const char *maybeNewline(const std::string &s) {
75+
// If the string already ends with a \n don't add another one.
76+
if (s.empty() || s.back() != '\n')
77+
return "\n";
78+
return "";
79+
}
80+
81+
bool ValueObjectPrinter::ShouldPrintObjectDescription() {
82+
return ShouldPrintValueObject() && m_options.m_use_object_desc && !IsNil() &&
83+
!IsUninitialized() && !m_options.m_pointer_as_array;
84+
}
85+
7286
llvm::Error ValueObjectPrinter::PrintValueObject() {
7387
// If the incoming ValueObject is in an error state, the best we're going to
7488
// get out of it is its type. But if we don't even have that, just print
@@ -77,6 +91,25 @@ llvm::Error ValueObjectPrinter::PrintValueObject() {
7791
!m_orig_valobj.GetCompilerType().IsValid())
7892
return m_orig_valobj.GetError().ToError();
7993

94+
std::optional<std::string> object_desc;
95+
if (ShouldPrintObjectDescription()) {
96+
// The object description is invoked now, but not printed until after
97+
// value/summary. Calling GetObjectDescription at the outset of printing
98+
// allows for early discovery of errors. In the case of an error, the value
99+
// object is printed normally.
100+
llvm::Expected<std::string> object_desc_or_err =
101+
GetMostSpecializedValue().GetObjectDescription();
102+
if (!object_desc_or_err) {
103+
auto error_msg = toString(object_desc_or_err.takeError());
104+
*m_stream << "error: " << error_msg << maybeNewline(error_msg);
105+
106+
// Print the value object directly.
107+
m_options.DisableObjectDescription();
108+
} else {
109+
object_desc = *object_desc_or_err;
110+
}
111+
}
112+
80113
if (ShouldPrintValueObject()) {
81114
PrintLocationIfNeeded();
82115
m_stream->Indent();
@@ -90,8 +123,10 @@ llvm::Error ValueObjectPrinter::PrintValueObject() {
90123
m_val_summary_ok =
91124
PrintValueAndSummaryIfNeeded(value_printed, summary_printed);
92125

93-
if (m_val_summary_ok)
126+
if (m_val_summary_ok) {
127+
PrintObjectDescriptionIfNeeded(object_desc);
94128
return PrintChildrenIfNeeded(value_printed, summary_printed);
129+
}
95130
m_stream->EOL();
96131

97132
return llvm::Error::success();
@@ -144,24 +179,6 @@ void ValueObjectPrinter::SetupMostSpecializedValue() {
144179
"SetupMostSpecialized value must compute a valid ValueObject");
145180
}
146181

147-
llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() {
148-
ValueObject &valobj = GetMostSpecializedValue();
149-
llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription();
150-
if (maybe_str)
151-
return maybe_str;
152-
153-
const char *str = nullptr;
154-
if (!str)
155-
str = valobj.GetSummaryAsCString();
156-
if (!str)
157-
str = valobj.GetValueAsCString();
158-
159-
if (!str)
160-
return maybe_str;
161-
llvm::consumeError(maybe_str.takeError());
162-
return str;
163-
}
164-
165182
const char *ValueObjectPrinter::GetRootNameForDisplay() {
166183
const char *root_valobj_name =
167184
m_options.m_root_valobj_name.empty()
@@ -468,38 +485,14 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
468485
return !error_printed;
469486
}
470487

471-
llvm::Error
472-
ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
473-
bool summary_printed) {
474-
if (ShouldPrintValueObject()) {
475-
// let's avoid the overly verbose no description error for a nil thing
476-
if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
477-
(!m_options.m_pointer_as_array)) {
478-
if (!m_options.m_hide_value || ShouldShowName())
479-
*m_stream << ' ';
480-
llvm::Expected<std::string> object_desc =
481-
(value_printed || summary_printed)
482-
? GetMostSpecializedValue().GetObjectDescription()
483-
: GetDescriptionForDisplay();
484-
if (!object_desc) {
485-
// If no value or summary was printed, surface the error.
486-
if (!value_printed && !summary_printed)
487-
return object_desc.takeError();
488-
// Otherwise gently nudge the user that they should have used
489-
// `p` instead of `po`. Unfortunately we cannot be more direct
490-
// about this, because we don't actually know what the user did.
491-
*m_stream << "warning: no object description available\n";
492-
llvm::consumeError(object_desc.takeError());
493-
} else {
494-
*m_stream << *object_desc;
495-
// If the description already ends with a \n don't add another one.
496-
if (object_desc->empty() || object_desc->back() != '\n')
497-
*m_stream << '\n';
498-
}
499-
return llvm::Error::success();
500-
}
501-
}
502-
return llvm::Error::success();
488+
void ValueObjectPrinter::PrintObjectDescriptionIfNeeded(
489+
std::optional<std::string> object_desc) {
490+
if (!object_desc)
491+
return;
492+
493+
if (!m_options.m_hide_value || ShouldShowName())
494+
*m_stream << ' ';
495+
*m_stream << *object_desc << maybeNewline(*object_desc);
503496
}
504497

505498
bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion(
@@ -552,7 +545,7 @@ bool ValueObjectPrinter::ShouldPrintChildren(
552545
if (m_options.m_pointer_as_array)
553546
return true;
554547

555-
if (m_options.m_use_objc)
548+
if (m_options.m_use_object_desc)
556549
return false;
557550

558551
bool print_children = true;
@@ -849,9 +842,6 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
849842

850843
llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
851844
bool summary_printed) {
852-
auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
853-
if (error)
854-
return error;
855845

856846
ValueObject &valobj = GetMostSpecializedValue();
857847

lldb/source/Expression/REPL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
321321
const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
322322

323323
EvaluateExpressionOptions expr_options = m_expr_options;
324-
expr_options.SetCoerceToId(m_varobj_options.use_objc);
324+
expr_options.SetCoerceToId(m_varobj_options.use_object_desc);
325325
expr_options.SetKeepInMemory(true);
326326
expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
327327
expr_options.SetGenerateDebugInfo(true);

lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Status OptionGroupValueObjectDisplay::SetOptionValue(
9191
flat_output = true;
9292
break;
9393
case 'O':
94-
use_objc = true;
94+
use_object_desc = true;
9595
break;
9696
case 'R':
9797
be_raw = true;
@@ -164,7 +164,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting(
164164
no_summary_depth = 0;
165165
show_location = false;
166166
flat_output = false;
167-
use_objc = false;
167+
use_object_desc = false;
168168
max_depth = UINT32_MAX;
169169
max_depth_is_default = true;
170170
ptr_depth = 0;
@@ -193,14 +193,14 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
193193
DumpValueObjectOptions options;
194194
options.SetMaximumPointerDepth(
195195
{DumpValueObjectOptions::PointerDepth::Mode::Always, ptr_depth});
196-
if (use_objc)
196+
if (use_object_desc)
197197
options.SetShowSummary(false);
198198
else
199199
options.SetOmitSummaryDepth(no_summary_depth);
200200
options.SetMaximumDepth(max_depth, max_depth_is_default)
201201
.SetShowTypes(show_types)
202202
.SetShowLocation(show_location)
203-
.SetUseObjectiveC(use_objc)
203+
.SetUseObjectDescription(use_object_desc)
204204
.SetUseDynamicType(use_dynamic)
205205
.SetUseSyntheticValue(use_synth)
206206
.SetFlatOutput(flat_output)
@@ -210,8 +210,9 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
210210

211211
if (lang_descr_verbosity ==
212212
eLanguageRuntimeDescriptionDisplayVerbosityCompact)
213-
options.SetHideRootType(use_objc).SetHideName(use_objc).SetHideValue(
214-
use_objc);
213+
options.SetHideRootType(use_object_desc)
214+
.SetHideName(use_object_desc)
215+
.SetHideValue(use_object_desc);
215216

216217
if (be_raw)
217218
options.SetRawDisplay();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
OBJC_SOURCES := main.m
2+
LD_EXTRAS := -lobjc -framework Foundation
3+
include Makefile.rules

0 commit comments

Comments
 (0)