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 14 def expectExprError(self, expr : str, expected : str): 15 frame = self.thread.GetFrameAtIndex(0) 16 value = frame.EvaluateExpression(expr) 17 errmsg = value.GetError().GetCString() 18 self.assertIn(expected, errmsg) 19 20 def test_expr_inside_lambda(self): 21 """Test that lldb evaluating expressions inside lambda expressions works correctly.""" 22 self.build() 23 (target, process, self.thread, bkpt) = \ 24 lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.cpp")) 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("(shadowed + this->shadowed) * (base_base_var + local_var - class_var)", 50 result_type="int", result_value="-5148") 51 52 # Check base-class function call 53 self.expect_expr("baz_virt()", result_type="int", result_value="2") 54 self.expect_expr("base_var", result_type="int", result_value="14") 55 self.expect_expr("this->shadowed", result_type="int", result_value="-1") 56 57 # 'p this' should yield 'struct Foo*' 58 frame = self.thread.GetFrameAtIndex(0) 59 outer_class_addr = frame.GetValueForVariablePath("this->this") 60 self.expect_expr("this", result_value=outer_class_addr.GetValue()) 61 62 lldbutil.continue_to_breakpoint(process, bkpt) 63 64 # Inside 'nested_lambda' 65 66 # Check access to captured 'this'. Should still be 'struct Foo*' 67 self.expect_expr("class_var", result_type="int", result_value="109") 68 self.expect_expr("global_var", result_type="int", result_value="-5") 69 self.expect_expr("this", result_value=outer_class_addr.GetValue()) 70 71 # Check access to captures 72 self.expect_expr("lambda_local_var", result_type="int", result_value="5") 73 self.expect_expr("local_var", result_type="int", result_value="137") 74 75 # Check access to variable in previous frame which we didn't capture 76 self.expectExprError("local_var_copy", "use of undeclared identifier") 77 78 lldbutil.continue_to_breakpoint(process, bkpt) 79 80 # By-ref mutates source variable 81 self.expect_expr("lambda_local_var", result_type="int", result_value="0") 82 83 # By-value doesn't mutate source variable 84 self.expect_expr("local_var_copy", result_type="int", result_value="136") 85 self.expect_expr("local_var", result_type="int", result_value="137") 86 87 lldbutil.continue_to_breakpoint(process, bkpt) 88 89 # Inside 'LocalLambdaClass::inner_method' 90 91 # Check access to captured 'this' 92 self.expect_expr("lambda_class_local", result_type="int", result_value="-12345") 93 self.expect_expr("this->lambda_class_local", result_type="int", result_value="-12345") 94 self.expect_expr("outer_ptr->class_var", result_type="int", result_value="109") 95 96 # 'p this' should yield 'struct LocalLambdaClass*' 97 frame = self.thread.GetFrameAtIndex(0) 98 local_class_addr = frame.GetValueForVariablePath("this->this") 99 self.assertNotEqual(local_class_addr, outer_class_addr) 100 self.expect_expr("this", result_value=local_class_addr.GetValue()) 101 102 # Can still access global variable 103 self.expect_expr("global_var", result_type="int", result_value="-5") 104 105 # Check access to outer top-level structure's members 106 self.expectExprError("class_var", ("use of non-static data member" 107 " 'class_var' of 'Foo' from nested type")) 108 109 self.expectExprError("base_var", ("use of non-static data member" 110 " 'base_var'")) 111 112 self.expectExprError("local_var", ("use of non-static data member 'local_var'" 113 " of '(unnamed class)' from nested type 'LocalLambdaClass'")) 114 115 # Inside non_capturing_method 116 lldbutil.continue_to_breakpoint(process, bkpt) 117 self.expect_expr("local", result_type="int", result_value="5") 118 self.expect_expr("local2", result_type="int", result_value="10") 119 self.expect_expr("local2 * local", result_type="int", result_value="50") 120 121 self.expectExprError("class_var", ("use of non-static data member" 122 " 'class_var' of 'Foo' from nested type")) 123