xref: /llvm-project/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py (revision 7349bc34836b73518ca3e9366019ef20094f2525)
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