1""" Test that evaluating expressions from within C++ lambdas works 2 Particularly, we test the case of capturing "this" and 3 using members of the captured object in expression evaluation 4 while we're on a breakpoint inside a lambda. 5""" 6 7 8import lldb 9from lldbsuite.test.lldbtest import * 10 11 12class ExprInsideLambdaTestCase(TestBase): 13 def expectExprError(self, expr: str, expected: str): 14 frame = self.thread.GetFrameAtIndex(0) 15 value = frame.EvaluateExpression(expr) 16 errmsg = value.GetError().GetCString() 17 self.assertIn(expected, errmsg) 18 19 def test_expr_inside_lambda(self): 20 """Test that lldb evaluating expressions inside lambda expressions works correctly.""" 21 self.build() 22 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint( 23 self, "break here", lldb.SBFileSpec("main.cpp") 24 ) 25 26 # Inside 'Foo::method' 27 28 # Check access to captured 'this' 29 self.expect_expr("class_var", result_type="int", result_value="109") 30 self.expect_expr("this->class_var", result_type="int", result_value="109") 31 32 # Check that captured shadowed variables take preference over the 33 # corresponding member variable 34 self.expect_expr("shadowed", result_type="int", result_value="5") 35 self.expect_expr("this->shadowed", result_type="int", result_value="-137") 36 37 # Check access to local captures 38 self.expect_expr("local_var", result_type="int", result_value="137") 39 self.expect_expr("*class_ptr", result_type="int", result_value="137") 40 41 # Check access to base class variables 42 self.expect_expr("base_var", result_type="int", result_value="14") 43 self.expect_expr("base_base_var", result_type="int", result_value="11") 44 45 # Check access to global variable 46 self.expect_expr("global_var", result_type="int", result_value="-5") 47 48 # Check access to multiple captures/member variables 49 self.expect_expr( 50 "(shadowed + this->shadowed) * (base_base_var + local_var - class_var)", 51 result_type="int", 52 result_value="-5148", 53 ) 54 55 # Check base-class function call 56 self.expect_expr("baz_virt()", result_type="int", result_value="2") 57 self.expect_expr("base_var", result_type="int", result_value="14") 58 self.expect_expr("this->shadowed", result_type="int", result_value="-1") 59 60 # 'p this' should yield 'struct Foo*' 61 frame = self.thread.GetFrameAtIndex(0) 62 outer_class_addr = frame.GetValueForVariablePath("this->this") 63 self.expect_expr("this", result_value=outer_class_addr.GetValue()) 64 65 lldbutil.continue_to_breakpoint(process, bkpt) 66 67 # Inside 'nested_lambda' 68 69 # Check access to captured 'this'. Should still be 'struct Foo*' 70 self.expect_expr("class_var", result_type="int", result_value="109") 71 self.expect_expr("global_var", result_type="int", result_value="-5") 72 self.expect_expr("this", result_value=outer_class_addr.GetValue()) 73 74 # Check access to captures 75 self.expect_expr("lambda_local_var", result_type="int", result_value="5") 76 self.expect_expr("local_var", result_type="int", result_value="137") 77 78 # Check access to variable in previous frame which we didn't capture 79 self.expectExprError("local_var_copy", "use of undeclared identifier") 80 81 lldbutil.continue_to_breakpoint(process, bkpt) 82 83 # By-ref mutates source variable 84 self.expect_expr("lambda_local_var", result_type="int", result_value="0") 85 86 # By-value doesn't mutate source variable 87 self.expect_expr("local_var_copy", result_type="int", result_value="136") 88 self.expect_expr("local_var", result_type="int", result_value="137") 89 90 lldbutil.continue_to_breakpoint(process, bkpt) 91 92 # Inside 'LocalLambdaClass::inner_method' 93 94 # Check access to captured 'this' 95 self.expect_expr("lambda_class_local", result_type="int", result_value="-12345") 96 self.expect_expr( 97 "this->lambda_class_local", result_type="int", result_value="-12345" 98 ) 99 self.expect_expr("outer_ptr->class_var", result_type="int", result_value="109") 100 101 # 'p this' should yield 'struct LocalLambdaClass*' 102 frame = self.thread.GetFrameAtIndex(0) 103 local_class_addr = frame.GetValueForVariablePath("this->this") 104 self.assertNotEqual(local_class_addr, outer_class_addr) 105 self.expect_expr("this", result_value=local_class_addr.GetValue()) 106 107 # Can still access global variable 108 self.expect_expr("global_var", result_type="int", result_value="-5") 109 110 # Check access to outer top-level structure's members 111 self.expectExprError( 112 "class_var", 113 ("use of non-static data member" " 'class_var' of 'Foo' from nested type"), 114 ) 115 116 self.expectExprError( 117 "base_var", ("use of non-static data member" " 'base_var'") 118 ) 119 120 self.expectExprError( 121 "local_var", 122 ( 123 "use of non-static data member 'local_var'" 124 " of '(unnamed class)' from nested type 'LocalLambdaClass'" 125 ), 126 ) 127 128 # Inside non_capturing_method 129 lldbutil.continue_to_breakpoint(process, bkpt) 130 self.expect_expr("local", result_type="int", result_value="5") 131 self.expect_expr("local2", result_type="int", result_value="10") 132 self.expect_expr("local2 * local", result_type="int", result_value="50") 133 134 self.expectExprError( 135 "class_var", 136 ("use of non-static data member" " 'class_var' of 'Foo' from nested type"), 137 ) 138