Skip to content

[lldb] Fix po alias by printing fix-its to the console. #68755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 13, 2023

Conversation

PortalPete
Copy link
Contributor

The po alias now matches the behavior of the expression command when the it can apply a Fix-It to an expression.
Modifications

  • Add has m_fixed_expression to the CommandObjectDWIMPrint class a protected member that stores the post Fix-It expression, just like the CommandObjectExpression class.
  • Converted messages to present tense.
  • Add test cases that confirms a Fix-It for a C++ expression for both po and expressions

rdar://115317419

@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2023

@llvm/pr-subscribers-lldb

Author: Pete Lawrence (PortalPete)

Changes

The po alias now matches the behavior of the expression command when the it can apply a Fix-It to an expression.
Modifications

  • Add has m_fixed_expression to the CommandObjectDWIMPrint class a protected member that stores the post Fix-It expression, just like the CommandObjectExpression class.
  • Converted messages to present tense.
  • Add test cases that confirms a Fix-It for a C++ expression for both po and expressions

rdar://115317419


Full diff: https://github.com/llvm/llvm-project/pull/68755.diff

9 Files Affected:

  • (modified) lldb/source/Commands/CommandObjectDWIMPrint.cpp (+13-2)
  • (modified) lldb/source/Commands/CommandObjectExpression.cpp (+4-4)
  • (modified) lldb/test/API/commands/expression/fixits/TestFixIts.py (+2-2)
  • (added) lldb/test/API/lang/cpp/dwim-print-fixit/Makefile (+3)
  • (added) lldb/test/API/lang/cpp/dwim-print-fixit/TestCppDWIMPrintFixIt.py (+24)
  • (added) lldb/test/API/lang/cpp/dwim-print-fixit/main.cpp (+5)
  • (added) lldb/test/API/lang/cpp/expression-fixit/Makefile (+3)
  • (added) lldb/test/API/lang/cpp/expression-fixit/TestCppExpressionFixIt.py (+24)
  • (added) lldb/test/API/lang/cpp/expression-fixit/main.cpp (+5)
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 7b168eab9e02d44..bdc17c9cffc779a 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -172,8 +172,19 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
   {
     auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
     ValueObjectSP valobj_sp;
-    ExpressionResults expr_result =
-        target.EvaluateExpression(expr, exe_scope, valobj_sp, eval_options);
+    std::string fixed_expression;
+
+    ExpressionResults expr_result = target.EvaluateExpression(
+        expr, exe_scope, valobj_sp, eval_options, &fixed_expression);
+
+    // Only mention Fix-Its if the expression evaluator applied them.
+    // Compiler errors refer to the final expression after applying Fix-It(s).
+    if (!fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
+      Stream &error_stream = result.GetErrorStream();
+      error_stream << "  Evaluated this expression after applying Fix-It(s):\n";
+      error_stream << "    " << fixed_expression << "\n";
+    }
+
     if (expr_result == eExpressionCompleted) {
       if (verbosity != eDWIMPrintVerbosityNone) {
         StringRef flags;
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index e7e6e3820b99133..2834be660abaf53 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -439,11 +439,11 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
   ExpressionResults success = target.EvaluateExpression(
       expr, frame, result_valobj_sp, eval_options, &m_fixed_expression);
 
-  // We only tell you about the FixIt if we applied it.  The compiler errors
-  // will suggest the FixIt if it parsed.
+  // Only mention Fix-Its if the expression evaluator applied them.
+  // Compiler errors refer to the final expression after applying Fix-It(s).
   if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
-    error_stream.Printf("  Fix-it applied, fixed expression was: \n    %s\n",
-                        m_fixed_expression.c_str());
+    error_stream << "  Evaluated this expression after applying Fix-It(s):\n";
+    error_stream << "    " << m_fixed_expression << "\n";
   }
 
   if (result_valobj_sp) {
diff --git a/lldb/test/API/commands/expression/fixits/TestFixIts.py b/lldb/test/API/commands/expression/fixits/TestFixIts.py
index 3bdeb84b4e79726..92a3ae8b943e318 100644
--- a/lldb/test/API/commands/expression/fixits/TestFixIts.py
+++ b/lldb/test/API/commands/expression/fixits/TestFixIts.py
@@ -22,7 +22,7 @@ def test_with_dummy_target(self):
         self.assertEqual(
             result, lldb.eReturnStatusSuccessFinishResult, ret_val.GetError()
         )
-        self.assertIn("Fix-it applied", ret_val.GetError())
+        self.assertIn("Evaluated this expression after applying Fix-It(s):", ret_val.GetError())
 
     def test_with_target(self):
         """Test calling expressions with errors that can be fixed by the FixIts."""
@@ -99,7 +99,7 @@ def test_with_target_error_applies_fixit(self):
         )
         self.assertEqual(result, lldb.eReturnStatusFailed, ret_val.GetError())
 
-        self.assertIn("Fix-it applied, fixed expression was:", ret_val.GetError())
+        self.assertIn("Evaluated this expression after applying Fix-It(s):", ret_val.GetError())
         self.assertIn("null_pointer->first", ret_val.GetError())
 
     # The final function call runs into SIGILL on aarch64-linux.
diff --git a/lldb/test/API/lang/cpp/dwim-print-fixit/Makefile b/lldb/test/API/lang/cpp/dwim-print-fixit/Makefile
new file mode 100644
index 000000000000000..99998b20bcb0502
--- /dev/null
+++ b/lldb/test/API/lang/cpp/dwim-print-fixit/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/dwim-print-fixit/TestCppDWIMPrintFixIt.py b/lldb/test/API/lang/cpp/dwim-print-fixit/TestCppDWIMPrintFixIt.py
new file mode 100644
index 000000000000000..260903f30464caa
--- /dev/null
+++ b/lldb/test/API/lang/cpp/dwim-print-fixit/TestCppDWIMPrintFixIt.py
@@ -0,0 +1,24 @@
+"""
+Tests whether the do-what-I-mean (DWIM) print `po` alias applies FixIts like `expr` does
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test_with_run_command(self):
+        """Confirms `po` shows an expression after applying Fix-It(s)."""
+
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect(
+            "dwim-print -O -- class C { int i; void f() { []() { ++i; }(); } }; 42",
+            error = True,
+            substrs=["Evaluated this expression after applying Fix-It(s)",
+                "class C { int i; void f() { [this]() { ++i; }(); } }"],
+        )
diff --git a/lldb/test/API/lang/cpp/dwim-print-fixit/main.cpp b/lldb/test/API/lang/cpp/dwim-print-fixit/main.cpp
new file mode 100644
index 000000000000000..e9cf11d18a6560d
--- /dev/null
+++ b/lldb/test/API/lang/cpp/dwim-print-fixit/main.cpp
@@ -0,0 +1,5 @@
+int main() {
+  long foo = 1234;
+
+  return 0; // break here
+}
diff --git a/lldb/test/API/lang/cpp/expression-fixit/Makefile b/lldb/test/API/lang/cpp/expression-fixit/Makefile
new file mode 100644
index 000000000000000..99998b20bcb0502
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-fixit/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/expression-fixit/TestCppExpressionFixIt.py b/lldb/test/API/lang/cpp/expression-fixit/TestCppExpressionFixIt.py
new file mode 100644
index 000000000000000..b6c255c5e004cfc
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-fixit/TestCppExpressionFixIt.py
@@ -0,0 +1,24 @@
+"""
+Tests whether the expression command applies FixIts
+"""
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test_with_run_command(self):
+        """Confirms `expression` shows an expression after applying Fix-It(s)."""
+
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect(
+            "expr class C { int i; void f() { []() { ++i; }(); } }; 42",
+            error = True,
+            substrs=["Evaluated this expression after applying Fix-It(s)",
+                "class C { int i; void f() { [this]() { ++i; }(); } }"],
+        )
diff --git a/lldb/test/API/lang/cpp/expression-fixit/main.cpp b/lldb/test/API/lang/cpp/expression-fixit/main.cpp
new file mode 100644
index 000000000000000..e9cf11d18a6560d
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-fixit/main.cpp
@@ -0,0 +1,5 @@
+int main() {
+  long foo = 1234;
+
+  return 0; // break here
+}

@github-actions
Copy link

github-actions bot commented Oct 11, 2023

✅ With the latest revision this PR passed the Python code formatter.

@medismailben
Copy link
Member

LGTM overall. I think you can make the test less redundant by using the same source file & Makefile for both tests.

The `po` alias now matches the behavior of the `expression` command when
the it can apply a Fix-It to an expression.
Modifications

- Add has `m_fixed_expression` to the `CommandObjectDWIMPrint` class a
`protected` member that stores the post Fix-It expression, just like the
`CommandObjectExpression` class.
- Converted messages to present tense.
- Add test cases that confirms a Fix-It for a C++ expression for both
`po` and `expressions`

rdar://115317419
@PortalPete
Copy link
Contributor Author

PortalPete commented Oct 12, 2023

Thanks for this suggestion, @medismailben.

LGTM overall. I think you can make the test less redundant by using the same source file & Makefile for both tests.

I wasn't sure which is better:

  • Multiple files, each with a single test
  • Fewer files, each with multiple tests.

Ok, I put the 2 new tests into a single, new file, which makes the file naming a bit simpler and set up for future FixIt tests specific to C++.

@medismailben
Copy link
Member

medismailben commented Oct 13, 2023

Ok, I put the 2 new tests into a single, new file, which makes the file naming a bit simpler and set up for future FixIt tests specific to C++.

This is exactly what I had in mind :) Thanks!

@adrian-prantl
Copy link
Collaborator

I'm testing this locally now and will then merge

@adrian-prantl adrian-prantl merged commit 8e2bd05 into llvm:main Oct 13, 2023
PortalPete added a commit to swiftlang/llvm-project that referenced this pull request Oct 17, 2023
The `po` alias now matches the behavior of the `expression` command when
the it can apply a Fix-It to an expression.
Modifications

- Add has `m_fixed_expression` to the `CommandObjectDWIMPrint` class a
`protected` member that stores the post Fix-It expression, just like the
`CommandObjectExpression` class.
- Converted messages to present tense.
- Add test cases that confirms a Fix-It for a C++ expression for both
`po` and `expressions`

rdar://115317419
(cherry picked from commit 8e2bd05)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants