@optave/codegraph 3.11.2 → 3.13.0
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 +73 -37
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +1 -0
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +6 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +272 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/triage.js +1 -1
- package/dist/cli/commands/triage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/options.d.ts +2 -1
- package/dist/cli/shared/options.d.ts.map +1 -1
- package/dist/cli/shared/options.js +11 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +8 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts +2 -0
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +24 -2
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/graph/builder/call-resolver.d.ts +16 -10
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +251 -34
- package/dist/domain/graph/builder/call-resolver.js.map +1 -1
- package/dist/domain/graph/builder/cha.d.ts +69 -0
- package/dist/domain/graph/builder/cha.d.ts.map +1 -0
- package/dist/domain/graph/builder/cha.js +158 -0
- package/dist/domain/graph/builder/cha.js.map +1 -0
- package/dist/domain/graph/builder/context.d.ts +3 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js +2 -0
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +25 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +178 -5
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +74 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +37 -2
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +704 -34
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +4 -0
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.js +783 -37
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts +1 -0
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +10 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/journal.js +1 -1
- package/dist/domain/graph/journal.js.map +1 -1
- package/dist/domain/graph/resolver/points-to.d.ts +53 -0
- package/dist/domain/graph/resolver/points-to.d.ts.map +1 -0
- package/dist/domain/graph/resolver/points-to.js +213 -0
- package/dist/domain/graph/resolver/points-to.js.map +1 -0
- package/dist/domain/graph/resolver/ts-resolver.d.ts +9 -0
- package/dist/domain/graph/resolver/ts-resolver.d.ts.map +1 -0
- package/dist/domain/graph/resolver/ts-resolver.js +476 -0
- package/dist/domain/graph/resolver/ts-resolver.js.map +1 -0
- package/dist/domain/parser.d.ts +12 -4
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +83 -20
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +35 -2
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
- package/dist/domain/wasm-worker-pool.js +34 -0
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +15 -1
- package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
- package/dist/extractors/c.js +3 -3
- package/dist/extractors/c.js.map +1 -1
- package/dist/extractors/clojure.js +1 -1
- package/dist/extractors/clojure.js.map +1 -1
- package/dist/extractors/cpp.d.ts.map +1 -1
- package/dist/extractors/cpp.js +45 -4
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +37 -8
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/cuda.d.ts.map +1 -1
- package/dist/extractors/cuda.js +45 -4
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/elixir.js +6 -6
- package/dist/extractors/elixir.js.map +1 -1
- package/dist/extractors/fsharp.js +1 -1
- package/dist/extractors/fsharp.js.map +1 -1
- package/dist/extractors/go.js +5 -5
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/haskell.js +1 -1
- package/dist/extractors/haskell.js.map +1 -1
- package/dist/extractors/helpers.d.ts +11 -0
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +40 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +10 -9
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts +2 -0
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +1812 -71
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.js +5 -5
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/lua.js +1 -1
- package/dist/extractors/lua.js.map +1 -1
- package/dist/extractors/objc.js +3 -3
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/ocaml.js +1 -1
- package/dist/extractors/ocaml.js.map +1 -1
- package/dist/extractors/php.js +2 -2
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.js +7 -7
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +2 -2
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/scala.js +1 -1
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/solidity.js +1 -1
- package/dist/extractors/solidity.js.map +1 -1
- package/dist/extractors/swift.js +4 -4
- package/dist/extractors/swift.js.map +1 -1
- package/dist/extractors/zig.js +4 -4
- package/dist/extractors/zig.js.map +1 -1
- package/dist/features/structure-query.d.ts +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +6 -6
- package/dist/features/structure-query.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts +85 -2
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +408 -19
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/native.d.ts +11 -0
- package/dist/infrastructure/native.d.ts.map +1 -1
- package/dist/infrastructure/native.js +78 -5
- package/dist/infrastructure/native.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +27 -0
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +59 -1
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
- package/dist/presentation/queries-cli/overview.js +5 -0
- package/dist/presentation/queries-cli/overview.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +2 -2
- package/dist/presentation/structure.js.map +1 -1
- package/dist/types.d.ts +221 -0
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +7 -8
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/batch.ts +1 -0
- package/src/cli/commands/build.ts +6 -1
- package/src/cli/commands/config.ts +353 -0
- package/src/cli/commands/triage.ts +1 -1
- package/src/cli/index.ts +10 -0
- package/src/cli/shared/options.ts +11 -1
- package/src/cli/types.ts +2 -0
- package/src/db/migrations.ts +8 -1
- package/src/domain/analysis/module-map.ts +29 -1
- package/src/domain/graph/builder/call-resolver.ts +263 -35
- package/src/domain/graph/builder/cha.ts +192 -0
- package/src/domain/graph/builder/context.ts +3 -0
- package/src/domain/graph/builder/helpers.ts +195 -5
- package/src/domain/graph/builder/incremental.ts +80 -1
- package/src/domain/graph/builder/pipeline.ts +49 -2
- package/src/domain/graph/builder/stages/build-edges.ts +867 -32
- package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
- package/src/domain/graph/builder/stages/finalize.ts +4 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +910 -43
- package/src/domain/graph/builder/stages/resolve-imports.ts +15 -1
- package/src/domain/graph/journal.ts +1 -1
- package/src/domain/graph/resolver/points-to.ts +254 -0
- package/src/domain/graph/resolver/ts-resolver.ts +536 -0
- package/src/domain/parser.ts +86 -17
- package/src/domain/wasm-worker-entry.ts +35 -2
- package/src/domain/wasm-worker-pool.ts +22 -0
- package/src/domain/wasm-worker-protocol.ts +15 -0
- package/src/extractors/c.ts +3 -3
- package/src/extractors/clojure.ts +1 -1
- package/src/extractors/cpp.ts +47 -4
- package/src/extractors/csharp.ts +33 -9
- package/src/extractors/cuda.ts +47 -4
- package/src/extractors/elixir.ts +6 -6
- package/src/extractors/fsharp.ts +1 -1
- package/src/extractors/go.ts +5 -5
- package/src/extractors/haskell.ts +1 -1
- package/src/extractors/helpers.ts +43 -0
- package/src/extractors/java.ts +10 -9
- package/src/extractors/javascript.ts +1929 -72
- package/src/extractors/kotlin.ts +5 -5
- package/src/extractors/lua.ts +1 -1
- package/src/extractors/objc.ts +3 -3
- package/src/extractors/ocaml.ts +1 -1
- package/src/extractors/php.ts +2 -2
- package/src/extractors/python.ts +7 -7
- package/src/extractors/ruby.ts +2 -2
- package/src/extractors/scala.ts +1 -1
- package/src/extractors/solidity.ts +1 -1
- package/src/extractors/swift.ts +4 -4
- package/src/extractors/zig.ts +4 -4
- package/src/features/structure-query.ts +7 -7
- package/src/index.ts +5 -1
- package/src/infrastructure/config.ts +494 -20
- package/src/infrastructure/native.ts +87 -5
- package/src/infrastructure/registry.ts +82 -1
- package/src/presentation/queries-cli/overview.ts +15 -1
- package/src/presentation/structure.ts +3 -3
- package/src/types.ts +235 -0
- package/grammars/tree-sitter-erlang.wasm +0 -0
package/src/domain/parser.ts
CHANGED
|
@@ -152,10 +152,13 @@ interface WasmExtractResult {
|
|
|
152
152
|
// Shared patterns for all JS/TS/TSX (class_declaration excluded — name type differs)
|
|
153
153
|
const COMMON_QUERY_PATTERNS: string[] = [
|
|
154
154
|
'(function_declaration name: (identifier) @fn_name) @fn_node',
|
|
155
|
+
'(generator_function_declaration name: (identifier) @fn_name) @fn_node',
|
|
155
156
|
'(variable_declarator name: (identifier) @varfn_name value: (arrow_function) @varfn_value)',
|
|
156
157
|
'(variable_declarator name: (identifier) @varfn_name value: (function_expression) @varfn_value)',
|
|
158
|
+
'(variable_declarator name: (identifier) @varfn_name value: (generator_function) @varfn_value)',
|
|
157
159
|
'(method_definition name: (property_identifier) @meth_name) @meth_node',
|
|
158
160
|
'(method_definition name: (private_property_identifier) @meth_name) @meth_node',
|
|
161
|
+
'(method_definition name: (computed_property_name) @meth_name) @meth_node',
|
|
159
162
|
'(import_statement source: (string) @imp_source) @imp_node',
|
|
160
163
|
'(export_statement) @exp_node',
|
|
161
164
|
'(call_expression function: (identifier) @callfn_name) @callfn_node',
|
|
@@ -166,12 +169,20 @@ const COMMON_QUERY_PATTERNS: string[] = [
|
|
|
166
169
|
'(expression_statement (assignment_expression left: (member_expression) @assign_left right: (_) @assign_right)) @assign_node',
|
|
167
170
|
];
|
|
168
171
|
|
|
169
|
-
// JS: class name is (identifier)
|
|
170
|
-
const
|
|
172
|
+
// JS: class name is (identifier) — declarations and expressions
|
|
173
|
+
const JS_CLASS_PATTERNS: string[] = [
|
|
174
|
+
'(class_declaration name: (identifier) @cls_name) @cls_node',
|
|
175
|
+
// class expressions: `return class Foo extends Bar { ... }` or `const X = class Foo { ... }`
|
|
176
|
+
'(class name: (identifier) @cls_name) @cls_node',
|
|
177
|
+
];
|
|
171
178
|
|
|
172
179
|
// TS/TSX: class name is (type_identifier), plus interface and type alias
|
|
180
|
+
// abstract_class_declaration is a separate node type in tree-sitter-typescript
|
|
173
181
|
const TS_EXTRA_PATTERNS: string[] = [
|
|
174
182
|
'(class_declaration name: (type_identifier) @cls_name) @cls_node',
|
|
183
|
+
'(abstract_class_declaration name: (type_identifier) @cls_name) @cls_node',
|
|
184
|
+
// class expressions: `return class Foo extends Bar { ... }`
|
|
185
|
+
'(class name: (type_identifier) @cls_name) @cls_node',
|
|
175
186
|
'(interface_declaration name: (type_identifier) @iface_name) @iface_node',
|
|
176
187
|
'(type_alias_declaration name: (type_identifier) @type_name) @type_node',
|
|
177
188
|
];
|
|
@@ -202,7 +213,7 @@ async function doLoadLanguage(entry: LanguageRegistryEntry): Promise<void> {
|
|
|
202
213
|
const isTS = entry.id === 'typescript' || entry.id === 'tsx';
|
|
203
214
|
const patterns = isTS
|
|
204
215
|
? [...COMMON_QUERY_PATTERNS, ...TS_EXTRA_PATTERNS]
|
|
205
|
-
: [...COMMON_QUERY_PATTERNS,
|
|
216
|
+
: [...COMMON_QUERY_PATTERNS, ...JS_CLASS_PATTERNS];
|
|
206
217
|
_queryCache.set(entry.id, new Query(lang, patterns.join('\n')));
|
|
207
218
|
}
|
|
208
219
|
} catch (e: unknown) {
|
|
@@ -211,7 +222,9 @@ async function doLoadLanguage(entry: LanguageRegistryEntry): Promise<void> {
|
|
|
211
222
|
file: entry.grammarFile,
|
|
212
223
|
cause: e as Error,
|
|
213
224
|
});
|
|
214
|
-
|
|
225
|
+
const isEnoent = (e as NodeJS.ErrnoException).code === 'ENOENT';
|
|
226
|
+
const log = isEnoent ? debug : warn;
|
|
227
|
+
log(
|
|
215
228
|
`${entry.id} parser failed to initialize: ${(e as Error).message}. ${entry.id} files will be skipped.`,
|
|
216
229
|
);
|
|
217
230
|
_cachedParsers!.set(entry.id, null);
|
|
@@ -455,7 +468,7 @@ export function getInstalledWasmExtensions(): Set<string> {
|
|
|
455
468
|
* Lowercase file extensions covered by the native Rust addon.
|
|
456
469
|
*
|
|
457
470
|
* Mirrors `LanguageKind::from_extension` in
|
|
458
|
-
* `crates/codegraph-core/src/
|
|
471
|
+
* `crates/codegraph-core/src/domain/parser.rs`. Used to classify why the
|
|
459
472
|
* native orchestrator dropped a file: extensions outside this set are a
|
|
460
473
|
* legitimate parser limit (no Rust extractor exists), while extensions inside
|
|
461
474
|
* it indicate a real native bug (parse/read/extract failure).
|
|
@@ -684,6 +697,24 @@ function patchTypeMap(r: any): void {
|
|
|
684
697
|
}
|
|
685
698
|
}
|
|
686
699
|
|
|
700
|
+
/** Normalize native returnTypeMap array to a Map instance, keeping highest-confidence entry per key. */
|
|
701
|
+
function patchReturnTypeMap(r: any): void {
|
|
702
|
+
if (!r.returnTypeMap || r.returnTypeMap instanceof Map) return;
|
|
703
|
+
const map = new Map<string, TypeMapEntry>();
|
|
704
|
+
for (const e of r.returnTypeMap as Array<{
|
|
705
|
+
name: string;
|
|
706
|
+
typeName: string;
|
|
707
|
+
confidence?: number;
|
|
708
|
+
}>) {
|
|
709
|
+
const conf = e.confidence ?? 1.0;
|
|
710
|
+
const existing = map.get(e.name);
|
|
711
|
+
if (!existing || conf > existing.confidence) {
|
|
712
|
+
map.set(e.name, { type: e.typeName, confidence: conf });
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
r.returnTypeMap = map.size > 0 ? map : new Map();
|
|
716
|
+
}
|
|
717
|
+
|
|
687
718
|
/** Wrap bindingType into binding object for dataflow argFlows and mutations. */
|
|
688
719
|
function patchDataflow(dataflow: any): void {
|
|
689
720
|
if (dataflow.argFlows) {
|
|
@@ -706,6 +737,7 @@ function patchNativeResult(r: any): ExtractorOutput {
|
|
|
706
737
|
if (r.definitions) patchDefinitions(r.definitions);
|
|
707
738
|
if (r.imports) patchImports(r.imports);
|
|
708
739
|
patchTypeMap(r);
|
|
740
|
+
patchReturnTypeMap(r);
|
|
709
741
|
if (r.dataflow) patchDataflow(r.dataflow);
|
|
710
742
|
|
|
711
743
|
return r;
|
|
@@ -1127,6 +1159,7 @@ async function backfillTypeMapBatch(
|
|
|
1127
1159
|
async function parseFilesWasm(
|
|
1128
1160
|
filePaths: string[],
|
|
1129
1161
|
rootDir: string,
|
|
1162
|
+
analysis: WorkerAnalysisOpts = FULL_ANALYSIS,
|
|
1130
1163
|
): Promise<Map<string, ExtractorOutput>> {
|
|
1131
1164
|
const result = new Map<string, ExtractorOutput>();
|
|
1132
1165
|
const pool = getWasmWorkerPool();
|
|
@@ -1139,7 +1172,7 @@ async function parseFilesWasm(
|
|
|
1139
1172
|
warn(`Skipping ${path.relative(rootDir, filePath)}: ${(err as Error).message}`);
|
|
1140
1173
|
continue;
|
|
1141
1174
|
}
|
|
1142
|
-
const output = await pool.parse(filePath, code,
|
|
1175
|
+
const output = await pool.parse(filePath, code, analysis);
|
|
1143
1176
|
if (output) {
|
|
1144
1177
|
const relPath = path.relative(rootDir, filePath).split(path.sep).join('/');
|
|
1145
1178
|
result.set(relPath, output);
|
|
@@ -1151,12 +1184,25 @@ async function parseFilesWasm(
|
|
|
1151
1184
|
/**
|
|
1152
1185
|
* Files at or below this count use the inline parse path (no worker spawn).
|
|
1153
1186
|
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1157
|
-
*
|
|
1187
|
+
* The worker pool exists for crash safety (#965): exotic (non-required) WASM
|
|
1188
|
+
* grammars can trigger uncatchable V8 fatal errors that would kill the main
|
|
1189
|
+
* process. Running them in a worker means only the worker dies; the pool
|
|
1190
|
+
* detects the exit, skips the file, respawns, and continues.
|
|
1191
|
+
*
|
|
1192
|
+
* JS/TS/TSX are required-tier grammars — they have never triggered the V8
|
|
1193
|
+
* fatal crash class and are safe to run inline. The primary hot caller
|
|
1194
|
+
* (this/super dispatch post-pass) exclusively handles JS/TS/TSX files and
|
|
1195
|
+
* measured ~55–64ms/file through the pool vs ~8–10ms/file inline (#1435);
|
|
1196
|
+
* IPC overhead scales linearly with file count, not amortised.
|
|
1197
|
+
*
|
|
1198
|
+
* The threshold is set high enough to keep typical this-dispatch batches
|
|
1199
|
+
* (≤ 18 files on the codegraph corpus) on the inline path, while still
|
|
1200
|
+
* routing truly large exotic-language drops (rare; typical HCL case is 4
|
|
1201
|
+
* files) through the pool for crash isolation. Exotic-language drops are
|
|
1202
|
+
* almost always well under this limit anyway, so they benefit from the
|
|
1203
|
+
* inline fast path too without meaningful crash risk increase.
|
|
1158
1204
|
*/
|
|
1159
|
-
const INLINE_BACKFILL_THRESHOLD =
|
|
1205
|
+
const INLINE_BACKFILL_THRESHOLD = 32;
|
|
1160
1206
|
|
|
1161
1207
|
/**
|
|
1162
1208
|
* Inline WASM parse (no worker) for small file batches.
|
|
@@ -1168,11 +1214,16 @@ const INLINE_BACKFILL_THRESHOLD = 16;
|
|
|
1168
1214
|
*
|
|
1169
1215
|
* Returns symbols with `_tree` set so `runAnalyses` can run AST/CFG/dataflow
|
|
1170
1216
|
* visitors via the unified walker (mirrors how WASM-engine results behaved
|
|
1171
|
-
* before the worker pool was introduced)
|
|
1217
|
+
* before the worker pool was introduced), unless `symbolsOnly` is true — in
|
|
1218
|
+
* that case `_tree` is not set, skipping all analysis visitor walks. Use
|
|
1219
|
+
* `symbolsOnly` when only definitions/calls/typeMap are needed (e.g. the
|
|
1220
|
+
* this/super dispatch post-pass) to avoid the analysis overhead on the inline
|
|
1221
|
+
* path, matching the optimization already applied to the worker-pool path.
|
|
1172
1222
|
*/
|
|
1173
1223
|
async function parseFilesWasmInline(
|
|
1174
1224
|
filePaths: string[],
|
|
1175
1225
|
rootDir: string,
|
|
1226
|
+
symbolsOnly = false,
|
|
1176
1227
|
): Promise<Map<string, ExtractorOutput>> {
|
|
1177
1228
|
const result = new Map<string, ExtractorOutput>();
|
|
1178
1229
|
if (filePaths.length === 0) return result;
|
|
@@ -1190,7 +1241,18 @@ async function parseFilesWasmInline(
|
|
|
1190
1241
|
if (!extracted) continue;
|
|
1191
1242
|
const relPath = path.relative(rootDir, filePath).split(path.sep).join('/');
|
|
1192
1243
|
const symbols = extracted.symbols as ExtractorOutput & { _tree?: unknown; _langId?: string };
|
|
1193
|
-
|
|
1244
|
+
// When symbolsOnly=true, skip setting _tree so runAnalyses does not run
|
|
1245
|
+
// AST/complexity/CFG/dataflow visitor walks — only definitions/calls/typeMap
|
|
1246
|
+
// are needed by callers like the this/super dispatch post-pass.
|
|
1247
|
+
if (!symbolsOnly) {
|
|
1248
|
+
symbols._tree = extracted.tree;
|
|
1249
|
+
} else if (typeof (extracted.tree as any)?.delete === 'function') {
|
|
1250
|
+
// Free the WASM-backed tree immediately — web-tree-sitter trees are backed
|
|
1251
|
+
// by WASM linear memory and require explicit disposal. When symbolsOnly is
|
|
1252
|
+
// true the tree is never stored anywhere, so we must delete it here to
|
|
1253
|
+
// avoid leaking WASM heap on every incremental rebuild.
|
|
1254
|
+
(extracted.tree as any).delete();
|
|
1255
|
+
}
|
|
1194
1256
|
symbols._langId = extracted.langId;
|
|
1195
1257
|
result.set(relPath, symbols);
|
|
1196
1258
|
}
|
|
@@ -1200,17 +1262,24 @@ async function parseFilesWasmInline(
|
|
|
1200
1262
|
/**
|
|
1201
1263
|
* Backfill helper: small batches use the inline (main-thread) path; larger
|
|
1202
1264
|
* batches keep the worker-pool isolation against tree-sitter WASM crashes
|
|
1203
|
-
* (#965).
|
|
1204
|
-
*
|
|
1265
|
+
* (#965). See INLINE_BACKFILL_THRESHOLD for threshold rationale.
|
|
1266
|
+
*
|
|
1267
|
+
* `opts.symbolsOnly` skips the AST/complexity/CFG/dataflow visitors in the
|
|
1268
|
+
* worker (and their result serialization across the thread boundary) for
|
|
1269
|
+
* callers that only consume definitions/calls/typeMap — the native
|
|
1270
|
+
* orchestrator's this-dispatch post-pass. Callers that ingest the files into
|
|
1271
|
+
* the DB (dropped-language backfill) must keep
|
|
1272
|
+
* the default full analysis.
|
|
1205
1273
|
*/
|
|
1206
1274
|
export async function parseFilesWasmForBackfill(
|
|
1207
1275
|
filePaths: string[],
|
|
1208
1276
|
rootDir: string,
|
|
1277
|
+
opts: { symbolsOnly?: boolean } = {},
|
|
1209
1278
|
): Promise<Map<string, ExtractorOutput>> {
|
|
1210
1279
|
if (filePaths.length <= INLINE_BACKFILL_THRESHOLD) {
|
|
1211
|
-
return parseFilesWasmInline(filePaths, rootDir);
|
|
1280
|
+
return parseFilesWasmInline(filePaths, rootDir, opts.symbolsOnly);
|
|
1212
1281
|
}
|
|
1213
|
-
return parseFilesWasm(filePaths, rootDir);
|
|
1282
|
+
return parseFilesWasm(filePaths, rootDir, opts.symbolsOnly ? EXTRACT_ONLY : FULL_ANALYSIS);
|
|
1214
1283
|
}
|
|
1215
1284
|
|
|
1216
1285
|
/**
|
|
@@ -109,10 +109,13 @@ function grammarPath(name: string): string {
|
|
|
109
109
|
|
|
110
110
|
const COMMON_QUERY_PATTERNS: string[] = [
|
|
111
111
|
'(function_declaration name: (identifier) @fn_name) @fn_node',
|
|
112
|
+
'(generator_function_declaration name: (identifier) @fn_name) @fn_node',
|
|
112
113
|
'(variable_declarator name: (identifier) @varfn_name value: (arrow_function) @varfn_value)',
|
|
113
114
|
'(variable_declarator name: (identifier) @varfn_name value: (function_expression) @varfn_value)',
|
|
115
|
+
'(variable_declarator name: (identifier) @varfn_name value: (generator_function) @varfn_value)',
|
|
114
116
|
'(method_definition name: (property_identifier) @meth_name) @meth_node',
|
|
115
117
|
'(method_definition name: (private_property_identifier) @meth_name) @meth_node',
|
|
118
|
+
'(method_definition name: (computed_property_name) @meth_name) @meth_node',
|
|
116
119
|
'(import_statement source: (string) @imp_source) @imp_node',
|
|
117
120
|
'(export_statement) @exp_node',
|
|
118
121
|
'(call_expression function: (identifier) @callfn_name) @callfn_node',
|
|
@@ -123,10 +126,17 @@ const COMMON_QUERY_PATTERNS: string[] = [
|
|
|
123
126
|
'(expression_statement (assignment_expression left: (member_expression) @assign_left right: (_) @assign_right)) @assign_node',
|
|
124
127
|
];
|
|
125
128
|
|
|
126
|
-
const
|
|
129
|
+
const JS_CLASS_PATTERNS: string[] = [
|
|
130
|
+
'(class_declaration name: (identifier) @cls_name) @cls_node',
|
|
131
|
+
// class expressions: `return class Foo extends Bar { ... }` or `const X = class Foo { ... }`
|
|
132
|
+
'(class name: (identifier) @cls_name) @cls_node',
|
|
133
|
+
];
|
|
127
134
|
|
|
128
135
|
const TS_EXTRA_PATTERNS: string[] = [
|
|
129
136
|
'(class_declaration name: (type_identifier) @cls_name) @cls_node',
|
|
137
|
+
'(abstract_class_declaration name: (type_identifier) @cls_name) @cls_node',
|
|
138
|
+
// class expressions: `return class Foo extends Bar { ... }`
|
|
139
|
+
'(class name: (type_identifier) @cls_name) @cls_node',
|
|
130
140
|
'(interface_declaration name: (type_identifier) @iface_name) @iface_node',
|
|
131
141
|
'(type_alias_declaration name: (type_identifier) @type_name) @type_node',
|
|
132
142
|
];
|
|
@@ -430,7 +440,7 @@ async function loadLanguageLazy(entry: LanguageRegistryEntry): Promise<Parser |
|
|
|
430
440
|
const isTS = entry.id === 'typescript' || entry.id === 'tsx';
|
|
431
441
|
const patterns = isTS
|
|
432
442
|
? [...COMMON_QUERY_PATTERNS, ...TS_EXTRA_PATTERNS]
|
|
433
|
-
: [...COMMON_QUERY_PATTERNS,
|
|
443
|
+
: [...COMMON_QUERY_PATTERNS, ...JS_CLASS_PATTERNS];
|
|
434
444
|
_queries.set(entry.id, new Query(lang, patterns.join('\n')));
|
|
435
445
|
}
|
|
436
446
|
return parser;
|
|
@@ -801,6 +811,29 @@ function serializeExtractorOutput(
|
|
|
801
811
|
_lineCount: code.split('\n').length,
|
|
802
812
|
dataflow: symbols.dataflow,
|
|
803
813
|
astNodes,
|
|
814
|
+
...(symbols.fnRefBindings?.length ? { fnRefBindings: symbols.fnRefBindings } : {}),
|
|
815
|
+
...(symbols.paramBindings?.length ? { paramBindings: symbols.paramBindings } : {}),
|
|
816
|
+
...(symbols.arrayElemBindings?.length ? { arrayElemBindings: symbols.arrayElemBindings } : {}),
|
|
817
|
+
...(symbols.spreadArgBindings?.length ? { spreadArgBindings: symbols.spreadArgBindings } : {}),
|
|
818
|
+
...(symbols.forOfBindings?.length ? { forOfBindings: symbols.forOfBindings } : {}),
|
|
819
|
+
...(symbols.arrayCallbackBindings?.length
|
|
820
|
+
? { arrayCallbackBindings: symbols.arrayCallbackBindings }
|
|
821
|
+
: {}),
|
|
822
|
+
...(symbols.objectRestParamBindings?.length
|
|
823
|
+
? { objectRestParamBindings: symbols.objectRestParamBindings }
|
|
824
|
+
: {}),
|
|
825
|
+
...(symbols.objectPropBindings?.length
|
|
826
|
+
? { objectPropBindings: symbols.objectPropBindings }
|
|
827
|
+
: {}),
|
|
828
|
+
...(symbols.thisCallBindings?.length ? { thisCallBindings: symbols.thisCallBindings } : {}),
|
|
829
|
+
...(symbols.newExpressions?.length ? { newExpressions: symbols.newExpressions } : {}),
|
|
830
|
+
...(symbols.definePropertyReceivers?.size
|
|
831
|
+
? { definePropertyReceivers: Array.from(symbols.definePropertyReceivers.entries()) }
|
|
832
|
+
: {}),
|
|
833
|
+
...(symbols.returnTypeMap?.size
|
|
834
|
+
? { returnTypeMap: Array.from(symbols.returnTypeMap.entries()) }
|
|
835
|
+
: {}),
|
|
836
|
+
...(symbols.callAssignments?.length ? { callAssignments: symbols.callAssignments } : {}),
|
|
804
837
|
};
|
|
805
838
|
}
|
|
806
839
|
|
|
@@ -106,6 +106,28 @@ function deserializeResult(ser: SerializedExtractorOutput | null): ExtractorOutp
|
|
|
106
106
|
// {line, kind, name, text?, receiver?} shape — see engine.ts:822 where the
|
|
107
107
|
// visitor output is cast the same way.
|
|
108
108
|
if (ser.astNodes !== undefined) out.astNodes = ser.astNodes as unknown as ASTNodeRow[];
|
|
109
|
+
if (ser.fnRefBindings?.length) out.fnRefBindings = ser.fnRefBindings;
|
|
110
|
+
if (ser.paramBindings?.length) out.paramBindings = ser.paramBindings;
|
|
111
|
+
if (ser.arrayElemBindings?.length) out.arrayElemBindings = ser.arrayElemBindings;
|
|
112
|
+
if (ser.spreadArgBindings?.length) out.spreadArgBindings = ser.spreadArgBindings;
|
|
113
|
+
if (ser.forOfBindings?.length) out.forOfBindings = ser.forOfBindings;
|
|
114
|
+
if (ser.arrayCallbackBindings?.length) out.arrayCallbackBindings = ser.arrayCallbackBindings;
|
|
115
|
+
if (ser.objectRestParamBindings?.length)
|
|
116
|
+
out.objectRestParamBindings = ser.objectRestParamBindings;
|
|
117
|
+
if (ser.objectPropBindings?.length) out.objectPropBindings = ser.objectPropBindings;
|
|
118
|
+
if (ser.thisCallBindings?.length) out.thisCallBindings = ser.thisCallBindings;
|
|
119
|
+
if (ser.newExpressions?.length) out.newExpressions = ser.newExpressions;
|
|
120
|
+
if (ser.definePropertyReceivers?.length) {
|
|
121
|
+
const m = new Map<string, string>();
|
|
122
|
+
for (const [k, v] of ser.definePropertyReceivers) m.set(k, v);
|
|
123
|
+
out.definePropertyReceivers = m;
|
|
124
|
+
}
|
|
125
|
+
if (ser.returnTypeMap?.length) {
|
|
126
|
+
const returnTypeMap = new Map<string, TypeMapEntry>();
|
|
127
|
+
for (const [k, v] of ser.returnTypeMap) returnTypeMap.set(k, v);
|
|
128
|
+
out.returnTypeMap = returnTypeMap;
|
|
129
|
+
}
|
|
130
|
+
if (ser.callAssignments?.length) out.callAssignments = ser.callAssignments;
|
|
109
131
|
return out;
|
|
110
132
|
}
|
|
111
133
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type {
|
|
14
14
|
Call,
|
|
15
|
+
CallAssignment,
|
|
15
16
|
ClassRelation,
|
|
16
17
|
DataflowResult,
|
|
17
18
|
Definition,
|
|
@@ -62,6 +63,20 @@ export interface SerializedExtractorOutput {
|
|
|
62
63
|
text?: string;
|
|
63
64
|
receiver?: string;
|
|
64
65
|
}>;
|
|
66
|
+
fnRefBindings?: import('../types.js').FnRefBinding[];
|
|
67
|
+
arrayElemBindings?: import('../types.js').ArrayElemBinding[];
|
|
68
|
+
spreadArgBindings?: import('../types.js').SpreadArgBinding[];
|
|
69
|
+
forOfBindings?: import('../types.js').ForOfBinding[];
|
|
70
|
+
arrayCallbackBindings?: import('../types.js').ArrayCallbackBinding[];
|
|
71
|
+
objectRestParamBindings?: import('../types.js').ObjectRestParamBinding[];
|
|
72
|
+
objectPropBindings?: import('../types.js').ObjectPropBinding[];
|
|
73
|
+
paramBindings?: import('../types.js').ParamBinding[];
|
|
74
|
+
thisCallBindings?: import('../types.js').ThisCallBinding[];
|
|
75
|
+
newExpressions?: readonly string[];
|
|
76
|
+
/** Serialized definePropertyReceivers map (funcName → receiverVarName) as tuple array. */
|
|
77
|
+
definePropertyReceivers?: Array<[string, string]>;
|
|
78
|
+
returnTypeMap?: Array<[string, TypeMapEntry]>;
|
|
79
|
+
callAssignments?: CallAssignment[];
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
export interface WorkerParseResponseOk {
|
package/src/extractors/c.ts
CHANGED
|
@@ -189,7 +189,7 @@ function extractCParameters(paramListNode: TreeSitterNode | null): SubDeclaratio
|
|
|
189
189
|
if (!paramListNode) return params;
|
|
190
190
|
for (let i = 0; i < paramListNode.childCount; i++) {
|
|
191
191
|
const param = paramListNode.child(i);
|
|
192
|
-
if (
|
|
192
|
+
if (param?.type !== 'parameter_declaration') continue;
|
|
193
193
|
const nameNode = param.childForFieldName('declarator');
|
|
194
194
|
if (nameNode) {
|
|
195
195
|
const name = unwrapCDeclaratorName(nameNode);
|
|
@@ -205,7 +205,7 @@ function extractStructFields(structNode: TreeSitterNode): SubDeclaration[] {
|
|
|
205
205
|
if (!body) return fields;
|
|
206
206
|
for (let i = 0; i < body.childCount; i++) {
|
|
207
207
|
const member = body.child(i);
|
|
208
|
-
if (
|
|
208
|
+
if (member?.type !== 'field_declaration') continue;
|
|
209
209
|
const nameNode = member.childForFieldName('declarator');
|
|
210
210
|
if (nameNode) {
|
|
211
211
|
const name = unwrapCDeclaratorName(nameNode);
|
|
@@ -221,7 +221,7 @@ function extractEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
|
|
|
221
221
|
if (!body) return entries;
|
|
222
222
|
for (let i = 0; i < body.childCount; i++) {
|
|
223
223
|
const member = body.child(i);
|
|
224
|
-
if (
|
|
224
|
+
if (member?.type !== 'enumerator') continue;
|
|
225
225
|
const nameNode = member.childForFieldName('name');
|
|
226
226
|
if (nameNode) {
|
|
227
227
|
entries.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
|
|
@@ -224,7 +224,7 @@ function extractClojureParams(defnNode: TreeSitterNode): SubDeclaration[] {
|
|
|
224
224
|
// Find the parameter vector [x y z]
|
|
225
225
|
for (let i = 0; i < defnNode.childCount; i++) {
|
|
226
226
|
const child = defnNode.child(i);
|
|
227
|
-
if (
|
|
227
|
+
if (child?.type !== 'vec_lit') continue;
|
|
228
228
|
for (let j = 0; j < child.childCount; j++) {
|
|
229
229
|
const param = child.child(j);
|
|
230
230
|
if (!param) continue;
|
package/src/extractors/cpp.ts
CHANGED
|
@@ -5,7 +5,13 @@ import type {
|
|
|
5
5
|
TreeSitterNode,
|
|
6
6
|
TreeSitterTree,
|
|
7
7
|
} from '../types.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
extractModifierVisibility,
|
|
10
|
+
findChild,
|
|
11
|
+
isCPrimitiveType,
|
|
12
|
+
nodeEndLine,
|
|
13
|
+
setTypeMapEntry,
|
|
14
|
+
} from './helpers.js';
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Extract symbols from C++ files.
|
|
@@ -50,6 +56,9 @@ function walkCppNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
50
56
|
case 'call_expression':
|
|
51
57
|
handleCppCallExpression(node, ctx);
|
|
52
58
|
break;
|
|
59
|
+
case 'declaration':
|
|
60
|
+
handleCppDeclaration(node, ctx);
|
|
61
|
+
break;
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -204,6 +213,40 @@ function handleCppInclude(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
204
213
|
});
|
|
205
214
|
}
|
|
206
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Seed typeMap for declaration-typed locals: `UserService svc;` and
|
|
218
|
+
* `UserService svc = makeService();` both yield typeMap["svc"] = "UserService"
|
|
219
|
+
* at confidence 0.9. Mirrors `match_c_family_type_map` ("declaration" branch)
|
|
220
|
+
* in the native Rust C++ extractor.
|
|
221
|
+
*/
|
|
222
|
+
function handleCppDeclaration(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
223
|
+
const typeNode = node.childForFieldName('type');
|
|
224
|
+
if (!typeNode) return;
|
|
225
|
+
const typeName = typeNode.text;
|
|
226
|
+
// Skip primitive types — they are never class/struct receivers
|
|
227
|
+
if (isCPrimitiveType(typeName)) return;
|
|
228
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
229
|
+
const child = node.child(i);
|
|
230
|
+
if (!child) continue;
|
|
231
|
+
const kind = child.type;
|
|
232
|
+
let nameNode: TreeSitterNode | null = null;
|
|
233
|
+
if (kind === 'init_declarator') {
|
|
234
|
+
nameNode = child.childForFieldName('declarator') ?? null;
|
|
235
|
+
} else if (kind === 'identifier') {
|
|
236
|
+
nameNode = child;
|
|
237
|
+
}
|
|
238
|
+
// Note: pointer_declarator / reference_declarator children (e.g. `UserService *svc;`)
|
|
239
|
+
// are intentionally skipped here — they are also skipped by the native Rust
|
|
240
|
+
// match_c_family_type_map helper, which only handles 'init_declarator' and
|
|
241
|
+
// 'identifier' children. Both engines have the same scope for this case.
|
|
242
|
+
if (!nameNode) continue;
|
|
243
|
+
const varName = unwrapCppDeclaratorName(nameNode);
|
|
244
|
+
if (varName) {
|
|
245
|
+
setTypeMapEntry(ctx.typeMap, varName, typeName, 0.9);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
207
250
|
function handleCppCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
208
251
|
const funcNode = node.childForFieldName('function');
|
|
209
252
|
if (!funcNode) return;
|
|
@@ -292,7 +335,7 @@ function extractCppParameters(paramListNode: TreeSitterNode | null): SubDeclarat
|
|
|
292
335
|
if (!paramListNode) return params;
|
|
293
336
|
for (let i = 0; i < paramListNode.childCount; i++) {
|
|
294
337
|
const param = paramListNode.child(i);
|
|
295
|
-
if (
|
|
338
|
+
if (param?.type !== 'parameter_declaration') continue;
|
|
296
339
|
const nameNode = param.childForFieldName('declarator');
|
|
297
340
|
if (nameNode) {
|
|
298
341
|
const name = unwrapCppDeclaratorName(nameNode);
|
|
@@ -309,7 +352,7 @@ function extractCppClassFields(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
309
352
|
if (!body) return fields;
|
|
310
353
|
for (let i = 0; i < body.childCount; i++) {
|
|
311
354
|
const member = body.child(i);
|
|
312
|
-
if (
|
|
355
|
+
if (member?.type !== 'field_declaration') continue;
|
|
313
356
|
const nameNode = member.childForFieldName('declarator');
|
|
314
357
|
if (nameNode) {
|
|
315
358
|
const name = unwrapCppDeclaratorName(nameNode);
|
|
@@ -330,7 +373,7 @@ function extractCppEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
|
|
|
330
373
|
if (!body) return entries;
|
|
331
374
|
for (let i = 0; i < body.childCount; i++) {
|
|
332
375
|
const member = body.child(i);
|
|
333
|
-
if (
|
|
376
|
+
if (member?.type !== 'enumerator') continue;
|
|
334
377
|
const nameNode = member.childForFieldName('name');
|
|
335
378
|
if (nameNode) {
|
|
336
379
|
entries.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
|
package/src/extractors/csharp.ts
CHANGED
|
@@ -28,6 +28,7 @@ export function extractCSharpSymbols(tree: TreeSitterTree, _filePath: string): E
|
|
|
28
28
|
classes: [],
|
|
29
29
|
exports: [],
|
|
30
30
|
typeMap: new Map(),
|
|
31
|
+
newExpressions: [],
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
walkCSharpNode(tree.rootNode, ctx);
|
|
@@ -252,7 +253,12 @@ function handleCsObjectCreation(node: TreeSitterNode, ctx: ExtractorOutput): voi
|
|
|
252
253
|
typeNode.type === 'generic_name'
|
|
253
254
|
? typeNode.childForFieldName('name')?.text || typeNode.child(0)?.text
|
|
254
255
|
: typeNode.text;
|
|
255
|
-
if (typeName)
|
|
256
|
+
if (typeName) {
|
|
257
|
+
ctx.calls.push({ name: typeName, line: node.startPosition.row + 1 });
|
|
258
|
+
// Phase 8.5 (RTA): record instantiated type for CHA filtering, matching
|
|
259
|
+
// the JS extractor's newExpressions extraction for cross-engine parity.
|
|
260
|
+
(ctx.newExpressions as string[]).push(typeName);
|
|
261
|
+
}
|
|
256
262
|
}
|
|
257
263
|
|
|
258
264
|
const CS_PARENT_TYPES = [
|
|
@@ -273,7 +279,7 @@ function extractCSharpParameters(paramListNode: TreeSitterNode | null): SubDecla
|
|
|
273
279
|
if (!paramListNode) return params;
|
|
274
280
|
for (let i = 0; i < paramListNode.childCount; i++) {
|
|
275
281
|
const param = paramListNode.child(i);
|
|
276
|
-
if (
|
|
282
|
+
if (param?.type !== 'parameter') continue;
|
|
277
283
|
const nameNode = param.childForFieldName('name');
|
|
278
284
|
if (nameNode) {
|
|
279
285
|
params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
@@ -288,12 +294,12 @@ function extractCSharpClassFields(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
288
294
|
if (!body) return fields;
|
|
289
295
|
for (let i = 0; i < body.childCount; i++) {
|
|
290
296
|
const member = body.child(i);
|
|
291
|
-
if (
|
|
297
|
+
if (member?.type !== 'field_declaration') continue;
|
|
292
298
|
const varDecl = findChild(member, 'variable_declaration');
|
|
293
299
|
if (!varDecl) continue;
|
|
294
300
|
for (let j = 0; j < varDecl.childCount; j++) {
|
|
295
301
|
const child = varDecl.child(j);
|
|
296
|
-
if (
|
|
302
|
+
if (child?.type !== 'variable_declarator') continue;
|
|
297
303
|
const nameNode = child.childForFieldName('name');
|
|
298
304
|
if (nameNode) {
|
|
299
305
|
fields.push({
|
|
@@ -326,16 +332,34 @@ function extractCSharpTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
326
332
|
/** Extract type info from a variable_declaration node (local vars with explicit types). */
|
|
327
333
|
function handleCSharpVarDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
328
334
|
const typeNode = node.childForFieldName('type') || node.child(0);
|
|
329
|
-
if (!typeNode
|
|
335
|
+
if (!typeNode) return;
|
|
336
|
+
|
|
337
|
+
if (typeNode.type === 'implicit_type') {
|
|
338
|
+
// var x = new Foo() — infer type from object_creation_expression initializer
|
|
339
|
+
if (!ctx.typeMap) return;
|
|
340
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
341
|
+
const child = node.child(i);
|
|
342
|
+
if (child?.type !== 'variable_declarator') continue;
|
|
343
|
+
const nameNode = child.childForFieldName('name') || child.child(0);
|
|
344
|
+
if (nameNode?.type !== 'identifier') continue;
|
|
345
|
+
const objCreation = findChild(child, 'object_creation_expression');
|
|
346
|
+
if (!objCreation) continue;
|
|
347
|
+
const ctorTypeNode = objCreation.childForFieldName('type');
|
|
348
|
+
if (!ctorTypeNode) continue;
|
|
349
|
+
const ctorType = extractCSharpTypeName(ctorTypeNode);
|
|
350
|
+
if (ctorType) setTypeMapEntry(ctx.typeMap, nameNode.text, ctorType, 1.0);
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
330
355
|
const typeName = extractCSharpTypeName(typeNode);
|
|
331
356
|
if (!typeName) return;
|
|
332
357
|
for (let i = 0; i < node.childCount; i++) {
|
|
333
358
|
const child = node.child(i);
|
|
334
|
-
if (
|
|
359
|
+
if (child?.type !== 'variable_declarator') continue;
|
|
335
360
|
const nameNode = child.childForFieldName('name') || child.child(0);
|
|
336
|
-
if (nameNode
|
|
337
|
-
|
|
338
|
-
}
|
|
361
|
+
if (nameNode?.type !== 'identifier' || !ctx.typeMap) continue;
|
|
362
|
+
if (typeName) setTypeMapEntry(ctx.typeMap, nameNode.text, typeName, 0.9);
|
|
339
363
|
}
|
|
340
364
|
}
|
|
341
365
|
|
package/src/extractors/cuda.ts
CHANGED
|
@@ -5,7 +5,13 @@ import type {
|
|
|
5
5
|
TreeSitterNode,
|
|
6
6
|
TreeSitterTree,
|
|
7
7
|
} from '../types.js';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
extractModifierVisibility,
|
|
10
|
+
findChild,
|
|
11
|
+
isCPrimitiveType,
|
|
12
|
+
nodeEndLine,
|
|
13
|
+
setTypeMapEntry,
|
|
14
|
+
} from './helpers.js';
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Extract symbols from CUDA files.
|
|
@@ -63,6 +69,9 @@ function walkCudaNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
63
69
|
case 'call_expression':
|
|
64
70
|
handleCudaCallExpression(node, ctx);
|
|
65
71
|
break;
|
|
72
|
+
case 'declaration':
|
|
73
|
+
handleCudaDeclaration(node, ctx);
|
|
74
|
+
break;
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -204,6 +213,40 @@ function handleCudaInclude(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
204
213
|
});
|
|
205
214
|
}
|
|
206
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Seed typeMap for declaration-typed locals: `UserService svc;` and
|
|
218
|
+
* `UserService svc = make();` both yield typeMap["svc"] = "UserService"
|
|
219
|
+
* at confidence 0.9. Mirrors `match_c_family_type_map` ("declaration" branch)
|
|
220
|
+
* in the native Rust CUDA extractor.
|
|
221
|
+
*/
|
|
222
|
+
function handleCudaDeclaration(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
223
|
+
const typeNode = node.childForFieldName('type');
|
|
224
|
+
if (!typeNode) return;
|
|
225
|
+
const typeName = typeNode.text;
|
|
226
|
+
// Skip primitive types — they are never class/struct receivers
|
|
227
|
+
if (isCPrimitiveType(typeName)) return;
|
|
228
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
229
|
+
const child = node.child(i);
|
|
230
|
+
if (!child) continue;
|
|
231
|
+
const kind = child.type;
|
|
232
|
+
let nameNode: TreeSitterNode | null = null;
|
|
233
|
+
if (kind === 'init_declarator') {
|
|
234
|
+
nameNode = child.childForFieldName('declarator') ?? null;
|
|
235
|
+
} else if (kind === 'identifier') {
|
|
236
|
+
nameNode = child;
|
|
237
|
+
}
|
|
238
|
+
// Note: pointer_declarator / reference_declarator children (e.g. `UserService *svc;`)
|
|
239
|
+
// are intentionally skipped here — they are also skipped by the native Rust
|
|
240
|
+
// match_c_family_type_map helper, which only handles 'init_declarator' and
|
|
241
|
+
// 'identifier' children. Both engines have the same scope for this case.
|
|
242
|
+
if (!nameNode) continue;
|
|
243
|
+
const varName = extractCudaFieldName(nameNode);
|
|
244
|
+
if (varName) {
|
|
245
|
+
setTypeMapEntry(ctx.typeMap, varName, typeName, 0.9);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
207
250
|
function handleCudaCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
208
251
|
const funcNode = node.childForFieldName('function');
|
|
209
252
|
if (!funcNode) return;
|
|
@@ -262,7 +305,7 @@ function extractCudaParameters(paramListNode: TreeSitterNode | null): SubDeclara
|
|
|
262
305
|
if (!paramListNode) return params;
|
|
263
306
|
for (let i = 0; i < paramListNode.childCount; i++) {
|
|
264
307
|
const param = paramListNode.child(i);
|
|
265
|
-
if (
|
|
308
|
+
if (param?.type !== 'parameter_declaration') continue;
|
|
266
309
|
const nameNode = param.childForFieldName('declarator');
|
|
267
310
|
if (nameNode) {
|
|
268
311
|
// Reuse the field-name drill helper so function-type parameters like
|
|
@@ -282,7 +325,7 @@ function extractCudaClassFields(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
282
325
|
if (!body) return fields;
|
|
283
326
|
for (let i = 0; i < body.childCount; i++) {
|
|
284
327
|
const member = body.child(i);
|
|
285
|
-
if (
|
|
328
|
+
if (member?.type !== 'field_declaration') continue;
|
|
286
329
|
const nameNode = member.childForFieldName('declarator');
|
|
287
330
|
if (!nameNode) continue;
|
|
288
331
|
// Skip method declarations — a `field_declaration` whose declarator
|
|
@@ -380,7 +423,7 @@ function extractCudaEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
|
|
|
380
423
|
if (!body) return entries;
|
|
381
424
|
for (let i = 0; i < body.childCount; i++) {
|
|
382
425
|
const member = body.child(i);
|
|
383
|
-
if (
|
|
426
|
+
if (member?.type !== 'enumerator') continue;
|
|
384
427
|
const nameNode = member.childForFieldName('name');
|
|
385
428
|
if (nameNode) {
|
|
386
429
|
entries.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
|