xref: /llvm-project/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
18184b252SMichael Buch""" Test that evaluating expressions from within C++ lambdas works
28184b252SMichael Buch    Particularly, we test the case of capturing "this" and
38184b252SMichael Buch    using members of the captured object in expression evaluation
48184b252SMichael Buch    while we're on a breakpoint inside a lambda.
58184b252SMichael Buch"""
68184b252SMichael Buch
78184b252SMichael Buch
88184b252SMichael Buchimport lldb
98184b252SMichael Buchfrom lldbsuite.test.lldbtest import *
108184b252SMichael Buch
118184b252SMichael Buch
128184b252SMichael Buchclass ExprInsideLambdaTestCase(TestBase):
138184b252SMichael Buch    def expectExprError(self, expr: str, expected: str):
148184b252SMichael Buch        frame = self.thread.GetFrameAtIndex(0)
158184b252SMichael Buch        value = frame.EvaluateExpression(expr)
168184b252SMichael Buch        errmsg = value.GetError().GetCString()
178184b252SMichael Buch        self.assertIn(expected, errmsg)
188184b252SMichael Buch
198184b252SMichael Buch    def test_expr_inside_lambda(self):
208184b252SMichael Buch        """Test that lldb evaluating expressions inside lambda expressions works correctly."""
218184b252SMichael Buch        self.build()
22*2238dcc3SJonas Devlieghere        (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(
23*2238dcc3SJonas Devlieghere            self, "break here", lldb.SBFileSpec("main.cpp")
24*2238dcc3SJonas Devlieghere        )
258184b252SMichael Buch
268184b252SMichael Buch        # Inside 'Foo::method'
278184b252SMichael Buch
288184b252SMichael Buch        # Check access to captured 'this'
298184b252SMichael Buch        self.expect_expr("class_var", result_type="int", result_value="109")
308184b252SMichael Buch        self.expect_expr("this->class_var", result_type="int", result_value="109")
318184b252SMichael Buch
328184b252SMichael Buch        # Check that captured shadowed variables take preference over the
338184b252SMichael Buch        # corresponding member variable
348184b252SMichael Buch        self.expect_expr("shadowed", result_type="int", result_value="5")
358184b252SMichael Buch        self.expect_expr("this->shadowed", result_type="int", result_value="-137")
368184b252SMichael Buch
378184b252SMichael Buch        # Check access to local captures
388184b252SMichael Buch        self.expect_expr("local_var", result_type="int", result_value="137")
398184b252SMichael Buch        self.expect_expr("*class_ptr", result_type="int", result_value="137")
408184b252SMichael Buch
418184b252SMichael Buch        # Check access to base class variables
428184b252SMichael Buch        self.expect_expr("base_var", result_type="int", result_value="14")
438184b252SMichael Buch        self.expect_expr("base_base_var", result_type="int", result_value="11")
448184b252SMichael Buch
458184b252SMichael Buch        # Check access to global variable
468184b252SMichael Buch        self.expect_expr("global_var", result_type="int", result_value="-5")
478184b252SMichael Buch
488184b252SMichael Buch        # Check access to multiple captures/member variables
49*2238dcc3SJonas Devlieghere        self.expect_expr(
50*2238dcc3SJonas Devlieghere            "(shadowed + this->shadowed) * (base_base_var + local_var - class_var)",
51*2238dcc3SJonas Devlieghere            result_type="int",
52*2238dcc3SJonas Devlieghere            result_value="-5148",
53*2238dcc3SJonas Devlieghere        )
548184b252SMichael Buch
558184b252SMichael Buch        # Check base-class function call
568184b252SMichael Buch        self.expect_expr("baz_virt()", result_type="int", result_value="2")
578184b252SMichael Buch        self.expect_expr("base_var", result_type="int", result_value="14")
588184b252SMichael Buch        self.expect_expr("this->shadowed", result_type="int", result_value="-1")
598184b252SMichael Buch
608184b252SMichael Buch        # 'p this' should yield 'struct Foo*'
618184b252SMichael Buch        frame = self.thread.GetFrameAtIndex(0)
628184b252SMichael Buch        outer_class_addr = frame.GetValueForVariablePath("this->this")
638184b252SMichael Buch        self.expect_expr("this", result_value=outer_class_addr.GetValue())
648184b252SMichael Buch
658184b252SMichael Buch        lldbutil.continue_to_breakpoint(process, bkpt)
668184b252SMichael Buch
678184b252SMichael Buch        # Inside 'nested_lambda'
688184b252SMichael Buch
698184b252SMichael Buch        # Check access to captured 'this'. Should still be 'struct Foo*'
708184b252SMichael Buch        self.expect_expr("class_var", result_type="int", result_value="109")
718184b252SMichael Buch        self.expect_expr("global_var", result_type="int", result_value="-5")
728184b252SMichael Buch        self.expect_expr("this", result_value=outer_class_addr.GetValue())
738184b252SMichael Buch
748184b252SMichael Buch        # Check access to captures
758184b252SMichael Buch        self.expect_expr("lambda_local_var", result_type="int", result_value="5")
768184b252SMichael Buch        self.expect_expr("local_var", result_type="int", result_value="137")
778184b252SMichael Buch
788184b252SMichael Buch        # Check access to variable in previous frame which we didn't capture
798184b252SMichael Buch        self.expectExprError("local_var_copy", "use of undeclared identifier")
808184b252SMichael Buch
818184b252SMichael Buch        lldbutil.continue_to_breakpoint(process, bkpt)
828184b252SMichael Buch
838184b252SMichael Buch        # By-ref mutates source variable
848184b252SMichael Buch        self.expect_expr("lambda_local_var", result_type="int", result_value="0")
858184b252SMichael Buch
868184b252SMichael Buch        # By-value doesn't mutate source variable
878184b252SMichael Buch        self.expect_expr("local_var_copy", result_type="int", result_value="136")
888184b252SMichael Buch        self.expect_expr("local_var", result_type="int", result_value="137")
898184b252SMichael Buch
908184b252SMichael Buch        lldbutil.continue_to_breakpoint(process, bkpt)
918184b252SMichael Buch
928184b252SMichael Buch        # Inside 'LocalLambdaClass::inner_method'
938184b252SMichael Buch
948184b252SMichael Buch        # Check access to captured 'this'
958184b252SMichael Buch        self.expect_expr("lambda_class_local", result_type="int", result_value="-12345")
96*2238dcc3SJonas Devlieghere        self.expect_expr(
97*2238dcc3SJonas Devlieghere            "this->lambda_class_local", result_type="int", result_value="-12345"
98*2238dcc3SJonas Devlieghere        )
998184b252SMichael Buch        self.expect_expr("outer_ptr->class_var", result_type="int", result_value="109")
1008184b252SMichael Buch
1018184b252SMichael Buch        # 'p this' should yield 'struct LocalLambdaClass*'
1028184b252SMichael Buch        frame = self.thread.GetFrameAtIndex(0)
1038184b252SMichael Buch        local_class_addr = frame.GetValueForVariablePath("this->this")
1048184b252SMichael Buch        self.assertNotEqual(local_class_addr, outer_class_addr)
1058184b252SMichael Buch        self.expect_expr("this", result_value=local_class_addr.GetValue())
1068184b252SMichael Buch
1078184b252SMichael Buch        # Can still access global variable
1088184b252SMichael Buch        self.expect_expr("global_var", result_type="int", result_value="-5")
1098184b252SMichael Buch
1108184b252SMichael Buch        # Check access to outer top-level structure's members
111*2238dcc3SJonas Devlieghere        self.expectExprError(
112*2238dcc3SJonas Devlieghere            "class_var",
113*2238dcc3SJonas Devlieghere            ("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
114*2238dcc3SJonas Devlieghere        )
1158184b252SMichael Buch
116*2238dcc3SJonas Devlieghere        self.expectExprError(
117*2238dcc3SJonas Devlieghere            "base_var", ("use of non-static data member" " 'base_var'")
118*2238dcc3SJonas Devlieghere        )
1198184b252SMichael Buch
120*2238dcc3SJonas Devlieghere        self.expectExprError(
121*2238dcc3SJonas Devlieghere            "local_var",
122*2238dcc3SJonas Devlieghere            (
123*2238dcc3SJonas Devlieghere                "use of non-static data member 'local_var'"
124*2238dcc3SJonas Devlieghere                " of '(unnamed class)' from nested type 'LocalLambdaClass'"
125*2238dcc3SJonas Devlieghere            ),
126*2238dcc3SJonas Devlieghere        )
1278184b252SMichael Buch
1288184b252SMichael Buch        # Inside non_capturing_method
1298184b252SMichael Buch        lldbutil.continue_to_breakpoint(process, bkpt)
1308184b252SMichael Buch        self.expect_expr("local", result_type="int", result_value="5")
1318184b252SMichael Buch        self.expect_expr("local2", result_type="int", result_value="10")
1328184b252SMichael Buch        self.expect_expr("local2 * local", result_type="int", result_value="50")
1338184b252SMichael Buch
134*2238dcc3SJonas Devlieghere        self.expectExprError(
135*2238dcc3SJonas Devlieghere            "class_var",
136*2238dcc3SJonas Devlieghere            ("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
137*2238dcc3SJonas Devlieghere        )
138