@lzehrung/codegraph 2.3.28 → 2.3.30
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/dist/bin/cli.js +7008 -4340
- package/dist/bin/query-index-worker.js +1357 -724
- package/dist/document-links/asciidoc.d.ts.map +1 -1
- package/dist/document-links/asciidoc.js +3 -4
- package/dist/document-links/asciidoc.js.map +1 -1
- package/dist/document-links/html-forms.d.ts +39 -0
- package/dist/document-links/html-forms.d.ts.map +1 -0
- package/dist/document-links/html-forms.js +94 -0
- package/dist/document-links/html-forms.js.map +1 -0
- package/dist/document-links/html.d.ts +8 -0
- package/dist/document-links/html.d.ts.map +1 -1
- package/dist/document-links/html.js +30 -15
- package/dist/document-links/html.js.map +1 -1
- package/dist/document-links/markdown.d.ts.map +1 -1
- package/dist/document-links/markdown.js +6 -7
- package/dist/document-links/markdown.js.map +1 -1
- package/dist/document-links/rst.d.ts.map +1 -1
- package/dist/document-links/rst.js +6 -0
- package/dist/document-links/rst.js.map +1 -1
- package/dist/document-links/sfc.d.ts.map +1 -1
- package/dist/document-links/sfc.js +4 -4
- package/dist/document-links/sfc.js.map +1 -1
- package/dist/graphs/angularjs.d.ts.map +1 -1
- package/dist/graphs/angularjs.js +9 -1
- package/dist/graphs/angularjs.js.map +1 -1
- package/dist/graphs/edge-resolution.d.ts.map +1 -1
- package/dist/graphs/edge-resolution.js +12 -2
- package/dist/graphs/edge-resolution.js.map +1 -1
- package/dist/graphs/specifiers.d.ts.map +1 -1
- package/dist/graphs/specifiers.js +62 -104
- package/dist/graphs/specifiers.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/ast.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/ast.js +3 -0
- package/dist/graphs/symbol-graph-detailed/ast.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/edge-passes.js +157 -91
- package/dist/graphs/symbol-graph-detailed/edge-passes.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts +34 -0
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js +531 -24
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js.map +1 -1
- package/dist/impact/analyzer.d.ts.map +1 -1
- package/dist/impact/analyzer.js +82 -4
- package/dist/impact/analyzer.js.map +1 -1
- package/dist/impact/call-compatibility/providers/index.d.ts +3 -1
- package/dist/impact/call-compatibility/providers/index.d.ts.map +1 -1
- package/dist/impact/call-compatibility/providers/index.js +11 -4
- package/dist/impact/call-compatibility/providers/index.js.map +1 -1
- package/dist/impact/call-compatibility.d.ts.map +1 -1
- package/dist/impact/call-compatibility.js +2 -7
- package/dist/impact/call-compatibility.js.map +1 -1
- package/dist/impact/map.d.ts.map +1 -1
- package/dist/impact/map.js +58 -1
- package/dist/impact/map.js.map +1 -1
- package/dist/impact/member-resolution-coverage.d.ts.map +1 -1
- package/dist/impact/member-resolution-coverage.js +2 -5
- package/dist/impact/member-resolution-coverage.js.map +1 -1
- package/dist/indexer/build-cache/manifest.d.ts +7 -0
- package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
- package/dist/indexer/build-cache/manifest.js +32 -1
- package/dist/indexer/build-cache/manifest.js.map +1 -1
- package/dist/indexer/build-cache/options.d.ts +20 -2
- package/dist/indexer/build-cache/options.d.ts.map +1 -1
- package/dist/indexer/build-cache/options.js +21 -3
- package/dist/indexer/build-cache/options.js.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.js +1 -0
- package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
- package/dist/indexer/build-index.d.ts.map +1 -1
- package/dist/indexer/build-index.js +80 -2
- package/dist/indexer/build-index.js.map +1 -1
- package/dist/indexer/build-manifest.d.ts +1 -0
- package/dist/indexer/build-manifest.d.ts.map +1 -1
- package/dist/indexer/build-manifest.js +18 -0
- package/dist/indexer/build-manifest.js.map +1 -1
- package/dist/indexer/build-workers.js +1 -1
- package/dist/indexer/build-workers.js.map +1 -1
- package/dist/indexer/declaration-visibility.d.ts +43 -0
- package/dist/indexer/declaration-visibility.d.ts.map +1 -0
- package/dist/indexer/declaration-visibility.js +202 -0
- package/dist/indexer/declaration-visibility.js.map +1 -0
- package/dist/indexer/imports/binding-ranges.d.ts +1 -1
- package/dist/indexer/imports/binding-ranges.d.ts.map +1 -1
- package/dist/indexer/imports/binding-ranges.js +2 -123
- package/dist/indexer/imports/binding-ranges.js.map +1 -1
- package/dist/indexer/imports/js-text-imports.d.ts.map +1 -1
- package/dist/indexer/imports/js-text-imports.js +5 -2
- package/dist/indexer/imports/js-text-imports.js.map +1 -1
- package/dist/indexer/imports/language-specific.d.ts.map +1 -1
- package/dist/indexer/imports/language-specific.js +58 -215
- package/dist/indexer/imports/language-specific.js.map +1 -1
- package/dist/indexer/imports/native-captures.d.ts.map +1 -1
- package/dist/indexer/imports/native-captures.js +23 -32
- package/dist/indexer/imports/native-captures.js.map +1 -1
- package/dist/indexer/imports/text-import-extractors.d.ts +37 -0
- package/dist/indexer/imports/text-import-extractors.d.ts.map +1 -0
- package/dist/indexer/imports/text-import-extractors.js +358 -0
- package/dist/indexer/imports/text-import-extractors.js.map +1 -0
- package/dist/indexer/locals-and-exports.d.ts.map +1 -1
- package/dist/indexer/locals-and-exports.js +26 -27
- package/dist/indexer/locals-and-exports.js.map +1 -1
- package/dist/indexer/navigation-goto.d.ts +1 -7
- package/dist/indexer/navigation-goto.d.ts.map +1 -1
- package/dist/indexer/navigation-goto.js +406 -276
- package/dist/indexer/navigation-goto.js.map +1 -1
- package/dist/indexer/navigation-resolve.d.ts.map +1 -1
- package/dist/indexer/navigation-resolve.js +20 -1
- package/dist/indexer/navigation-resolve.js.map +1 -1
- package/dist/indexer/navigation.d.ts.map +1 -1
- package/dist/indexer/navigation.js +49 -7
- package/dist/indexer/navigation.js.map +1 -1
- package/dist/indexer/parse-context.js +2 -2
- package/dist/indexer/parse-context.js.map +1 -1
- package/dist/indexer/scope-nodes.d.ts +108 -0
- package/dist/indexer/scope-nodes.d.ts.map +1 -0
- package/dist/indexer/scope-nodes.js +238 -0
- package/dist/indexer/scope-nodes.js.map +1 -0
- package/dist/indexer/scope.d.ts.map +1 -1
- package/dist/indexer/scope.js +70 -130
- package/dist/indexer/scope.js.map +1 -1
- package/dist/indexer/types.d.ts +7 -0
- package/dist/indexer/types.d.ts.map +1 -1
- package/dist/languages/definitions/c-family.d.ts +18 -4
- package/dist/languages/definitions/c-family.d.ts.map +1 -1
- package/dist/languages/definitions/c-family.js +51 -13
- package/dist/languages/definitions/c-family.js.map +1 -1
- package/dist/languages/definitions/c.d.ts.map +1 -1
- package/dist/languages/definitions/c.js +7 -43
- package/dist/languages/definitions/c.js.map +1 -1
- package/dist/languages/definitions/cpp.d.ts.map +1 -1
- package/dist/languages/definitions/cpp.js +34 -53
- package/dist/languages/definitions/cpp.js.map +1 -1
- package/dist/languages/definitions/csharp.d.ts.map +1 -1
- package/dist/languages/definitions/csharp.js +47 -53
- package/dist/languages/definitions/csharp.js.map +1 -1
- package/dist/languages/definitions/css-like.d.ts.map +1 -1
- package/dist/languages/definitions/css-like.js +13 -10
- package/dist/languages/definitions/css-like.js.map +1 -1
- package/dist/languages/definitions/go.d.ts.map +1 -1
- package/dist/languages/definitions/go.js +29 -42
- package/dist/languages/definitions/go.js.map +1 -1
- package/dist/languages/definitions/html.d.ts.map +1 -1
- package/dist/languages/definitions/html.js +15 -14
- package/dist/languages/definitions/html.js.map +1 -1
- package/dist/languages/definitions/java.d.ts.map +1 -1
- package/dist/languages/definitions/java.js +42 -48
- package/dist/languages/definitions/java.js.map +1 -1
- package/dist/languages/definitions/javascript.d.ts.map +1 -1
- package/dist/languages/definitions/javascript.js +26 -54
- package/dist/languages/definitions/javascript.js.map +1 -1
- package/dist/languages/definitions/js-family.d.ts +15 -1
- package/dist/languages/definitions/js-family.d.ts.map +1 -1
- package/dist/languages/definitions/js-family.js +51 -0
- package/dist/languages/definitions/js-family.js.map +1 -1
- package/dist/languages/definitions/kotlin.d.ts.map +1 -1
- package/dist/languages/definitions/kotlin.js +26 -43
- package/dist/languages/definitions/kotlin.js.map +1 -1
- package/dist/languages/definitions/php.d.ts.map +1 -1
- package/dist/languages/definitions/php.js +50 -60
- package/dist/languages/definitions/php.js.map +1 -1
- package/dist/languages/definitions/python.d.ts +5 -1
- package/dist/languages/definitions/python.d.ts.map +1 -1
- package/dist/languages/definitions/python.js +62 -14
- package/dist/languages/definitions/python.js.map +1 -1
- package/dist/languages/definitions/ruby.d.ts.map +1 -1
- package/dist/languages/definitions/ruby.js +14 -17
- package/dist/languages/definitions/ruby.js.map +1 -1
- package/dist/languages/definitions/rust.d.ts.map +1 -1
- package/dist/languages/definitions/rust.js +30 -52
- package/dist/languages/definitions/rust.js.map +1 -1
- package/dist/languages/definitions/scss.d.ts.map +1 -1
- package/dist/languages/definitions/scss.js +36 -30
- package/dist/languages/definitions/scss.js.map +1 -1
- package/dist/languages/definitions/sfc-graph.d.ts +4 -0
- package/dist/languages/definitions/sfc-graph.d.ts.map +1 -0
- package/dist/languages/definitions/sfc-graph.js +16 -0
- package/dist/languages/definitions/sfc-graph.js.map +1 -0
- package/dist/languages/definitions/shared.d.ts +33 -0
- package/dist/languages/definitions/shared.d.ts.map +1 -0
- package/dist/languages/definitions/shared.js +63 -0
- package/dist/languages/definitions/shared.js.map +1 -0
- package/dist/languages/definitions/sql.d.ts.map +1 -1
- package/dist/languages/definitions/sql.js +1 -0
- package/dist/languages/definitions/sql.js.map +1 -1
- package/dist/languages/definitions/svelte.d.ts.map +1 -1
- package/dist/languages/definitions/svelte.js +2 -10
- package/dist/languages/definitions/svelte.js.map +1 -1
- package/dist/languages/definitions/swift.d.ts.map +1 -1
- package/dist/languages/definitions/swift.js +37 -31
- package/dist/languages/definitions/swift.js.map +1 -1
- package/dist/languages/definitions/typescript.d.ts.map +1 -1
- package/dist/languages/definitions/typescript.js +65 -79
- package/dist/languages/definitions/typescript.js.map +1 -1
- package/dist/languages/definitions/vue.d.ts.map +1 -1
- package/dist/languages/definitions/vue.js +2 -10
- package/dist/languages/definitions/vue.js.map +1 -1
- package/dist/languages/definitions/zig.d.ts.map +1 -1
- package/dist/languages/definitions/zig.js +9 -15
- package/dist/languages/definitions/zig.js.map +1 -1
- package/dist/languages/graph-captures.d.ts +40 -0
- package/dist/languages/graph-captures.d.ts.map +1 -0
- package/dist/languages/graph-captures.js +46 -0
- package/dist/languages/graph-captures.js.map +1 -0
- package/dist/languages/import-statement-parsers.d.ts +17 -0
- package/dist/languages/import-statement-parsers.d.ts.map +1 -1
- package/dist/languages/import-statement-parsers.js +108 -0
- package/dist/languages/import-statement-parsers.js.map +1 -1
- package/dist/languages/js-family.d.ts +2 -0
- package/dist/languages/js-family.d.ts.map +1 -1
- package/dist/languages/js-family.js +15 -6
- package/dist/languages/js-family.js.map +1 -1
- package/dist/languages/types.d.ts +4 -0
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/types.js +1 -1
- package/dist/languages/types.js.map +1 -1
- package/dist/languages.js +1 -1
- package/dist/languages.js.map +1 -1
- package/dist/native/contracts.d.ts +1 -1
- package/dist/native/contracts.d.ts.map +1 -1
- package/dist/native/js-bridge.d.ts +10 -0
- package/dist/native/js-bridge.d.ts.map +1 -1
- package/dist/native/js-bridge.js +10 -0
- package/dist/native/js-bridge.js.map +1 -1
- package/dist/native/native-backend-report.d.ts.map +1 -1
- package/dist/native/native-backend-report.js +2 -0
- package/dist/native/native-backend-report.js.map +1 -1
- package/dist/sql/graph.d.ts +1 -1
- package/dist/sql/graph.d.ts.map +1 -1
- package/dist/sql/graph.js.map +1 -1
- package/dist/sql/lookup.d.ts +7 -0
- package/dist/sql/lookup.d.ts.map +1 -1
- package/dist/sql/lookup.js +17 -0
- package/dist/sql/lookup.js.map +1 -1
- package/dist/sql/source-graph.d.ts +2 -0
- package/dist/sql/source-graph.d.ts.map +1 -1
- package/dist/sql/source-graph.js +20 -1
- package/dist/sql/source-graph.js.map +1 -1
- package/dist/util/comments.d.ts +7 -7
- package/dist/util/comments.d.ts.map +1 -1
- package/dist/util/comments.js +15 -214
- package/dist/util/comments.js.map +1 -1
- package/dist/util/lines.d.ts.map +1 -1
- package/dist/util/lines.js +4 -1
- package/dist/util/lines.js.map +1 -1
- package/dist/util/member-access.d.ts +2 -0
- package/dist/util/member-access.d.ts.map +1 -1
- package/dist/util/member-access.js +18 -5
- package/dist/util/member-access.js.map +1 -1
- package/dist/util/paths.d.ts +4 -0
- package/dist/util/paths.d.ts.map +1 -1
- package/dist/util/paths.js +26 -0
- package/dist/util/paths.js.map +1 -1
- package/dist/util/project-files.js +1 -1
- package/dist/util/project-files.js.map +1 -1
- package/dist/util/resolution/cargo-targets.d.ts.map +1 -1
- package/dist/util/resolution/cargo-targets.js +17 -14
- package/dist/util/resolution/cargo-targets.js.map +1 -1
- package/dist/util/resolution/cpp.d.ts +6 -0
- package/dist/util/resolution/cpp.d.ts.map +1 -0
- package/dist/util/resolution/cpp.js +69 -0
- package/dist/util/resolution/cpp.js.map +1 -0
- package/dist/util/resolution/csharp.d.ts +8 -0
- package/dist/util/resolution/csharp.d.ts.map +1 -0
- package/dist/util/resolution/csharp.js +103 -0
- package/dist/util/resolution/csharp.js.map +1 -0
- package/dist/util/resolution/files.d.ts +6 -0
- package/dist/util/resolution/files.d.ts.map +1 -1
- package/dist/util/resolution/files.js +108 -4
- package/dist/util/resolution/files.js.map +1 -1
- package/dist/util/resolution/go.d.ts +1 -0
- package/dist/util/resolution/go.d.ts.map +1 -1
- package/dist/util/resolution/go.js +4 -3
- package/dist/util/resolution/go.js.map +1 -1
- package/dist/util/resolution/jvm.d.ts +3 -3
- package/dist/util/resolution/jvm.d.ts.map +1 -1
- package/dist/util/resolution/jvm.js +90 -54
- package/dist/util/resolution/jvm.js.map +1 -1
- package/dist/util/resolution/node.js +2 -2
- package/dist/util/resolution/node.js.map +1 -1
- package/dist/util/resolution/php-composer.d.ts.map +1 -1
- package/dist/util/resolution/php-composer.js +8 -7
- package/dist/util/resolution/php-composer.js.map +1 -1
- package/dist/util/resolution/php.d.ts.map +1 -1
- package/dist/util/resolution/php.js +30 -43
- package/dist/util/resolution/php.js.map +1 -1
- package/dist/util/resolution/project-symbols.d.ts +5 -7
- package/dist/util/resolution/project-symbols.d.ts.map +1 -1
- package/dist/util/resolution/project-symbols.js +23 -9
- package/dist/util/resolution/project-symbols.js.map +1 -1
- package/dist/util/resolution/python.d.ts.map +1 -1
- package/dist/util/resolution/python.js +107 -62
- package/dist/util/resolution/python.js.map +1 -1
- package/dist/util/resolution/rust.d.ts.map +1 -1
- package/dist/util/resolution/rust.js +45 -34
- package/dist/util/resolution/rust.js.map +1 -1
- package/dist/util/resolution/tsconfig.d.ts.map +1 -1
- package/dist/util/resolution/tsconfig.js +3 -9
- package/dist/util/resolution/tsconfig.js.map +1 -1
- package/dist/util/resolution-candidates.d.ts +5 -1
- package/dist/util/resolution-candidates.d.ts.map +1 -1
- package/dist/util/resolution-candidates.js +18 -0
- package/dist/util/resolution-candidates.js.map +1 -1
- package/dist/util/resolution.d.ts.map +1 -1
- package/dist/util/resolution.js +95 -49
- package/dist/util/resolution.js.map +1 -1
- package/dist/util/specifiers.d.ts +4 -10
- package/dist/util/specifiers.d.ts.map +1 -1
- package/dist/util/specifiers.js +213 -164
- package/dist/util/specifiers.js.map +1 -1
- package/dist/util/trivia-tables.d.ts +69 -0
- package/dist/util/trivia-tables.d.ts.map +1 -0
- package/dist/util/trivia-tables.js +186 -0
- package/dist/util/trivia-tables.js.map +1 -0
- package/dist/util/trivia.d.ts +24 -0
- package/dist/util/trivia.d.ts.map +1 -0
- package/dist/util/trivia.js +621 -0
- package/dist/util/trivia.js.map +1 -0
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -1
- package/dist/util.js.map +1 -1
- package/dist/worker/native-extract-worker.d.ts.map +1 -1
- package/dist/worker/native-extract-worker.js +4 -4
- package/dist/worker/native-extract-worker.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
2
|
import { SymbolKind } from "../../indexer/types.js";
|
|
3
3
|
import { sliceText } from "../../util/ast.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { XID_IDENTIFIER_SOURCE } from "../../util/identifiers.js";
|
|
5
|
+
import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isMemberReferencePropertyIdentifier, isReceiverNameNode, } from "../../util/member-access.js";
|
|
6
6
|
const THIS_SUPER_RECEIVERS = { own: ["this"], supertype: ["super"] };
|
|
7
7
|
const SELF_RECEIVERS = { own: ["self"], supertype: ["super"] };
|
|
8
8
|
const RECEIVER_KEYWORDS = {
|
|
9
9
|
cpp: { own: ["this"], supertype: [] },
|
|
10
10
|
csharp: { own: ["this"], supertype: ["base"] },
|
|
11
|
+
go: { own: [], supertype: [] },
|
|
11
12
|
java: THIS_SUPER_RECEIVERS,
|
|
12
13
|
js: THIS_SUPER_RECEIVERS,
|
|
13
14
|
kotlin: THIS_SUPER_RECEIVERS,
|
|
@@ -15,12 +16,44 @@ const RECEIVER_KEYWORDS = {
|
|
|
15
16
|
python: { own: ["self", "cls"], supertype: [] },
|
|
16
17
|
ruby: { own: ["self"], supertype: [] },
|
|
17
18
|
rust: { own: ["self", "Self"], supertype: [] },
|
|
18
|
-
svelte: THIS_SUPER_RECEIVERS,
|
|
19
19
|
swift: SELF_RECEIVERS,
|
|
20
20
|
ts: THIS_SUPER_RECEIVERS,
|
|
21
21
|
tsx: THIS_SUPER_RECEIVERS,
|
|
22
22
|
zig: { own: ["self"], supertype: [] },
|
|
23
23
|
};
|
|
24
|
+
const INSTANCE_RECEIVER_KEYWORDS = new Set(["this", "$this"]);
|
|
25
|
+
/** Every language that declares receiver keywords, guarded by the registry-consistency test. */
|
|
26
|
+
export const receiverKeywordLanguageIds = Object.keys(RECEIVER_KEYWORDS);
|
|
27
|
+
/** Languages whose grammar distinguishes static members from instance members. */
|
|
28
|
+
const STATIC_MEMBER_LANGUAGES = {
|
|
29
|
+
cpp: true,
|
|
30
|
+
csharp: true,
|
|
31
|
+
java: true,
|
|
32
|
+
js: true,
|
|
33
|
+
php: true,
|
|
34
|
+
swift: true,
|
|
35
|
+
ts: true,
|
|
36
|
+
tsx: true,
|
|
37
|
+
};
|
|
38
|
+
/** Every language with a static-member distinction, guarded by the registry-consistency test. */
|
|
39
|
+
export const staticMemberLanguageIds = Object.keys(STATIC_MEMBER_LANGUAGES);
|
|
40
|
+
/** Languages that emit proven receiver `calls` edges from the shared keyword table. */
|
|
41
|
+
export function supportsReceiverCallEdges(languageId) {
|
|
42
|
+
return RECEIVER_KEYWORDS[languageId] !== undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Languages where goto and references require proven receivers and do not fall back to a bare name. */
|
|
45
|
+
export function supportsReceiverMemberNavigation(languageId) {
|
|
46
|
+
return RECEIVER_KEYWORDS[languageId] !== undefined;
|
|
47
|
+
}
|
|
48
|
+
export function isKeywordReceiver(languageId, receiverName) {
|
|
49
|
+
const keywords = RECEIVER_KEYWORDS[languageId];
|
|
50
|
+
if (!keywords)
|
|
51
|
+
return false;
|
|
52
|
+
return keywords.own.includes(receiverName) || keywords.supertype.includes(receiverName);
|
|
53
|
+
}
|
|
54
|
+
export function hasStaticMemberDistinction(languageId) {
|
|
55
|
+
return STATIC_MEMBER_LANGUAGES[languageId] !== undefined;
|
|
56
|
+
}
|
|
24
57
|
/**
|
|
25
58
|
* Call nodes that carry the receiver and the member name on the call node itself
|
|
26
59
|
* instead of exposing a member-access callee.
|
|
@@ -39,7 +72,6 @@ const MEMBER_CONTAINER_TYPES = {
|
|
|
39
72
|
class_definition: true,
|
|
40
73
|
class_specifier: true,
|
|
41
74
|
enum_declaration: true,
|
|
42
|
-
extension_declaration: true,
|
|
43
75
|
impl_item: true,
|
|
44
76
|
interface_declaration: true,
|
|
45
77
|
module: true,
|
|
@@ -87,14 +119,20 @@ const VALUE_BINDING_TYPES = {
|
|
|
87
119
|
short_var_declaration: true,
|
|
88
120
|
simple_parameter: true,
|
|
89
121
|
typed_parameter: true,
|
|
122
|
+
var_spec: true,
|
|
90
123
|
variable_declaration: true,
|
|
91
124
|
variable_declarator: true,
|
|
92
125
|
};
|
|
93
|
-
/**
|
|
94
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Parameter lists whose identifier children are value bindings (Ruby has no wrapping param node).
|
|
128
|
+
* Union of the receiver-call and call-compatibility lists so Kotlin `function_value_parameters`
|
|
129
|
+
* and Ruby `block_parameters` are both recognized.
|
|
130
|
+
*/
|
|
131
|
+
export const PARAMETER_LIST_NODE_TYPES = {
|
|
95
132
|
block_parameters: true,
|
|
96
133
|
formal_parameters: true,
|
|
97
134
|
function_parameter_clause: true,
|
|
135
|
+
function_value_parameters: true,
|
|
98
136
|
lambda_parameters: true,
|
|
99
137
|
method_parameters: true,
|
|
100
138
|
parameter_list: true,
|
|
@@ -135,6 +173,65 @@ const BINDING_SCOPE_TYPES = {
|
|
|
135
173
|
impl_item: true,
|
|
136
174
|
translation_unit: true,
|
|
137
175
|
};
|
|
176
|
+
const BINDING_CONTAINER_TYPES = new Set([
|
|
177
|
+
"program",
|
|
178
|
+
"compilation_unit",
|
|
179
|
+
"source_file",
|
|
180
|
+
"translation_unit",
|
|
181
|
+
"statement_block",
|
|
182
|
+
"block",
|
|
183
|
+
"compound_statement",
|
|
184
|
+
"function_body",
|
|
185
|
+
"body_statement",
|
|
186
|
+
"function_declaration",
|
|
187
|
+
"function_item",
|
|
188
|
+
"function_definition",
|
|
189
|
+
"function",
|
|
190
|
+
"function_expression",
|
|
191
|
+
"arrow_function",
|
|
192
|
+
"method_definition",
|
|
193
|
+
"method_declaration",
|
|
194
|
+
"method",
|
|
195
|
+
"impl_item",
|
|
196
|
+
]);
|
|
197
|
+
const BINDING_DECLARATION_TYPES = new Set([
|
|
198
|
+
"variable_declarator",
|
|
199
|
+
"variable_declaration",
|
|
200
|
+
"let_declaration",
|
|
201
|
+
"assignment",
|
|
202
|
+
"assignment_expression",
|
|
203
|
+
"assignment_statement",
|
|
204
|
+
"formal_parameter",
|
|
205
|
+
"required_parameter",
|
|
206
|
+
"optional_parameter",
|
|
207
|
+
"simple_parameter",
|
|
208
|
+
"parameter",
|
|
209
|
+
"parameter_declaration",
|
|
210
|
+
"typed_parameter",
|
|
211
|
+
"short_var_declaration",
|
|
212
|
+
"var_spec",
|
|
213
|
+
"property_declaration",
|
|
214
|
+
"local_variable_declaration",
|
|
215
|
+
"local_declaration_statement",
|
|
216
|
+
]);
|
|
217
|
+
const RUBY_CONSTANT_SOURCE = String.raw `(?=\p{Lu})${XID_IDENTIFIER_SOURCE}`;
|
|
218
|
+
/** Proven construction forms that name a receiver's type, keyed by language. */
|
|
219
|
+
const LANGUAGE_CONSTRUCTION_FORMS = {
|
|
220
|
+
cpp: { newExpression: true },
|
|
221
|
+
csharp: { newExpression: true },
|
|
222
|
+
go: { compositeLiteral: true },
|
|
223
|
+
java: { newExpression: true },
|
|
224
|
+
js: { newExpression: true },
|
|
225
|
+
kotlin: { capitalizedCall: true },
|
|
226
|
+
php: { newExpression: true },
|
|
227
|
+
python: { capitalizedCall: true },
|
|
228
|
+
ruby: { rubyNew: true },
|
|
229
|
+
rust: { capitalizedCall: true, rustUnitStruct: true },
|
|
230
|
+
swift: { capitalizedCall: true },
|
|
231
|
+
ts: { newExpression: true },
|
|
232
|
+
tsx: { newExpression: true },
|
|
233
|
+
zig: { compositeLiteral: true },
|
|
234
|
+
};
|
|
138
235
|
/** Guards against a cyclic or pathological declared hierarchy. */
|
|
139
236
|
const MAX_SUPERTYPE_DEPTH = 16;
|
|
140
237
|
/**
|
|
@@ -179,19 +276,24 @@ export function receiverCallAccess(sup, callNode, callee) {
|
|
|
179
276
|
*/
|
|
180
277
|
function bindingIdentifier(node, sup) {
|
|
181
278
|
const named = node.childForFieldName("name");
|
|
182
|
-
if (named &&
|
|
183
|
-
(isIdentifierType(sup, named.type) || named.type === "identifier" || named.type === "field_identifier")) {
|
|
279
|
+
if (named && (isReceiverNameNode(sup, named.type) || named.type === "field_identifier")) {
|
|
184
280
|
return named;
|
|
185
281
|
}
|
|
186
|
-
if (node.type === "assignment" ||
|
|
282
|
+
if (node.type === "assignment" ||
|
|
283
|
+
node.type === "assignment_expression" ||
|
|
284
|
+
node.type === "assignment_statement" ||
|
|
285
|
+
node.type === "short_var_declaration") {
|
|
187
286
|
const left = node.childForFieldName("left") ?? node.child(0);
|
|
188
|
-
if (left && (
|
|
287
|
+
if (left && isReceiverNameNode(sup, left.type))
|
|
189
288
|
return left;
|
|
289
|
+
if (left?.type === "expression_list" || left?.type === "pattern") {
|
|
290
|
+
return left.namedChildren.find((child) => isReceiverNameNode(sup, child.type)) ?? null;
|
|
291
|
+
}
|
|
190
292
|
return null;
|
|
191
293
|
}
|
|
192
294
|
let current = node.childForFieldName("declarator");
|
|
193
295
|
while (current) {
|
|
194
|
-
if (current.type
|
|
296
|
+
if (isReceiverNameNode(sup, current.type) || current.type === "field_identifier") {
|
|
195
297
|
return current;
|
|
196
298
|
}
|
|
197
299
|
const nested = current.childForFieldName("declarator");
|
|
@@ -201,8 +303,15 @@ function bindingIdentifier(node, sup) {
|
|
|
201
303
|
}
|
|
202
304
|
return (current.namedChildren.find((child) => child.type === "identifier" || child.type === "field_identifier") ?? null);
|
|
203
305
|
}
|
|
204
|
-
const identifiers = node.namedChildren.filter((child) => child.type
|
|
205
|
-
|
|
306
|
+
const identifiers = node.namedChildren.filter((child) => isReceiverNameNode(sup, child.type) || child.type === "field_identifier");
|
|
307
|
+
if (identifiers.length === 0)
|
|
308
|
+
return null;
|
|
309
|
+
// `let name = Type;` / `var name = Type{}` put the binding first and the type second.
|
|
310
|
+
// C++ parameters keep the name last, after the type.
|
|
311
|
+
if (node.type === "let_declaration" || node.type === "variable_declaration" || node.type === "variable_declarator") {
|
|
312
|
+
return identifiers[0];
|
|
313
|
+
}
|
|
314
|
+
return identifiers[identifiers.length - 1];
|
|
206
315
|
}
|
|
207
316
|
/**
|
|
208
317
|
* Whether a scope encloses `receiver` and binds `receiverName` as a value before it.
|
|
@@ -215,7 +324,7 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
215
324
|
return false;
|
|
216
325
|
if (node !== receiver && BINDING_SCOPE_TYPES[node.type] && !containsIndex(node, receiver.startIndex))
|
|
217
326
|
return false;
|
|
218
|
-
if (
|
|
327
|
+
if (PARAMETER_LIST_NODE_TYPES[node.type]) {
|
|
219
328
|
for (const child of node.namedChildren) {
|
|
220
329
|
if (child.startIndex >= receiver.startIndex)
|
|
221
330
|
continue;
|
|
@@ -223,7 +332,7 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
223
332
|
// name in ERROR. Treat recovered parameter names as value bindings.
|
|
224
333
|
const names = child.type === "ERROR" ? child.namedChildren : [child];
|
|
225
334
|
for (const name of names) {
|
|
226
|
-
if ((
|
|
335
|
+
if ((isReceiverNameNode(sup, name.type) || name.type === "identifier" || name.type === "constant") &&
|
|
227
336
|
sliceText(name, source) === receiverName) {
|
|
228
337
|
return true;
|
|
229
338
|
}
|
|
@@ -246,6 +355,326 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
246
355
|
function containsIndex(node, index) {
|
|
247
356
|
return node.startIndex <= index && node.endIndex >= index;
|
|
248
357
|
}
|
|
358
|
+
function constructorNameNode(node, sup) {
|
|
359
|
+
const constructor = node.childForFieldName("constructor") ?? node.child(0);
|
|
360
|
+
if (constructor && isReceiverNameNode(sup, constructor.type)) {
|
|
361
|
+
return constructor;
|
|
362
|
+
}
|
|
363
|
+
for (const child of node.namedChildren) {
|
|
364
|
+
if (isReceiverNameNode(sup, child.type) || child.type === "type_identifier" || child.type === "constant") {
|
|
365
|
+
return child;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
function rubyNewReceiverNameNode(node, source, sup) {
|
|
371
|
+
if (!new RegExp(String.raw `^(?:${RUBY_CONSTANT_SOURCE})\.new$`, "u").test(sliceText(node, source)))
|
|
372
|
+
return null;
|
|
373
|
+
return node.namedChildren.find((child) => isReceiverNameNode(sup, child.type) || child.type === "constant") ?? null;
|
|
374
|
+
}
|
|
375
|
+
export function unwrapNamedType(node, sup) {
|
|
376
|
+
let current = node;
|
|
377
|
+
while (current) {
|
|
378
|
+
if (current.type === "type_annotation" ||
|
|
379
|
+
current.type === "named_type" ||
|
|
380
|
+
current.type === "user_type" ||
|
|
381
|
+
current.type === "type" ||
|
|
382
|
+
current.type === "parenthesized_type" ||
|
|
383
|
+
current.type === "pointer_type" ||
|
|
384
|
+
current.type === "reference_type" ||
|
|
385
|
+
current.type === "optional_type" ||
|
|
386
|
+
current.type === "nullable_type") {
|
|
387
|
+
current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (current.type === "generic_type" || current.type === "generic_name") {
|
|
391
|
+
current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
if (!current)
|
|
397
|
+
return null;
|
|
398
|
+
if (isReceiverNameNode(sup, current.type) || current.type === "type_identifier" || current.type === "name") {
|
|
399
|
+
return current;
|
|
400
|
+
}
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
function capitalizedCallTypeName(expr, source, sup) {
|
|
404
|
+
if (expr.type !== "call" && expr.type !== "call_expression")
|
|
405
|
+
return null;
|
|
406
|
+
const callee = expr.childForFieldName("function") ?? expr.namedChildren[0] ?? null;
|
|
407
|
+
if (!callee || !isReceiverNameNode(sup, callee.type))
|
|
408
|
+
return null;
|
|
409
|
+
const name = sliceText(callee, source);
|
|
410
|
+
if (!name)
|
|
411
|
+
return null;
|
|
412
|
+
const first = name[0];
|
|
413
|
+
if (first !== first.toUpperCase())
|
|
414
|
+
return null;
|
|
415
|
+
return callee;
|
|
416
|
+
}
|
|
417
|
+
function compositeLiteralTypeName(expr, source, sup) {
|
|
418
|
+
let current = expr;
|
|
419
|
+
if (current.type === "unary_expression") {
|
|
420
|
+
const operand = current.childForFieldName("operand");
|
|
421
|
+
if (!operand)
|
|
422
|
+
return null;
|
|
423
|
+
const operator = current.childForFieldName("operator");
|
|
424
|
+
let isAddr = sliceText(current, source).startsWith("&");
|
|
425
|
+
if (operator)
|
|
426
|
+
isAddr = sliceText(operator, source) === "&";
|
|
427
|
+
if (!isAddr)
|
|
428
|
+
return null;
|
|
429
|
+
current = operand;
|
|
430
|
+
}
|
|
431
|
+
if (current.type !== "composite_literal" && current.type !== "struct_initializer")
|
|
432
|
+
return null;
|
|
433
|
+
const typeNode = current.childForFieldName("type") ??
|
|
434
|
+
current.namedChildren.find((child) => child.type === "type_identifier" || child.type === "identifier") ??
|
|
435
|
+
null;
|
|
436
|
+
return typeNode ? (unwrapNamedType(typeNode, sup) ?? typeNode) : null;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Resolves the node naming the type a construction expression denotes, or null
|
|
440
|
+
* when the expression is not a proven constructor form.
|
|
441
|
+
*/
|
|
442
|
+
export function constructionTypeName(expr, source, sup) {
|
|
443
|
+
const forms = LANGUAGE_CONSTRUCTION_FORMS[sup.id];
|
|
444
|
+
if (!forms)
|
|
445
|
+
return null;
|
|
446
|
+
if (forms.newExpression && (expr.type === "new_expression" || expr.type === "object_creation_expression")) {
|
|
447
|
+
return constructorNameNode(expr, sup);
|
|
448
|
+
}
|
|
449
|
+
if (forms.rubyNew && expr.type === "call") {
|
|
450
|
+
const rubyConstructor = rubyNewReceiverNameNode(expr, source, sup);
|
|
451
|
+
if (rubyConstructor)
|
|
452
|
+
return rubyConstructor;
|
|
453
|
+
}
|
|
454
|
+
if (forms.compositeLiteral) {
|
|
455
|
+
const composite = compositeLiteralTypeName(expr, source, sup);
|
|
456
|
+
if (composite)
|
|
457
|
+
return composite;
|
|
458
|
+
}
|
|
459
|
+
if (forms.capitalizedCall) {
|
|
460
|
+
const fromCall = capitalizedCallTypeName(expr, source, sup);
|
|
461
|
+
if (fromCall)
|
|
462
|
+
return fromCall;
|
|
463
|
+
}
|
|
464
|
+
// Rust unit structs are constructed by the type name itself: `let service = Service;`.
|
|
465
|
+
if (forms.rustUnitStruct && isReceiverNameNode(sup, expr.type)) {
|
|
466
|
+
const name = sliceText(expr, source);
|
|
467
|
+
const first = name[0];
|
|
468
|
+
if (first && first === first.toUpperCase() && first !== first.toLowerCase())
|
|
469
|
+
return expr;
|
|
470
|
+
}
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
function bindingValueExpression(node) {
|
|
474
|
+
const named = node.childForFieldName("value") ?? node.childForFieldName("right") ?? node.childForFieldName("default_value");
|
|
475
|
+
if (named) {
|
|
476
|
+
if (named.type === "expression_list")
|
|
477
|
+
return named.namedChildren[0] ?? null;
|
|
478
|
+
return named;
|
|
479
|
+
}
|
|
480
|
+
const expressionTypes = new Set([
|
|
481
|
+
"new_expression",
|
|
482
|
+
"object_creation_expression",
|
|
483
|
+
"call",
|
|
484
|
+
"call_expression",
|
|
485
|
+
"composite_literal",
|
|
486
|
+
"struct_initializer",
|
|
487
|
+
"unary_expression",
|
|
488
|
+
]);
|
|
489
|
+
return node.namedChildren.find((child) => expressionTypes.has(child.type)) ?? null;
|
|
490
|
+
}
|
|
491
|
+
function declaredTypeNameNode(node, sup) {
|
|
492
|
+
const typeField = node.childForFieldName("type");
|
|
493
|
+
if (typeField)
|
|
494
|
+
return unwrapNamedType(typeField, sup);
|
|
495
|
+
const typedChild = node.namedChildren.find((child) => child.type === "named_type" ||
|
|
496
|
+
child.type === "user_type" ||
|
|
497
|
+
child.type === "type_annotation" ||
|
|
498
|
+
child.type === "type");
|
|
499
|
+
if (typedChild)
|
|
500
|
+
return unwrapNamedType(typedChild, sup);
|
|
501
|
+
const ids = node.namedChildren.filter((child) => isReceiverNameNode(sup, child.type) || child.type === "type_identifier" || child.type === "name");
|
|
502
|
+
if (ids.length >= 2)
|
|
503
|
+
return unwrapNamedType(ids[0], sup);
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
function goBindingNameNodes(node) {
|
|
507
|
+
if (node.type === "short_var_declaration") {
|
|
508
|
+
const left = node.childForFieldName("left");
|
|
509
|
+
return (left?.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
510
|
+
}
|
|
511
|
+
if (node.type === "var_spec") {
|
|
512
|
+
return (node.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
513
|
+
}
|
|
514
|
+
return [];
|
|
515
|
+
}
|
|
516
|
+
function bindingDeclaresReceiverName(node, receiverName, source, sup) {
|
|
517
|
+
if (sup.id === "go") {
|
|
518
|
+
const goNames = goBindingNameNodes(node);
|
|
519
|
+
if (goNames.some((name) => sliceText(name, source) === receiverName))
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
const name = bindingIdentifier(node, sup);
|
|
523
|
+
if (name && sliceText(name, source) === receiverName)
|
|
524
|
+
return true;
|
|
525
|
+
if (node.type === "property_declaration") {
|
|
526
|
+
return node.namedChildren.some((child) => {
|
|
527
|
+
if (child.type === "variable_declaration" || child.type === "pattern") {
|
|
528
|
+
return child.namedChildren.some((inner) => isReceiverNameNode(sup, inner.type) && sliceText(inner, source) === receiverName);
|
|
529
|
+
}
|
|
530
|
+
return isReceiverNameNode(sup, child.type) && sliceText(child, source) === receiverName;
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
function constructionTypeFromBinding(node, receiverName, source, sup) {
|
|
536
|
+
if (sup.id === "go" && (node.type === "short_var_declaration" || node.type === "var_spec")) {
|
|
537
|
+
return constructorFromGoBinding(node, receiverName, source, sup) ?? declaredTypeNameNode(node, sup);
|
|
538
|
+
}
|
|
539
|
+
const value = bindingValueExpression(node);
|
|
540
|
+
if (value) {
|
|
541
|
+
const fromValue = constructionTypeName(value, source, sup);
|
|
542
|
+
if (fromValue)
|
|
543
|
+
return fromValue;
|
|
544
|
+
}
|
|
545
|
+
return declaredTypeNameNode(node, sup);
|
|
546
|
+
}
|
|
547
|
+
function constructorFromGoBinding(node, receiverName, source, sup) {
|
|
548
|
+
if (node.type === "short_var_declaration") {
|
|
549
|
+
const left = node.childForFieldName("left");
|
|
550
|
+
const right = node.childForFieldName("right");
|
|
551
|
+
if (!left || !right)
|
|
552
|
+
return null;
|
|
553
|
+
const names = (left.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
554
|
+
const values = right.namedChildren ?? [];
|
|
555
|
+
const index = names.findIndex((name) => sliceText(name, source) === receiverName);
|
|
556
|
+
if (index < 0)
|
|
557
|
+
return null;
|
|
558
|
+
const value = values[index] ?? null;
|
|
559
|
+
return value ? constructionTypeName(value, source, sup) : null;
|
|
560
|
+
}
|
|
561
|
+
if (node.type !== "var_spec")
|
|
562
|
+
return null;
|
|
563
|
+
const value = node.childForFieldName("value");
|
|
564
|
+
if (value) {
|
|
565
|
+
const first = value.type === "expression_list" ? (value.namedChildren[0] ?? null) : value;
|
|
566
|
+
const fromValue = first ? constructionTypeName(first, source, sup) : null;
|
|
567
|
+
if (fromValue)
|
|
568
|
+
return fromValue;
|
|
569
|
+
}
|
|
570
|
+
const typeNode = node.childForFieldName("type");
|
|
571
|
+
return typeNode ? unwrapNamedType(typeNode, sup) : null;
|
|
572
|
+
}
|
|
573
|
+
function bindingProof(node, receiverName, source, sup) {
|
|
574
|
+
if (!BINDING_DECLARATION_TYPES.has(node.type))
|
|
575
|
+
return { status: "none" };
|
|
576
|
+
if (!bindingDeclaresReceiverName(node, receiverName, source, sup))
|
|
577
|
+
return { status: "none" };
|
|
578
|
+
const typeNode = constructionTypeFromBinding(node, receiverName, source, sup);
|
|
579
|
+
if (typeNode)
|
|
580
|
+
return { status: "type", node: typeNode };
|
|
581
|
+
return { status: "unproven" };
|
|
582
|
+
}
|
|
583
|
+
function isSkippableBindingContainer(node, receiver) {
|
|
584
|
+
return BINDING_CONTAINER_TYPES.has(node.type) && !containsIndex(node, receiver.startIndex);
|
|
585
|
+
}
|
|
586
|
+
function findPriorConstructorInContainer(node, receiver, receiverName, source, sup) {
|
|
587
|
+
let constructor = null;
|
|
588
|
+
let sawUnproven = false;
|
|
589
|
+
const visit = (current) => {
|
|
590
|
+
if (current.startIndex >= receiver.startIndex)
|
|
591
|
+
return true;
|
|
592
|
+
if (current !== node && isSkippableBindingContainer(current, receiver))
|
|
593
|
+
return true;
|
|
594
|
+
const proof = bindingProof(current, receiverName, source, sup);
|
|
595
|
+
if (proof.status === "unproven") {
|
|
596
|
+
if (constructor) {
|
|
597
|
+
constructor = null;
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
sawUnproven = true;
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
if (proof.status === "type") {
|
|
604
|
+
if (sawUnproven) {
|
|
605
|
+
constructor = null;
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
if (constructor && sliceText(constructor, source) !== sliceText(proof.node, source)) {
|
|
609
|
+
constructor = null;
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
constructor = proof.node;
|
|
613
|
+
return true;
|
|
614
|
+
}
|
|
615
|
+
for (const child of current.namedChildren) {
|
|
616
|
+
if (!visit(child))
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
return true;
|
|
620
|
+
};
|
|
621
|
+
visit(node);
|
|
622
|
+
return constructor;
|
|
623
|
+
}
|
|
624
|
+
function bindingContainerDeclaresNameBefore(node, receiver, receiverName, source, sup) {
|
|
625
|
+
const visit = (current) => {
|
|
626
|
+
if (current.startIndex >= receiver.startIndex)
|
|
627
|
+
return false;
|
|
628
|
+
if (current !== node && isSkippableBindingContainer(current, receiver))
|
|
629
|
+
return false;
|
|
630
|
+
if (BINDING_DECLARATION_TYPES.has(current.type) &&
|
|
631
|
+
bindingDeclaresReceiverName(current, receiverName, source, sup)) {
|
|
632
|
+
return true;
|
|
633
|
+
}
|
|
634
|
+
for (const child of current.namedChildren) {
|
|
635
|
+
if (visit(child))
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
};
|
|
640
|
+
return visit(node);
|
|
641
|
+
}
|
|
642
|
+
function rootOf(node) {
|
|
643
|
+
let current = node;
|
|
644
|
+
while (current.parent)
|
|
645
|
+
current = current.parent;
|
|
646
|
+
return current;
|
|
647
|
+
}
|
|
648
|
+
function findVisiblePriorConstructor(receiver, receiverName, source, sup) {
|
|
649
|
+
let current = receiver;
|
|
650
|
+
while (current) {
|
|
651
|
+
if (BINDING_CONTAINER_TYPES.has(current.type)) {
|
|
652
|
+
const constructor = findPriorConstructorInContainer(current, receiver, receiverName, source, sup);
|
|
653
|
+
if (constructor || bindingContainerDeclaresNameBefore(current, receiver, receiverName, source, sup)) {
|
|
654
|
+
return constructor;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
current = current.parent;
|
|
658
|
+
}
|
|
659
|
+
return findPriorConstructorInContainer(rootOf(receiver), receiver, receiverName, source, sup);
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Resolves the node naming the type a receiver expression was constructed from, or
|
|
663
|
+
* null when no constructor is proven for it. Shared with detailed symbol-graph call
|
|
664
|
+
* extraction so `goto` and resolved `calls` edges accept the same receiver forms.
|
|
665
|
+
*/
|
|
666
|
+
export function receiverConstructorExpression(obj, source, sup) {
|
|
667
|
+
const direct = constructionTypeName(obj, source, sup);
|
|
668
|
+
if (direct)
|
|
669
|
+
return direct;
|
|
670
|
+
if (!isReceiverNameNode(sup, obj.type))
|
|
671
|
+
return null;
|
|
672
|
+
const receiverName = sliceText(obj, source);
|
|
673
|
+
return findVisiblePriorConstructor(obj, receiverName, source, sup);
|
|
674
|
+
}
|
|
675
|
+
function ownTypeMemberScope(receiverName) {
|
|
676
|
+
return INSTANCE_RECEIVER_KEYWORDS.has(receiverName) ? "instance" : "any";
|
|
677
|
+
}
|
|
249
678
|
/**
|
|
250
679
|
* Classifies a receiver as the declaring type, a supertype, or a named/constructed type.
|
|
251
680
|
* Returns null when the receiver cannot be proven.
|
|
@@ -257,10 +686,10 @@ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope,
|
|
|
257
686
|
if (!text)
|
|
258
687
|
return null;
|
|
259
688
|
if (keywords?.own.includes(text))
|
|
260
|
-
return { kind: "own-type" };
|
|
689
|
+
return { kind: "own-type", memberScope: ownTypeMemberScope(text) };
|
|
261
690
|
if (keywords?.supertype.includes(text))
|
|
262
|
-
return { kind: "supertype" };
|
|
263
|
-
const receiverIsName =
|
|
691
|
+
return { kind: "supertype", memberScope: "any" };
|
|
692
|
+
const receiverIsName = isReceiverNameNode(sup, receiver.type);
|
|
264
693
|
const cacheKey = `${cacheScope}\u0000${text}`;
|
|
265
694
|
let proof = proofCache.get(cacheKey);
|
|
266
695
|
if (!proof) {
|
|
@@ -271,8 +700,13 @@ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope,
|
|
|
271
700
|
};
|
|
272
701
|
proofCache.set(cacheKey, proof);
|
|
273
702
|
}
|
|
274
|
-
if (proof.constructed)
|
|
275
|
-
return {
|
|
703
|
+
if (proof.constructed) {
|
|
704
|
+
return {
|
|
705
|
+
kind: "named-type",
|
|
706
|
+
typeName: sliceText(proof.constructed, source),
|
|
707
|
+
memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
|
|
708
|
+
};
|
|
709
|
+
}
|
|
276
710
|
if (!receiverIsName)
|
|
277
711
|
return null;
|
|
278
712
|
// A name bound by a local or parameter is a value, not a type. Without this guard
|
|
@@ -287,7 +721,11 @@ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope,
|
|
|
287
721
|
const typeScoped = TYPE_SCOPED_ACCESS_TYPES[accessNode.type] === true || between.includes("::");
|
|
288
722
|
if (receiver.type !== "type_identifier" && !typeScoped)
|
|
289
723
|
return null;
|
|
290
|
-
return {
|
|
724
|
+
return {
|
|
725
|
+
kind: "named-type",
|
|
726
|
+
typeName: text,
|
|
727
|
+
memberScope: hasStaticMemberDistinction(sup.id) && typeScoped ? "static" : "any",
|
|
728
|
+
};
|
|
291
729
|
}
|
|
292
730
|
/** Whether a resolved definition can declare callable members. */
|
|
293
731
|
export function declaresMembers(def) {
|
|
@@ -314,6 +752,69 @@ export function callArgumentCount(callNode) {
|
|
|
314
752
|
return 0;
|
|
315
753
|
return (argumentNode.namedChildren ?? []).filter((argument) => argument.type !== "comment").length;
|
|
316
754
|
}
|
|
755
|
+
function parseDefNodeId(id) {
|
|
756
|
+
const indexSep = id.lastIndexOf("::");
|
|
757
|
+
if (indexSep <= 0)
|
|
758
|
+
return null;
|
|
759
|
+
const index = Number(id.slice(indexSep + 2));
|
|
760
|
+
if (!Number.isFinite(index))
|
|
761
|
+
return null;
|
|
762
|
+
const rest = id.slice(0, indexSep);
|
|
763
|
+
const nameSep = rest.lastIndexOf("::");
|
|
764
|
+
if (nameSep <= 0)
|
|
765
|
+
return null;
|
|
766
|
+
return { file: rest.slice(0, nameSep), name: rest.slice(nameSep + 2), index };
|
|
767
|
+
}
|
|
768
|
+
function loadSource(file, cache) {
|
|
769
|
+
const cached = cache.get(file);
|
|
770
|
+
if (cached !== undefined)
|
|
771
|
+
return cached;
|
|
772
|
+
try {
|
|
773
|
+
const source = readFileSync(file, "utf8");
|
|
774
|
+
cache.set(file, source);
|
|
775
|
+
return source;
|
|
776
|
+
}
|
|
777
|
+
catch {
|
|
778
|
+
cache.set(file, "");
|
|
779
|
+
return "";
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function memberIdLooksStatic(memberId, sourceCache) {
|
|
783
|
+
const parsed = parseDefNodeId(memberId);
|
|
784
|
+
if (!parsed)
|
|
785
|
+
return false;
|
|
786
|
+
const source = loadSource(parsed.file, sourceCache);
|
|
787
|
+
if (!source)
|
|
788
|
+
return false;
|
|
789
|
+
const beforeBrace = source.lastIndexOf("{", parsed.index);
|
|
790
|
+
const beforeSemi = source.lastIndexOf(";", parsed.index);
|
|
791
|
+
const beforeClose = source.lastIndexOf("}", parsed.index);
|
|
792
|
+
const declStart = Math.max(beforeBrace, beforeSemi, beforeClose);
|
|
793
|
+
const prefix = source.slice(declStart + 1, parsed.index);
|
|
794
|
+
return /(?:^|[^\w$])static(?:$|[^\w$])/.test(prefix) || /(?:^|[^\w$])def\s+self\s*\./.test(prefix);
|
|
795
|
+
}
|
|
796
|
+
function inferCallMemberScope(site, sourceCache) {
|
|
797
|
+
const source = loadSource(site.file, sourceCache);
|
|
798
|
+
if (!source)
|
|
799
|
+
return "any";
|
|
800
|
+
const start = site.range.start.index ?? 0;
|
|
801
|
+
const before = source.slice(Math.max(0, start - 120), start);
|
|
802
|
+
if (/\b(?:self|static|parent|super|base)\s*::\s*$/i.test(before))
|
|
803
|
+
return "any";
|
|
804
|
+
if (/::\s*$/.test(before))
|
|
805
|
+
return "static";
|
|
806
|
+
if (/\?->\s*$/.test(before) || /->\s*$/.test(before))
|
|
807
|
+
return "instance";
|
|
808
|
+
if (/\)\s*\.\s*$/.test(before))
|
|
809
|
+
return "instance";
|
|
810
|
+
// HeritageEdges does not yet copy classifyReceiver.memberScope onto candidates.
|
|
811
|
+
// A lowercase dotted receiver is an instance value (`c.StaticMethod()`), not a type.
|
|
812
|
+
if (/(?:^|[^A-Za-z0-9_$])[a-z_][A-Za-z0-9_]*\s*\.\s*$/.test(before))
|
|
813
|
+
return "instance";
|
|
814
|
+
if (/(?:^|[^A-Za-z0-9_$])[A-Z][A-Za-z0-9_]*\s*\.\s*$/.test(before))
|
|
815
|
+
return "static";
|
|
816
|
+
return "any";
|
|
817
|
+
}
|
|
317
818
|
/**
|
|
318
819
|
* Records proven `calls` edges for deferred receiver invocations.
|
|
319
820
|
* Ambiguous names at a level stop the walk.
|
|
@@ -351,14 +852,16 @@ export function emitReceiverCallEdges(graph, candidates, recordEdge) {
|
|
|
351
852
|
return supertypesByOwner.get(ownerId) ?? [];
|
|
352
853
|
return (classAncestorsByOwner.get(ownerId) ?? []).filter((id) => graph.nodes.get(id)?.kind === "class");
|
|
353
854
|
};
|
|
855
|
+
const sourceCache = new Map();
|
|
354
856
|
for (const candidate of candidates) {
|
|
355
857
|
const owner = candidate.ownerId ?? ownerByMember.get(candidate.callerId);
|
|
356
858
|
if (!owner)
|
|
357
859
|
continue;
|
|
860
|
+
const memberScope = candidate.memberScope ?? inferCallMemberScope(candidate.site, sourceCache);
|
|
358
861
|
let level = candidate.viaSupertypes ? nextOwners(owner, true) : [owner];
|
|
359
862
|
const visited = new Set(level);
|
|
360
863
|
for (let depth = 0; depth < MAX_SUPERTYPE_DEPTH && level.length; depth += 1) {
|
|
361
|
-
const lookup = provenMemberTarget(graph, membersByOwner, level, candidate);
|
|
864
|
+
const lookup = provenMemberTarget(graph, membersByOwner, level, candidate, memberScope, sourceCache);
|
|
362
865
|
if (lookup.status === "unique") {
|
|
363
866
|
recordEdge(candidate.callerId, lookup.memberId, "calls", candidate.site);
|
|
364
867
|
break;
|
|
@@ -384,13 +887,17 @@ export function emitReceiverCallEdges(graph, candidates, recordEdge) {
|
|
|
384
887
|
* `ambiguous` means this depth matched the name but could not prove one member,
|
|
385
888
|
* including arity ambiguity, and the walk must stop.
|
|
386
889
|
*/
|
|
387
|
-
function provenMemberTarget(graph, membersByOwner, owners, candidate) {
|
|
890
|
+
function provenMemberTarget(graph, membersByOwner, owners, candidate, memberScope, sourceCache) {
|
|
388
891
|
const matches = new Set();
|
|
389
892
|
for (const ownerId of owners) {
|
|
390
893
|
for (const memberId of membersByOwner.get(ownerId) ?? []) {
|
|
391
894
|
const node = graph.nodes.get(memberId);
|
|
392
895
|
if (!node || node.kind !== "function" || node.name !== candidate.memberName)
|
|
393
896
|
continue;
|
|
897
|
+
if (memberScope === "static" && !memberIdLooksStatic(memberId, sourceCache))
|
|
898
|
+
continue;
|
|
899
|
+
if (memberScope === "instance" && memberIdLooksStatic(memberId, sourceCache))
|
|
900
|
+
continue;
|
|
394
901
|
matches.add(memberId);
|
|
395
902
|
}
|
|
396
903
|
}
|