@opensip-cli/graph-rust 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/__tests__/body-signature-population.test.d.ts +2 -0
- package/dist/__tests__/body-signature-population.test.d.ts.map +1 -0
- package/dist/__tests__/body-signature-population.test.js +44 -0
- package/dist/__tests__/body-signature-population.test.js.map +1 -0
- package/dist/__tests__/resolve.test.d.ts.map +1 -1
- package/dist/__tests__/resolve.test.js +0 -1
- package/dist/__tests__/resolve.test.js.map +1 -1
- package/dist/body-digest.d.ts +2 -2
- package/dist/body-digest.d.ts.map +1 -1
- package/dist/body-digest.js +2 -2
- package/dist/body-digest.js.map +1 -1
- package/dist/resolve-dependencies.js +0 -1
- package/dist/resolve-dependencies.js.map +1 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +9 -4
- package/dist/resolve.js.map +1 -1
- package/dist/walk-helpers.d.ts +22 -0
- package/dist/walk-helpers.d.ts.map +1 -0
- package/dist/walk-helpers.js +156 -0
- package/dist/walk-helpers.js.map +1 -0
- package/dist/walk-use-sites.d.ts +8 -0
- package/dist/walk-use-sites.d.ts.map +1 -0
- package/dist/walk-use-sites.js +176 -0
- package/dist/walk-use-sites.js.map +1 -0
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +5 -420
- package/dist/walk.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rust `use` / `extern crate` dependency-site collection for the walker.
|
|
3
|
+
*/
|
|
4
|
+
import { namedChildrenOf } from '@opensip-cli/graph-adapter-common';
|
|
5
|
+
/** Walk top-level `use` and `extern crate` declarations as dependency sites. */
|
|
6
|
+
export function collectDependencySites(file, moduleInitHash, out) {
|
|
7
|
+
for (const stmt of namedChildrenOf(file.tree.rootNode)) {
|
|
8
|
+
if (stmt.type === 'use_declaration') {
|
|
9
|
+
collectFromUseDeclaration(stmt, file, moduleInitHash, out);
|
|
10
|
+
}
|
|
11
|
+
else if (stmt.type === 'extern_crate_declaration') {
|
|
12
|
+
collectFromExternCrate(stmt, file, moduleInitHash, out);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function collectFromUseDeclaration(decl, file, ownerHash, out) {
|
|
17
|
+
const body = pickUsePathNode(decl);
|
|
18
|
+
if (!body)
|
|
19
|
+
return;
|
|
20
|
+
const ctx = {
|
|
21
|
+
file,
|
|
22
|
+
ownerHash,
|
|
23
|
+
line: decl.startPosition.row + 1,
|
|
24
|
+
column: decl.startPosition.column,
|
|
25
|
+
};
|
|
26
|
+
emitFromUseSegment(body, [], ctx, out);
|
|
27
|
+
}
|
|
28
|
+
function pickUsePathNode(decl) {
|
|
29
|
+
for (let i = decl.namedChildCount - 1; i >= 0; i--) {
|
|
30
|
+
const c = decl.namedChild(i);
|
|
31
|
+
if (!c)
|
|
32
|
+
continue;
|
|
33
|
+
if (c.type === 'visibility_modifier')
|
|
34
|
+
continue;
|
|
35
|
+
return c;
|
|
36
|
+
}
|
|
37
|
+
/* v8 ignore next */
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function emitFromUseSegment(node, prefix, ctx, out) {
|
|
41
|
+
switch (node.type) {
|
|
42
|
+
case 'scoped_identifier':
|
|
43
|
+
case 'identifier':
|
|
44
|
+
case 'crate':
|
|
45
|
+
case 'super':
|
|
46
|
+
case 'self': {
|
|
47
|
+
emitFromPathLeaf(node, prefix, ctx, out);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
case 'use_as_clause': {
|
|
51
|
+
emitFromUseAsClause(node, prefix, ctx, out);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
case 'use_wildcard': {
|
|
55
|
+
emitFromUseWildcard(node, prefix, ctx, out);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case 'scoped_use_list': {
|
|
59
|
+
emitFromScopedUseList(node, prefix, ctx, out);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
case 'use_list': {
|
|
63
|
+
emitFromUseList(node, prefix, ctx, out);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
/* v8 ignore start */
|
|
67
|
+
default: {
|
|
68
|
+
emitFromUnknownUseShape(node, prefix, ctx, out);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
/* v8 ignore stop */
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function emitFromPathLeaf(node, prefix, ctx, out) {
|
|
75
|
+
const segments = decodePathSegments(node);
|
|
76
|
+
pushDepSite([...prefix, ...segments], node, ctx, out);
|
|
77
|
+
}
|
|
78
|
+
function emitFromUseAsClause(node, prefix, ctx, out) {
|
|
79
|
+
const inner = node.namedChild(0);
|
|
80
|
+
if (inner) {
|
|
81
|
+
emitFromUseSegment(inner, prefix, ctx, out);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function emitFromUseWildcard(node, prefix, ctx, out) {
|
|
85
|
+
const inner = node.namedChild(0);
|
|
86
|
+
const segments = inner ? decodePathSegments(inner) : [];
|
|
87
|
+
pushDepSite([...prefix, ...segments, '*'], node, ctx, out);
|
|
88
|
+
}
|
|
89
|
+
// @graph-ignore-next-line graph:cycle -- intentional recursion over nested `use` scoped-list AST nodes
|
|
90
|
+
function emitFromScopedUseList(node, prefix, ctx, out) {
|
|
91
|
+
const split = splitScopedUseListChildren(node);
|
|
92
|
+
if (split.list === null)
|
|
93
|
+
return;
|
|
94
|
+
const newPrefix = [...prefix, ...split.pathSegs];
|
|
95
|
+
emitUseListItems(split.list, newPrefix, ctx, out);
|
|
96
|
+
}
|
|
97
|
+
function splitScopedUseListChildren(node) {
|
|
98
|
+
let pathSegs = [];
|
|
99
|
+
let list = null;
|
|
100
|
+
for (const c of namedChildrenOf(node)) {
|
|
101
|
+
if (c.type === 'use_list') {
|
|
102
|
+
list = c;
|
|
103
|
+
}
|
|
104
|
+
else if (list === null) {
|
|
105
|
+
pathSegs = decodePathSegments(c);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { pathSegs, list };
|
|
109
|
+
}
|
|
110
|
+
function emitFromUseList(node, prefix, ctx, out) {
|
|
111
|
+
emitUseListItems(node, prefix, ctx, out);
|
|
112
|
+
}
|
|
113
|
+
function emitUseListItems(list, prefix, ctx, out) {
|
|
114
|
+
for (const item of namedChildrenOf(list)) {
|
|
115
|
+
if (item.type === 'self') {
|
|
116
|
+
pushDepSite([...prefix], item, ctx, out);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
emitFromUseSegment(item, prefix, ctx, out);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/* v8 ignore start */
|
|
123
|
+
function emitFromUnknownUseShape(node, prefix, ctx, out) {
|
|
124
|
+
const text = node.text;
|
|
125
|
+
if (text.length > 0) {
|
|
126
|
+
pushDepSite([...prefix, text], node, ctx, out);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/* v8 ignore stop */
|
|
130
|
+
function decodePathSegments(node) {
|
|
131
|
+
if (node.type === 'identifier' ||
|
|
132
|
+
node.type === 'crate' ||
|
|
133
|
+
node.type === 'super' ||
|
|
134
|
+
node.type === 'self') {
|
|
135
|
+
return [node.text];
|
|
136
|
+
}
|
|
137
|
+
if (node.type === 'scoped_identifier') {
|
|
138
|
+
const out = [];
|
|
139
|
+
for (const c of namedChildrenOf(node)) {
|
|
140
|
+
out.push(...decodePathSegments(c));
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/* v8 ignore next */
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
function pushDepSite(segments, node, ctx, out) {
|
|
148
|
+
if (segments.length === 0) {
|
|
149
|
+
/* v8 ignore next */
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
out.push({
|
|
153
|
+
nodeRef: node,
|
|
154
|
+
sourceFileRef: ctx.file,
|
|
155
|
+
ownerHash: ctx.ownerHash,
|
|
156
|
+
specifier: segments.join('::'),
|
|
157
|
+
line: ctx.line,
|
|
158
|
+
column: ctx.column,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function collectFromExternCrate(decl, file, ownerHash, out) {
|
|
162
|
+
for (const c of namedChildrenOf(decl)) {
|
|
163
|
+
if (c.type === 'identifier') {
|
|
164
|
+
out.push({
|
|
165
|
+
nodeRef: decl,
|
|
166
|
+
sourceFileRef: file,
|
|
167
|
+
ownerHash,
|
|
168
|
+
specifier: c.text,
|
|
169
|
+
line: decl.startPosition.row + 1,
|
|
170
|
+
column: decl.startPosition.column,
|
|
171
|
+
});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=walk-use-sites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-use-sites.js","sourceRoot":"","sources":["../src/walk-use-sites.ts"],"names":[],"mappings":"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"}
|
package/dist/walk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAuBH,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAOhE,QAAA,MAAQ,UAAU,0BAIhB,CAAC;AAEH,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,iBAAiB,CAAC,GAAG,UAAU,CAE3E"}
|
package/dist/walk.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// @fitness-ignore-file file-length-limit -- tree-sitter language walker spanning AST cases; cohesive grammar-driven dispatch already split (body-digest, walk-metadata extracted by earlier pass), further split would fragment per-node logic.
|
|
2
|
-
// @fitness-ignore-file context-mutation -- `ctx: WalkCtx` here is a function-scoped traversal accumulator (callSites array, occurrence sink, parser refs) threaded through the AST walk, NOT a shared request/execution context. `ctx.callSites.push(...)` is the intended local-accumulator append. The check's `LOCAL_DECLARATION_PATTERNS` heuristic doesn't see it because `ctx` arrives as a typed parameter, not via `const ctx = …`.
|
|
3
|
-
// @fitness-ignore-file performance-anti-patterns -- spread used to flatten AST child nodes during tree-sitter walk; bounded by node arity at each step
|
|
4
1
|
/**
|
|
5
2
|
* Rust walkProject — emit FunctionOccurrences + CallSiteRecords.
|
|
6
3
|
*
|
|
@@ -43,8 +40,10 @@
|
|
|
43
40
|
* this (you can have `#[cfg(test)] mod tests` in any module).
|
|
44
41
|
*/
|
|
45
42
|
import { relative, sep } from 'node:path';
|
|
46
|
-
import { childrenOf, makeFileClassifier,
|
|
47
|
-
import {
|
|
43
|
+
import { childrenOf, makeFileClassifier, record, runWalk, synthesizeModuleInit as buildModuleInit, } from '@opensip-cli/graph-adapter-common';
|
|
44
|
+
import { digestSyntheticBody } from './body-digest.js';
|
|
45
|
+
import { buildClosureOccurrence, buildFunctionOccurrence, implTargetName, } from './walk-helpers.js';
|
|
46
|
+
import { collectDependencySites } from './walk-use-sites.js';
|
|
48
47
|
const TEST_PATH_RE = /(?:^|\/)tests?\//;
|
|
49
48
|
const TEST_FILE_NAME_RE = /(?:^|\/)[^/]*_test\.rs$/;
|
|
50
49
|
const GENERATED_PATH_RE = /\btarget\/|\.generated\./;
|
|
@@ -72,9 +71,6 @@ function walkFile(absPath, file, projectDirAbs, sinks) {
|
|
|
72
71
|
qualifiedName: `${qualifiedBase}::<module-init>`,
|
|
73
72
|
});
|
|
74
73
|
record(out, moduleInit);
|
|
75
|
-
// Phase 4 (DEC-498): walk top-level `use` (and `extern crate`)
|
|
76
|
-
// declarations as dependency sites. Owner is the file's synthesized
|
|
77
|
-
// module-init occurrence.
|
|
78
74
|
collectDependencySites(file, moduleInit.bodyHash, dependencySites);
|
|
79
75
|
const ctx = {
|
|
80
76
|
file,
|
|
@@ -88,241 +84,7 @@ function walkFile(absPath, file, projectDirAbs, sinks) {
|
|
|
88
84
|
for (const child of childrenOf(file.tree.rootNode))
|
|
89
85
|
visit(child, initialFrame, ctx);
|
|
90
86
|
}
|
|
91
|
-
|
|
92
|
-
* Walk a Rust file's top-level `use_declaration` and `extern_crate_declaration`
|
|
93
|
-
* nodes; emit one `DependencySiteRecord` per terminal path. Phase 4 of
|
|
94
|
-
* opensip's substrate consolidation (DEC-498).
|
|
95
|
-
*
|
|
96
|
-
* `use_declaration`'s single named child is one of:
|
|
97
|
-
*
|
|
98
|
-
* - `scoped_identifier` — e.g. `use std::collections::HashMap;` →
|
|
99
|
-
* emit specifier `'std::collections::HashMap'`.
|
|
100
|
-
* - `identifier` — e.g. `use foo;` → emit specifier `'foo'`.
|
|
101
|
-
* - `use_as_clause` — e.g. `use std::collections::HashMap as Map;` →
|
|
102
|
-
* extract the underlying path (LHS of `as`); alias is dropped.
|
|
103
|
-
* - `scoped_use_list` — grouped form. Combines a path prefix with a
|
|
104
|
-
* `use_list` of one-or-more children. Each child may itself be a
|
|
105
|
-
* `scoped_use_list` (nested groups), `scoped_identifier`,
|
|
106
|
-
* `identifier`, `use_as_clause`, `use_wildcard`, or `self` (bare
|
|
107
|
-
* `self` inside the list refers to the prefix itself).
|
|
108
|
-
* - `use_list` — bare `{a, b}` without prefix (rare at top level —
|
|
109
|
-
* usually appears under a `scoped_use_list`).
|
|
110
|
-
* - `use_wildcard` — e.g. `use std::prelude::v1::*;` → emit specifier
|
|
111
|
-
* ending in `::*`; resolver treats globs as unresolved (no single
|
|
112
|
-
* module target). Documented v1 limitation.
|
|
113
|
-
*
|
|
114
|
-
* `extern_crate_declaration` — legacy Rust 2015-edition form (mostly
|
|
115
|
-
* gone in 2018+). `extern crate foo;` → emit specifier `'foo'`.
|
|
116
|
-
*
|
|
117
|
-
* Visibility modifiers (`pub use ...`) and the `use`/`extern`/`crate`
|
|
118
|
-
* keywords are ignored — we emit one dep site per import target.
|
|
119
|
-
*
|
|
120
|
-
* Out of scope at v1:
|
|
121
|
-
* - Conditional imports inside function bodies (`fn f() { use foo; }`).
|
|
122
|
-
* Rust permits these; the walker only inspects file top-level.
|
|
123
|
-
* - `use ::absolute::path;` (leading `::`) — uncommon; would be
|
|
124
|
-
* emitted with the leading separator stripped.
|
|
125
|
-
*/
|
|
126
|
-
function collectDependencySites(file, moduleInitHash, out) {
|
|
127
|
-
for (const stmt of namedChildrenOf(file.tree.rootNode)) {
|
|
128
|
-
if (stmt.type === 'use_declaration') {
|
|
129
|
-
collectFromUseDeclaration(stmt, file, moduleInitHash, out);
|
|
130
|
-
}
|
|
131
|
-
else if (stmt.type === 'extern_crate_declaration') {
|
|
132
|
-
collectFromExternCrate(stmt, file, moduleInitHash, out);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
function collectFromUseDeclaration(decl, file, ownerHash, out) {
|
|
137
|
-
// The path-bearing child is the last named child (skipping
|
|
138
|
-
// visibility_modifier on `pub use ...`).
|
|
139
|
-
const body = pickUsePathNode(decl);
|
|
140
|
-
if (!body)
|
|
141
|
-
return;
|
|
142
|
-
const ctx = {
|
|
143
|
-
file,
|
|
144
|
-
ownerHash,
|
|
145
|
-
line: decl.startPosition.row + 1,
|
|
146
|
-
column: decl.startPosition.column,
|
|
147
|
-
out,
|
|
148
|
-
};
|
|
149
|
-
emitFromUseSegment(body, [], ctx);
|
|
150
|
-
}
|
|
151
|
-
function pickUsePathNode(decl) {
|
|
152
|
-
// Walk named children in reverse, taking the first non-visibility node.
|
|
153
|
-
for (let i = decl.namedChildCount - 1; i >= 0; i--) {
|
|
154
|
-
const c = decl.namedChild(i);
|
|
155
|
-
if (!c)
|
|
156
|
-
continue;
|
|
157
|
-
if (c.type === 'visibility_modifier')
|
|
158
|
-
continue;
|
|
159
|
-
return c;
|
|
160
|
-
}
|
|
161
|
-
/* v8 ignore next */
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Walk one path-bearing sub-node of a use declaration. `prefix` is the
|
|
166
|
-
* canonical path segments accumulated from enclosing `scoped_use_list`
|
|
167
|
-
* groups. The function dispatches by node type and emits one
|
|
168
|
-
* `DependencySiteRecord` per terminal path.
|
|
169
|
-
*/
|
|
170
|
-
function emitFromUseSegment(node, prefix, ctx) {
|
|
171
|
-
switch (node.type) {
|
|
172
|
-
case 'scoped_identifier':
|
|
173
|
-
case 'identifier':
|
|
174
|
-
case 'crate':
|
|
175
|
-
case 'super':
|
|
176
|
-
case 'self': {
|
|
177
|
-
emitFromPathLeaf(node, prefix, ctx);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
case 'use_as_clause': {
|
|
181
|
-
emitFromUseAsClause(node, prefix, ctx);
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
case 'use_wildcard': {
|
|
185
|
-
emitFromUseWildcard(node, prefix, ctx);
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
case 'scoped_use_list': {
|
|
189
|
-
emitFromScopedUseList(node, prefix, ctx);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
case 'use_list': {
|
|
193
|
-
emitFromUseList(node, prefix, ctx);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
/* v8 ignore start */
|
|
197
|
-
default: {
|
|
198
|
-
emitFromUnknownUseShape(node, prefix, ctx);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
/* v8 ignore stop */
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
function emitFromPathLeaf(node, prefix, ctx) {
|
|
205
|
-
const segments = decodePathSegments(node);
|
|
206
|
-
pushDepSite([...prefix, ...segments], node, ctx);
|
|
207
|
-
}
|
|
208
|
-
function emitFromUseAsClause(node, prefix, ctx) {
|
|
209
|
-
// `<path> as <alias>` — emit the underlying path only.
|
|
210
|
-
const inner = node.namedChild(0);
|
|
211
|
-
if (inner) {
|
|
212
|
-
emitFromUseSegment(inner, prefix, ctx);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function emitFromUseWildcard(node, prefix, ctx) {
|
|
216
|
-
// `<path>::*` — single emission with `*` as the trailing segment.
|
|
217
|
-
// The grammar nests the path under the wildcard (single named
|
|
218
|
-
// child); we append `'*'` to the segments.
|
|
219
|
-
const inner = node.namedChild(0);
|
|
220
|
-
const segments = inner ? decodePathSegments(inner) : [];
|
|
221
|
-
pushDepSite([...prefix, ...segments, '*'], node, ctx);
|
|
222
|
-
}
|
|
223
|
-
// @graph-ignore-next-line graph:cycle -- intentional recursion over nested `use` scoped-list AST nodes (path::{a, b::{c}})
|
|
224
|
-
function emitFromScopedUseList(node, prefix, ctx) {
|
|
225
|
-
// `<path>::{<list>}` — combine path + each list child.
|
|
226
|
-
// Children order: a path-like (identifier / scoped_identifier /
|
|
227
|
-
// crate / super / self) then a `use_list`.
|
|
228
|
-
const split = splitScopedUseListChildren(node);
|
|
229
|
-
if (split.list === null)
|
|
230
|
-
return;
|
|
231
|
-
const newPrefix = [...prefix, ...split.pathSegs];
|
|
232
|
-
emitUseListItems(split.list, newPrefix, ctx);
|
|
233
|
-
}
|
|
234
|
-
function splitScopedUseListChildren(node) {
|
|
235
|
-
let pathSegs = [];
|
|
236
|
-
let list = null;
|
|
237
|
-
for (const c of namedChildrenOf(node)) {
|
|
238
|
-
if (c.type === 'use_list') {
|
|
239
|
-
list = c;
|
|
240
|
-
}
|
|
241
|
-
else if (list === null) {
|
|
242
|
-
pathSegs = decodePathSegments(c);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return { pathSegs, list };
|
|
246
|
-
}
|
|
247
|
-
function emitFromUseList(node, prefix, ctx) {
|
|
248
|
-
// Bare `{a, b}` — uncommon at top level; descend with current prefix.
|
|
249
|
-
emitUseListItems(node, prefix, ctx);
|
|
250
|
-
}
|
|
251
|
-
function emitUseListItems(list, prefix, ctx) {
|
|
252
|
-
for (const item of namedChildrenOf(list)) {
|
|
253
|
-
if (item.type === 'self') {
|
|
254
|
-
// `use a::b::{self, X}` — `self` refers to the parent path,
|
|
255
|
-
// i.e. emit the prefix itself.
|
|
256
|
-
pushDepSite([...prefix], item, ctx);
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
emitFromUseSegment(item, prefix, ctx);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/* v8 ignore start */
|
|
263
|
-
function emitFromUnknownUseShape(node, prefix, ctx) {
|
|
264
|
-
// Unknown shape — defensive fallback: emit raw text as a single
|
|
265
|
-
// segment so downstream attribution still has something to show.
|
|
266
|
-
const text = node.text;
|
|
267
|
-
if (text.length > 0) {
|
|
268
|
-
pushDepSite([...prefix, text], node, ctx);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
/* v8 ignore stop */
|
|
272
|
-
/**
|
|
273
|
-
* Decode a path-bearing node into canonical `::`-separated segments.
|
|
274
|
-
* Accepts `scoped_identifier` (recursive), `identifier`, `crate`,
|
|
275
|
-
* `super`, `self`. Returns `[]` for unknown shapes (caller skips).
|
|
276
|
-
*/
|
|
277
|
-
function decodePathSegments(node) {
|
|
278
|
-
if (node.type === 'identifier' ||
|
|
279
|
-
node.type === 'crate' ||
|
|
280
|
-
node.type === 'super' ||
|
|
281
|
-
node.type === 'self') {
|
|
282
|
-
return [node.text];
|
|
283
|
-
}
|
|
284
|
-
if (node.type === 'scoped_identifier') {
|
|
285
|
-
const out = [];
|
|
286
|
-
for (const c of namedChildrenOf(node)) {
|
|
287
|
-
out.push(...decodePathSegments(c));
|
|
288
|
-
}
|
|
289
|
-
return out;
|
|
290
|
-
}
|
|
291
|
-
/* v8 ignore next */
|
|
292
|
-
return [];
|
|
293
|
-
}
|
|
294
|
-
function pushDepSite(segments, node, ctx) {
|
|
295
|
-
if (segments.length === 0) {
|
|
296
|
-
/* v8 ignore next */
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
ctx.out.push({
|
|
300
|
-
nodeRef: node,
|
|
301
|
-
sourceFileRef: ctx.file,
|
|
302
|
-
ownerHash: ctx.ownerHash,
|
|
303
|
-
specifier: segments.join('::'),
|
|
304
|
-
line: ctx.line,
|
|
305
|
-
column: ctx.column,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
function collectFromExternCrate(decl, file, ownerHash, out) {
|
|
309
|
-
// `extern crate <name>;` or `extern crate <name> as <alias>;`. The
|
|
310
|
-
// crate name is the first identifier (not the `crate` keyword token).
|
|
311
|
-
for (const c of namedChildrenOf(decl)) {
|
|
312
|
-
if (c.type === 'identifier') {
|
|
313
|
-
out.push({
|
|
314
|
-
nodeRef: decl,
|
|
315
|
-
sourceFileRef: file,
|
|
316
|
-
ownerHash,
|
|
317
|
-
specifier: c.text,
|
|
318
|
-
line: decl.startPosition.row + 1,
|
|
319
|
-
column: decl.startPosition.column,
|
|
320
|
-
});
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
// @graph-ignore-next-line graph:cycle -- intentional recursive-descent AST visitor; the cycle is the traversal (visit re-enters via the impl/item helpers)
|
|
87
|
+
// @graph-ignore-next-line graph:cycle -- intentional recursive-descent AST visitor
|
|
326
88
|
function visit(node, frame, ctx) {
|
|
327
89
|
if (node.type === 'impl_item') {
|
|
328
90
|
visitImpl(node, frame, ctx);
|
|
@@ -348,9 +110,6 @@ function visit(node, frame, ctx) {
|
|
|
348
110
|
}
|
|
349
111
|
function visitImpl(node, frame, ctx) {
|
|
350
112
|
const typeName = implTargetName(node);
|
|
351
|
-
// Don't emit a function for the `impl` block itself — its body is a
|
|
352
|
-
// declaration list whose function_items are emitted as methods. Keep
|
|
353
|
-
// module-init as the owner; descend with impl context.
|
|
354
113
|
const childFrame = { ownerHash: frame.ownerHash, enclosingImpl: typeName };
|
|
355
114
|
for (const child of childrenOf(node))
|
|
356
115
|
visit(child, childFrame, ctx);
|
|
@@ -387,178 +146,4 @@ function visitClosure(node, frame, ctx) {
|
|
|
387
146
|
}
|
|
388
147
|
return true;
|
|
389
148
|
}
|
|
390
|
-
function buildFunctionOccurrence(node, frame, ctx) {
|
|
391
|
-
const name = nameOf(node) ?? '<anon-fn>';
|
|
392
|
-
const digest = digestRustBody(ctx.file.source.slice(node.startIndex, node.endIndex));
|
|
393
|
-
const isTest = ctx.fileInTestFile || hasTestAttribute(node);
|
|
394
|
-
const kind = classifyRustFunctionKind(name, frame.enclosingImpl);
|
|
395
|
-
const qualifiedBase = ctx.filePathProjectRel.replace(/\.rs$/, '').split('/').join('::');
|
|
396
|
-
const qualifiedName = frame.enclosingImpl === null
|
|
397
|
-
? `${qualifiedBase}::${name}`
|
|
398
|
-
: `${qualifiedBase}::${frame.enclosingImpl}::${name}`;
|
|
399
|
-
return {
|
|
400
|
-
bodyHash: digest.hash,
|
|
401
|
-
bodySize: digest.size,
|
|
402
|
-
simpleName: name,
|
|
403
|
-
qualifiedName,
|
|
404
|
-
filePath: ctx.filePathProjectRel,
|
|
405
|
-
line: node.startPosition.row + 1,
|
|
406
|
-
column: node.startPosition.column,
|
|
407
|
-
endLine: node.endPosition.row + 1,
|
|
408
|
-
kind,
|
|
409
|
-
params: extractParams(node),
|
|
410
|
-
returnType: null,
|
|
411
|
-
enclosingClass: frame.enclosingImpl,
|
|
412
|
-
decorators: extractAttributes(node),
|
|
413
|
-
visibility: classifyVisibility(node),
|
|
414
|
-
inTestFile: isTest,
|
|
415
|
-
definedInGenerated: ctx.definedInGenerated,
|
|
416
|
-
calls: [],
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
function buildClosureOccurrence(node, ctx) {
|
|
420
|
-
const digest = digestRustBody(ctx.file.source.slice(node.startIndex, node.endIndex));
|
|
421
|
-
const startLine = node.startPosition.row + 1;
|
|
422
|
-
const startCol = node.startPosition.column;
|
|
423
|
-
const simpleName = `<arrow:${ctx.filePathProjectRel}:${String(startLine)}:${String(startCol)}>`;
|
|
424
|
-
const qualifiedBase = ctx.filePathProjectRel.replace(/\.rs$/, '').split('/').join('::');
|
|
425
|
-
return {
|
|
426
|
-
bodyHash: digest.hash,
|
|
427
|
-
bodySize: digest.size,
|
|
428
|
-
simpleName,
|
|
429
|
-
qualifiedName: `${qualifiedBase}::<closure:${String(startLine)}:${String(startCol)}>`,
|
|
430
|
-
filePath: ctx.filePathProjectRel,
|
|
431
|
-
line: startLine,
|
|
432
|
-
column: startCol,
|
|
433
|
-
endLine: node.endPosition.row + 1,
|
|
434
|
-
kind: 'arrow',
|
|
435
|
-
params: extractClosureParams(node),
|
|
436
|
-
returnType: null,
|
|
437
|
-
enclosingClass: null,
|
|
438
|
-
decorators: [],
|
|
439
|
-
visibility: 'private',
|
|
440
|
-
inTestFile: ctx.fileInTestFile,
|
|
441
|
-
definedInGenerated: ctx.definedInGenerated,
|
|
442
|
-
calls: [],
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
// ── helpers ───────────────────────────────────────────────────────
|
|
446
|
-
function implTargetName(node) {
|
|
447
|
-
const ty = node.childForFieldName('type');
|
|
448
|
-
if (ty)
|
|
449
|
-
return ty.text;
|
|
450
|
-
/* v8 ignore start -- defensive: tree-sitter-rust always exposes the `type`
|
|
451
|
-
field on a well-formed impl_item, so these fallbacks fire only on
|
|
452
|
-
malformed/partial ASTs that valid Rust source doesn't produce. */
|
|
453
|
-
// Fallback: first type_identifier child.
|
|
454
|
-
for (const c of namedChildrenOf(node)) {
|
|
455
|
-
if (c.type === 'type_identifier' || c.type === 'generic_type')
|
|
456
|
-
return c.text;
|
|
457
|
-
}
|
|
458
|
-
return '<anon-impl>';
|
|
459
|
-
/* v8 ignore stop */
|
|
460
|
-
}
|
|
461
|
-
function classifyVisibility(node) {
|
|
462
|
-
for (const c of childrenOf(node)) {
|
|
463
|
-
if (c.type === 'visibility_modifier')
|
|
464
|
-
return 'exported';
|
|
465
|
-
}
|
|
466
|
-
return 'module-local';
|
|
467
|
-
}
|
|
468
|
-
function extractParams(node) {
|
|
469
|
-
const params = node.childForFieldName('parameters');
|
|
470
|
-
if (!params)
|
|
471
|
-
return [];
|
|
472
|
-
return collectParamEntries(params);
|
|
473
|
-
}
|
|
474
|
-
// Closures use the same `parameters` field as `function_item`; an alias
|
|
475
|
-
// keeps call-site names readable without duplicating the body
|
|
476
|
-
// (sonarjs/no-identical-functions).
|
|
477
|
-
const extractClosureParams = extractParams;
|
|
478
|
-
function collectParamEntries(params) {
|
|
479
|
-
const out = [];
|
|
480
|
-
for (const child of namedChildrenOf(params)) {
|
|
481
|
-
const param = decodeParam(child);
|
|
482
|
-
if (param)
|
|
483
|
-
out.push(param);
|
|
484
|
-
}
|
|
485
|
-
return out;
|
|
486
|
-
}
|
|
487
|
-
function decodeParam(child) {
|
|
488
|
-
switch (child.type) {
|
|
489
|
-
case 'self_parameter': {
|
|
490
|
-
return { name: 'self', optional: false, rest: false };
|
|
491
|
-
}
|
|
492
|
-
case 'parameter': {
|
|
493
|
-
const pat = child.childForFieldName('pattern') ?? child.namedChild(0);
|
|
494
|
-
if (!pat)
|
|
495
|
-
return null;
|
|
496
|
-
return { name: pat.text, optional: false, rest: false };
|
|
497
|
-
}
|
|
498
|
-
/* v8 ignore start -- defensive: function_item / impl-method params arrive as
|
|
499
|
-
`self_parameter` / `parameter` nodes; the bare-`identifier` (closure-shaped)
|
|
500
|
-
and unexpected-node-kind fallbacks guard AST shapes the walk's param paths
|
|
501
|
-
don't reach. */
|
|
502
|
-
case 'identifier': {
|
|
503
|
-
// Closure params often appear as bare identifiers.
|
|
504
|
-
return { name: child.text, optional: false, rest: false };
|
|
505
|
-
}
|
|
506
|
-
default: {
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
509
|
-
/* v8 ignore stop */
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
function extractAttributes(node) {
|
|
513
|
-
const out = [];
|
|
514
|
-
// Attributes precede the function_item as siblings inside the parent.
|
|
515
|
-
// tree-sitter-rust models them as `attribute_item` nodes preceding
|
|
516
|
-
// the function_item, OR (more commonly in practice) as
|
|
517
|
-
// `attribute_item` children of the function_item's parent that
|
|
518
|
-
// appear before the function_item by source position.
|
|
519
|
-
for (const c of childrenOf(node)) {
|
|
520
|
-
if (c.type === 'attribute_item' || c.type === 'inner_attribute_item') {
|
|
521
|
-
out.push(c.text.trim());
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// Also scan preceding siblings (attribute_item is structurally a
|
|
525
|
-
// sibling of function_item under most parents).
|
|
526
|
-
const parent = node.parent;
|
|
527
|
-
if (parent) {
|
|
528
|
-
for (const sib of parent.children) {
|
|
529
|
-
// web-tree-sitter returns fresh Node wrappers per access, so the
|
|
530
|
-
// `node` handle passed in is never reference-identical to its twin
|
|
531
|
-
// in `parent.children`. Compare by stable byte offset instead of
|
|
532
|
-
// `===` (which would never match → scan past `node` and wrongly
|
|
533
|
-
// attribute later siblings' attributes to it).
|
|
534
|
-
if (sib === null || sib.startIndex >= node.startIndex)
|
|
535
|
-
break;
|
|
536
|
-
if (sib.type === 'attribute_item' || sib.type === 'inner_attribute_item') {
|
|
537
|
-
out.push(sib.text.trim());
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
// Dedupe.
|
|
542
|
-
return [...new Set(out)];
|
|
543
|
-
}
|
|
544
|
-
function hasTestAttribute(node) {
|
|
545
|
-
const attrs = extractAttributes(node);
|
|
546
|
-
for (const a of attrs) {
|
|
547
|
-
if (a.includes('#[test]'))
|
|
548
|
-
return true;
|
|
549
|
-
/* v8 ignore next */
|
|
550
|
-
if (a.includes('cfg(test)'))
|
|
551
|
-
return true;
|
|
552
|
-
}
|
|
553
|
-
return false;
|
|
554
|
-
}
|
|
555
|
-
// Body digest helpers (stripRustComments, normalizeWhitespace, sha256,
|
|
556
|
-
// digestRustBody, digestSyntheticBody, BodyDigest) live in body-digest.ts.
|
|
557
|
-
function classifyRustFunctionKind(name, enclosingImpl) {
|
|
558
|
-
if (enclosingImpl === null)
|
|
559
|
-
return 'function-declaration';
|
|
560
|
-
if (name === 'new')
|
|
561
|
-
return 'constructor';
|
|
562
|
-
return 'method';
|
|
563
|
-
}
|
|
564
149
|
//# sourceMappingURL=walk.js.map
|