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

Reply via email to