Skip to content

Commit 927c40e

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 30469c7 commit 927c40e

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
@@ -76,7 +76,9 @@ class DumpValueObjectOptions {
7676

7777
DumpValueObjectOptions &SetShowLocation(bool show = false);
7878

79-
DumpValueObjectOptions &SetUseObjectiveC(bool use = false);
79+
DumpValueObjectOptions &DisableObjectDescription();
80+
81+
DumpValueObjectOptions &SetUseObjectDescription(bool use = false);
8082

8183
DumpValueObjectOptions &SetShowSummary(bool show = true);
8284

@@ -143,13 +145,14 @@ class DumpValueObjectOptions {
143145
ChildPrintingDecider m_child_printing_decider;
144146
PointerAsArraySettings m_pointer_as_array;
145147
unsigned m_expand_ptr_type_flags = 0;
148+
// The following flags commonly default to false.
146149
bool m_use_synthetic : 1;
147150
bool m_scope_already_checked : 1;
148151
bool m_flat_output : 1;
149152
bool m_ignore_cap : 1;
150153
bool m_show_types : 1;
151154
bool m_show_location : 1;
152-
bool m_use_objc : 1;
155+
bool m_use_object_desc : 1;
153156
bool m_hide_root_type : 1;
154157
bool m_hide_root_name : 1;
155158
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
@@ -17,7 +17,7 @@ DumpValueObjectOptions::DumpValueObjectOptions()
1717
: m_summary_sp(), m_root_valobj_name(), m_decl_printing_helper(),
1818
m_child_printing_decider(), m_pointer_as_array(), m_use_synthetic(true),
1919
m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
20-
m_show_types(false), m_show_location(false), m_use_objc(false),
20+
m_show_types(false), m_show_location(false), m_use_object_desc(false),
2121
m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
2222
m_hide_value(false), m_run_validator(false),
2323
m_use_type_display_name(true), m_allow_oneliner_mode(true),
@@ -65,8 +65,19 @@ DumpValueObjectOptions &DumpValueObjectOptions::SetShowLocation(bool show) {
6565
return *this;
6666
}
6767

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

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() const {
@@ -524,7 +517,7 @@ bool ValueObjectPrinter::ShouldPrintChildren(
524517
if (m_options.m_pointer_as_array)
525518
return true;
526519

527-
if (m_options.m_use_objc)
520+
if (m_options.m_use_object_desc)
528521
return false;
529522

530523
bool print_children = true;
@@ -819,9 +812,6 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
819812

820813
llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
821814
bool summary_printed) {
822-
auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
823-
if (error)
824-
return error;
825815

826816
ValueObject &valobj = GetMostSpecializedValue();
827817

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;
@@ -192,14 +192,14 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
192192
lldb::Format format, lldb::TypeSummaryImplSP summary_sp) {
193193
DumpValueObjectOptions options;
194194
options.SetMaximumPointerDepth(ptr_depth);
195-
if (use_objc)
195+
if (use_object_desc)
196196
options.SetShowSummary(false);
197197
else
198198
options.SetOmitSummaryDepth(no_summary_depth);
199199
options.SetMaximumDepth(max_depth, max_depth_is_default)
200200
.SetShowTypes(show_types)
201201
.SetShowLocation(show_location)
202-
.SetUseObjectiveC(use_objc)
202+
.SetUseObjectDescription(use_object_desc)
203203
.SetUseDynamicType(use_dynamic)
204204
.SetUseSyntheticValue(use_synth)
205205
.SetFlatOutput(flat_output)
@@ -209,8 +209,9 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
209209

210210
if (lang_descr_verbosity ==
211211
eLanguageRuntimeDescriptionDisplayVerbosityCompact)
212-
options.SetHideRootType(use_objc).SetHideName(use_objc).SetHideValue(
213-
use_objc);
212+
options.SetHideRootType(use_object_desc)
213+
.SetHideName(use_object_desc)
214+
.SetHideValue(use_object_desc);
214215

215216
if (be_raw)
216217
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)