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 mydir = TestBase.compute_mydir(__file__) 14 15 def test_with_dummy_target(self): 16 """Test calling expressions in the dummy target with errors that can be fixed by the FixIts.""" 17 18 # Enable fix-its as they were intentionally disabled by TestBase.setUp. 19 self.runCmd("settings set target.auto-apply-fixits true") 20 21 ret_val = lldb.SBCommandReturnObject() 22 result = self.dbg.GetCommandInterpreter().HandleCommand("expression ((1 << 16) - 1))", ret_val) 23 self.assertEqual(result, lldb.eReturnStatusSuccessFinishResult, "The expression was successful.") 24 self.assertTrue("Fix-it applied" in ret_val.GetError(), "Found the applied FixIt.") 25 26 @expectedFailureAll(archs=["aarch64"], oslist=["linux"]) 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(self, 31 'Stop here to evaluate expressions', 32 lldb.SBFileSpec("main.cpp")) 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.assertTrue(value.GetError().Success()) 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 X { int m; }; X x; X *ptr = &x; int m = ptr.m;" 52 value = frame.EvaluateExpression(expr, top_level_options) 53 # A successfully parsed top-level expression will yield an error 54 # that there is 'no value'. If a parsing error would have happened we 55 # would get a different error kind, so let's check the error kind here. 56 self.assertEquals(value.GetError().GetCString(), "error: No value") 57 58 # Try with two errors: 59 two_error_expression = "my_pointer.second->a" 60 value = frame.EvaluateExpression(two_error_expression, options) 61 self.assertTrue(value.IsValid()) 62 self.assertTrue(value.GetError().Success()) 63 self.assertEquals(value.GetValueAsUnsigned(), 20) 64 65 # Try a Fix-It that is stored in the 'note:' diagnostic of an error. 66 # The Fix-It here is adding parantheses around the ToStr parameters. 67 fixit_in_note_expr ="#define ToStr(x) #x\nToStr(0 {, })" 68 value = frame.EvaluateExpression(fixit_in_note_expr, options) 69 self.assertTrue(value.IsValid()) 70 self.assertTrue(value.GetError().Success(), value.GetError()) 71 self.assertEquals(value.GetSummary(), '"(0 {, })"') 72 73 # Now turn off the fixits, and the expression should fail: 74 options.SetAutoApplyFixIts(False) 75 value = frame.EvaluateExpression(two_error_expression, options) 76 self.assertTrue(value.IsValid()) 77 self.assertTrue(value.GetError().Fail()) 78 error_string = value.GetError().GetCString() 79 self.assertTrue( 80 error_string.find("fixed expression suggested:") != -1, 81 "Fix was suggested") 82 self.assertTrue( 83 error_string.find("my_pointer->second.a") != -1, 84 "Fix was right") 85 86 87 # Test repeatedly applying Fix-Its to expressions and reparsing them. 88 multiple_runs_options = lldb.SBExpressionOptions() 89 multiple_runs_options.SetAutoApplyFixIts(True) 90 multiple_runs_options.SetTopLevel(True) 91 92 # An expression that needs two parse attempts with one Fix-It each 93 # to be successfully parsed. 94 two_runs_expr = """ 95 struct Data { int m; }; 96 97 template<typename T> 98 struct S1 : public T { 99 using T::TypeDef; 100 int f() { 101 Data d; 102 d.m = 123; 103 // The first error as the using above requires a 'typename '. 104 // Will trigger a Fix-It that puts 'typename' in the right place. 105 typename S1<T>::TypeDef i = &d; 106 // i has the type "Data *", so this should be i.m. 107 // The second run will change the . to -> via the Fix-It. 108 return i.m; 109 } 110 }; 111 112 struct ClassWithTypeDef { 113 typedef Data *TypeDef; 114 }; 115 116 int test_X(int i) { 117 S1<ClassWithTypeDef> s1; 118 return s1.f(); 119 } 120 """ 121 122 # Disable retries which will fail. 123 multiple_runs_options.SetRetriesWithFixIts(0) 124 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options) 125 self.assertIn("expression failed to parse, fixed expression suggested:", 126 value.GetError().GetCString()) 127 self.assertIn("using typename T::TypeDef", 128 value.GetError().GetCString()) 129 # The second Fix-It shouldn't be suggested here as Clang should have 130 # aborted the parsing process. 131 self.assertNotIn("i->m", 132 value.GetError().GetCString()) 133 134 # Retry once, but the expression needs two retries. 135 multiple_runs_options.SetRetriesWithFixIts(1) 136 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options) 137 self.assertIn("expression failed to parse, fixed expression suggested:", 138 value.GetError().GetCString()) 139 # Both our fixed expressions should be in the suggested expression. 140 self.assertIn("using typename T::TypeDef", 141 value.GetError().GetCString()) 142 self.assertIn("i->m", 143 value.GetError().GetCString()) 144 145 # Retry twice, which will get the expression working. 146 multiple_runs_options.SetRetriesWithFixIts(2) 147 value = frame.EvaluateExpression(two_runs_expr, multiple_runs_options) 148 # This error signals success for top level expressions. 149 self.assertEquals(value.GetError().GetCString(), "error: No value") 150 151 # Test that the code above compiles to the right thing. 152 self.expect_expr("test_X(1)", result_type="int", result_value="123") 153