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