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