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