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