Skip to content

Commit dd9232e

Browse files
committed
Expanding the unit tests for 'evaluate' to cover more than the 'result' field.
1 parent a20b2bc commit dd9232e

File tree

4 files changed

+155
-48
lines changed

4 files changed

+155
-48
lines changed

lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py

Lines changed: 147 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,67 @@
77
import lldbdap_testcase
88
from lldbsuite.test.decorators import skipIfWindows
99
from lldbsuite.test.lldbtest import line_number
10+
from typing import TypedDict, Optional
11+
12+
13+
class EvaluateResponseBody(TypedDict, total=False):
14+
result: str
15+
variablesReference: int
16+
type: Optional[str]
17+
memoryReference: Optional[str]
18+
valueLocationReference: Optional[int]
1019

1120

1221
class TestDAP_evaluate(lldbdap_testcase.DAPTestCaseBase):
13-
def assertEvaluate(self, expression, regex):
22+
def assertEvaluate(
23+
self,
24+
expression,
25+
result: str,
26+
want_type="",
27+
want_varref=False,
28+
want_memref=True,
29+
want_locref=False,
30+
):
31+
resp = self.dap_server.request_evaluate(expression, context=self.context)
32+
self.assertTrue(
33+
resp["success"], f"Failed to evaluate expression {expression!r}"
34+
)
35+
body: EvaluateResponseBody = resp["body"]
1436
self.assertRegex(
15-
self.dap_server.request_evaluate(expression, context=self.context)["body"][
16-
"result"
17-
],
18-
regex,
37+
body["result"],
38+
result,
39+
f"Unexpected 'result' for expression {expression!r} in response body {body}",
1940
)
41+
if want_varref:
42+
self.assertNotEqual(
43+
body["variablesReference"],
44+
0,
45+
f"Unexpected 'variablesReference' for expression {expression!r} in response body {body}",
46+
)
47+
else:
48+
self.assertEqual(
49+
body["variablesReference"],
50+
0,
51+
f"Unexpected 'variablesReference' for expression {expression!r} in response body {body}",
52+
)
53+
if want_type:
54+
self.assertEqual(
55+
body["type"],
56+
want_type,
57+
f"Unexpected 'type' for expression {expression!r} in response body {body}",
58+
)
59+
if want_memref:
60+
self.assertIn(
61+
"memoryReference",
62+
body,
63+
f"Unexpected 'memoryReference' for expression {expression!r} in response body {body}",
64+
)
65+
if want_locref:
66+
self.assertIn(
67+
"valueLocationReference",
68+
body,
69+
f"Unexpected 'valueLocationReference' for expression {expression!r} in response body {body}",
70+
)
2071

