1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
""" 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"),
)
|