Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit 1b1d6f0

Browse files
author
Hendrik van Antwerpen
committed
Share partial stack manipulation logic between append and from_node
1 parent a5d7b84 commit 1b1d6f0

9 files changed

+380
-238
lines changed

stack-graphs/src/partial.rs

Lines changed: 189 additions & 129 deletions
Large diffs are not rendered by default.

stack-graphs/tests/it/c/can_find_local_nodes.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,7 @@ fn check_local_nodes(graph: &TestGraph, file: &str, expected_local_nodes: &[&str
9292
fn class_field_through_function_parameter() {
9393
let graph = test_graphs::class_field_through_function_parameter::new();
9494
check_local_nodes(&graph, "main.py", &[]);
95-
check_local_nodes(
96-
&graph,
97-
"a.py",
98-
&[
99-
"[a.py(8) reference x]", //
100-
],
101-
);
95+
check_local_nodes(&graph, "a.py", &[]);
10296
check_local_nodes(&graph, "b.py", &[]);
10397
}
10498

stack-graphs/tests/it/c/can_find_partial_paths_in_file.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,20 @@ fn class_field_through_function_parameter() {
146146
// definition of `__main__` module
147147
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
148148
// reference to `a` in import statement
149-
"<%1> () [main.py(17) reference a] -> [root] <a,%1> ()",
149+
"<%1> ($1) [main.py(17) reference a] -> [root] <a,%1> ($1)",
150150
// `from a import *` means we can rewrite any lookup of `__main__.*` → `a.*`
151151
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
152152
// reference to `b` in import statement
153-
"<%1> () [main.py(15) reference b] -> [root] <b,%1> ()",
153+
"<%1> ($1) [main.py(15) reference b] -> [root] <b,%1> ($1)",
154154
// `from b import *` means we can rewrite any lookup of `__main__.*` → `b.*`
155155
"<__main__.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
156156
// we can look for every reference in either `a` or `b`
157-
"<%1> () [main.py(9) reference A] -> [root] <a.A,%1> ()",
158-
"<%1> () [main.py(9) reference A] -> [root] <b.A,%1> ()",
159-
"<%1> () [main.py(10) reference bar] -> [root] <a.foo()/([main.py(7)]).bar,%1> ()",
160-
"<%1> () [main.py(10) reference bar] -> [root] <b.foo()/([main.py(7)]).bar,%1> ()",
161-
"<%1> () [main.py(13) reference foo] -> [root] <a.foo,%1> ()",
162-
"<%1> () [main.py(13) reference foo] -> [root] <b.foo,%1> ()",
157+
"<%1> ($1) [main.py(9) reference A] -> [root] <a.A,%1> ($1)",
158+
"<%1> ($1) [main.py(9) reference A] -> [root] <b.A,%1> ($1)",
159+
"<%1> ($1) [main.py(10) reference bar] -> [root] <a.foo()/([main.py(7)],$1).bar,%1> ($1)",
160+
"<%1> ($1) [main.py(10) reference bar] -> [root] <b.foo()/([main.py(7)],$1).bar,%1> ($1)",
161+
"<%1> ($1) [main.py(13) reference foo] -> [root] <a.foo,%1> ($1)",
162+
"<%1> ($1) [main.py(13) reference foo] -> [root] <b.foo,%1> ($1)",
163163
// parameter 0 of function call is `A`, which we can look up in either `a` or `b`
164164
"<0,%1> ($1) [main.py(7) exported scope] -> [root] <a.A,%1> ($1)",
165165
"<0,%1> ($1) [main.py(7) exported scope] -> [root] <b.A,%1> ($1)",
@@ -173,8 +173,12 @@ fn class_field_through_function_parameter() {
173173
"<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)",
174174
// definition of `foo` function
175175
"<a.foo,%1> ($1) [root] -> [a.py(5) definition foo] <%1> ($1)",
176-
// reference to `x` in function body can resolve to formal parameter
177-
"<%1> () [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()",
176+
// reference to `x` in function body can resolve to formal parameter, and may have passed in parameters...
177+
"<%1> ($1) [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()",
178+
// ...which we can look up either the 0th actual positional parameter...
179+
"<%1> ($1) [a.py(8) reference x] -> [jump to scope] <0,%1> ($1)",
180+
// ...or the actual named parameter `x`
181+
"<%1> ($1) [a.py(8) reference x] -> [jump to scope] <x,%1> ($1)",
178182
// result of function is `x`, which is passed in as a formal parameter...
179183
"<a.foo()/($2),%1> ($1) [root] -> [a.py(14) definition x] <%1> ()",
180184
// ...which we can look up either the 0th actual positional parameter...
@@ -209,11 +213,11 @@ fn cyclic_imports_python() {
209213
// definition of `__main__` module
210214
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
211215
// reference to `a` in import statement
212-
"<%1> () [main.py(8) reference a] -> [root] <a,%1> ()",
216+
"<%1> ($1) [main.py(8) reference a] -> [root] <a,%1> ($1)",
213217
// `from a import *` means we can rewrite any lookup of `__main__.*` → `a.*`
214218
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
215219
// reference to `foo` becomes `a.foo` because of import statement
216-
"<%1> () [main.py(6) reference foo] -> [root] <a.foo,%1> ()",
220+
"<%1> ($1) [main.py(6) reference foo] -> [root] <a.foo,%1> ($1)",
217221
],
218222
);
219223
check_partial_paths_in_file(
@@ -223,7 +227,7 @@ fn cyclic_imports_python() {
223227
// definition of `a` module
224228
"<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)",
225229
// reference to `b` in import statement
226-
"<%1> () [a.py(6) reference b] -> [root] <b,%1> ()",
230+
"<%1> ($1) [a.py(6) reference b] -> [root] <b,%1> ($1)",
227231
// `from b import *` means we can rewrite any lookup of `a.*` → `b.*`
228232
"<a.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
229233
],
@@ -235,7 +239,7 @@ fn cyclic_imports_python() {
235239
// definition of `b` module
236240
"<b,%1> ($1) [root] -> [b.py(0) definition b] <%1> ($1)",
237241
// reference to `a` in import statement
238-
"<%1> () [b.py(8) reference a] -> [root] <a,%1> ()",
242+
"<%1> ($1) [b.py(8) reference a] -> [root] <a,%1> ($1)",
239243
// `from a import *` means we can rewrite any lookup of `b.*` → `a.*`
240244
"<b.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
241245
// definition of `foo`
@@ -254,16 +258,16 @@ fn cyclic_imports_rust() {
254258
// paths involving the root node.
255259
&[
256260
// reference to `a` in `main` function
257-
"<%1> () [test.rs(103) reference a] -> [test.rs(201) definition a] <%1> ()",
261+
"<%1> ($1) [test.rs(103) reference a] -> [test.rs(201) definition a] <%1> ($1)",
258262
// reference to `a` in `b` function
259-
"<%1> () [test.rs(307) reference a] -> [test.rs(201) definition a] <%1> ()",
263+
"<%1> ($1) [test.rs(307) reference a] -> [test.rs(201) definition a] <%1> ($1)",
260264
// reference to `b` in `a` function
261-
"<%1> () [test.rs(206) reference b] -> [test.rs(301) definition b] <%1> ()",
265+
"<%1> ($1) [test.rs(206) reference b] -> [test.rs(301) definition b] <%1> ($1)",
262266
// reference to `FOO` in `main` can resolve either to `a::BAR` or `b::FOO`
263-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ()",
264-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ()",
267+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ($1)",
268+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ($1)",
265269
// reference to `BAR` in `b` resolves _only_ to `a::BAR`
266-
"<%1> () [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ()",
270+
"<%1> ($1) [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ($1)",
267271
],
268272
);
269273
}
@@ -278,11 +282,11 @@ fn sequenced_import_star() {
278282
// definition of `__main__` module
279283
"<__main__,%1> ($1) [root] -> [main.py(0) definition __main__] <%1> ($1)",
280284
// reference to `a` in import statement
281-
"<%1> () [main.py(8) reference a] -> [root] <a,%1> ()",
285+
"<%1> ($1) [main.py(8) reference a] -> [root] <a,%1> ($1)",
282286
// `from a import *` means we can rewrite any lookup of `__main__.*` → `a.*`
283287
"<__main__.,%1> ($1) [root] -> [root] <a.,%1> ($1)",
284288
// reference to `foo` becomes `a.foo` because of import statement
285-
"<%1> () [main.py(6) reference foo] -> [root] <a.foo,%1> ()",
289+
"<%1> ($1) [main.py(6) reference foo] -> [root] <a.foo,%1> ($1)",
286290
],
287291
);
288292
check_partial_paths_in_file(
@@ -292,7 +296,7 @@ fn sequenced_import_star() {
292296
// definition of `a` module
293297
"<a,%1> ($1) [root] -> [a.py(0) definition a] <%1> ($1)",
294298
// reference to `b` in import statement
295-
"<%1> () [a.py(6) reference b] -> [root] <b,%1> ()",
299+
"<%1> ($1) [a.py(6) reference b] -> [root] <b,%1> ($1)",
296300
// `from b import *` means we can rewrite any lookup of `a.*` → `b.*`
297301
"<a.,%1> ($1) [root] -> [root] <b.,%1> ($1)",
298302
],

stack-graphs/tests/it/c/can_jump_to_definition_with_phased_partial_path_stitching.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -242,23 +242,23 @@ fn class_field_through_function_parameter() {
242242
"main.py",
243243
&[
244244
// reference to `a` in import statement
245-
"<%1> () [main.py(17) reference a] -> [a.py(0) definition a] <%1> ()",
245+
"<%1> ($1) [main.py(17) reference a] -> [a.py(0) definition a] <%1> ($1)",
246246
// reference to `b` in import statement
247-
"<%1> () [main.py(15) reference b] -> [b.py(0) definition b] <%1> ()",
247+
"<%1> ($1) [main.py(15) reference b] -> [b.py(0) definition b] <%1> ($1)",
248248
// reference to `foo` in function call resolves to function definition
249-
"<%1> () [main.py(13) reference foo] -> [a.py(5) definition foo] <%1> ()",
249+
"<%1> ($1) [main.py(13) reference foo] -> [a.py(5) definition foo] <%1> ($1)",
250250
// reference to `A` as function parameter resolves to class definition
251-
"<%1> () [main.py(9) reference A] -> [b.py(5) definition A] <%1> ()",
251+
"<%1> ($1) [main.py(9) reference A] -> [b.py(5) definition A] <%1> ($1)",
252252
// reference to `bar` on result flows through body of `foo` to find `A.bar`
253-
"<%1> () [main.py(10) reference bar] -> [b.py(8) definition bar] <%1> ()",
253+
"<%1> ($1) [main.py(10) reference bar] -> [b.py(8) definition bar] <%1> ($1)",
254254
],
255255
);
256256
check_jump_to_definition(
257257
&graph,
258258
"a.py",
259259
&[
260260
// reference to `x` in function body resolves to formal parameter
261-
"<%1> () [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()",
261+
"<%1> ($1) [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()",
262262
],
263263
);
264264
check_jump_to_definition(
@@ -278,25 +278,25 @@ fn cyclic_imports_python() {
278278
"main.py",
279279
&[
280280
// reference to `a` in import statement
281-
"<%1> () [main.py(8) reference a] -> [a.py(0) definition a] <%1> ()",
281+
"<%1> ($1) [main.py(8) reference a] -> [a.py(0) definition a] <%1> ($1)",
282282
// reference to `foo` resolves through intermediate file to find `b.foo`
283-
"<%1> () [main.py(6) reference foo] -> [b.py(6) definition foo] <%1> ()",
283+
"<%1> ($1) [main.py(6) reference foo] -> [b.py(6) definition foo] <%1> ($1)",
284284
],
285285
);
286286
check_jump_to_definition(
287287
&graph,
288288
"a.py",
289289
&[
290290
// reference to `b` in import statement
291-
"<%1> () [a.py(6) reference b] -> [b.py(0) definition b] <%1> ()",
291+
"<%1> ($1) [a.py(6) reference b] -> [b.py(0) definition b] <%1> ($1)",
292292
],
293293
);
294294
check_jump_to_definition(
295295
&graph,
296296
"b.py",
297297
&[
298298
// reference to `a` in import statement
299-
"<%1> () [b.py(8) reference a] -> [a.py(0) definition a] <%1> ()",
299+
"<%1> ($1) [b.py(8) reference a] -> [a.py(0) definition a] <%1> ($1)",
300300
],
301301
);
302302
}
@@ -309,16 +309,16 @@ fn cyclic_imports_rust() {
309309
"test.rs",
310310
&[
311311
// reference to `a` in `a::FOO` resolves to module definition
312-
"<%1> () [test.rs(103) reference a] -> [test.rs(201) definition a] <%1> ()",
312+
"<%1> ($1) [test.rs(103) reference a] -> [test.rs(201) definition a] <%1> ($1)",
313313
// reference to `a::FOO` in `main` can resolve either to `a::BAR` or `b::FOO`
314-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ()",
315-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ()",
314+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ($1)",
315+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ($1)",
316316
// reference to `b` in use statement resolves to module definition
317-
"<%1> () [test.rs(206) reference b] -> [test.rs(301) definition b] <%1> ()",
317+
"<%1> ($1) [test.rs(206) reference b] -> [test.rs(301) definition b] <%1> ($1)",
318318
// reference to `a` in use statement resolves to module definition
319-
"<%1> () [test.rs(307) reference a] -> [test.rs(201) definition a] <%1> ()",
319+
"<%1> ($1) [test.rs(307) reference a] -> [test.rs(201) definition a] <%1> ($1)",
320320
// reference to `BAR` in module `b` can _only_ resolve to `a::BAR`
321-
"<%1> () [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ()",
321+
"<%1> ($1) [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ($1)",
322322
],
323323
);
324324
}
@@ -331,17 +331,17 @@ fn sequenced_import_star() {
331331
"main.py",
332332
&[
333333
// reference to `a` in import statement
334-
"<%1> () [main.py(8) reference a] -> [a.py(0) definition a] <%1> ()",
334+
"<%1> ($1) [main.py(8) reference a] -> [a.py(0) definition a] <%1> ($1)",
335335
// reference to `foo` resolves through intermediate file to find `b.foo`
336-
"<%1> () [main.py(6) reference foo] -> [b.py(5) definition foo] <%1> ()",
336+
"<%1> ($1) [main.py(6) reference foo] -> [b.py(5) definition foo] <%1> ($1)",
337337
],
338338
);
339339
check_jump_to_definition(
340340
&graph,
341341
"a.py",
342342
&[
343343
// reference to `b` in import statement
344-
"<%1> () [a.py(6) reference b] -> [b.py(0) definition b] <%1> ()",
344+
"<%1> ($1) [a.py(6) reference b] -> [b.py(0) definition b] <%1> ($1)",
345345
],
346346
);
347347
check_jump_to_definition(

stack-graphs/tests/it/can_find_local_nodes.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@ fn check_local_nodes(graph: &StackGraph, file: &str, expected_local_nodes: &[&st
4444
fn class_field_through_function_parameter() {
4545
let graph = test_graphs::class_field_through_function_parameter::new();
4646
check_local_nodes(&graph, "main.py", &[]);
47-
check_local_nodes(
48-
&graph,
49-
"a.py",
50-
&[
51-
"[a.py(8) reference x]", //
52-
],
53-
);
47+
check_local_nodes(&graph, "a.py", &[]);
5448
check_local_nodes(&graph, "b.py", &[]);
5549
}
5650

stack-graphs/tests/it/can_find_node_partial_paths_in_database.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,18 @@ fn class_field_through_function_parameter() {
5555
&mut graph,
5656
("main.py", 10),
5757
&[
58-
"<%1> () [main.py(10) reference bar] -> [root] <a.foo()/([main.py(7)]).bar,%1> ()",
59-
"<%1> () [main.py(10) reference bar] -> [root] <b.foo()/([main.py(7)]).bar,%1> ()",
58+
"<%1> ($1) [main.py(10) reference bar] -> [root] <a.foo()/([main.py(7)],$1).bar,%1> ($1)",
59+
"<%1> ($1) [main.py(10) reference bar] -> [root] <b.foo()/([main.py(7)],$1).bar,%1> ($1)",
6060
],
6161
);
6262
check_node_partial_paths(
6363
&mut graph,
6464
("a.py", 8),
65-
&["<%1> () [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()"],
65+
&[
66+
"<%1> ($1) [a.py(8) reference x] -> [a.py(14) definition x] <%1> ()",
67+
"<%1> ($1) [a.py(8) reference x] -> [jump to scope] <0,%1> ($1)",
68+
"<%1> ($1) [a.py(8) reference x] -> [jump to scope] <x,%1> ($1)",
69+
],
6670
);
6771
// no references in b.py
6872
}
@@ -73,17 +77,17 @@ fn cyclic_imports_python() {
7377
check_node_partial_paths(
7478
&mut graph,
7579
("main.py", 6),
76-
&["<%1> () [main.py(6) reference foo] -> [root] <a.foo,%1> ()"],
80+
&["<%1> ($1) [main.py(6) reference foo] -> [root] <a.foo,%1> ($1)"],
7781
);
7882
check_node_partial_paths(
7983
&mut graph,
8084
("a.py", 6),
81-
&["<%1> () [a.py(6) reference b] -> [root] <b,%1> ()"],
85+
&["<%1> ($1) [a.py(6) reference b] -> [root] <b,%1> ($1)"],
8286
);
8387
check_node_partial_paths(
8488
&mut graph,
8589
("b.py", 8),
86-
&["<%1> () [b.py(8) reference a] -> [root] <a,%1> ()"],
90+
&["<%1> ($1) [b.py(8) reference a] -> [root] <a,%1> ($1)"],
8791
);
8892
}
8993

@@ -94,14 +98,14 @@ fn cyclic_imports_rust() {
9498
&mut graph,
9599
("test.rs", 101),
96100
&[
97-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ()",
98-
"<%1> () [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ()",
101+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(204) definition BAR] <%1> ($1)",
102+
"<%1> ($1) [test.rs(101) reference FOO] -> [test.rs(304) definition FOO] <%1> ($1)",
99103
],
100104
);
101105
check_node_partial_paths(
102106
&mut graph,
103107
("test.rs", 305),
104-
&["<%1> () [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ()"],
108+
&["<%1> ($1) [test.rs(305) reference BAR] -> [test.rs(204) definition BAR] <%1> ($1)"],
105109
);
106110
}
107111

@@ -111,12 +115,12 @@ fn sequenced_import_star() {
111115
check_node_partial_paths(
112116
&mut graph,
113117
("main.py", 6),
114-
&["<%1> () [main.py(6) reference foo] -> [root] <a.foo,%1> ()"],
118+
&["<%1> ($1) [main.py(6) reference foo] -> [root] <a.foo,%1> ($1)"],
115119
);
116120
check_node_partial_paths(
117121
&mut graph,
118122
("a.py", 6),
119-
&["<%1> () [a.py(6) reference b] -> [root] <b,%1> ()"],
123+
&["<%1> ($1) [a.py(6) reference b] -> [root] <b,%1> ($1)"],
120124
);
121125
// no references in b.py
122126
}

0 commit comments

Comments
 (0)