kastiglione created this revision. kastiglione added reviewers: aprantl, jingham, JDevlieghere, augusto2112. Herald added a project: All. kastiglione requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
The `frame variable` command can handle mistaken use of `.` for `->`, and vice versa, but up until now it has been an error when the user makes such a mistake. This change adds a flag to `frame variable` which allows these mistakes to be fixed. The idea is why make the user manually edit the command if lldb can figure it out. This is similar to `expression` which supports fixits supplied by the compiler, which include correcting `.` to `->`, and vice versa. There are a couple of details that differ slightly from `expression`: 1. The `--apply-fixits`/`-X` flag doesn't take a bool value, this matches the convention used by many `frame variable` flags. 2. The fixed expression is printed, but there is no diagnostic message to draw attention to the fix. I wasn't sure it was worth the noise, so I went with the simple approach. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D147385 Files: lldb/include/lldb/Interpreter/OptionGroupVariable.h lldb/source/Commands/CommandObjectFrame.cpp lldb/source/Interpreter/OptionGroupVariable.cpp lldb/test/API/commands/frame/var/fixits/Makefile lldb/test/API/commands/frame/var/fixits/TestFrameVarApplyFixits.py lldb/test/API/commands/frame/var/fixits/main.c
Index: lldb/test/API/commands/frame/var/fixits/main.c =================================================================== --- /dev/null +++ lldb/test/API/commands/frame/var/fixits/main.c @@ -0,0 +1,10 @@ +struct Structure { + int num; +}; + +int main() { + struct Structure s = {30}; + struct Structure *p = &s; + // break here + return 0; +} Index: lldb/test/API/commands/frame/var/fixits/TestFrameVarApplyFixits.py =================================================================== --- /dev/null +++ lldb/test/API/commands/frame/var/fixits/TestFrameVarApplyFixits.py @@ -0,0 +1,24 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + + +class TestCase(TestBase): + def test_frame_variable_apply_fixits(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + + self.expect( + "frame variable s->num", + error=True, + startstr='error: "s" is not a pointer and -> was used to attempt to access "num". Did you mean "s.num"?', + ) + self.expect("frame variable --apply-fixits s->num", startstr="(int) s.num = 30") + + self.expect( + "frame variable p.num", + error=True, + startstr='error: "p" is a pointer and . was used to attempt to access "num". Did you mean "p->num"?', + ) + self.expect("frame variable --apply-fixits p.num", startstr="(int) p->num = 30") Index: lldb/test/API/commands/frame/var/fixits/Makefile =================================================================== --- /dev/null +++ lldb/test/API/commands/frame/var/fixits/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules Index: lldb/source/Interpreter/OptionGroupVariable.cpp =================================================================== --- lldb/source/Interpreter/OptionGroupVariable.cpp +++ lldb/source/Interpreter/OptionGroupVariable.cpp @@ -42,6 +42,9 @@ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."}, + {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "apply-fixits", 'X', + OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, + "simple fix-it corrections will be applied to the variable path."}, {LLDB_OPT_SET_1, false, "summary", 'y', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeName, "Specify the summary that the variable output should use."}, @@ -70,7 +73,8 @@ : include_frame_options(show_frame_options), show_args(false), show_recognized_args(false), show_locals(false), show_globals(false), use_regex(false), show_scope(false), show_decl(false), - summary(ValidateNamedSummary), summary_string(ValidateSummaryString) {} + apply_fixits(false), summary(ValidateNamedSummary), + summary_string(ValidateSummaryString) {} Status OptionGroupVariable::SetOptionValue(uint32_t option_idx, @@ -102,6 +106,9 @@ case 't': show_recognized_args = false; break; + case 'X': + apply_fixits = true; + break; case 'y': error = summary.SetCurrentValue(option_arg); break; @@ -124,6 +131,7 @@ show_decl = false; use_regex = false; show_scope = false; + apply_fixits = false; summary.Clear(); summary_string.Clear(); } Index: lldb/source/Commands/CommandObjectFrame.cpp =================================================================== --- lldb/source/Commands/CommandObjectFrame.cpp +++ lldb/source/Commands/CommandObjectFrame.cpp @@ -578,9 +578,11 @@ { Status error; uint32_t expr_path_options = - StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | StackFrame::eExpressionPathOptionsInspectAnonymousUnions; + if (!m_option_variable.apply_fixits) + expr_path_options |= + StackFrame::eExpressionPathOptionCheckPtrVsMember; lldb::VariableSP var_sp; valobj_sp = frame->GetValueForVariableExpressionPath( entry.ref(), m_varobj_options.use_dynamic, expr_path_options, @@ -602,10 +604,16 @@ options.SetVariableFormatDisplayLanguage( valobj_sp->GetPreferredDisplayLanguage()); - Stream &output_stream = result.GetOutputStream(); + // Use the returned value's expression path, because it might + // differ from the input expression (when fixits are used). + StreamString expr_path_stream; + valobj_sp->GetExpressionPath( + expr_path_stream, + ValueObject::eGetExpressionPathFormatHonorPointers); + auto root_name = expr_path_stream.GetString(); options.SetRootValueObjectName( - valobj_sp->GetParent() ? entry.c_str() : nullptr); - valobj_sp->Dump(output_stream, options); + valobj_sp->GetParent() ? root_name.data() : nullptr); + valobj_sp->Dump(result.GetOutputStream(), options); } else { if (auto error_cstr = error.AsCString(nullptr)) result.AppendError(error_cstr); Index: lldb/include/lldb/Interpreter/OptionGroupVariable.h =================================================================== --- lldb/include/lldb/Interpreter/OptionGroupVariable.h +++ lldb/include/lldb/Interpreter/OptionGroupVariable.h @@ -35,7 +35,7 @@ // true) show_locals : 1, // Frame option only (include_frame_options == true) show_globals : 1, // Frame option only (include_frame_options == true) - use_regex : 1, show_scope : 1, show_decl : 1; + use_regex : 1, show_scope : 1, show_decl : 1, apply_fixits : 1; OptionValueString summary; // the name of a named summary OptionValueString summary_string; // a summary string
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits