""" 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"),
)