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