184 lines · python
1"""2Test calling an expression with errors that a FixIt can fix.3"""4 5import lldb6from lldbsuite.test.decorators import *7from lldbsuite.test.lldbtest import *8from lldbsuite.test import lldbutil9 10 11class ExprCommandWithFixits(TestBase):12 def test_with_dummy_target(self):13 """Test calling expressions in the dummy target with errors that can be fixed by the FixIts."""14 15 # Enable fix-its as they were intentionally disabled by TestBase.setUp.16 self.runCmd("settings set target.auto-apply-fixits true")17 18 ret_val = lldb.SBCommandReturnObject()19 result = self.dbg.GetCommandInterpreter().HandleCommand(20 "expression ((1 << 16) - 1))", ret_val21 )22 self.assertEqual(23 result, lldb.eReturnStatusSuccessFinishResult, ret_val.GetError()24 )25 self.assertIn(26 "Evaluated this expression after applying Fix-It(s):", ret_val.GetError()27 )28 29 def test_with_target(self):30 """Test calling expressions with errors that can be fixed by the FixIts."""31 self.build()32 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(33 self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")34 )35 36 options = lldb.SBExpressionOptions()37 options.SetAutoApplyFixIts(True)38 39 top_level_options = lldb.SBExpressionOptions()40 top_level_options.SetAutoApplyFixIts(True)41 top_level_options.SetTopLevel(True)42 43 frame = self.thread.GetFrameAtIndex(0)44 45 # Try with one error:46 value = frame.EvaluateExpression("my_pointer.first", options)47 self.assertTrue(value.IsValid())48 self.assertSuccess(value.GetError())49 self.assertEqual(value.GetValueAsUnsigned(), 10)50 51 # Try with one error in a top-level expression.52 # The Fix-It changes "ptr.m" to "ptr->m".53 expr = "struct MyTy { int m; }; MyTy x; MyTy *ptr = &x; int m = ptr.m;"54 value = frame.EvaluateExpression(expr, top_level_options)55 # A successfully parsed top-level expression will yield an56 # unknown error. If a parsing error would have happened we57 # would get a different error kind, so let's check the error58 # kind here.59 self.assertEqual(value.GetError().GetCString(), "unknown error")60 61 # Try with two errors:62 two_error_expression = "my_pointer.second->a"63 value = frame.EvaluateExpression(two_error_expression, options)64 self.assertTrue(value.IsValid())65 self.assertSuccess(value.GetError())66 self.assertEqual(value.GetValueAsUnsigned(), 20)67 68 # Try a Fix-It that is stored in the 'note:' diagnostic of an error.69 # The Fix-It here is adding parantheses around the ToStr parameters.70 fixit_in_note_expr = "#define ToStr(x) #x\nToStr(0 {, })"71 value = frame.EvaluateExpression(fixit_in_note_expr, options)72 self.assertTrue(value.IsValid())73 self.assertSuccess(value.GetError())74 self.assertEqual(value.GetSummary(), '"(0 {, })"')75 76 # Now turn off the fixits, and the expression should fail:77 options.SetAutoApplyFixIts(False)78 value = frame.EvaluateExpression(two_error_expression, options)79 self.assertTrue(value.IsValid())80 self.assertTrue(value.GetError().Fail())81 error_string = value.GetError().GetCString()82 self.assertNotEqual(83 error_string.find("fixed expression suggested:"), -1, "Fix was suggested"84 )85 self.assertNotEqual(86 error_string.find("my_pointer->second.a"), -1, "Fix was right"87 )88 89 def test_with_target_error_applies_fixit(self):90 """Check that applying a Fix-it which fails to execute correctly still91 prints that the Fix-it was applied."""92 self.build()93 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(94 self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")95 )96 # Enable fix-its as they were intentionally disabled by TestBase.setUp.97 self.runCmd("settings set target.auto-apply-fixits true")98 ret_val = lldb.SBCommandReturnObject()99 result = self.dbg.GetCommandInterpreter().HandleCommand(100 "expression null_pointer.first", ret_val101 )102 self.assertEqual(result, lldb.eReturnStatusFailed, ret_val.GetError())103 104 self.assertIn(105 "Evaluated this expression after applying Fix-It(s):", ret_val.GetError()106 )107 self.assertIn("null_pointer->first", ret_val.GetError())108 109 @expectedFailureAll(110 archs=["aarch64"], oslist=["freebsd"], bugnumber="llvm.org/pr49407"111 )112 def test_with_multiple_retries(self):113 """Test calling expressions with errors that can be fixed by the FixIts."""114 self.build()115 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(116 self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")117 )118 119 # Test repeatedly applying Fix-Its to expressions and reparsing them.120 multiple_runs_options = lldb.SBExpressionOptions()121 multiple_runs_options.SetAutoApplyFixIts(True)122 multiple_runs_options.SetTopLevel(True)123 124 frame = self.thread.GetFrameAtIndex(0)125 126 # An expression that needs two parse attempts with one Fix-It each127 # to be successfully parsed.128 two_runs_expr = """129 struct Data { int m; };130 131 template<typename T>132 struct S1 : public T {133 using T::TypeDef;134 int f() {135 Data data;136 data.m = 123;137 // The first error as the using above requires a 'typename '.138 // Will trigger a Fix-It that puts 'typename' in the right place.139 typename S1<T>::TypeDef i = &data;140 // i has the type "Data *", so this should be i.m.141 // The second run will change the . to -> via the Fix-It.142 return i.m;143 }144 };145 146 struct ClassWithTypeDef {147 typedef Data *TypeDef;148 };149 150 int test_X(int i) {151 S1<ClassWithTypeDef> s1;152 return s1.f();153 }154 """155 156 # Disable retries which will fail.157 multiple_runs_options.SetRetriesWithFixIts(0)158 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)159 errmsg = value.GetError().GetCString()160 self.assertIn("using declaration resolved to type without 'typename'", errmsg)161 self.assertIn("fixed expression suggested:", errmsg)162 self.assertIn("using typename T::TypeDef", errmsg)163 # The second Fix-It shouldn't be suggested here as Clang should have164 # aborted the parsing process.165 self.assertNotIn("i->m", errmsg)166 167 # Retry once, but the expression needs two retries.168 multiple_runs_options.SetRetriesWithFixIts(1)169 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)170 errmsg = value.GetError().GetCString()171 self.assertIn("fixed expression suggested:", errmsg)172 # Both our fixed expressions should be in the suggested expression.173 self.assertIn("using typename T::TypeDef", errmsg)174 self.assertIn("i->m", errmsg)175 176 # Retry twice, which will get the expression working.177 multiple_runs_options.SetRetriesWithFixIts(2)178 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options)179 # This error signals success for top level expressions.180 self.assertEqual(value.GetError().GetCString(), "unknown error")181 182 # Test that the code above compiles to the right thing.183 self.expect_expr("test_X(1)", result_type="int", result_value="123")184