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