This is an ongoing series of commits that are reformatting our Python code. Reformatting is done with `black` (23.1.0). If you end up having problems merging this commit because you have made changes to a python file, the best way to handle that is to run `git checkout --ours <yourfile>` and then reformat it with black. RFC: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Differential revision: https://reviews.llvm.org/D151460
138 lines
5.6 KiB
Python
138 lines
5.6 KiB
Python
""" Test that evaluating expressions from within C++ lambdas works
|
|
Particularly, we test the case of capturing "this" and
|
|
using members of the captured object in expression evaluation
|
|
while we're on a breakpoint inside a lambda.
|
|
"""
|
|
|
|
|
|
import lldb
|
|
from lldbsuite.test.lldbtest import *
|
|
|
|
|
|
class ExprInsideLambdaTestCase(TestBase):
|
|
def expectExprError(self, expr: str, expected: str):
|
|
frame = self.thread.GetFrameAtIndex(0)
|
|
value = frame.EvaluateExpression(expr)
|
|
errmsg = value.GetError().GetCString()
|
|
self.assertIn(expected, errmsg)
|
|
|
|
def test_expr_inside_lambda(self):
|
|
"""Test that lldb evaluating expressions inside lambda expressions works correctly."""
|
|
self.build()
|
|
(target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(
|
|
self, "break here", lldb.SBFileSpec("main.cpp")
|
|
)
|
|
|
|
# Inside 'Foo::method'
|
|
|
|
# Check access to captured 'this'
|
|
self.expect_expr("class_var", result_type="int", result_value="109")
|
|
self.expect_expr("this->class_var", result_type="int", result_value="109")
|
|
|
|
# Check that captured shadowed variables take preference over the
|
|
# corresponding member variable
|
|
self.expect_expr("shadowed", result_type="int", result_value="5")
|
|
self.expect_expr("this->shadowed", result_type="int", result_value="-137")
|
|
|
|
# Check access to local captures
|
|
self.expect_expr("local_var", result_type="int", result_value="137")
|
|
self.expect_expr("*class_ptr", result_type="int", result_value="137")
|
|
|
|
# Check access to base class variables
|
|
self.expect_expr("base_var", result_type="int", result_value="14")
|
|
self.expect_expr("base_base_var", result_type="int", result_value="11")
|
|
|
|
# Check access to global variable
|
|
self.expect_expr("global_var", result_type="int", result_value="-5")
|
|
|
|
# Check access to multiple captures/member variables
|
|
self.expect_expr(
|
|
"(shadowed + this->shadowed) * (base_base_var + local_var - class_var)",
|
|
result_type="int",
|
|
result_value="-5148",
|
|
)
|
|
|
|
# Check base-class function call
|
|
self.expect_expr("baz_virt()", result_type="int", result_value="2")
|
|
self.expect_expr("base_var", result_type="int", result_value="14")
|
|
self.expect_expr("this->shadowed", result_type="int", result_value="-1")
|
|
|
|
# 'p this' should yield 'struct Foo*'
|
|
frame = self.thread.GetFrameAtIndex(0)
|
|
outer_class_addr = frame.GetValueForVariablePath("this->this")
|
|
self.expect_expr("this", result_value=outer_class_addr.GetValue())
|
|
|
|
lldbutil.continue_to_breakpoint(process, bkpt)
|
|
|
|
# Inside 'nested_lambda'
|
|
|
|
# Check access to captured 'this'. Should still be 'struct Foo*'
|
|
self.expect_expr("class_var", result_type="int", result_value="109")
|
|
self.expect_expr("global_var", result_type="int", result_value="-5")
|
|
self.expect_expr("this", result_value=outer_class_addr.GetValue())
|
|
|
|
# Check access to captures
|
|
self.expect_expr("lambda_local_var", result_type="int", result_value="5")
|
|
self.expect_expr("local_var", result_type="int", result_value="137")
|
|
|
|
# Check access to variable in previous frame which we didn't capture
|
|
self.expectExprError("local_var_copy", "use of undeclared identifier")
|
|
|
|
lldbutil.continue_to_breakpoint(process, bkpt)
|
|
|
|
# By-ref mutates source variable
|
|
self.expect_expr("lambda_local_var", result_type="int", result_value="0")
|
|
|
|
# By-value doesn't mutate source variable
|
|
self.expect_expr("local_var_copy", result_type="int", result_value="136")
|
|
self.expect_expr("local_var", result_type="int", result_value="137")
|
|
|
|
lldbutil.continue_to_breakpoint(process, bkpt)
|
|
|
|
# Inside 'LocalLambdaClass::inner_method'
|
|
|
|
# Check access to captured 'this'
|
|
self.expect_expr("lambda_class_local", result_type="int", result_value="-12345")
|
|
self.expect_expr(
|
|
"this->lambda_class_local", result_type="int", result_value="-12345"
|
|
)
|
|
self.expect_expr("outer_ptr->class_var", result_type="int", result_value="109")
|
|
|
|
# 'p this' should yield 'struct LocalLambdaClass*'
|
|
frame = self.thread.GetFrameAtIndex(0)
|
|
local_class_addr = frame.GetValueForVariablePath("this->this")
|
|
self.assertNotEqual(local_class_addr, outer_class_addr)
|
|
self.expect_expr("this", result_value=local_class_addr.GetValue())
|
|
|
|
# Can still access global variable
|
|
self.expect_expr("global_var", result_type="int", result_value="-5")
|
|
|
|
# Check access to outer top-level structure's members
|
|
self.expectExprError(
|
|
"class_var",
|
|
("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
|
|
)
|
|
|
|
self.expectExprError(
|
|
"base_var", ("use of non-static data member" " 'base_var'")
|
|
)
|
|
|
|
self.expectExprError(
|
|
"local_var",
|
|
(
|
|
"use of non-static data member 'local_var'"
|
|
" of '(unnamed class)' from nested type 'LocalLambdaClass'"
|
|
),
|
|
)
|
|
|
|
# Inside non_capturing_method
|
|
lldbutil.continue_to_breakpoint(process, bkpt)
|
|
self.expect_expr("local", result_type="int", result_value="5")
|
|
self.expect_expr("local2", result_type="int", result_value="10")
|
|
self.expect_expr("local2 * local", result_type="int", result_value="50")
|
|
|
|
self.expectExprError(
|
|
"class_var",
|
|
("use of non-static data member" " 'class_var' of 'Foo' from nested type"),
|
|
)
|