@lzehrung/codegraph 2.3.29 → 2.3.31
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 +6602 -4453
- package/dist/bin/query-index-worker.js +1302 -753
- 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 +8 -3
- 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/edge-passes.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/edge-passes.js +118 -86
- package/dist/graphs/symbol-graph-detailed/edge-passes.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts +27 -0
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js +509 -42
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js.map +1 -1
- package/dist/impact/call-compatibility/providers/index.d.ts +15 -1
- package/dist/impact/call-compatibility/providers/index.d.ts.map +1 -1
- package/dist/impact/call-compatibility/providers/index.js +21 -20
- package/dist/impact/call-compatibility/providers/index.js.map +1 -1
- package/dist/impact/call-compatibility/providers/profiles.d.ts +80 -0
- package/dist/impact/call-compatibility/providers/profiles.d.ts.map +1 -0
- package/dist/impact/call-compatibility/providers/profiles.js +164 -0
- package/dist/impact/call-compatibility/providers/profiles.js.map +1 -0
- package/dist/impact/call-compatibility.d.ts.map +1 -1
- package/dist/impact/call-compatibility.js +73 -108
- package/dist/impact/call-compatibility.js.map +1 -1
- package/dist/impact/member-resolution-coverage.d.ts.map +1 -1
- package/dist/impact/member-resolution-coverage.js +2 -2
- 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 +16 -2
- package/dist/indexer/build-cache/options.d.ts.map +1 -1
- package/dist/indexer/build-cache/options.js +17 -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 +2 -2
- 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/import-binding-tables.d.ts +64 -0
- package/dist/indexer/imports/import-binding-tables.d.ts.map +1 -0
- package/dist/indexer/imports/import-binding-tables.js +419 -0
- package/dist/indexer/imports/import-binding-tables.js.map +1 -0
- 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 +3 -22
- package/dist/indexer/imports/language-specific.d.ts.map +1 -1
- package/dist/indexer/imports/language-specific.js +54 -573
- 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/imports.d.ts.map +1 -1
- package/dist/indexer/imports.js +2 -1
- package/dist/indexer/imports.js.map +1 -1
- package/dist/indexer/locals-and-exports.d.ts.map +1 -1
- package/dist/indexer/locals-and-exports.js +23 -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 +181 -381
- 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 +39 -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 +15 -61
- 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 +46 -52
- 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.map +1 -1
- package/dist/languages/definitions/python.js +23 -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 +33 -49
- 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 +56 -90
- 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/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/dynamic-import-tables.d.ts +88 -0
- package/dist/util/dynamic-import-tables.d.ts.map +1 -0
- package/dist/util/dynamic-import-tables.js +100 -0
- package/dist/util/dynamic-import-tables.js.map +1 -0
- 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-tables.d.ts +72 -0
- package/dist/util/member-access-tables.d.ts.map +1 -0
- package/dist/util/member-access-tables.js +167 -0
- package/dist/util/member-access-tables.js.map +1 -0
- 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 +61 -95
- 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 +4 -3
- package/dist/util/resolution/csharp.d.ts.map +1 -1
- package/dist/util/resolution/csharp.js +27 -113
- package/dist/util/resolution/csharp.js.map +1 -1
- 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 +93 -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 +131 -165
- 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,26 +1,26 @@
|
|
|
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 {
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
php:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
svelte: THIS_SUPER_RECEIVERS,
|
|
19
|
-
swift: SELF_RECEIVERS,
|
|
20
|
-
ts: THIS_SUPER_RECEIVERS,
|
|
21
|
-
tsx: THIS_SUPER_RECEIVERS,
|
|
22
|
-
zig: { own: ["self"], supertype: [] },
|
|
4
|
+
import { XID_IDENTIFIER_SOURCE } from "../../util/identifiers.js";
|
|
5
|
+
import { MEMBER_ACCESS_ROWS } from "../../util/member-access-tables.js";
|
|
6
|
+
import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isMemberReferencePropertyIdentifier, isReceiverNameNode, } from "../../util/member-access.js";
|
|
7
|
+
const INSTANCE_RECEIVER_KEYWORDS = new Set(["this", "$this"]);
|
|
8
|
+
/** Languages whose grammar distinguishes static members from instance members. */
|
|
9
|
+
const STATIC_MEMBER_LANGUAGES = {
|
|
10
|
+
cpp: true,
|
|
11
|
+
csharp: true,
|
|
12
|
+
java: true,
|
|
13
|
+
js: true,
|
|
14
|
+
php: true,
|
|
15
|
+
swift: true,
|
|
16
|
+
ts: true,
|
|
17
|
+
tsx: true,
|
|
23
18
|
};
|
|
19
|
+
/** Every language with a static-member distinction, guarded by the registry-consistency test. */
|
|
20
|
+
export const staticMemberLanguageIds = Object.keys(STATIC_MEMBER_LANGUAGES);
|
|
21
|
+
export function hasStaticMemberDistinction(languageId) {
|
|
22
|
+
return STATIC_MEMBER_LANGUAGES[languageId] !== undefined;
|
|
23
|
+
}
|
|
24
24
|
/**
|
|
25
25
|
* Call nodes that carry the receiver and the member name on the call node itself
|
|
26
26
|
* instead of exposing a member-access callee.
|
|
@@ -39,7 +39,6 @@ const MEMBER_CONTAINER_TYPES = {
|
|
|
39
39
|
class_definition: true,
|
|
40
40
|
class_specifier: true,
|
|
41
41
|
enum_declaration: true,
|
|
42
|
-
extension_declaration: true,
|
|
43
42
|
impl_item: true,
|
|
44
43
|
interface_declaration: true,
|
|
45
44
|
module: true,
|
|
@@ -91,11 +90,16 @@ const VALUE_BINDING_TYPES = {
|
|
|
91
90
|
variable_declaration: true,
|
|
92
91
|
variable_declarator: true,
|
|
93
92
|
};
|
|
94
|
-
/**
|
|
95
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Parameter lists whose identifier children are value bindings (Ruby has no wrapping param node).
|
|
95
|
+
* Union of the receiver-call and call-compatibility lists so Kotlin `function_value_parameters`
|
|
96
|
+
* and Ruby `block_parameters` are both recognized.
|
|
97
|
+
*/
|
|
98
|
+
export const PARAMETER_LIST_NODE_TYPES = {
|
|
96
99
|
block_parameters: true,
|
|
97
100
|
formal_parameters: true,
|
|
98
101
|
function_parameter_clause: true,
|
|
102
|
+
function_value_parameters: true,
|
|
99
103
|
lambda_parameters: true,
|
|
100
104
|
method_parameters: true,
|
|
101
105
|
parameter_list: true,
|
|
@@ -136,6 +140,65 @@ const BINDING_SCOPE_TYPES = {
|
|
|
136
140
|
impl_item: true,
|
|
137
141
|
translation_unit: true,
|
|
138
142
|
};
|
|
143
|
+
const BINDING_CONTAINER_TYPES = new Set([
|
|
144
|
+
"program",
|
|
145
|
+
"compilation_unit",
|
|
146
|
+
"source_file",
|
|
147
|
+
"translation_unit",
|
|
148
|
+
"statement_block",
|
|
149
|
+
"block",
|
|
150
|
+
"compound_statement",
|
|
151
|
+
"function_body",
|
|
152
|
+
"body_statement",
|
|
153
|
+
"function_declaration",
|
|
154
|
+
"function_item",
|
|
155
|
+
"function_definition",
|
|
156
|
+
"function",
|
|
157
|
+
"function_expression",
|
|
158
|
+
"arrow_function",
|
|
159
|
+
"method_definition",
|
|
160
|
+
"method_declaration",
|
|
161
|
+
"method",
|
|
162
|
+
"impl_item",
|
|
163
|
+
]);
|
|
164
|
+
const BINDING_DECLARATION_TYPES = new Set([
|
|
165
|
+
"variable_declarator",
|
|
166
|
+
"variable_declaration",
|
|
167
|
+
"let_declaration",
|
|
168
|
+
"assignment",
|
|
169
|
+
"assignment_expression",
|
|
170
|
+
"assignment_statement",
|
|
171
|
+
"formal_parameter",
|
|
172
|
+
"required_parameter",
|
|
173
|
+
"optional_parameter",
|
|
174
|
+
"simple_parameter",
|
|
175
|
+
"parameter",
|
|
176
|
+
"parameter_declaration",
|
|
177
|
+
"typed_parameter",
|
|
178
|
+
"short_var_declaration",
|
|
179
|
+
"var_spec",
|
|
180
|
+
"property_declaration",
|
|
181
|
+
"local_variable_declaration",
|
|
182
|
+
"local_declaration_statement",
|
|
183
|
+
]);
|
|
184
|
+
const RUBY_CONSTANT_SOURCE = String.raw `(?=\p{Lu})${XID_IDENTIFIER_SOURCE}`;
|
|
185
|
+
/** Proven construction forms that name a receiver's type, keyed by language. */
|
|
186
|
+
const LANGUAGE_CONSTRUCTION_FORMS = {
|
|
187
|
+
cpp: { newExpression: true },
|
|
188
|
+
csharp: { newExpression: true },
|
|
189
|
+
go: { compositeLiteral: true },
|
|
190
|
+
java: { newExpression: true },
|
|
191
|
+
js: { newExpression: true },
|
|
192
|
+
kotlin: { capitalizedCall: true },
|
|
193
|
+
php: { newExpression: true },
|
|
194
|
+
python: { capitalizedCall: true },
|
|
195
|
+
ruby: { rubyNew: true },
|
|
196
|
+
rust: { capitalizedCall: true, rustUnitStruct: true },
|
|
197
|
+
swift: { capitalizedCall: true },
|
|
198
|
+
ts: { newExpression: true },
|
|
199
|
+
tsx: { newExpression: true },
|
|
200
|
+
zig: { compositeLiteral: true },
|
|
201
|
+
};
|
|
139
202
|
/** Guards against a cyclic or pathological declared hierarchy. */
|
|
140
203
|
const MAX_SUPERTYPE_DEPTH = 16;
|
|
141
204
|
/**
|
|
@@ -180,8 +243,7 @@ export function receiverCallAccess(sup, callNode, callee) {
|
|
|
180
243
|
*/
|
|
181
244
|
function bindingIdentifier(node, sup) {
|
|
182
245
|
const named = node.childForFieldName("name");
|
|
183
|
-
if (named &&
|
|
184
|
-
(isIdentifierType(sup, named.type) || named.type === "identifier" || named.type === "field_identifier")) {
|
|
246
|
+
if (named && (isReceiverNameNode(sup, named.type) || named.type === "field_identifier")) {
|
|
185
247
|
return named;
|
|
186
248
|
}
|
|
187
249
|
if (node.type === "assignment" ||
|
|
@@ -189,16 +251,16 @@ function bindingIdentifier(node, sup) {
|
|
|
189
251
|
node.type === "assignment_statement" ||
|
|
190
252
|
node.type === "short_var_declaration") {
|
|
191
253
|
const left = node.childForFieldName("left") ?? node.child(0);
|
|
192
|
-
if (left && (
|
|
254
|
+
if (left && isReceiverNameNode(sup, left.type))
|
|
193
255
|
return left;
|
|
194
|
-
if (left?.type === "expression_list") {
|
|
195
|
-
return
|
|
256
|
+
if (left?.type === "expression_list" || left?.type === "pattern") {
|
|
257
|
+
return left.namedChildren.find((child) => isReceiverNameNode(sup, child.type)) ?? null;
|
|
196
258
|
}
|
|
197
259
|
return null;
|
|
198
260
|
}
|
|
199
261
|
let current = node.childForFieldName("declarator");
|
|
200
262
|
while (current) {
|
|
201
|
-
if (current.type
|
|
263
|
+
if (isReceiverNameNode(sup, current.type) || current.type === "field_identifier") {
|
|
202
264
|
return current;
|
|
203
265
|
}
|
|
204
266
|
const nested = current.childForFieldName("declarator");
|
|
@@ -208,8 +270,15 @@ function bindingIdentifier(node, sup) {
|
|
|
208
270
|
}
|
|
209
271
|
return (current.namedChildren.find((child) => child.type === "identifier" || child.type === "field_identifier") ?? null);
|
|
210
272
|
}
|
|
211
|
-
const identifiers = node.namedChildren.filter((child) => child.type
|
|
212
|
-
|
|
273
|
+
const identifiers = node.namedChildren.filter((child) => isReceiverNameNode(sup, child.type) || child.type === "field_identifier");
|
|
274
|
+
if (identifiers.length === 0)
|
|
275
|
+
return null;
|
|
276
|
+
// `let name = Type;` / `var name = Type{}` put the binding first and the type second.
|
|
277
|
+
// C++ parameters keep the name last, after the type.
|
|
278
|
+
if (node.type === "let_declaration" || node.type === "variable_declaration" || node.type === "variable_declarator") {
|
|
279
|
+
return identifiers[0];
|
|
280
|
+
}
|
|
281
|
+
return identifiers[identifiers.length - 1];
|
|
213
282
|
}
|
|
214
283
|
/**
|
|
215
284
|
* Whether a scope encloses `receiver` and binds `receiverName` as a value before it.
|
|
@@ -222,7 +291,7 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
222
291
|
return false;
|
|
223
292
|
if (node !== receiver && BINDING_SCOPE_TYPES[node.type] && !containsIndex(node, receiver.startIndex))
|
|
224
293
|
return false;
|
|
225
|
-
if (
|
|
294
|
+
if (PARAMETER_LIST_NODE_TYPES[node.type]) {
|
|
226
295
|
for (const child of node.namedChildren) {
|
|
227
296
|
if (child.startIndex >= receiver.startIndex)
|
|
228
297
|
continue;
|
|
@@ -230,7 +299,7 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
230
299
|
// name in ERROR. Treat recovered parameter names as value bindings.
|
|
231
300
|
const names = child.type === "ERROR" ? child.namedChildren : [child];
|
|
232
301
|
for (const name of names) {
|
|
233
|
-
if ((
|
|
302
|
+
if ((isReceiverNameNode(sup, name.type) || name.type === "identifier" || name.type === "constant") &&
|
|
234
303
|
sliceText(name, source) === receiverName) {
|
|
235
304
|
return true;
|
|
236
305
|
}
|
|
@@ -253,21 +322,341 @@ function bindsLocalValue(receiver, receiverName, source, sup) {
|
|
|
253
322
|
function containsIndex(node, index) {
|
|
254
323
|
return node.startIndex <= index && node.endIndex >= index;
|
|
255
324
|
}
|
|
325
|
+
function constructorNameNode(node, sup) {
|
|
326
|
+
const constructor = node.childForFieldName("constructor") ?? node.child(0);
|
|
327
|
+
if (constructor && isReceiverNameNode(sup, constructor.type)) {
|
|
328
|
+
return constructor;
|
|
329
|
+
}
|
|
330
|
+
for (const child of node.namedChildren) {
|
|
331
|
+
if (isReceiverNameNode(sup, child.type) || child.type === "type_identifier" || child.type === "constant") {
|
|
332
|
+
return child;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
function rubyNewReceiverNameNode(node, source, sup) {
|
|
338
|
+
if (!new RegExp(String.raw `^(?:${RUBY_CONSTANT_SOURCE})\.new$`, "u").test(sliceText(node, source)))
|
|
339
|
+
return null;
|
|
340
|
+
return node.namedChildren.find((child) => isReceiverNameNode(sup, child.type) || child.type === "constant") ?? null;
|
|
341
|
+
}
|
|
342
|
+
export function unwrapNamedType(node, sup) {
|
|
343
|
+
let current = node;
|
|
344
|
+
while (current) {
|
|
345
|
+
if (current.type === "type_annotation" ||
|
|
346
|
+
current.type === "named_type" ||
|
|
347
|
+
current.type === "user_type" ||
|
|
348
|
+
current.type === "type" ||
|
|
349
|
+
current.type === "parenthesized_type" ||
|
|
350
|
+
current.type === "pointer_type" ||
|
|
351
|
+
current.type === "reference_type" ||
|
|
352
|
+
current.type === "optional_type" ||
|
|
353
|
+
current.type === "nullable_type") {
|
|
354
|
+
current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (current.type === "generic_type" || current.type === "generic_name") {
|
|
358
|
+
current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
if (!current)
|
|
364
|
+
return null;
|
|
365
|
+
if (isReceiverNameNode(sup, current.type) || current.type === "type_identifier" || current.type === "name") {
|
|
366
|
+
return current;
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
function capitalizedCallTypeName(expr, source, sup) {
|
|
371
|
+
if (expr.type !== "call" && expr.type !== "call_expression")
|
|
372
|
+
return null;
|
|
373
|
+
const callee = expr.childForFieldName("function") ?? expr.namedChildren[0] ?? null;
|
|
374
|
+
if (!callee || !isReceiverNameNode(sup, callee.type))
|
|
375
|
+
return null;
|
|
376
|
+
const name = sliceText(callee, source);
|
|
377
|
+
if (!name)
|
|
378
|
+
return null;
|
|
379
|
+
const first = name[0];
|
|
380
|
+
if (first !== first.toUpperCase())
|
|
381
|
+
return null;
|
|
382
|
+
return callee;
|
|
383
|
+
}
|
|
384
|
+
function compositeLiteralTypeName(expr, source, sup) {
|
|
385
|
+
let current = expr;
|
|
386
|
+
if (current.type === "unary_expression") {
|
|
387
|
+
const operand = current.childForFieldName("operand");
|
|
388
|
+
if (!operand)
|
|
389
|
+
return null;
|
|
390
|
+
const operator = current.childForFieldName("operator");
|
|
391
|
+
let isAddr = sliceText(current, source).startsWith("&");
|
|
392
|
+
if (operator)
|
|
393
|
+
isAddr = sliceText(operator, source) === "&";
|
|
394
|
+
if (!isAddr)
|
|
395
|
+
return null;
|
|
396
|
+
current = operand;
|
|
397
|
+
}
|
|
398
|
+
if (current.type !== "composite_literal" && current.type !== "struct_initializer")
|
|
399
|
+
return null;
|
|
400
|
+
const typeNode = current.childForFieldName("type") ??
|
|
401
|
+
current.namedChildren.find((child) => child.type === "type_identifier" || child.type === "identifier") ??
|
|
402
|
+
null;
|
|
403
|
+
return typeNode ? (unwrapNamedType(typeNode, sup) ?? typeNode) : null;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Resolves the node naming the type a construction expression denotes, or null
|
|
407
|
+
* when the expression is not a proven constructor form.
|
|
408
|
+
*/
|
|
409
|
+
export function constructionTypeName(expr, source, sup) {
|
|
410
|
+
const forms = LANGUAGE_CONSTRUCTION_FORMS[sup.id];
|
|
411
|
+
if (!forms)
|
|
412
|
+
return null;
|
|
413
|
+
if (forms.newExpression && (expr.type === "new_expression" || expr.type === "object_creation_expression")) {
|
|
414
|
+
return constructorNameNode(expr, sup);
|
|
415
|
+
}
|
|
416
|
+
if (forms.rubyNew && expr.type === "call") {
|
|
417
|
+
const rubyConstructor = rubyNewReceiverNameNode(expr, source, sup);
|
|
418
|
+
if (rubyConstructor)
|
|
419
|
+
return rubyConstructor;
|
|
420
|
+
}
|
|
421
|
+
if (forms.compositeLiteral) {
|
|
422
|
+
const composite = compositeLiteralTypeName(expr, source, sup);
|
|
423
|
+
if (composite)
|
|
424
|
+
return composite;
|
|
425
|
+
}
|
|
426
|
+
if (forms.capitalizedCall) {
|
|
427
|
+
const fromCall = capitalizedCallTypeName(expr, source, sup);
|
|
428
|
+
if (fromCall)
|
|
429
|
+
return fromCall;
|
|
430
|
+
}
|
|
431
|
+
// Rust unit structs are constructed by the type name itself: `let service = Service;`.
|
|
432
|
+
if (forms.rustUnitStruct && isReceiverNameNode(sup, expr.type)) {
|
|
433
|
+
const name = sliceText(expr, source);
|
|
434
|
+
const first = name[0];
|
|
435
|
+
if (first && first === first.toUpperCase() && first !== first.toLowerCase())
|
|
436
|
+
return expr;
|
|
437
|
+
}
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
function bindingValueExpression(node) {
|
|
441
|
+
const named = node.childForFieldName("value") ?? node.childForFieldName("right") ?? node.childForFieldName("default_value");
|
|
442
|
+
if (named) {
|
|
443
|
+
if (named.type === "expression_list")
|
|
444
|
+
return named.namedChildren[0] ?? null;
|
|
445
|
+
return named;
|
|
446
|
+
}
|
|
447
|
+
const expressionTypes = new Set([
|
|
448
|
+
"new_expression",
|
|
449
|
+
"object_creation_expression",
|
|
450
|
+
"call",
|
|
451
|
+
"call_expression",
|
|
452
|
+
"composite_literal",
|
|
453
|
+
"struct_initializer",
|
|
454
|
+
"unary_expression",
|
|
455
|
+
]);
|
|
456
|
+
return node.namedChildren.find((child) => expressionTypes.has(child.type)) ?? null;
|
|
457
|
+
}
|
|
458
|
+
function declaredTypeNameNode(node, sup) {
|
|
459
|
+
const typeField = node.childForFieldName("type");
|
|
460
|
+
if (typeField)
|
|
461
|
+
return unwrapNamedType(typeField, sup);
|
|
462
|
+
const typedChild = node.namedChildren.find((child) => child.type === "named_type" ||
|
|
463
|
+
child.type === "user_type" ||
|
|
464
|
+
child.type === "type_annotation" ||
|
|
465
|
+
child.type === "type");
|
|
466
|
+
if (typedChild)
|
|
467
|
+
return unwrapNamedType(typedChild, sup);
|
|
468
|
+
const ids = node.namedChildren.filter((child) => isReceiverNameNode(sup, child.type) || child.type === "type_identifier" || child.type === "name");
|
|
469
|
+
if (ids.length >= 2)
|
|
470
|
+
return unwrapNamedType(ids[0], sup);
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
function goBindingNameNodes(node) {
|
|
474
|
+
if (node.type === "short_var_declaration") {
|
|
475
|
+
const left = node.childForFieldName("left");
|
|
476
|
+
return (left?.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
477
|
+
}
|
|
478
|
+
if (node.type === "var_spec") {
|
|
479
|
+
return (node.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
480
|
+
}
|
|
481
|
+
return [];
|
|
482
|
+
}
|
|
483
|
+
function bindingDeclaresReceiverName(node, receiverName, source, sup) {
|
|
484
|
+
if (sup.id === "go") {
|
|
485
|
+
const goNames = goBindingNameNodes(node);
|
|
486
|
+
if (goNames.some((name) => sliceText(name, source) === receiverName))
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
const name = bindingIdentifier(node, sup);
|
|
490
|
+
if (name && sliceText(name, source) === receiverName)
|
|
491
|
+
return true;
|
|
492
|
+
if (node.type === "property_declaration") {
|
|
493
|
+
return node.namedChildren.some((child) => {
|
|
494
|
+
if (child.type === "variable_declaration" || child.type === "pattern") {
|
|
495
|
+
return child.namedChildren.some((inner) => isReceiverNameNode(sup, inner.type) && sliceText(inner, source) === receiverName);
|
|
496
|
+
}
|
|
497
|
+
return isReceiverNameNode(sup, child.type) && sliceText(child, source) === receiverName;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
function constructionTypeFromBinding(node, receiverName, source, sup) {
|
|
503
|
+
if (sup.id === "go" && (node.type === "short_var_declaration" || node.type === "var_spec")) {
|
|
504
|
+
return constructorFromGoBinding(node, receiverName, source, sup) ?? declaredTypeNameNode(node, sup);
|
|
505
|
+
}
|
|
506
|
+
const value = bindingValueExpression(node);
|
|
507
|
+
if (value) {
|
|
508
|
+
const fromValue = constructionTypeName(value, source, sup);
|
|
509
|
+
if (fromValue)
|
|
510
|
+
return fromValue;
|
|
511
|
+
}
|
|
512
|
+
return declaredTypeNameNode(node, sup);
|
|
513
|
+
}
|
|
514
|
+
function constructorFromGoBinding(node, receiverName, source, sup) {
|
|
515
|
+
if (node.type === "short_var_declaration") {
|
|
516
|
+
const left = node.childForFieldName("left");
|
|
517
|
+
const right = node.childForFieldName("right");
|
|
518
|
+
if (!left || !right)
|
|
519
|
+
return null;
|
|
520
|
+
const names = (left.namedChildren ?? []).filter((child) => child.type === "identifier");
|
|
521
|
+
const values = right.namedChildren ?? [];
|
|
522
|
+
const index = names.findIndex((name) => sliceText(name, source) === receiverName);
|
|
523
|
+
if (index < 0)
|
|
524
|
+
return null;
|
|
525
|
+
const value = values[index] ?? null;
|
|
526
|
+
return value ? constructionTypeName(value, source, sup) : null;
|
|
527
|
+
}
|
|
528
|
+
if (node.type !== "var_spec")
|
|
529
|
+
return null;
|
|
530
|
+
const value = node.childForFieldName("value");
|
|
531
|
+
if (value) {
|
|
532
|
+
const first = value.type === "expression_list" ? (value.namedChildren[0] ?? null) : value;
|
|
533
|
+
const fromValue = first ? constructionTypeName(first, source, sup) : null;
|
|
534
|
+
if (fromValue)
|
|
535
|
+
return fromValue;
|
|
536
|
+
}
|
|
537
|
+
const typeNode = node.childForFieldName("type");
|
|
538
|
+
return typeNode ? unwrapNamedType(typeNode, sup) : null;
|
|
539
|
+
}
|
|
540
|
+
function bindingProof(node, receiverName, source, sup) {
|
|
541
|
+
if (!BINDING_DECLARATION_TYPES.has(node.type))
|
|
542
|
+
return { status: "none" };
|
|
543
|
+
if (!bindingDeclaresReceiverName(node, receiverName, source, sup))
|
|
544
|
+
return { status: "none" };
|
|
545
|
+
const typeNode = constructionTypeFromBinding(node, receiverName, source, sup);
|
|
546
|
+
if (typeNode)
|
|
547
|
+
return { status: "type", node: typeNode };
|
|
548
|
+
return { status: "unproven" };
|
|
549
|
+
}
|
|
550
|
+
function isSkippableBindingContainer(node, receiver) {
|
|
551
|
+
return BINDING_CONTAINER_TYPES.has(node.type) && !containsIndex(node, receiver.startIndex);
|
|
552
|
+
}
|
|
553
|
+
function findPriorConstructorInContainer(node, receiver, receiverName, source, sup) {
|
|
554
|
+
let constructor = null;
|
|
555
|
+
let sawUnproven = false;
|
|
556
|
+
const visit = (current) => {
|
|
557
|
+
if (current.startIndex >= receiver.startIndex)
|
|
558
|
+
return true;
|
|
559
|
+
if (current !== node && isSkippableBindingContainer(current, receiver))
|
|
560
|
+
return true;
|
|
561
|
+
const proof = bindingProof(current, receiverName, source, sup);
|
|
562
|
+
if (proof.status === "unproven") {
|
|
563
|
+
if (constructor) {
|
|
564
|
+
constructor = null;
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
sawUnproven = true;
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
if (proof.status === "type") {
|
|
571
|
+
if (sawUnproven) {
|
|
572
|
+
constructor = null;
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
if (constructor && sliceText(constructor, source) !== sliceText(proof.node, source)) {
|
|
576
|
+
constructor = null;
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
constructor = proof.node;
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
for (const child of current.namedChildren) {
|
|
583
|
+
if (!visit(child))
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
return true;
|
|
587
|
+
};
|
|
588
|
+
visit(node);
|
|
589
|
+
return constructor;
|
|
590
|
+
}
|
|
591
|
+
function bindingContainerDeclaresNameBefore(node, receiver, receiverName, source, sup) {
|
|
592
|
+
const visit = (current) => {
|
|
593
|
+
if (current.startIndex >= receiver.startIndex)
|
|
594
|
+
return false;
|
|
595
|
+
if (current !== node && isSkippableBindingContainer(current, receiver))
|
|
596
|
+
return false;
|
|
597
|
+
if (BINDING_DECLARATION_TYPES.has(current.type) &&
|
|
598
|
+
bindingDeclaresReceiverName(current, receiverName, source, sup)) {
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
for (const child of current.namedChildren) {
|
|
602
|
+
if (visit(child))
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
};
|
|
607
|
+
return visit(node);
|
|
608
|
+
}
|
|
609
|
+
function rootOf(node) {
|
|
610
|
+
let current = node;
|
|
611
|
+
while (current.parent)
|
|
612
|
+
current = current.parent;
|
|
613
|
+
return current;
|
|
614
|
+
}
|
|
615
|
+
function findVisiblePriorConstructor(receiver, receiverName, source, sup) {
|
|
616
|
+
let current = receiver;
|
|
617
|
+
while (current) {
|
|
618
|
+
if (BINDING_CONTAINER_TYPES.has(current.type)) {
|
|
619
|
+
const constructor = findPriorConstructorInContainer(current, receiver, receiverName, source, sup);
|
|
620
|
+
if (constructor || bindingContainerDeclaresNameBefore(current, receiver, receiverName, source, sup)) {
|
|
621
|
+
return constructor;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
current = current.parent;
|
|
625
|
+
}
|
|
626
|
+
return findPriorConstructorInContainer(rootOf(receiver), receiver, receiverName, source, sup);
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Resolves the node naming the type a receiver expression was constructed from, or
|
|
630
|
+
* null when no constructor is proven for it. Shared with detailed symbol-graph call
|
|
631
|
+
* extraction so `goto` and resolved `calls` edges accept the same receiver forms.
|
|
632
|
+
*/
|
|
633
|
+
export function receiverConstructorExpression(obj, source, sup) {
|
|
634
|
+
const direct = constructionTypeName(obj, source, sup);
|
|
635
|
+
if (direct)
|
|
636
|
+
return direct;
|
|
637
|
+
if (!isReceiverNameNode(sup, obj.type))
|
|
638
|
+
return null;
|
|
639
|
+
const receiverName = sliceText(obj, source);
|
|
640
|
+
return findVisiblePriorConstructor(obj, receiverName, source, sup);
|
|
641
|
+
}
|
|
642
|
+
function ownTypeMemberScope(receiverName) {
|
|
643
|
+
return INSTANCE_RECEIVER_KEYWORDS.has(receiverName) ? "instance" : "any";
|
|
644
|
+
}
|
|
256
645
|
/**
|
|
257
646
|
* Classifies a receiver as the declaring type, a supertype, or a named/constructed type.
|
|
258
647
|
* Returns null when the receiver cannot be proven.
|
|
259
648
|
* Named-local constructor lookup is memoized per enclosing function and receiver text.
|
|
260
649
|
*/
|
|
261
650
|
export function classifyReceiver(sup, receiver, source, proofCache, cacheScope, accessNode) {
|
|
262
|
-
const keywords =
|
|
651
|
+
const keywords = MEMBER_ACCESS_ROWS[sup.id]?.receiverKeywords;
|
|
263
652
|
const text = sliceText(receiver, source).trim();
|
|
264
653
|
if (!text)
|
|
265
654
|
return null;
|
|
266
655
|
if (keywords?.own.includes(text))
|
|
267
|
-
return { kind: "own-type" };
|
|
656
|
+
return { kind: "own-type", memberScope: ownTypeMemberScope(text) };
|
|
268
657
|
if (keywords?.supertype.includes(text))
|
|
269
|
-
return { kind: "supertype" };
|
|
270
|
-
const receiverIsName =
|
|
658
|
+
return { kind: "supertype", memberScope: "any" };
|
|
659
|
+
const receiverIsName = isReceiverNameNode(sup, receiver.type);
|
|
271
660
|
const cacheKey = `${cacheScope}\u0000${text}`;
|
|
272
661
|
let proof = proofCache.get(cacheKey);
|
|
273
662
|
if (!proof) {
|
|
@@ -278,8 +667,13 @@ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope,
|
|
|
278
667
|
};
|
|
279
668
|
proofCache.set(cacheKey, proof);
|
|
280
669
|
}
|
|
281
|
-
if (proof.constructed)
|
|
282
|
-
return {
|
|
670
|
+
if (proof.constructed) {
|
|
671
|
+
return {
|
|
672
|
+
kind: "named-type",
|
|
673
|
+
typeName: sliceText(proof.constructed, source),
|
|
674
|
+
memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
|
|
675
|
+
};
|
|
676
|
+
}
|
|
283
677
|
if (!receiverIsName)
|
|
284
678
|
return null;
|
|
285
679
|
// A name bound by a local or parameter is a value, not a type. Without this guard
|
|
@@ -294,7 +688,11 @@ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope,
|
|
|
294
688
|
const typeScoped = TYPE_SCOPED_ACCESS_TYPES[accessNode.type] === true || between.includes("::");
|
|
295
689
|
if (receiver.type !== "type_identifier" && !typeScoped)
|
|
296
690
|
return null;
|
|
297
|
-
return {
|
|
691
|
+
return {
|
|
692
|
+
kind: "named-type",
|
|
693
|
+
typeName: text,
|
|
694
|
+
memberScope: hasStaticMemberDistinction(sup.id) && typeScoped ? "static" : "any",
|
|
695
|
+
};
|
|
298
696
|
}
|
|
299
697
|
/** Whether a resolved definition can declare callable members. */
|
|
300
698
|
export function declaresMembers(def) {
|
|
@@ -321,6 +719,69 @@ export function callArgumentCount(callNode) {
|
|
|
321
719
|
return 0;
|
|
322
720
|
return (argumentNode.namedChildren ?? []).filter((argument) => argument.type !== "comment").length;
|
|
323
721
|
}
|
|
722
|
+
function parseDefNodeId(id) {
|
|
723
|
+
const indexSep = id.lastIndexOf("::");
|
|
724
|
+
if (indexSep <= 0)
|
|
725
|
+
return null;
|
|
726
|
+
const index = Number(id.slice(indexSep + 2));
|
|
727
|
+
if (!Number.isFinite(index))
|
|
728
|
+
return null;
|
|
729
|
+
const rest = id.slice(0, indexSep);
|
|
730
|
+
const nameSep = rest.lastIndexOf("::");
|
|
731
|
+
if (nameSep <= 0)
|
|
732
|
+
return null;
|
|
733
|
+
return { file: rest.slice(0, nameSep), name: rest.slice(nameSep + 2), index };
|
|
734
|
+
}
|
|
735
|
+
function loadSource(file, cache) {
|
|
736
|
+
const cached = cache.get(file);
|
|
737
|
+
if (cached !== undefined)
|
|
738
|
+
return cached;
|
|
739
|
+
try {
|
|
740
|
+
const source = readFileSync(file, "utf8");
|
|
741
|
+
cache.set(file, source);
|
|
742
|
+
return source;
|
|
743
|
+
}
|
|
744
|
+
catch {
|
|
745
|
+
cache.set(file, "");
|
|
746
|
+
return "";
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function memberIdLooksStatic(memberId, sourceCache) {
|
|
750
|
+
const parsed = parseDefNodeId(memberId);
|
|
751
|
+
if (!parsed)
|
|
752
|
+
return false;
|
|
753
|
+
const source = loadSource(parsed.file, sourceCache);
|
|
754
|
+
if (!source)
|
|
755
|
+
return false;
|
|
756
|
+
const beforeBrace = source.lastIndexOf("{", parsed.index);
|
|
757
|
+
const beforeSemi = source.lastIndexOf(";", parsed.index);
|
|
758
|
+
const beforeClose = source.lastIndexOf("}", parsed.index);
|
|
759
|
+
const declStart = Math.max(beforeBrace, beforeSemi, beforeClose);
|
|
760
|
+
const prefix = source.slice(declStart + 1, parsed.index);
|
|
761
|
+
return /(?:^|[^\w$])static(?:$|[^\w$])/.test(prefix) || /(?:^|[^\w$])def\s+self\s*\./.test(prefix);
|
|
762
|
+
}
|
|
763
|
+
function inferCallMemberScope(site, sourceCache) {
|
|
764
|
+
const source = loadSource(site.file, sourceCache);
|
|
765
|
+
if (!source)
|
|
766
|
+
return "any";
|
|
767
|
+
const start = site.range.start.index ?? 0;
|
|
768
|
+
const before = source.slice(Math.max(0, start - 120), start);
|
|
769
|
+
if (/\b(?:self|static|parent|super|base)\s*::\s*$/i.test(before))
|
|
770
|
+
return "any";
|
|
771
|
+
if (/::\s*$/.test(before))
|
|
772
|
+
return "static";
|
|
773
|
+
if (/\?->\s*$/.test(before) || /->\s*$/.test(before))
|
|
774
|
+
return "instance";
|
|
775
|
+
if (/\)\s*\.\s*$/.test(before))
|
|
776
|
+
return "instance";
|
|
777
|
+
// HeritageEdges does not yet copy classifyReceiver.memberScope onto candidates.
|
|
778
|
+
// A lowercase dotted receiver is an instance value (`c.StaticMethod()`), not a type.
|
|
779
|
+
if (/(?:^|[^A-Za-z0-9_$])[a-z_][A-Za-z0-9_]*\s*\.\s*$/.test(before))
|
|
780
|
+
return "instance";
|
|
781
|
+
if (/(?:^|[^A-Za-z0-9_$])[A-Z][A-Za-z0-9_]*\s*\.\s*$/.test(before))
|
|
782
|
+
return "static";
|
|
783
|
+
return "any";
|
|
784
|
+
}
|
|
324
785
|
/**
|
|
325
786
|
* Records proven `calls` edges for deferred receiver invocations.
|
|
326
787
|
* Ambiguous names at a level stop the walk.
|
|
@@ -358,14 +819,16 @@ export function emitReceiverCallEdges(graph, candidates, recordEdge) {
|
|
|
358
819
|
return supertypesByOwner.get(ownerId) ?? [];
|
|
359
820
|
return (classAncestorsByOwner.get(ownerId) ?? []).filter((id) => graph.nodes.get(id)?.kind === "class");
|
|
360
821
|
};
|
|
822
|
+
const sourceCache = new Map();
|
|
361
823
|
for (const candidate of candidates) {
|
|
362
824
|
const owner = candidate.ownerId ?? ownerByMember.get(candidate.callerId);
|
|
363
825
|
if (!owner)
|
|
364
826
|
continue;
|
|
827
|
+
const memberScope = candidate.memberScope ?? inferCallMemberScope(candidate.site, sourceCache);
|
|
365
828
|
let level = candidate.viaSupertypes ? nextOwners(owner, true) : [owner];
|
|
366
829
|
const visited = new Set(level);
|
|
367
830
|
for (let depth = 0; depth < MAX_SUPERTYPE_DEPTH && level.length; depth += 1) {
|
|
368
|
-
const lookup = provenMemberTarget(graph, membersByOwner, level, candidate);
|
|
831
|
+
const lookup = provenMemberTarget(graph, membersByOwner, level, candidate, memberScope, sourceCache);
|
|
369
832
|
if (lookup.status === "unique") {
|
|
370
833
|
recordEdge(candidate.callerId, lookup.memberId, "calls", candidate.site);
|
|
371
834
|
break;
|
|
@@ -391,13 +854,17 @@ export function emitReceiverCallEdges(graph, candidates, recordEdge) {
|
|
|
391
854
|
* `ambiguous` means this depth matched the name but could not prove one member,
|
|
392
855
|
* including arity ambiguity, and the walk must stop.
|
|
393
856
|
*/
|
|
394
|
-
function provenMemberTarget(graph, membersByOwner, owners, candidate) {
|
|
857
|
+
function provenMemberTarget(graph, membersByOwner, owners, candidate, memberScope, sourceCache) {
|
|
395
858
|
const matches = new Set();
|
|
396
859
|
for (const ownerId of owners) {
|
|
397
860
|
for (const memberId of membersByOwner.get(ownerId) ?? []) {
|
|
398
861
|
const node = graph.nodes.get(memberId);
|
|
399
862
|
if (!node || node.kind !== "function" || node.name !== candidate.memberName)
|
|
400
863
|
continue;
|
|
864
|
+
if (memberScope === "static" && !memberIdLooksStatic(memberId, sourceCache))
|
|
865
|
+
continue;
|
|
866
|
+
if (memberScope === "instance" && memberIdLooksStatic(memberId, sourceCache))
|
|
867
|
+
continue;
|
|
401
868
|
matches.add(memberId);
|
|
402
869
|
}
|
|
403
870
|
}
|