2172
def assertEvaluateFailure(self, expression):
2273
self.assertNotIn(
@@ -71,29 +122,39 @@ def run_test_evaluate_expressions(
71122
self.continue_to_breakpoint(breakpoint_1)
72123

73124
# Expressions at breakpoint 1, which is in main
74-
self.assertEvaluate("var1", "20")
125+
self.assertEvaluate("var1", "20", want_type="int")
75126
# Empty expression should equate to the previous expression.
76127
if context == "repl":
77128
self.assertEvaluate("", "20")
78129
else:
79130
self.assertEvaluateFailure("")
80-
self.assertEvaluate("var2", "21")
131+
self.assertEvaluate("var2", "21", want_type="int")
81132
if context == "repl":
82-
self.assertEvaluate("", "21")
83-
self.assertEvaluate("", "21")
84-
self.assertEvaluate("static_int", "42")
85-
self.assertEvaluate("non_static_int", "43")
86-
self.assertEvaluate("struct1.foo", "15")
87-
self.assertEvaluate("struct2->foo", "16")
133+
self.assertEvaluate("", "21", want_type="int")
134+
self.assertEvaluate("", "21", want_type="int")
135+
self.assertEvaluate("static_int", "42", want_type="int")
136+
self.assertEvaluate("non_static_int", "43", want_type="int")
137+
self.assertEvaluate("struct1.foo", "15", want_type="int")
138+
self.assertEvaluate("struct2->foo", "16", want_type="int")
88139

89140
if self.isResultExpandedDescription():
90141
self.assertEvaluate(
91142
"struct1",
92143
r"\(my_struct\) (struct1|\$\d+) = \(foo = 15\)",
144+
want_type="my_struct",
145+
want_varref=True,
146+
)
147+
self.assertEvaluate(
148+
"struct2",
149+
r"\(my_struct \*\) (struct2|\$\d+) = 0x.*",
150+
want_type="my_struct *",
151+
want_varref=True,
93152
)
94-
self.assertEvaluate("struct2", r"\(my_struct \*\) (struct2|\$\d+) = 0x.*")
95153
self.assertEvaluate(
96-
"struct3", r"\(my_struct \*\) (struct3|\$\d+) = nullptr"
154+
"struct3",
155+
r"\(my_struct \*\) (struct3|\$\d+) = nullptr",
156+
want_type="my_struct *",
157+
want_varref=True,
97158
)
98159
else:
99160
self.assertEvaluate(
@@ -103,16 +164,22 @@ def run_test_evaluate_expressions(
103164
if enableAutoVariableSummaries
104165
else "my_struct @ 0x"
105166
),
167+
want_varref=True,
106168
)
107169
self.assertEvaluate(
108-
"struct2", "0x.* {foo:16}" if enableAutoVariableSummaries else "0x.*"
170+
"struct2",
171+
"0x.* {foo:16}" if enableAutoVariableSummaries else "0x.*",
172+
want_varref=True,
173+
want_type="my_struct *",
174+
)
175+
self.assertEvaluate(
176+
"struct3", "0x.*0", want_varref=True, want_type="my_struct *"
109177
)
110-
self.assertEvaluate("struct3", "0x.*0")
111178

112179
if context == "repl":
113180
# In the repl context expressions may be interpreted as lldb
114181
# commands since no variables have the same name as the command.
115-
self.assertEvaluate("list", r".*")
182+
self.assertEvaluate("list", r".*", want_memref=False)
116183
else:
117184
self.assertEvaluateFailure("list") # local variable of a_function
118185

@@ -121,10 +188,26 @@ def run_test_evaluate_expressions(
121188
self.assertEvaluateFailure("foo") # member of my_struct
122189

123190
if self.isExpressionParsedExpected():
124-
self.assertEvaluate("a_function", "0x.*a.out`a_function.*")
125-
self.assertEvaluate("a_function(1)", "1")
126-
self.assertEvaluate("var2 + struct1.foo", "36")
127-
self.assertEvaluate("foo_func", "0x.*a.out`foo_func.*")
191+
self.assertEvaluate(
192+
"a_function",
193+
"0x.*a.out`a_function.*",
194+
want_type="int (*)(int)",
195+
want_varref=True,
196+
want_memref=False,
197+
want_locref=True,
198+
)
199+
self.assertEvaluate(
200+
"a_function(1)", "1", want_memref=False, want_type="int"
201+
)
202+
self.assertEvaluate("var2 + struct1.foo", "36", want_memref=False)
203+
self.assertEvaluate(
204+
"foo_func",
205+
"0x.*a.out`foo_func.*",
206+
want_type="int (*)()",
207+
want_varref=True,
208+
want_memref=False,
209+
want_locref=True,
210+
)
128211
self.assertEvaluate("foo_var", "44")
129212
else:
130213
self.assertEvaluateFailure("a_function")
@@ -145,6 +228,8 @@ def run_test_evaluate_expressions(
145228
self.assertEvaluate(
146229
"struct1",
147230
r"\(my_struct\) (struct1|\$\d+) = \(foo = 15\)",
231+
want_type="my_struct",
232+
want_varref=True,
148233
)
149234
else:
150235
self.assertEvaluate(
@@ -154,15 +239,26 @@ def run_test_evaluate_expressions(
154239
if enableAutoVariableSummaries
155240
else "my_struct @ 0x"
156241
),
242+
want_type="my_struct",
243+
want_varref=True,
157244
)
158245
self.assertEvaluate("struct1.foo", "15")
159246
self.assertEvaluate("struct2->foo", "16")
160247

161248
if self.isExpressionParsedExpected():
162-
self.assertEvaluate("a_function", "0x.*a.out`a_function.*")
163-
self.assertEvaluate("a_function(1)", "1")
164-
self.assertEvaluate("var2 + struct1.foo", "17")
165-
self.assertEvaluate("foo_func", "0x.*a.out`foo_func.*")
249+
self.assertEvaluate(
250+
"a_function",
251+
"0x.*a.out`a_function.*",
252+
want_type="int (*)(int)",
253+
want_varref=True,
254+
want_memref=False,
255+
want_locref=True,
256+
)
257+
self.assertEvaluate("a_function(1)", "1", want_memref=False)
258+
self.assertEvaluate("var2 + struct1.foo", "17", want_memref=False)
259+
self.assertEvaluate(
260+
"foo_func", "0x.*a.out`foo_func.*", want_varref=True, want_memref=False
261+
)
166262
self.assertEvaluate("foo_var", "44")
167263
else:
168264
self.assertEvaluateFailure("a_function")
@@ -185,10 +281,18 @@ def run_test_evaluate_expressions(
185281
self.assertEvaluateFailure("var2 + struct1.foo")
186282

187283
if self.isExpressionParsedExpected():
188-
self.assertEvaluate("a_function", "0x.*a.out`a_function.*")
189-
self.assertEvaluate("a_function(1)", "1")
190-
self.assertEvaluate("list + 1", "43")
191-
self.assertEvaluate("foo_func", "0x.*a.out`foo_func.*")
284+
self.assertEvaluate(
285+
"a_function",
286+
"0x.*a.out`a_function.*",
287+
want_varref=True,
288+
want_memref=False,
289+
want_locref=True,
290+
)
291+
self.assertEvaluate("a_function(1)", "1", want_memref=False)
292+
self.assertEvaluate("list + 1", "43", want_memref=False)
293+
self.assertEvaluate(
294+
"foo_func", "0x.*a.out`foo_func.*", want_varref=True, want_memref=False
295+
)
192296
self.assertEvaluate("foo_var", "44")
193297
else:
194298
self.assertEvaluateFailure("a_function")
@@ -199,26 +303,28 @@ def run_test_evaluate_expressions(
199303

200304
# Now we check that values are updated after stepping
201305
self.continue_to_breakpoint(breakpoint_4)
202-
self.assertEvaluate("my_vec", "size=2")
306+
self.assertEvaluate("my_vec", "size=2", want_varref=True)
203307
self.continue_to_breakpoint(breakpoint_5)
204-
self.assertEvaluate("my_vec", "size=3")
308+
self.assertEvaluate("my_vec", "size=3", want_varref=True)
205309

206-
self.assertEvaluate("my_map", "size=2")
310+
self.assertEvaluate("my_map", "size=2", want_varref=True)
207311
self.continue_to_breakpoint(breakpoint_6)
208-
self.assertEvaluate("my_map", "size=3")
312+
self.assertEvaluate("my_map", "size=3", want_varref=True)
209313

210-
self.assertEvaluate("my_bool_vec", "size=1")
314+
self.assertEvaluate("my_bool_vec", "size=1", want_varref=True)
211315
self.continue_to_breakpoint(breakpoint_7)
212-
self.assertEvaluate("my_bool_vec", "size=2")
316+
self.assertEvaluate("my_bool_vec", "size=2", want_varref=True)
213317

214318
self.continue_to_breakpoint(breakpoint_8)
215319
# Test memory read, especially with 'empty' repeat commands.
216320
if context == "repl":
217-
self.assertEvaluate("memory read -c 1 &my_ints", ".* 05 .*\n")
218-
self.assertEvaluate("", ".* 0a .*\n")
219-
self.assertEvaluate("", ".* 0f .*\n")
220-
self.assertEvaluate("", ".* 14 .*\n")
221-
self.assertEvaluate("", ".* 19 .*\n")
321+
self.assertEvaluate(
322+
"memory read -c 1 &my_ints", ".* 05 .*\n", want_memref=False
323+
)
324+
self.assertEvaluate("", ".* 0a .*\n", want_memref=False)
325+
self.assertEvaluate("", ".* 0f .*\n", want_memref=False)
326+
self.assertEvaluate("", ".* 14 .*\n", want_memref=False)
327+
self.assertEvaluate("", ".* 19 .*\n", want_memref=False)
222328

223329
self.continue_to_exit()
224330

lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,20 @@ EvaluateRequestHandler::Run(const EvaluateArguments &arguments) const {
9999

100100
VariableDescription desc(value,
101101
dap.configuration.enableAutoVariableSummaries);
102+
102103
body.result = desc.GetResult(arguments.context);
103104
body.type = desc.display_type_name;
105+
104106
if (value.MightHaveChildren() || ValuePointsToCode(value))
105107
body.variablesReference = dap.variables.InsertVariable(
106108
value, /*is_permanent=*/arguments.context == eEvaluateContextRepl);
109+
107110
if (lldb::addr_t addr = value.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
108111
body.memoryReference = EncodeMemoryReference(addr);
109112

110113
if (ValuePointsToCode(value) &&
111114
body.variablesReference != LLDB_DAP_INVALID_VARRERF)
112-
body.valueLocationReference = body.variablesReference;
115+
body.valueLocationReference = PackLocation(body.variablesReference, true);
113116

114117
return body;
115118
}

lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -673,15 +673,13 @@ bool fromJSON(const llvm::json::Value &Params, EvaluateArguments &Args,
673673
}
674674

675675
llvm::json::Value toJSON(const EvaluateResponseBody &Body) {
676-
json::Object result{{"result", Body.result}};
676+
json::Object result{{"result", Body.result},
677+
{"variablesReference", Body.variablesReference}};
677678

678679
if (!Body.type.empty())
679680
result.insert({"type", Body.type});
680681
if (Body.presentationHint)
681682
result.insert({"presentationHint", Body.presentationHint});
682-
if (Body.variablesReference != 0 &&
683-
Body.variablesReference != LLDB_DAP_INVALID_VARRERF)
684-
result.insert({"variablesReference", Body.variablesReference});
685683
if (Body.namedVariables)
686684
result.insert({"namedVariables", Body.namedVariables});
687685
if (Body.indexedVariables)

lldb/tools/lldb-dap/Protocol/ProtocolRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ struct EvaluateResponseBody {
11451145
/// children can be retrieved by passing `variablesReference` to the
11461146
/// `variables` request as long as execution remains suspended. See 'Lifetime
11471147
/// of Object References' in the Overview section for details.
1148-
int64_t variablesReference = LLDB_DAP_INVALID_VARRERF;
1148+
int64_t variablesReference = 0;
11491149

11501150
/// The number of named child variables.
11511151
/// The client can use this information to present the variables in a paged
@@ -1174,7 +1174,7 @@ struct EvaluateResponseBody {
11741174
///
11751175
/// This reference shares the same lifetime as the `variablesReference`. See
11761176
/// 'Lifetime of Object References' in the Overview section for details.
1177-
uint32_t valueLocationReference = LLDB_DAP_INVALID_VALUE_LOC;
1177+
uint64_t valueLocationReference = LLDB_DAP_INVALID_VALUE_LOC;
11781178
};
11791179
llvm::json::Value toJSON(const EvaluateResponseBody &);
11801180

0 commit comments

Comments
 (0)