@colbymchenry/codegraph-darwin-x64 0.9.8 → 1.0.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/lib/dist/bin/codegraph.d.ts +1 -0
- package/lib/dist/bin/codegraph.d.ts.map +1 -1
- package/lib/dist/bin/codegraph.js +247 -39
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/context/index.d.ts +9 -0
- package/lib/dist/context/index.d.ts.map +1 -1
- package/lib/dist/context/index.js +102 -6
- package/lib/dist/context/index.js.map +1 -1
- package/lib/dist/context/markers.d.ts +19 -0
- package/lib/dist/context/markers.d.ts.map +1 -0
- package/lib/dist/context/markers.js +22 -0
- package/lib/dist/context/markers.js.map +1 -0
- package/lib/dist/db/index.d.ts.map +1 -1
- package/lib/dist/db/index.js +2 -1
- package/lib/dist/db/index.js.map +1 -1
- package/lib/dist/db/migrations.d.ts +1 -1
- package/lib/dist/db/migrations.d.ts.map +1 -1
- package/lib/dist/db/migrations.js +10 -1
- package/lib/dist/db/migrations.js.map +1 -1
- package/lib/dist/db/queries.d.ts +43 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +103 -7
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/db/schema.sql +1 -0
- package/lib/dist/db/sqlite-adapter.d.ts +7 -0
- package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/lib/dist/db/sqlite-adapter.js +3 -0
- package/lib/dist/db/sqlite-adapter.js.map +1 -1
- package/lib/dist/directory.d.ts +34 -2
- package/lib/dist/directory.d.ts.map +1 -1
- package/lib/dist/directory.js +129 -35
- package/lib/dist/directory.js.map +1 -1
- package/lib/dist/extraction/astro-extractor.d.ts +79 -0
- package/lib/dist/extraction/astro-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/astro-extractor.js +320 -0
- package/lib/dist/extraction/astro-extractor.js.map +1 -0
- package/lib/dist/extraction/extraction-version.d.ts +25 -0
- package/lib/dist/extraction/extraction-version.d.ts.map +1 -0
- package/lib/dist/extraction/extraction-version.js +28 -0
- package/lib/dist/extraction/extraction-version.js.map +1 -0
- package/lib/dist/extraction/function-ref.d.ts +118 -0
- package/lib/dist/extraction/function-ref.d.ts.map +1 -0
- package/lib/dist/extraction/function-ref.js +727 -0
- package/lib/dist/extraction/function-ref.js.map +1 -0
- package/lib/dist/extraction/generated-detection.d.ts.map +1 -1
- package/lib/dist/extraction/generated-detection.js +3 -0
- package/lib/dist/extraction/generated-detection.js.map +1 -1
- package/lib/dist/extraction/grammars.d.ts +7 -1
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +52 -4
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +34 -0
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +346 -62
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.d.ts +8 -0
- package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +87 -28
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/extraction/languages/csharp.d.ts +22 -0
- package/lib/dist/extraction/languages/csharp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/csharp.js +84 -2
- package/lib/dist/extraction/languages/csharp.js.map +1 -1
- package/lib/dist/extraction/languages/dart.d.ts.map +1 -1
- package/lib/dist/extraction/languages/dart.js +161 -1
- package/lib/dist/extraction/languages/dart.js.map +1 -1
- package/lib/dist/extraction/languages/go.d.ts.map +1 -1
- package/lib/dist/extraction/languages/go.js +43 -2
- package/lib/dist/extraction/languages/go.js.map +1 -1
- package/lib/dist/extraction/languages/index.d.ts.map +1 -1
- package/lib/dist/extraction/languages/index.js +2 -0
- package/lib/dist/extraction/languages/index.js.map +1 -1
- package/lib/dist/extraction/languages/java.d.ts.map +1 -1
- package/lib/dist/extraction/languages/java.js +42 -1
- package/lib/dist/extraction/languages/java.js.map +1 -1
- package/lib/dist/extraction/languages/javascript.d.ts.map +1 -1
- package/lib/dist/extraction/languages/javascript.js +16 -0
- package/lib/dist/extraction/languages/javascript.js.map +1 -1
- package/lib/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/lib/dist/extraction/languages/kotlin.js +69 -0
- package/lib/dist/extraction/languages/kotlin.js.map +1 -1
- package/lib/dist/extraction/languages/objc.d.ts.map +1 -1
- package/lib/dist/extraction/languages/objc.js +42 -0
- package/lib/dist/extraction/languages/objc.js.map +1 -1
- package/lib/dist/extraction/languages/pascal.d.ts.map +1 -1
- package/lib/dist/extraction/languages/pascal.js +11 -0
- package/lib/dist/extraction/languages/pascal.js.map +1 -1
- package/lib/dist/extraction/languages/php.d.ts.map +1 -1
- package/lib/dist/extraction/languages/php.js +90 -1
- package/lib/dist/extraction/languages/php.js.map +1 -1
- package/lib/dist/extraction/languages/r.d.ts +3 -0
- package/lib/dist/extraction/languages/r.d.ts.map +1 -0
- package/lib/dist/extraction/languages/r.js +314 -0
- package/lib/dist/extraction/languages/r.js.map +1 -0
- package/lib/dist/extraction/languages/ruby.d.ts.map +1 -1
- package/lib/dist/extraction/languages/ruby.js +35 -0
- package/lib/dist/extraction/languages/ruby.js.map +1 -1
- package/lib/dist/extraction/languages/rust.d.ts.map +1 -1
- package/lib/dist/extraction/languages/rust.js +35 -2
- package/lib/dist/extraction/languages/rust.js.map +1 -1
- package/lib/dist/extraction/languages/scala.d.ts.map +1 -1
- package/lib/dist/extraction/languages/scala.js +61 -1
- package/lib/dist/extraction/languages/scala.js.map +1 -1
- package/lib/dist/extraction/languages/swift.d.ts.map +1 -1
- package/lib/dist/extraction/languages/swift.js +61 -0
- package/lib/dist/extraction/languages/swift.js.map +1 -1
- package/lib/dist/extraction/languages/typescript.d.ts +13 -0
- package/lib/dist/extraction/languages/typescript.d.ts.map +1 -1
- package/lib/dist/extraction/languages/typescript.js +38 -0
- package/lib/dist/extraction/languages/typescript.js.map +1 -1
- package/lib/dist/extraction/liquid-extractor.d.ts +7 -0
- package/lib/dist/extraction/liquid-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/liquid-extractor.js +53 -9
- package/lib/dist/extraction/liquid-extractor.js.map +1 -1
- package/lib/dist/extraction/razor-extractor.d.ts +42 -0
- package/lib/dist/extraction/razor-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/razor-extractor.js +285 -0
- package/lib/dist/extraction/razor-extractor.js.map +1 -0
- package/lib/dist/extraction/svelte-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/svelte-extractor.js +6 -3
- package/lib/dist/extraction/svelte-extractor.js.map +1 -1
- package/lib/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter-helpers.js +59 -10
- package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/lib/dist/extraction/tree-sitter-types.d.ts +33 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts +237 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +1820 -68
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/extraction/vue-extractor.d.ts +15 -0
- package/lib/dist/extraction/vue-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/vue-extractor.js +94 -3
- package/lib/dist/extraction/vue-extractor.js.map +1 -1
- package/lib/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/lib/dist/graph/queries.d.ts.map +1 -1
- package/lib/dist/graph/queries.js +13 -40
- package/lib/dist/graph/queries.js.map +1 -1
- package/lib/dist/graph/traversal.d.ts.map +1 -1
- package/lib/dist/graph/traversal.js +16 -4
- package/lib/dist/graph/traversal.js.map +1 -1
- package/lib/dist/index.d.ts +41 -3
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +99 -9
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +52 -2
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +34 -11
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +44 -12
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +6 -10
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/codex.js +4 -6
- package/lib/dist/installer/targets/codex.js.map +1 -1
- package/lib/dist/installer/targets/gemini.js +4 -6
- package/lib/dist/installer/targets/gemini.js.map +1 -1
- package/lib/dist/installer/targets/opencode.d.ts +9 -1
- package/lib/dist/installer/targets/opencode.d.ts.map +1 -1
- package/lib/dist/installer/targets/opencode.js +91 -40
- package/lib/dist/installer/targets/opencode.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +14 -0
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +19 -2
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/mcp/daemon.d.ts +60 -1
- package/lib/dist/mcp/daemon.d.ts.map +1 -1
- package/lib/dist/mcp/daemon.js +221 -8
- package/lib/dist/mcp/daemon.js.map +1 -1
- package/lib/dist/mcp/dynamic-boundaries.d.ts +41 -0
- package/lib/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
- package/lib/dist/mcp/dynamic-boundaries.js +359 -0
- package/lib/dist/mcp/dynamic-boundaries.js.map +1 -0
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +18 -9
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/ppid-watchdog.d.ts +44 -0
- package/lib/dist/mcp/ppid-watchdog.d.ts.map +1 -0
- package/lib/dist/mcp/ppid-watchdog.js +27 -0
- package/lib/dist/mcp/ppid-watchdog.js.map +1 -0
- package/lib/dist/mcp/proxy.d.ts +6 -0
- package/lib/dist/mcp/proxy.d.ts.map +1 -1
- package/lib/dist/mcp/proxy.js +153 -24
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +12 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +58 -32
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.d.ts +2 -0
- package/lib/dist/mcp/session.d.ts.map +1 -1
- package/lib/dist/mcp/session.js +49 -2
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/stdin-teardown.d.ts +27 -0
- package/lib/dist/mcp/stdin-teardown.d.ts.map +1 -0
- package/lib/dist/mcp/stdin-teardown.js +49 -0
- package/lib/dist/mcp/stdin-teardown.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +110 -49
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +1222 -972
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/mcp/transport.d.ts.map +1 -1
- package/lib/dist/mcp/transport.js +18 -2
- package/lib/dist/mcp/transport.js.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.d.ts +3 -3
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +549 -21
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
- package/lib/dist/resolution/frameworks/astro.d.ts +9 -0
- package/lib/dist/resolution/frameworks/astro.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/astro.js +169 -0
- package/lib/dist/resolution/frameworks/astro.js.map +1 -0
- package/lib/dist/resolution/frameworks/expo-modules.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/expo-modules.js +6 -1
- package/lib/dist/resolution/frameworks/expo-modules.js.map +1 -1
- package/lib/dist/resolution/frameworks/index.d.ts +1 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +5 -1
- package/lib/dist/resolution/frameworks/index.js.map +1 -1
- package/lib/dist/resolution/frameworks/java.js +6 -1
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/python.js +7 -3
- package/lib/dist/resolution/frameworks/python.js.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.js +53 -3
- package/lib/dist/resolution/frameworks/react-native.js.map +1 -1
- package/lib/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/react.js +15 -3
- package/lib/dist/resolution/frameworks/react.js.map +1 -1
- package/lib/dist/resolution/frameworks/svelte.js +5 -1
- package/lib/dist/resolution/frameworks/svelte.js.map +1 -1
- package/lib/dist/resolution/frameworks/vue.js +24 -27
- package/lib/dist/resolution/frameworks/vue.js.map +1 -1
- package/lib/dist/resolution/import-resolver.d.ts +10 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +564 -2
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts +80 -0
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +457 -7
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts +61 -0
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +590 -14
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- package/lib/dist/resolution/types.d.ts +27 -3
- package/lib/dist/resolution/types.d.ts.map +1 -1
- package/lib/dist/resolution/workspace-packages.d.ts +48 -0
- package/lib/dist/resolution/workspace-packages.d.ts.map +1 -0
- package/lib/dist/resolution/workspace-packages.js +208 -0
- package/lib/dist/resolution/workspace-packages.js.map +1 -0
- package/lib/dist/search/query-utils.d.ts +35 -1
- package/lib/dist/search/query-utils.d.ts.map +1 -1
- package/lib/dist/search/query-utils.js +109 -10
- package/lib/dist/search/query-utils.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +124 -32
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +326 -111
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/telemetry/index.d.ts +146 -0
- package/lib/dist/telemetry/index.d.ts.map +1 -0
- package/lib/dist/telemetry/index.js +544 -0
- package/lib/dist/telemetry/index.js.map +1 -0
- package/lib/dist/types.d.ts +25 -2
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +3 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/dist/upgrade/index.d.ts +132 -0
- package/lib/dist/upgrade/index.d.ts.map +1 -0
- package/lib/dist/upgrade/index.js +462 -0
- package/lib/dist/upgrade/index.js.map +1 -0
- package/lib/dist/utils.d.ts +30 -24
- package/lib/dist/utils.d.ts.map +1 -1
- package/lib/dist/utils.js +64 -48
- package/lib/dist/utils.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -29
- package/lib/package.json +1 -2
- package/package.json +1 -1
- package/lib/node_modules/chokidar/LICENSE +0 -21
- package/lib/node_modules/chokidar/README.md +0 -305
- package/lib/node_modules/chokidar/esm/handler.d.ts +0 -90
- package/lib/node_modules/chokidar/esm/handler.js +0 -629
- package/lib/node_modules/chokidar/esm/index.d.ts +0 -215
- package/lib/node_modules/chokidar/esm/index.js +0 -798
- package/lib/node_modules/chokidar/esm/package.json +0 -1
- package/lib/node_modules/chokidar/handler.d.ts +0 -90
- package/lib/node_modules/chokidar/handler.js +0 -635
- package/lib/node_modules/chokidar/index.d.ts +0 -215
- package/lib/node_modules/chokidar/index.js +0 -804
- package/lib/node_modules/chokidar/package.json +0 -69
- package/lib/node_modules/readdirp/LICENSE +0 -21
- package/lib/node_modules/readdirp/README.md +0 -120
- package/lib/node_modules/readdirp/esm/index.d.ts +0 -108
- package/lib/node_modules/readdirp/esm/index.js +0 -257
- package/lib/node_modules/readdirp/esm/package.json +0 -1
- package/lib/node_modules/readdirp/index.d.ts +0 -108
- package/lib/node_modules/readdirp/index.js +0 -263
- package/lib/node_modules/readdirp/package.json +0 -70
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Function-as-value capture (#756) — registration-linking for callbacks.
|
|
4
|
+
*
|
|
5
|
+
* A function name used as a VALUE — passed as a call argument
|
|
6
|
+
* (`register_handler(target_cb)`, `signal(SIGINT, handler)`), assigned to a
|
|
7
|
+
* field or function pointer (`o->cb = target_cb`, `OnFire := TargetCb`),
|
|
8
|
+
* placed in a struct/object initializer (`{ .recv_cb = my_cb }`,
|
|
9
|
+
* `{ recv: targetCb }`, `Ops{Cb: targetCb}`), or listed in a function table
|
|
10
|
+
* (`static cb_t table[] = { cb_a, cb_b }`) — is a real dependency that static
|
|
11
|
+
* call extraction misses entirely: `callers(target_cb)` showed nothing but
|
|
12
|
+
* direct calls, so every callback looked dead and its registration sites were
|
|
13
|
+
* invisible to impact analysis.
|
|
14
|
+
*
|
|
15
|
+
* This module captures those value positions during the AST walk as
|
|
16
|
+
* `function_ref` candidates. Capture is table-driven per language (the value
|
|
17
|
+
* positions and wrapper forms differ per grammar — `&fn` in C, `Main::fn` in
|
|
18
|
+
* Java, `::fn` in Kotlin, `#selector(fn)` in Swift, `@TargetCb` in Pascal,
|
|
19
|
+
* `method(:fn)` in Ruby). Candidates are GATED at end-of-file extraction
|
|
20
|
+
* (see `TreeSitterExtractor.flushFnRefCandidates`): only names matching a
|
|
21
|
+
* same-file function/method or an imported binding survive, which bounds
|
|
22
|
+
* volume and keeps precision high. Resolution then matches survivors against
|
|
23
|
+
* function/method nodes ONLY (`matchFunctionRef` in
|
|
24
|
+
* `src/resolution/name-matcher.ts`) and persists them as `references` edges,
|
|
25
|
+
* which `callers`/`impact` already traverse.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately NOT covered (resolving the *dispatch* — `o->cb(x)` → the
|
|
28
|
+
* registered function — needs data-flow through struct fields; a wrong edge
|
|
29
|
+
* is worse than none): indirect-call resolution and `obj.method` member
|
|
30
|
+
* values where `obj` isn't `this`/`self` (the receiver's type is statically
|
|
31
|
+
* unknowable without local data-flow).
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.FN_REF_SPECS = void 0;
|
|
35
|
+
exports.captureFnRefCandidates = captureFnRefCandidates;
|
|
36
|
+
const tree_sitter_helpers_1 = require("./tree-sitter-helpers");
|
|
37
|
+
/** Names that are never function references even when grammars call them identifiers. */
|
|
38
|
+
const NAME_STOPLIST = new Set([
|
|
39
|
+
'this',
|
|
40
|
+
'self',
|
|
41
|
+
'super',
|
|
42
|
+
'null',
|
|
43
|
+
'nil',
|
|
44
|
+
'true',
|
|
45
|
+
'false',
|
|
46
|
+
'undefined',
|
|
47
|
+
'new',
|
|
48
|
+
'NULL',
|
|
49
|
+
'nullptr',
|
|
50
|
+
'None',
|
|
51
|
+
]);
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Per-language specs. Node types verified against each grammar (probe fixtures
|
|
54
|
+
// in the #756 investigation; see docs/design/function-ref-capture.md).
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
/** C / C++ / Objective-C share the C-family initializer & assignment shapes. */
|
|
57
|
+
function cFamilySpec(extra) {
|
|
58
|
+
return {
|
|
59
|
+
idTypes: new Set(['identifier']),
|
|
60
|
+
dispatch: new Map([
|
|
61
|
+
['argument_list', { mode: 'args' }],
|
|
62
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
63
|
+
['init_declarator', { mode: 'varinit', field: 'value' }],
|
|
64
|
+
['initializer_list', { mode: 'list' }],
|
|
65
|
+
['initializer_pair', { mode: 'value', field: 'value' }],
|
|
66
|
+
]),
|
|
67
|
+
unwrap: new Map([['pointer_expression', 'argument']]),
|
|
68
|
+
special: new Set(extra?.special ?? []),
|
|
69
|
+
// C has no symbol imports, and callbacks are registered cross-file at repo
|
|
70
|
+
// scale (redis: server.c's command table names handlers from t_*.c) — so
|
|
71
|
+
// initializer positions bypass the gate and lean on resolution's
|
|
72
|
+
// unique-or-drop rule. ONLY 'value'/'list' (struct/array initializers),
|
|
73
|
+
// and the flush additionally requires FILE scope: a C file-scope
|
|
74
|
+
// initializer is a constant-expression context, so a bare identifier
|
|
75
|
+
// there can only be a function address (or enum/macro, which the
|
|
76
|
+
// function-kind filter drops) — never a variable. 'rhs'/'varinit' were
|
|
77
|
+
// tried and produced false edges (`prev = next`, `*str = field` — data
|
|
78
|
+
// assignments matching a unique same-named function elsewhere), so
|
|
79
|
+
// assignments stay gated to same-file/import.
|
|
80
|
+
ungatedModes: new Set(['value', 'list']),
|
|
81
|
+
addressOfOnly: extra?.addressOfOnly,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// `this.handleClick` capture (member_expression) emits a `this.`-PREFIXED
|
|
85
|
+
// candidate name: resolution scopes it to the enclosing symbol's class
|
|
86
|
+
// (qualified-name prefix), so `this.fonts` (a property, post-#808) and
|
|
87
|
+
// inherited/unknown members yield no edge, while same-class methods —
|
|
88
|
+
// `btn.on('click', this.handleClick)`, the observer-registration idiom —
|
|
89
|
+
// resolve precisely. Bare identifiers stay function-kind-only (a bare id can
|
|
90
|
+
// never be a method value in JS).
|
|
91
|
+
const TS_JS_SPEC = {
|
|
92
|
+
idTypes: new Set(['identifier']),
|
|
93
|
+
dispatch: new Map([
|
|
94
|
+
['arguments', { mode: 'args' }],
|
|
95
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
96
|
+
['variable_declarator', { mode: 'varinit', field: 'value' }],
|
|
97
|
+
['pair', { mode: 'value', field: 'value' }],
|
|
98
|
+
['array', { mode: 'list' }],
|
|
99
|
+
]),
|
|
100
|
+
special: new Set(['member_expression']),
|
|
101
|
+
};
|
|
102
|
+
const PYTHON_SPEC = {
|
|
103
|
+
idTypes: new Set(['identifier']),
|
|
104
|
+
dispatch: new Map([
|
|
105
|
+
['argument_list', { mode: 'args' }],
|
|
106
|
+
['assignment', { mode: 'rhs', field: 'right' }],
|
|
107
|
+
['keyword_argument', { mode: 'value', field: 'value' }], // Thread(target=worker)
|
|
108
|
+
['pair', { mode: 'value', field: 'value' }],
|
|
109
|
+
['list', { mode: 'list' }],
|
|
110
|
+
]),
|
|
111
|
+
special: new Set(['attribute']),
|
|
112
|
+
};
|
|
113
|
+
const GO_SPEC = {
|
|
114
|
+
idTypes: new Set(['identifier']),
|
|
115
|
+
dispatch: new Map([
|
|
116
|
+
['argument_list', { mode: 'args' }],
|
|
117
|
+
['assignment_statement', { mode: 'rhs', field: 'right' }],
|
|
118
|
+
['short_var_declaration', { mode: 'rhs', field: 'right' }],
|
|
119
|
+
['var_spec', { mode: 'varinit', field: 'value' }],
|
|
120
|
+
['keyed_element', { mode: 'value' }], // value = last literal_element child
|
|
121
|
+
['literal_value', { mode: 'list' }], // positional composite literals
|
|
122
|
+
]),
|
|
123
|
+
layers: new Map([
|
|
124
|
+
['literal_element', null],
|
|
125
|
+
['expression_list', null],
|
|
126
|
+
]),
|
|
127
|
+
};
|
|
128
|
+
const RUST_SPEC = {
|
|
129
|
+
idTypes: new Set(['identifier']),
|
|
130
|
+
dispatch: new Map([
|
|
131
|
+
['arguments', { mode: 'args' }],
|
|
132
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
133
|
+
['field_initializer', { mode: 'value', field: 'value' }],
|
|
134
|
+
['array_expression', { mode: 'list' }],
|
|
135
|
+
['static_item', { mode: 'varinit', field: 'value' }],
|
|
136
|
+
['let_declaration', { mode: 'varinit', field: 'value' }],
|
|
137
|
+
]),
|
|
138
|
+
};
|
|
139
|
+
const JAVA_SPEC = {
|
|
140
|
+
// No bare-identifier function values in Java — only method references.
|
|
141
|
+
idTypes: new Set(),
|
|
142
|
+
dispatch: new Map([
|
|
143
|
+
['argument_list', { mode: 'args' }],
|
|
144
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
145
|
+
['variable_declarator', { mode: 'varinit', field: 'value' }],
|
|
146
|
+
]),
|
|
147
|
+
special: new Set(['method_reference']),
|
|
148
|
+
};
|
|
149
|
+
const KOTLIN_SPEC = {
|
|
150
|
+
idTypes: new Set(),
|
|
151
|
+
dispatch: new Map([
|
|
152
|
+
['value_arguments', { mode: 'args' }],
|
|
153
|
+
['assignment', { mode: 'rhs' }], // RHS = last named child (no field in grammar)
|
|
154
|
+
]),
|
|
155
|
+
layers: new Map([['value_argument', null]]),
|
|
156
|
+
special: new Set(['callable_reference', 'navigation_expression']),
|
|
157
|
+
};
|
|
158
|
+
const CSHARP_SPEC = {
|
|
159
|
+
idTypes: new Set(['identifier']),
|
|
160
|
+
dispatch: new Map([
|
|
161
|
+
['argument_list', { mode: 'args' }],
|
|
162
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }], // covers `+=` event subscription
|
|
163
|
+
['initializer_expression', { mode: 'list' }],
|
|
164
|
+
['variable_declarator', { mode: 'varinit' }],
|
|
165
|
+
]),
|
|
166
|
+
layers: new Map([['argument', null]]),
|
|
167
|
+
special: new Set(['member_access_expression']),
|
|
168
|
+
};
|
|
169
|
+
const RUBY_SPEC = {
|
|
170
|
+
// Bare identifiers in Ruby args are method CALLS or locals, never function
|
|
171
|
+
// values — only the `method(:name)` idiom (and `&method(:name)`) plus
|
|
172
|
+
// hook-DSL symbols (`before_action :authenticate`) qualify.
|
|
173
|
+
idTypes: new Set(),
|
|
174
|
+
dispatch: new Map([
|
|
175
|
+
['argument_list', { mode: 'args' }],
|
|
176
|
+
['pair', { mode: 'value', field: 'value' }],
|
|
177
|
+
]),
|
|
178
|
+
layers: new Map([['block_argument', null]]),
|
|
179
|
+
special: new Set(['call', 'simple_symbol']),
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Rails/ActiveSupport-style hook DSLs whose symbol arguments name a method of
|
|
183
|
+
* the enclosing class: lifecycle callbacks (`before_action`, `after_save`,
|
|
184
|
+
* `around_create`, `skip_before_action`…), `validate :method`, `set_callback`,
|
|
185
|
+
* `helper_method`, and `rescue_from(..., with: :handler)`. NOT `validates`
|
|
186
|
+
* (plural) — its symbols name ATTRIBUTES, not methods.
|
|
187
|
+
*/
|
|
188
|
+
const RUBY_HOOK_RE = /^(skip_)?(before|after|around)_[a-z_]+$/;
|
|
189
|
+
const RUBY_HOOK_NAMES = new Set(['validate', 'set_callback', 'helper_method', 'rescue_from']);
|
|
190
|
+
function isRubyHookCall(name) {
|
|
191
|
+
return RUBY_HOOK_RE.test(name) || RUBY_HOOK_NAMES.has(name);
|
|
192
|
+
}
|
|
193
|
+
const SWIFT_SPEC = {
|
|
194
|
+
idTypes: new Set(['simple_identifier']),
|
|
195
|
+
dispatch: new Map([
|
|
196
|
+
['value_arguments', { mode: 'args' }],
|
|
197
|
+
['assignment', { mode: 'rhs', field: 'result' }],
|
|
198
|
+
['array_literal', { mode: 'list' }],
|
|
199
|
+
['property_declaration', { mode: 'varinit', field: 'value' }],
|
|
200
|
+
]),
|
|
201
|
+
layers: new Map([['value_argument', 'value']]),
|
|
202
|
+
special: new Set(['selector_expression']),
|
|
203
|
+
};
|
|
204
|
+
const SCALA_SPEC = {
|
|
205
|
+
idTypes: new Set(['identifier']),
|
|
206
|
+
dispatch: new Map([
|
|
207
|
+
['arguments', { mode: 'args' }],
|
|
208
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
209
|
+
['val_definition', { mode: 'varinit', field: 'value' }],
|
|
210
|
+
]),
|
|
211
|
+
unwrap: new Map([['postfix_expression', null]]), // eta-expansion `fn _`
|
|
212
|
+
};
|
|
213
|
+
const DART_SPEC = {
|
|
214
|
+
idTypes: new Set(['identifier']),
|
|
215
|
+
dispatch: new Map([
|
|
216
|
+
['arguments', { mode: 'args' }],
|
|
217
|
+
['assignment_expression', { mode: 'rhs', field: 'right' }],
|
|
218
|
+
['pair', { mode: 'value', field: 'value' }],
|
|
219
|
+
['list_literal', { mode: 'list' }],
|
|
220
|
+
['static_final_declaration', { mode: 'varinit' }],
|
|
221
|
+
]),
|
|
222
|
+
layers: new Map([['argument', null]]),
|
|
223
|
+
};
|
|
224
|
+
const LUA_SPEC = {
|
|
225
|
+
idTypes: new Set(['identifier']),
|
|
226
|
+
dispatch: new Map([
|
|
227
|
+
['arguments', { mode: 'args' }],
|
|
228
|
+
['assignment_statement', { mode: 'rhs' }], // RHS expression_list children carry `value` fields
|
|
229
|
+
['field', { mode: 'value', field: 'value' }], // table fields, keyed AND positional
|
|
230
|
+
]),
|
|
231
|
+
layers: new Map([['expression_list', null]]),
|
|
232
|
+
};
|
|
233
|
+
const PASCAL_SPEC = {
|
|
234
|
+
idTypes: new Set(['identifier']),
|
|
235
|
+
dispatch: new Map([
|
|
236
|
+
['exprArgs', { mode: 'args' }],
|
|
237
|
+
['assignment', { mode: 'rhs', field: 'rhs' }], // OnClick := Handler
|
|
238
|
+
]),
|
|
239
|
+
unwrap: new Map([['exprUnary', 'operand']]), // @Handler
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* PHP core functions whose string arguments are CALLABLES — the positional
|
|
243
|
+
* prior that makes a bare string trustworthy as a function reference.
|
|
244
|
+
* Deliberately core-PHP only; framework registries (WordPress `add_action`)
|
|
245
|
+
* belong in a frameworks/ resolver if ever added.
|
|
246
|
+
*/
|
|
247
|
+
const PHP_CALLABLE_HOFS = new Set([
|
|
248
|
+
'array_map', 'array_filter', 'array_walk', 'array_walk_recursive', 'array_reduce',
|
|
249
|
+
'usort', 'uasort', 'uksort',
|
|
250
|
+
'array_udiff', 'array_udiff_assoc', 'array_uintersect', 'array_uintersect_assoc',
|
|
251
|
+
'call_user_func', 'call_user_func_array',
|
|
252
|
+
'forward_static_call', 'forward_static_call_array',
|
|
253
|
+
'preg_replace_callback', 'preg_replace_callback_array',
|
|
254
|
+
'register_shutdown_function', 'register_tick_function',
|
|
255
|
+
'set_error_handler', 'set_exception_handler', 'spl_autoload_register',
|
|
256
|
+
'ob_start', 'iterator_apply', 'header_register_callback',
|
|
257
|
+
'is_callable',
|
|
258
|
+
]);
|
|
259
|
+
const PHP_SPEC = {
|
|
260
|
+
// PHP has no bare-identifier function values (the first-class callable
|
|
261
|
+
// `fn(...)` already extracts as a `calls` edge). What qualifies:
|
|
262
|
+
// - a string argument to a known callable-taking core function
|
|
263
|
+
// (`usort($a, 'cmp_items')`) — see PHP_CALLABLE_HOFS
|
|
264
|
+
// - array callables: `[$this, 'method']` (class-scoped) and
|
|
265
|
+
// `[Foo::class, 'method']` (qualified), in any call's arguments
|
|
266
|
+
idTypes: new Set(),
|
|
267
|
+
dispatch: new Map([['arguments', { mode: 'args' }]]),
|
|
268
|
+
layers: new Map([['argument', null]]),
|
|
269
|
+
special: new Set(['encapsed_string', 'string', 'array_creation_expression']),
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Capture specs by language.
|
|
273
|
+
*/
|
|
274
|
+
exports.FN_REF_SPECS = {
|
|
275
|
+
c: cFamilySpec(),
|
|
276
|
+
cpp: cFamilySpec({ addressOfOnly: true }),
|
|
277
|
+
objc: cFamilySpec({ special: ['selector_expression'] }),
|
|
278
|
+
typescript: TS_JS_SPEC,
|
|
279
|
+
tsx: TS_JS_SPEC,
|
|
280
|
+
javascript: TS_JS_SPEC,
|
|
281
|
+
jsx: TS_JS_SPEC,
|
|
282
|
+
python: PYTHON_SPEC,
|
|
283
|
+
go: GO_SPEC,
|
|
284
|
+
rust: RUST_SPEC,
|
|
285
|
+
java: JAVA_SPEC,
|
|
286
|
+
kotlin: KOTLIN_SPEC,
|
|
287
|
+
csharp: CSHARP_SPEC,
|
|
288
|
+
php: PHP_SPEC,
|
|
289
|
+
ruby: RUBY_SPEC,
|
|
290
|
+
swift: SWIFT_SPEC,
|
|
291
|
+
scala: SCALA_SPEC,
|
|
292
|
+
dart: DART_SPEC,
|
|
293
|
+
lua: LUA_SPEC,
|
|
294
|
+
luau: LUA_SPEC,
|
|
295
|
+
pascal: PASCAL_SPEC,
|
|
296
|
+
};
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// Capture
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
/**
|
|
301
|
+
* Extract candidate names from a dispatched container node. Returns the
|
|
302
|
+
* (name, position) pairs of every function-value-shaped expression found.
|
|
303
|
+
*/
|
|
304
|
+
function captureFnRefCandidates(container, rule, spec, source) {
|
|
305
|
+
const valueNodes = [];
|
|
306
|
+
switch (rule.mode) {
|
|
307
|
+
case 'args':
|
|
308
|
+
case 'list': {
|
|
309
|
+
for (let i = 0; i < container.namedChildCount; i++) {
|
|
310
|
+
const child = container.namedChild(i);
|
|
311
|
+
if (child)
|
|
312
|
+
valueNodes.push(child);
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
case 'rhs': {
|
|
317
|
+
const rhs = rule.field
|
|
318
|
+
? (0, tree_sitter_helpers_1.getChildByField)(container, rule.field)
|
|
319
|
+
: container.namedChild(container.namedChildCount - 1);
|
|
320
|
+
if (rhs) {
|
|
321
|
+
// Param-storage skip: `this.status = status` / `o->cb = cb` — when
|
|
322
|
+
// the assigned member's name EQUALS the RHS identifier, the RHS is a
|
|
323
|
+
// local/parameter being stored, and the function it holds (if any)
|
|
324
|
+
// is unknowable statically. A same-named function elsewhere would
|
|
325
|
+
// resolve to the WRONG target (excalidraw A/B finding), so skip.
|
|
326
|
+
const lhs = (0, tree_sitter_helpers_1.getChildByField)(container, 'left') ??
|
|
327
|
+
(0, tree_sitter_helpers_1.getChildByField)(container, 'lhs') ??
|
|
328
|
+
(0, tree_sitter_helpers_1.getChildByField)(container, 'target') ??
|
|
329
|
+
(container.namedChildCount >= 2 ? container.namedChild(0) : null);
|
|
330
|
+
const lhsText = lhs ? (0, tree_sitter_helpers_1.getNodeText)(lhs, source) : '';
|
|
331
|
+
const lhsLastName = lhsText.match(/([A-Za-z_$][A-Za-z0-9_$]*)\s*$/)?.[1];
|
|
332
|
+
const rhsText = (0, tree_sitter_helpers_1.getNodeText)(rhs, source).trim();
|
|
333
|
+
if (lhsLastName && lhsLastName === rhsText)
|
|
334
|
+
break;
|
|
335
|
+
valueNodes.push(rhs);
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case 'value': {
|
|
340
|
+
let value = rule.field ? (0, tree_sitter_helpers_1.getChildByField)(container, rule.field) : null;
|
|
341
|
+
// Keyed containers without a value field (Go keyed_element): the value
|
|
342
|
+
// is the LAST named child (the first is the key).
|
|
343
|
+
if (!value && container.namedChildCount > 0) {
|
|
344
|
+
value = container.namedChild(container.namedChildCount - 1);
|
|
345
|
+
}
|
|
346
|
+
if (value)
|
|
347
|
+
valueNodes.push(value);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
case 'varinit': {
|
|
351
|
+
// Destructuring (`const { center } = ellipse`) extracts DATA from the
|
|
352
|
+
// RHS — never a function alias. Without this skip, a parameter that
|
|
353
|
+
// shadows a same-named imported function produced a wrong edge.
|
|
354
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(container, 'name') ?? (0, tree_sitter_helpers_1.getChildByField)(container, 'pattern');
|
|
355
|
+
if (nameNode && (nameNode.type === 'object_pattern' || nameNode.type === 'array_pattern' ||
|
|
356
|
+
nameNode.type === 'tuple_pattern' || nameNode.type === 'struct_pattern')) {
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
if (rule.field) {
|
|
360
|
+
const value = (0, tree_sitter_helpers_1.getChildByField)(container, rule.field);
|
|
361
|
+
if (value)
|
|
362
|
+
valueNodes.push(value);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// No value field in this grammar (C# variable_declarator, Dart
|
|
366
|
+
// static_final_declaration): the initializer is the last named child —
|
|
367
|
+
// but a declarator WITHOUT an initializer has its NAME there instead.
|
|
368
|
+
// Require ≥2 named children and never pick the name/pattern child.
|
|
369
|
+
const value = container.namedChild(container.namedChildCount - 1);
|
|
370
|
+
const nameChild = (0, tree_sitter_helpers_1.getChildByField)(container, 'name') ?? (0, tree_sitter_helpers_1.getChildByField)(container, 'pattern');
|
|
371
|
+
if (value &&
|
|
372
|
+
container.namedChildCount >= 2 &&
|
|
373
|
+
(!nameChild || value.id !== nameChild.id)) {
|
|
374
|
+
valueNodes.push(value);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const out = [];
|
|
381
|
+
for (const v of valueNodes) {
|
|
382
|
+
// A bare identifier is one that normalizes without passing through an
|
|
383
|
+
// unwrap/special reference form. C++'s addressOfOnly policy (applied at
|
|
384
|
+
// flush, where file scope is known) drops bare ids outside file-scope
|
|
385
|
+
// initializer tables.
|
|
386
|
+
const explicitRef = !spec.idTypes.has(v.type);
|
|
387
|
+
for (const { name, node, skipGate } of normalizeValue(v, spec, source, 0)) {
|
|
388
|
+
if (!name || NAME_STOPLIST.has(name))
|
|
389
|
+
continue;
|
|
390
|
+
out.push({
|
|
391
|
+
name,
|
|
392
|
+
line: node.startPosition.row + 1,
|
|
393
|
+
column: node.startPosition.column,
|
|
394
|
+
mode: rule.mode,
|
|
395
|
+
explicitRef,
|
|
396
|
+
skipGate,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return out;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Normalize one value expression to zero or more function names. Recursion is
|
|
404
|
+
* bounded (wrapper layers only); anything that isn't a recognized
|
|
405
|
+
* function-value shape yields [].
|
|
406
|
+
*/
|
|
407
|
+
function normalizeValue(node, spec, source, depth) {
|
|
408
|
+
if (depth > 4)
|
|
409
|
+
return [];
|
|
410
|
+
const type = node.type;
|
|
411
|
+
// Bare identifier
|
|
412
|
+
if (spec.idTypes.has(type)) {
|
|
413
|
+
return [{ name: (0, tree_sitter_helpers_1.getNodeText)(node, source), node }];
|
|
414
|
+
}
|
|
415
|
+
// Transparent layers (argument, value_argument, literal_element,
|
|
416
|
+
// expression_list, block_argument). expression_list fans out (Go `a, b = f, g`).
|
|
417
|
+
const layerField = spec.layers?.get(type);
|
|
418
|
+
if (spec.layers?.has(type)) {
|
|
419
|
+
// Labeled-argument param-forward skip (Swift/Kotlin): `value: value` /
|
|
420
|
+
// `delay: delay` — when the label EQUALS the value identifier, the value
|
|
421
|
+
// is a forwarded local/parameter, not a function reference (Alamofire
|
|
422
|
+
// A/B finding; same rationale as the `this.x = x` assignment skip).
|
|
423
|
+
if (type === 'value_argument') {
|
|
424
|
+
const label = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
|
|
425
|
+
const value = (0, tree_sitter_helpers_1.getChildByField)(node, 'value') ?? node.namedChild(node.namedChildCount - 1);
|
|
426
|
+
if (label &&
|
|
427
|
+
value &&
|
|
428
|
+
(0, tree_sitter_helpers_1.getNodeText)(label, source).trim() === (0, tree_sitter_helpers_1.getNodeText)(value, source).trim()) {
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (layerField) {
|
|
433
|
+
const inner = (0, tree_sitter_helpers_1.getChildByField)(node, layerField);
|
|
434
|
+
return inner ? normalizeValue(inner, spec, source, depth + 1) : [];
|
|
435
|
+
}
|
|
436
|
+
const results = [];
|
|
437
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
438
|
+
const child = node.namedChild(i);
|
|
439
|
+
if (child)
|
|
440
|
+
results.push(...normalizeValue(child, spec, source, depth + 1));
|
|
441
|
+
}
|
|
442
|
+
return results;
|
|
443
|
+
}
|
|
444
|
+
// Unary wrappers: &fn / @Fn / `fn _`
|
|
445
|
+
const unwrapField = spec.unwrap?.get(type);
|
|
446
|
+
if (spec.unwrap?.has(type)) {
|
|
447
|
+
// C-family `pointer_expression` covers BOTH `&x` (address-of — a function
|
|
448
|
+
// value) and `*x` (dereference — a data read, never a function value).
|
|
449
|
+
// Only `&` qualifies; without this, fmt's `*begin` reads resolved to its
|
|
450
|
+
// free `begin()` functions.
|
|
451
|
+
if (type === 'pointer_expression' && node.child(0)?.type !== '&')
|
|
452
|
+
return [];
|
|
453
|
+
const inner = unwrapField ? (0, tree_sitter_helpers_1.getChildByField)(node, unwrapField) : node.namedChild(0);
|
|
454
|
+
if (!inner)
|
|
455
|
+
return [];
|
|
456
|
+
// C++ `&Widget::on_click` — keep the QUALIFIED name. Resolution scopes the
|
|
457
|
+
// method to that class (more precise than a bare-name match, and exempt
|
|
458
|
+
// from the cpp bare-ids-are-free-functions rule since `&Cls::m` is an
|
|
459
|
+
// explicit member-pointer).
|
|
460
|
+
if (inner.type === 'qualified_identifier') {
|
|
461
|
+
const text = (0, tree_sitter_helpers_1.getNodeText)(inner, source).trim();
|
|
462
|
+
return /^[A-Za-z_][\w:]*$/.test(text) ? [{ name: text, node: inner }] : [];
|
|
463
|
+
}
|
|
464
|
+
return normalizeValue(inner, spec, source, depth + 1);
|
|
465
|
+
}
|
|
466
|
+
// Special whole-node reference forms
|
|
467
|
+
if (spec.special?.has(type)) {
|
|
468
|
+
return normalizeSpecial(node, type, source);
|
|
469
|
+
}
|
|
470
|
+
return [];
|
|
471
|
+
}
|
|
472
|
+
/** Rightmost descendant-or-self named child of one of the given types. */
|
|
473
|
+
function lastNamedOfType(node, types) {
|
|
474
|
+
let found = null;
|
|
475
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
476
|
+
const child = node.namedChild(i);
|
|
477
|
+
if (!child)
|
|
478
|
+
continue;
|
|
479
|
+
if (types.has(child.type))
|
|
480
|
+
found = child;
|
|
481
|
+
const deeper = lastNamedOfType(child, types);
|
|
482
|
+
if (deeper)
|
|
483
|
+
found = deeper;
|
|
484
|
+
}
|
|
485
|
+
return found;
|
|
486
|
+
}
|
|
487
|
+
function normalizeSpecial(node, type, source) {
|
|
488
|
+
switch (type) {
|
|
489
|
+
// Java method references. Receiver decides the resolution route (#808):
|
|
490
|
+
// `this::run0` / `super::close` → `this.<m>` (class-scoped resolver;
|
|
491
|
+
// super rides the inherited-member supertype pass)
|
|
492
|
+
// `Type::method` (capitalized) → qualified `Type::method` (suffix-
|
|
493
|
+
// matched against that type's members, cross-file capable)
|
|
494
|
+
// `variable::method` → nothing (receiver type unknown statically —
|
|
495
|
+
// the deferred obj.method class)
|
|
496
|
+
case 'method_reference': {
|
|
497
|
+
let last = null;
|
|
498
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
499
|
+
const child = node.namedChild(i);
|
|
500
|
+
if (child && child.type === 'identifier')
|
|
501
|
+
last = child;
|
|
502
|
+
}
|
|
503
|
+
if (!last)
|
|
504
|
+
return [];
|
|
505
|
+
const m = (0, tree_sitter_helpers_1.getNodeText)(last, source);
|
|
506
|
+
const text = (0, tree_sitter_helpers_1.getNodeText)(node, source);
|
|
507
|
+
if (text.startsWith('this::') || text.startsWith('super::')) {
|
|
508
|
+
return [{ name: `this.${m}`, node: last }];
|
|
509
|
+
}
|
|
510
|
+
const recv = text.match(/^([A-Z][A-Za-z0-9_]*)\s*::/);
|
|
511
|
+
if (recv) {
|
|
512
|
+
// `Type::method` — but `Type::new` (constructor ref) has no method
|
|
513
|
+
// node to land on; let the stoplist drop it via the bare name.
|
|
514
|
+
return m === 'new' ? [] : [{ name: `${recv[1]}::${m}`, node: last }];
|
|
515
|
+
}
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
// Kotlin `::targetCb` (one part) / `OtherClass::handle` (two parts —
|
|
519
|
+
// receiver is a type_identifier; lowercase receivers are variables, the
|
|
520
|
+
// deferred obj.method class).
|
|
521
|
+
case 'callable_reference': {
|
|
522
|
+
let receiver = null;
|
|
523
|
+
let member = null;
|
|
524
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
525
|
+
const child = node.namedChild(i);
|
|
526
|
+
if (!child)
|
|
527
|
+
continue;
|
|
528
|
+
if (child.type === 'type_identifier')
|
|
529
|
+
receiver = child;
|
|
530
|
+
if (child.type === 'simple_identifier')
|
|
531
|
+
member = child;
|
|
532
|
+
}
|
|
533
|
+
if (!member)
|
|
534
|
+
return [];
|
|
535
|
+
const m = (0, tree_sitter_helpers_1.getNodeText)(member, source);
|
|
536
|
+
if (!receiver)
|
|
537
|
+
return [{ name: m, node: member }]; // ::topLevelFn
|
|
538
|
+
const recvText = (0, tree_sitter_helpers_1.getNodeText)(receiver, source);
|
|
539
|
+
return /^[A-Z]/.test(recvText)
|
|
540
|
+
? [{ name: `${recvText}::${m}`, node: member }]
|
|
541
|
+
: []; // variable::method — unknown receiver type
|
|
542
|
+
}
|
|
543
|
+
// Kotlin `this::fire` parses as navigation_expression with a `::fire`
|
|
544
|
+
// navigation_suffix — route through the class-scoped `this.` resolver.
|
|
545
|
+
// Ordinary `a.b` navigation (and any non-`this` receiver) MUST yield
|
|
546
|
+
// nothing.
|
|
547
|
+
case 'navigation_expression': {
|
|
548
|
+
if (!(0, tree_sitter_helpers_1.getNodeText)(node, source).startsWith('this::'))
|
|
549
|
+
return [];
|
|
550
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
551
|
+
const child = node.namedChild(i);
|
|
552
|
+
if (child && child.type === 'navigation_suffix' && (0, tree_sitter_helpers_1.getNodeText)(child, source).startsWith('::')) {
|
|
553
|
+
const id = child.namedChild(child.namedChildCount - 1);
|
|
554
|
+
if (id)
|
|
555
|
+
return [{ name: `this.${(0, tree_sitter_helpers_1.getNodeText)(id, source)}`, node: id }];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return [];
|
|
559
|
+
}
|
|
560
|
+
// Swift `#selector(Holder.fire)` → fire. ObjC `@selector(storeImage:)` →
|
|
561
|
+
// `storeImage:` verbatim (ObjC method nodes keep their selector colons).
|
|
562
|
+
case 'selector_expression': {
|
|
563
|
+
const inner = node.namedChild(0);
|
|
564
|
+
if (!inner)
|
|
565
|
+
return [];
|
|
566
|
+
if (inner.type === 'identifier' || inner.type === 'simple_identifier') {
|
|
567
|
+
return [{ name: (0, tree_sitter_helpers_1.getNodeText)(inner, source), node: inner }];
|
|
568
|
+
}
|
|
569
|
+
// Swift dotted form: rightmost simple_identifier. ObjC keyword selector:
|
|
570
|
+
// text as-is.
|
|
571
|
+
const last = lastNamedOfType(node, new Set(['simple_identifier']));
|
|
572
|
+
if (last)
|
|
573
|
+
return [{ name: (0, tree_sitter_helpers_1.getNodeText)(last, source), node: last }];
|
|
574
|
+
return [{ name: (0, tree_sitter_helpers_1.getNodeText)(inner, source).trim(), node: inner }];
|
|
575
|
+
}
|
|
576
|
+
// Ruby `method(:target_cb)` — a `call` whose method is literally `method`
|
|
577
|
+
// with a single symbol argument.
|
|
578
|
+
case 'call': {
|
|
579
|
+
const method = (0, tree_sitter_helpers_1.getChildByField)(node, 'method');
|
|
580
|
+
if (!method || (0, tree_sitter_helpers_1.getNodeText)(method, source) !== 'method')
|
|
581
|
+
return [];
|
|
582
|
+
const args = (0, tree_sitter_helpers_1.getChildByField)(node, 'arguments');
|
|
583
|
+
if (!args || args.namedChildCount !== 1)
|
|
584
|
+
return [];
|
|
585
|
+
const sym = args.namedChild(0);
|
|
586
|
+
if (!sym || sym.type !== 'simple_symbol')
|
|
587
|
+
return [];
|
|
588
|
+
const name = (0, tree_sitter_helpers_1.getNodeText)(sym, source).replace(/^:/, '');
|
|
589
|
+
return name ? [{ name, node: sym }] : [];
|
|
590
|
+
}
|
|
591
|
+
// `this.handleClick` (TS/JS) — object must be EXACTLY `this`. The name
|
|
592
|
+
// keeps the `this.` prefix so resolution can scope it to the enclosing
|
|
593
|
+
// class (see resolveThisMemberFnRef) instead of bare name-matching.
|
|
594
|
+
case 'member_expression': {
|
|
595
|
+
const obj = (0, tree_sitter_helpers_1.getChildByField)(node, 'object');
|
|
596
|
+
const prop = (0, tree_sitter_helpers_1.getChildByField)(node, 'property');
|
|
597
|
+
if (obj && prop && obj.type === 'this' && prop.type === 'property_identifier') {
|
|
598
|
+
return [{ name: `this.${(0, tree_sitter_helpers_1.getNodeText)(prop, source)}`, node: prop }];
|
|
599
|
+
}
|
|
600
|
+
return [];
|
|
601
|
+
}
|
|
602
|
+
// `self.handle_click` (Python) — object must be EXACTLY `self`.
|
|
603
|
+
case 'attribute': {
|
|
604
|
+
const obj = (0, tree_sitter_helpers_1.getChildByField)(node, 'object');
|
|
605
|
+
const attr = (0, tree_sitter_helpers_1.getChildByField)(node, 'attribute');
|
|
606
|
+
if (obj && attr && obj.type === 'identifier' && (0, tree_sitter_helpers_1.getNodeText)(obj, source) === 'self') {
|
|
607
|
+
return [{ name: (0, tree_sitter_helpers_1.getNodeText)(attr, source), node: attr }];
|
|
608
|
+
}
|
|
609
|
+
return [];
|
|
610
|
+
}
|
|
611
|
+
// `this.Run0` (C#) — receiver must be EXACTLY `this`. Two grammar shapes:
|
|
612
|
+
// newer tree-sitter-c-sharp exposes an `expression` field holding a
|
|
613
|
+
// `this_expression`; the vendored grammar keeps `this` as an anonymous
|
|
614
|
+
// token (only the `name` field is a named child), so fall back to the
|
|
615
|
+
// node text.
|
|
616
|
+
case 'member_access_expression': {
|
|
617
|
+
const name = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
|
|
618
|
+
if (!name)
|
|
619
|
+
return [];
|
|
620
|
+
const expr = (0, tree_sitter_helpers_1.getChildByField)(node, 'expression');
|
|
621
|
+
const isThisReceiver = expr
|
|
622
|
+
? expr.type === 'this_expression' || expr.type === 'this'
|
|
623
|
+
: (0, tree_sitter_helpers_1.getNodeText)(node, source).startsWith('this.');
|
|
624
|
+
return isThisReceiver ? [{ name: (0, tree_sitter_helpers_1.getNodeText)(name, source), node: name }] : [];
|
|
625
|
+
}
|
|
626
|
+
// PHP string callable — trustworthy ONLY as an argument to a known
|
|
627
|
+
// callable-taking core function (`usort($a, 'cmp_items')`). PHP global
|
|
628
|
+
// functions are referenced cross-file without imports, so these skip the
|
|
629
|
+
// name gate and rely on resolution's unique-or-drop rule. A
|
|
630
|
+
// `'Cls::method'` string becomes a qualified candidate.
|
|
631
|
+
case 'encapsed_string':
|
|
632
|
+
case 'string': {
|
|
633
|
+
const callee = phpEnclosingCallName(node);
|
|
634
|
+
if (!callee || !PHP_CALLABLE_HOFS.has(callee))
|
|
635
|
+
return [];
|
|
636
|
+
const content = phpStringContent(node, source);
|
|
637
|
+
if (!content)
|
|
638
|
+
return [];
|
|
639
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(content)) {
|
|
640
|
+
return [{ name: content, node, skipGate: true }];
|
|
641
|
+
}
|
|
642
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*::[A-Za-z_][A-Za-z0-9_]*$/.test(content)) {
|
|
643
|
+
return [{ name: content, node, skipGate: true }];
|
|
644
|
+
}
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
// PHP array callables, valid in ANY call's arguments (the shape itself is
|
|
648
|
+
// unambiguous): `[$this, 'method']` → class-scoped `this.method`;
|
|
649
|
+
// `[Foo::class, 'method']` → qualified `Foo::method`.
|
|
650
|
+
case 'array_creation_expression': {
|
|
651
|
+
if (node.namedChildCount !== 2)
|
|
652
|
+
return [];
|
|
653
|
+
const recv = node.namedChild(0)?.namedChild(0);
|
|
654
|
+
const strEl = node.namedChild(1)?.namedChild(0);
|
|
655
|
+
if (!recv || !strEl)
|
|
656
|
+
return [];
|
|
657
|
+
if (strEl.type !== 'encapsed_string' && strEl.type !== 'string')
|
|
658
|
+
return [];
|
|
659
|
+
const member = phpStringContent(strEl, source);
|
|
660
|
+
if (!member || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(member))
|
|
661
|
+
return [];
|
|
662
|
+
if (recv.type === 'variable_name' && (0, tree_sitter_helpers_1.getNodeText)(recv, source) === '$this') {
|
|
663
|
+
return [{ name: `this.${member}`, node: strEl }];
|
|
664
|
+
}
|
|
665
|
+
if (recv.type === 'class_constant_access_expression') {
|
|
666
|
+
const cls = recv.namedChild(0);
|
|
667
|
+
const kw = recv.namedChild(1);
|
|
668
|
+
if (cls && kw && (0, tree_sitter_helpers_1.getNodeText)(kw, source) === 'class') {
|
|
669
|
+
return [{ name: `${(0, tree_sitter_helpers_1.getNodeText)(cls, source)}::${member}`, node: strEl }];
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return [];
|
|
673
|
+
}
|
|
674
|
+
// Ruby hook-DSL symbols (`before_action :authenticate`,
|
|
675
|
+
// `rescue_from E, with: :render_404`): the symbol names a method of the
|
|
676
|
+
// ENCLOSING class — route through the class-scoped `this.` resolver
|
|
677
|
+
// (which also walks superclasses, covering ApplicationController-style
|
|
678
|
+
// inheritance). Symbols under any other call yield nothing.
|
|
679
|
+
case 'simple_symbol': {
|
|
680
|
+
const call = rubyEnclosingCall(node);
|
|
681
|
+
if (!call)
|
|
682
|
+
return [];
|
|
683
|
+
const method = (0, tree_sitter_helpers_1.getChildByField)(call, 'method');
|
|
684
|
+
if (!method || !isRubyHookCall((0, tree_sitter_helpers_1.getNodeText)(method, source)))
|
|
685
|
+
return [];
|
|
686
|
+
const sym = (0, tree_sitter_helpers_1.getNodeText)(node, source).replace(/^:/, '');
|
|
687
|
+
if (!/^[A-Za-z_][A-Za-z0-9_?!]*$/.test(sym))
|
|
688
|
+
return [];
|
|
689
|
+
return [{ name: `this.${sym}`, node }];
|
|
690
|
+
}
|
|
691
|
+
default:
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
/** Content of a PHP string literal node (single- or double-quoted). */
|
|
696
|
+
function phpStringContent(node, source) {
|
|
697
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
698
|
+
const child = node.namedChild(i);
|
|
699
|
+
if (child?.type === 'string_content')
|
|
700
|
+
return (0, tree_sitter_helpers_1.getNodeText)(child, source).trim();
|
|
701
|
+
}
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
/** The function name of the PHP call whose arguments contain `node`, if any. */
|
|
705
|
+
function phpEnclosingCallName(node) {
|
|
706
|
+
let cur = node.parent;
|
|
707
|
+
for (let hops = 0; cur && hops < 4; hops++, cur = cur.parent) {
|
|
708
|
+
if (cur.type === 'function_call_expression') {
|
|
709
|
+
const fn = (0, tree_sitter_helpers_1.getChildByField)(cur, 'function');
|
|
710
|
+
return fn ? fn.text : null;
|
|
711
|
+
}
|
|
712
|
+
if (cur.type === 'member_call_expression' || cur.type === 'scoped_call_expression') {
|
|
713
|
+
return null; // method calls aren't core HOFs
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return null;
|
|
717
|
+
}
|
|
718
|
+
/** The Ruby `call` node whose argument_list (or keyword pair) contains `node`. */
|
|
719
|
+
function rubyEnclosingCall(node) {
|
|
720
|
+
let cur = node.parent;
|
|
721
|
+
for (let hops = 0; cur && hops < 4; hops++, cur = cur.parent) {
|
|
722
|
+
if (cur.type === 'call')
|
|
723
|
+
return cur;
|
|
724
|
+
}
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
//# sourceMappingURL=function-ref.js.map
|