Skip to content

Commit ae7e1b8

Browse files
authored
[lldb] Print ValueObject when GetObjectDescription fails (#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.
1 parent ffaba75 commit ae7e1b8

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
@@ -93,7 +93,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
9393
dump_options.SetHideRootName(suppress_result)
9494
.SetExpandPointerTypeFlags(lldb::eTypeIsObjC);
9595

96-
bool is_po = m_varobj_options.use_objc;
96+
bool is_po = m_varobj_options.use_object_desc;
9797

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

lldb/source/Commands/CommandObjectExpression.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ EvaluateExpressionOptions
202202
CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
203203
const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
204204
EvaluateExpressionOptions options;
205-
options.SetCoerceToId(display_opts.use_objc);
205+
options.SetCoerceToId(display_opts.use_object_desc);
206206
options.SetUnwindOnError(unwind_on_error);
207207
options.SetIgnoreBreakpoints(ignore_breakpoints);
208208
options.SetKeepInMemory(true);
@@ -241,11 +241,11 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
241241
bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
242242
const OptionGroupValueObjectDisplay &display_opts) const {
243243
// Explicitly disabling persistent results takes precedence over the
244-
// m_verbosity/use_objc logic.
244+
// m_verbosity/use_object_desc logic.
245245
if (suppress_persistent_result != eLazyBoolCalculate)
246246
return suppress_persistent_result == eLazyBoolYes;
247247

248-
return display_opts.use_objc &&
248+
return display_opts.use_object_desc &&
249249
m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
250250
}
251251

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

333333
void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
334334
EvaluateExpressionOptions options;
335-
options.SetCoerceToId(m_varobj_options.use_objc);
335+
options.SetCoerceToId(m_varobj_options.use_object_desc);
336336
options.SetLanguage(m_command_options.language);
337337
options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
338338
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,9 +14,11 @@
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>
1920
#include <memory>
21+
#include <optional>
2022

2123
using namespace lldb;
2224
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
@@ -90,7 +90,7 @@ Status OptionGroupValueObjectDisplay::SetOptionValue(
9090
flat_output = true;
9191
break;
9292
case 'O':
93-
use_objc = true;
93+
use_object_desc = true;
9494
break;
9595
case 'R':
9696
be_raw = true;
@@ -163,7 +163,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting(
163163
no_summary_depth = 0;
164164
show_location = false;
165165
flat_output = false;
166-
use_objc = false;
166+
use_object_desc = false;
167167
max_depth = UINT32_MAX;
168168
max_depth_is_default = true;
169169
ptr_depth = 0;
@@ -191,14 +191,14 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
191191
lldb::Format format, lldb::TypeSummaryImplSP summary_sp) {
192192
DumpValueObjectOptions options;
193193
options.SetMaximumPointerDepth(ptr_depth);
194-
if (use_objc)
194+
if (use_object_desc)
195195
options.SetShowSummary(false);
196196
else
197197
options.SetOmitSummaryDepth(no_summary_depth);
198198
options.SetMaximumDepth(max_depth, max_depth_is_default)
199199
.SetShowTypes(show_types)
200200
.SetShowLocation(show_location)
201-
.SetUseObjectiveC(use_objc)
201+
.SetUseObjectDescription(use_object_desc)
202202
.SetUseDynamicType(use_dynamic)
203203
.SetUseSyntheticValue(use_synth)
204204
.SetFlatOutput(flat_output)
@@ -208,8 +208,9 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
208208

209209
if (lang_descr_verbosity ==
210210
eLanguageRuntimeDescriptionDisplayVerbosityCompact)
211-
options.SetHideRootType(use_objc).SetHideName(use_objc).SetHideValue(
212-
use_objc);
211+
options.SetHideRootType(use_object_desc)
212+
.SetHideName(use_object_desc)
213+
.SetHideValue(use_object_desc);
213214

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