Skip to content

Commit 6855e5c

Browse files
da-viperSquallATF
authored andcommitted
1 parent 54b065e commit 6855e5c

File tree

6 files changed

+160
-11
lines changed

6 files changed

+160
-11
lines changed

lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,9 @@ def do_test_scopes_variables_setVariable_evaluate(
341341

342342
verify_locals["argc"]["equals"]["value"] = "123"
343343
verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
344-
verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
345-
verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
346-
verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
344+
verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "89"}}
345+
verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "42"}}
346+
verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "72"}}
347347

348348
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
349349

@@ -353,32 +353,32 @@ def do_test_scopes_variables_setVariable_evaluate(
353353
self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"]
354354
)
355355

356-
self.assertTrue(
357-
self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
358-
)
359356
self.assertTrue(
360357
self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
361358
)
362359
self.assertTrue(
363360
self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
364361
)
362+
self.assertTrue(
363+
self.dap_server.request_setVariable(1, "x @ main.cpp:23", 23)["success"]
364+
)
365365

366366
# The following should have no effect
367367
self.assertFalse(
368-
self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[
368+
self.dap_server.request_setVariable(1, "x @ main.cpp:23", "invalid")[
369369
"success"
370370
]
371371
)
372372

373-
verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
374373
verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
375374
verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
375+
verify_locals["x @ main.cpp:23"]["equals"]["value"] = "23"
376376

377377
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
378378

379379
# The plain x variable shold refer to the innermost x
380380
self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"])
381-
verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
381+
verify_locals["x @ main.cpp:23"]["equals"]["value"] = "22"
382382

383383
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
384384

@@ -394,10 +394,10 @@ def do_test_scopes_variables_setVariable_evaluate(
394394
locals = self.dap_server.get_local_variables()
395395
names = [var["name"] for var in locals]
396396
# The first shadowed x shouldn't have a suffix anymore
397-
verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
398-
self.assertNotIn("x @ main.cpp:17", names)
397+
verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}
399398
self.assertNotIn("x @ main.cpp:19", names)
400399
self.assertNotIn("x @ main.cpp:21", names)
400+
self.assertNotIn("x @ main.cpp:23", names)
401401

402402
self.verify_variables(verify_locals, locals)
403403

@@ -663,6 +663,54 @@ def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
663663
]["variables"]
664664
self.verify_variables(verify_children, children)
665665

666+
def test_return_variables(self):
667+
"""
668+
Test the stepping out of a function with return value show the variable correctly.
669+
"""
670+
program = self.getBuildArtifact("a.out")
671+
self.build_and_launch(program)
672+
673+
return_name = "(Return Value)"
674+
verify_locals = {
675+
return_name: {"equals": {"type": "int", "value": "300"}},
676+
"argc": {},
677+
"argv": {},
678+
"pt": {},
679+
"x": {},
680+
"return_result": {"equals": {"type": "int"}},
681+
}
682+
683+
function_name = "test_return_variable"
684+
breakpoint_ids = self.set_function_breakpoints([function_name])
685+
686+
self.assertEqual(len(breakpoint_ids), 1)
687+
self.continue_to_breakpoints(breakpoint_ids)
688+
689+
threads = self.dap_server.get_threads()
690+
for thread in threads:
691+
if thread.get("reason") == "breakpoint":
692+
thread_id = thread["id"]
693+
694+
self.stepOut(threadId=thread_id)
695+
696+
local_variables = self.dap_server.get_local_variables()
697+
varref_dict = {}
698+
699+
# `verify_variable` function only checks if the local variables
700+
# are in the `verify_dict` passed this will cause this test to pass
701+
# even if there is no return value.
702+
local_variable_names = [
703+
variable["name"] for variable in local_variables
704+
]
705+
self.assertIn(
706+
return_name,
707+
local_variable_names,
708+
"return variable is not in local variables",
709+
)
710+
711+
self.verify_variables(verify_locals, local_variables, varref_dict)
712+
break
713+
666714
@skipIfWindows
667715
def test_indexedVariables(self):
668716
self.do_test_indexedVariables(enableSyntheticChildDebugging=False)

lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,59 @@ def test_get_num_children(self):
4040
"`script formatter.num_children_calls", context="repl"
4141
)["body"]["result"],
4242
)
43+
44+
@skipIf(archs=["arm64"])
45+
def test_return_variable_with_children(self):
46+
"""
47+
Test the stepping out of a function with return value show the children correctly
48+
"""
49+
program = self.getBuildArtifact("a.out")
50+
self.build_and_launch(program)
51+
52+
function_name = "test_return_variable_with_children"
53+
breakpoint_ids = self.set_function_breakpoints([function_name])
54+
55+
self.assertEqual(len(breakpoint_ids), 1)
56+
self.continue_to_breakpoints(breakpoint_ids)
57+
58+
threads = self.dap_server.get_threads()
59+
for thread in threads:
60+
if thread.get("reason") == "breakpoint":
61+
thread_id = thread.get("id")
62+
self.assertIsNot(thread_id, None)
63+
64+
self.stepOut(threadId=thread_id)
65+
66+
local_variables = self.dap_server.get_local_variables()
67+
68+
# verify has return variable as local
69+
result_variable = list(
70+
filter(
71+
lambda val: val.get("name") == "(Return Value)", local_variables
72+
)
73+
)
74+
self.assertEqual(len(result_variable), 1)
75+
result_variable = result_variable[0]
76+
77+
result_var_ref = result_variable.get("variablesReference")
78+
self.assertIsNot(result_var_ref, None, "There is no result value")
79+
80+
result_value = self.dap_server.request_variables(result_var_ref)
81+
result_children = result_value["body"]["variables"]
82+
self.assertNotEqual(
83+
result_children, None, "The result does not have children"
84+
)
85+
86+
verify_children = {"buffer": '"hello world!"', "x": "10", "y": "20"}
87+
for child in result_children:
88+
actual_name = child["name"]
89+
actual_value = child["value"]
90+
verify_value = verify_children.get(actual_name)
91+
self.assertNotEqual(verify_value, None)
92+
self.assertEqual(
93+
actual_value,
94+
verify_value,
95+
"Expected child value does not match",
96+
)
97+
98+
break
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
struct Indexed {};
22
struct NotIndexed {};
33

4+
#define BUFFER_SIZE 16
5+
struct NonPrimitive {
6+
char buffer[BUFFER_SIZE];
7+
int x;
8+
long y;
9+
};
10+
11+
NonPrimitive test_return_variable_with_children() {
12+
return NonPrimitive{"hello world!", 10, 20};
13+
}
14+
415
int main() {
516
Indexed indexed;
617
NotIndexed not_indexed;
18+
NonPrimitive non_primitive_result = test_return_variable_with_children();
719
return 0; // break here
820
}

lldb/test/API/tools/lldb-dap/variables/main.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ struct PointType {
99
int g_global = 123;
1010
static int s_global = 234;
1111
int test_indexedVariables();
12+
int test_return_variable();
13+
1214
int main(int argc, char const *argv[]) {
1315
static float s_local = 2.25;
1416
PointType pt = {11, 22, {0}};
@@ -22,6 +24,9 @@ int main(int argc, char const *argv[]) {
2224
s_global = x; // breakpoint 2
2325
}
2426
}
27+
{
28+
int return_result = test_return_variable();
29+
}
2530
return test_indexedVariables(); // breakpoint 3
2631
}
2732

@@ -34,3 +39,7 @@ int test_indexedVariables() {
3439
large_vector.assign(200, 0);
3540
return 0; // breakpoint 4
3641
}
42+
43+
int test_return_variable() {
44+
return 300; // breakpoint 5
45+
}

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,29 @@ void VariablesRequestHandler::operator()(
164164
variable_name_counts[GetNonNullVariableName(variable)]++;
165165
}
166166

167+
// Show return value if there is any ( in the local top frame )
168+
if (variablesReference == VARREF_LOCALS) {
169+
auto process = dap.target.GetProcess();
170+
auto selected_thread = process.GetSelectedThread();
171+
lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue();
172+
173+
if (stop_return_value.IsValid() &&
174+
(selected_thread.GetSelectedFrame().GetFrameID() == 0)) {
175+
auto renamed_return_value = stop_return_value.Clone("(Return Value)");
176+
int64_t return_var_ref = 0;
177+
178+
if (stop_return_value.MightHaveChildren() ||
179+
stop_return_value.IsSynthetic()) {
180+
return_var_ref = dap.variables.InsertVariable(stop_return_value,
181+
/*is_permanent=*/false);
182+
}
183+
variables.emplace_back(
184+
CreateVariable(renamed_return_value, return_var_ref, hex,
185+
dap.enable_auto_variable_summaries,
186+
dap.enable_synthetic_child_debugging, false));
187+
}
188+
}
189+
167190
// Now we construct the result with unique display variable names
168191
for (auto i = start_idx; i < end_idx; ++i) {
169192
lldb::SBValue variable = top_scope->GetValueAtIndex(i);

llvm/docs/ReleaseNotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ Changes to LLDB
656656
### Changes to lldb-dap
657657

658658
* Breakpoints can now be set for specific columns within a line.
659+
* Function return value is now displayed on step-out.
659660

660661
Changes to BOLT
661662
---------------------------------

0 commit comments

Comments
 (0)