@lzehrung/codegraph 2.3.30 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -137
- package/codegraph-skill/codegraph/SKILL.md +5 -3
- package/dist/agent/artifact.d.ts +2 -0
- package/dist/agent/artifact.d.ts.map +1 -1
- package/dist/agent/artifact.js.map +1 -1
- package/dist/agent/search.d.ts.map +1 -1
- package/dist/agent/search.js +3 -0
- package/dist/agent/search.js.map +1 -1
- package/dist/agent/session.d.ts +3 -0
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +10 -2
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cli.js +42229 -28876
- package/dist/bin/query-index-worker.js +73 -11
- package/dist/cli/affected.d.ts.map +1 -1
- package/dist/cli/affected.js +4 -1
- package/dist/cli/affected.js.map +1 -1
- package/dist/cli/command-catalog.js +1 -1
- package/dist/cli/command-catalog.js.map +1 -1
- package/dist/cli/graph-queries.d.ts.map +1 -1
- package/dist/cli/graph-queries.js +27 -1
- package/dist/cli/graph-queries.js.map +1 -1
- package/dist/cli/help.d.ts +2 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +4 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/options.js +2 -2
- package/dist/cli/options.js.map +1 -1
- package/dist/drift/artifact.d.ts.map +1 -1
- package/dist/drift/artifact.js +15 -18
- package/dist/drift/artifact.js.map +1 -1
- package/dist/drift/compare.js +1 -1
- package/dist/drift/compare.js.map +1 -1
- package/dist/drift/snapshot.d.ts.map +1 -1
- package/dist/drift/snapshot.js +5 -6
- package/dist/drift/snapshot.js.map +1 -1
- package/dist/drift/types.d.ts +2 -0
- package/dist/drift/types.d.ts.map +1 -1
- package/dist/drift/types.js.map +1 -1
- package/dist/graph-builder.d.ts.map +1 -1
- package/dist/graph-builder.js +4 -6
- package/dist/graph-builder.js.map +1 -1
- package/dist/graph-edge-collector.d.ts +3 -0
- package/dist/graph-edge-collector.d.ts.map +1 -1
- package/dist/graph-edge-collector.js +8 -5
- package/dist/graph-edge-collector.js.map +1 -1
- package/dist/graphs/angularjs.d.ts.map +1 -1
- package/dist/graphs/angularjs.js +2 -1
- package/dist/graphs/angularjs.js.map +1 -1
- package/dist/graphs/edge-resolution.d.ts +4 -1
- package/dist/graphs/edge-resolution.d.ts.map +1 -1
- package/dist/graphs/edge-resolution.js +26 -2
- package/dist/graphs/edge-resolution.js.map +1 -1
- package/dist/graphs/specifiers.d.ts.map +1 -1
- package/dist/graphs/specifiers.js +6 -2
- package/dist/graphs/specifiers.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/ast.d.ts +20 -0
- package/dist/graphs/symbol-graph-detailed/ast.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/ast.js +154 -15
- package/dist/graphs/symbol-graph-detailed/ast.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts +51 -8
- package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/edge-passes.js +823 -132
- package/dist/graphs/symbol-graph-detailed/edge-passes.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/import-aliases.d.ts +2 -1
- package/dist/graphs/symbol-graph-detailed/import-aliases.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/import-aliases.js +139 -7
- package/dist/graphs/symbol-graph-detailed/import-aliases.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/member-chains.d.ts +1 -0
- package/dist/graphs/symbol-graph-detailed/member-chains.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/member-chains.js +3 -1
- package/dist/graphs/symbol-graph-detailed/member-chains.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts +128 -22
- package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js +872 -125
- package/dist/graphs/symbol-graph-detailed/receiver-calls.js.map +1 -1
- package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
- package/dist/graphs/symbol-graph-detailed.js +434 -40
- package/dist/graphs/symbol-graph-detailed.js.map +1 -1
- package/dist/graphs/symbol-graph.d.ts +2 -0
- package/dist/graphs/symbol-graph.d.ts.map +1 -1
- package/dist/graphs/symbol-graph.js +34 -16
- package/dist/graphs/symbol-graph.js.map +1 -1
- package/dist/impact/call-compatibility/providers/index.d.ts +12 -0
- package/dist/impact/call-compatibility/providers/index.d.ts.map +1 -1
- package/dist/impact/call-compatibility/providers/index.js +16 -22
- package/dist/impact/call-compatibility/providers/index.js.map +1 -1
- package/dist/impact/call-compatibility/providers/types.d.ts +2 -0
- package/dist/impact/call-compatibility/providers/types.d.ts.map +1 -1
- package/dist/impact/call-compatibility/types.d.ts +6 -0
- package/dist/impact/call-compatibility/types.d.ts.map +1 -1
- package/dist/impact/call-compatibility.d.ts.map +1 -1
- package/dist/impact/call-compatibility.js +316 -552
- package/dist/impact/call-compatibility.js.map +1 -1
- package/dist/impact/map.js +1 -0
- 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 +1 -1
- package/dist/impact/member-resolution-coverage.js.map +1 -1
- package/dist/impact/reference-cache.d.ts.map +1 -1
- package/dist/impact/reference-cache.js +2 -2
- package/dist/impact/reference-cache.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/indexer/ambiguous-resolution.d.ts +11 -0
- package/dist/indexer/ambiguous-resolution.d.ts.map +1 -0
- package/dist/indexer/ambiguous-resolution.js +19 -0
- package/dist/indexer/ambiguous-resolution.js.map +1 -0
- package/dist/indexer/build-cache/module-cache.d.ts +38 -0
- package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache/module-cache.js +151 -9
- package/dist/indexer/build-cache/module-cache.js.map +1 -1
- package/dist/indexer/build-cache/options.d.ts +16 -43
- package/dist/indexer/build-cache/options.d.ts.map +1 -1
- package/dist/indexer/build-cache/options.js +16 -43
- package/dist/indexer/build-cache/options.js.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.d.ts +1 -0
- package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
- package/dist/indexer/build-cache/project-snapshot.js +117 -24
- package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
- package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -1
- package/dist/indexer/build-cache/resolver-environment.js +32 -2
- package/dist/indexer/build-cache/resolver-environment.js.map +1 -1
- package/dist/indexer/build-cache.d.ts +1 -1
- package/dist/indexer/build-cache.d.ts.map +1 -1
- package/dist/indexer/build-cache.js +1 -1
- package/dist/indexer/build-cache.js.map +1 -1
- package/dist/indexer/build-index.d.ts.map +1 -1
- package/dist/indexer/build-index.js +593 -22
- package/dist/indexer/build-index.js.map +1 -1
- package/dist/indexer/call-hierarchy.js +1 -1
- package/dist/indexer/call-hierarchy.js.map +1 -1
- package/dist/indexer/compilation-units.d.ts +101 -0
- package/dist/indexer/compilation-units.d.ts.map +1 -0
- package/dist/indexer/compilation-units.js +605 -0
- package/dist/indexer/compilation-units.js.map +1 -0
- package/dist/indexer/cpp-callables.d.ts +20 -0
- package/dist/indexer/cpp-callables.d.ts.map +1 -0
- package/dist/indexer/cpp-callables.js +554 -0
- package/dist/indexer/cpp-callables.js.map +1 -0
- package/dist/indexer/declaration-visibility.d.ts +36 -2
- package/dist/indexer/declaration-visibility.d.ts.map +1 -1
- package/dist/indexer/declaration-visibility.js +136 -2
- package/dist/indexer/declaration-visibility.js.map +1 -1
- package/dist/indexer/expand-star-imports.d.ts.map +1 -1
- package/dist/indexer/expand-star-imports.js +28 -6
- package/dist/indexer/expand-star-imports.js.map +1 -1
- package/dist/indexer/import-types.d.ts +37 -0
- package/dist/indexer/import-types.d.ts.map +1 -1
- package/dist/indexer/import-types.js +24 -1
- package/dist/indexer/import-types.js.map +1 -1
- 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/context.d.ts +11 -1
- package/dist/indexer/imports/context.d.ts.map +1 -1
- package/dist/indexer/imports/import-binding-tables.d.ts +75 -0
- package/dist/indexer/imports/import-binding-tables.d.ts.map +1 -0
- package/dist/indexer/imports/import-binding-tables.js +544 -0
- package/dist/indexer/imports/import-binding-tables.js.map +1 -0
- package/dist/indexer/imports/js-text-imports.js +4 -4
- 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 +29 -362
- 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 +18 -6
- package/dist/indexer/imports/native-captures.js.map +1 -1
- package/dist/indexer/imports/python.d.ts +10 -2
- package/dist/indexer/imports/python.d.ts.map +1 -1
- package/dist/indexer/imports/python.js +91 -40
- package/dist/indexer/imports/python.js.map +1 -1
- package/dist/indexer/imports/text-import-extractors.d.ts.map +1 -1
- package/dist/indexer/imports/text-import-extractors.js +51 -12
- package/dist/indexer/imports/text-import-extractors.js.map +1 -1
- package/dist/indexer/imports.d.ts.map +1 -1
- package/dist/indexer/imports.js +25 -5
- package/dist/indexer/imports.js.map +1 -1
- package/dist/indexer/incremental-plan.d.ts +33 -0
- package/dist/indexer/incremental-plan.d.ts.map +1 -1
- package/dist/indexer/incremental-plan.js +187 -1
- package/dist/indexer/incremental-plan.js.map +1 -1
- package/dist/indexer/locals-and-exports.d.ts +2 -0
- package/dist/indexer/locals-and-exports.d.ts.map +1 -1
- package/dist/indexer/locals-and-exports.js +565 -54
- package/dist/indexer/locals-and-exports.js.map +1 -1
- package/dist/indexer/name-lookup-policies/c-family.d.ts +7 -0
- package/dist/indexer/name-lookup-policies/c-family.d.ts.map +1 -0
- package/dist/indexer/name-lookup-policies/c-family.js +117 -0
- package/dist/indexer/name-lookup-policies/c-family.js.map +1 -0
- package/dist/indexer/name-lookup-policies/csharp-using-static.d.ts +11 -0
- package/dist/indexer/name-lookup-policies/csharp-using-static.d.ts.map +1 -0
- package/dist/indexer/name-lookup-policies/csharp-using-static.js +136 -0
- package/dist/indexer/name-lookup-policies/csharp-using-static.js.map +1 -0
- package/dist/indexer/name-lookup-policies/implicit-self.d.ts +10 -0
- package/dist/indexer/name-lookup-policies/implicit-self.d.ts.map +1 -0
- package/dist/indexer/name-lookup-policies/implicit-self.js +113 -0
- package/dist/indexer/name-lookup-policies/implicit-self.js.map +1 -0
- package/dist/indexer/name-lookup-policies/index.d.ts +3 -0
- package/dist/indexer/name-lookup-policies/index.d.ts.map +1 -0
- package/dist/indexer/name-lookup-policies/index.js +106 -0
- package/dist/indexer/name-lookup-policies/index.js.map +1 -0
- package/dist/indexer/name-lookup-policies/php.d.ts +3 -0
- package/dist/indexer/name-lookup-policies/php.d.ts.map +1 -0
- package/dist/indexer/name-lookup-policies/php.js +75 -0
- package/dist/indexer/name-lookup-policies/php.js.map +1 -0
- package/dist/indexer/name-resolution-types.d.ts +99 -0
- package/dist/indexer/name-resolution-types.d.ts.map +1 -0
- package/dist/indexer/name-resolution-types.js +2 -0
- package/dist/indexer/name-resolution-types.js.map +1 -0
- package/dist/indexer/name-resolution.d.ts +52 -0
- package/dist/indexer/name-resolution.d.ts.map +1 -0
- package/dist/indexer/name-resolution.js +189 -0
- package/dist/indexer/name-resolution.js.map +1 -0
- package/dist/indexer/navigation-cpp.d.ts +50 -0
- package/dist/indexer/navigation-cpp.d.ts.map +1 -0
- package/dist/indexer/navigation-cpp.js +654 -0
- package/dist/indexer/navigation-cpp.js.map +1 -0
- package/dist/indexer/navigation-goto.d.ts +107 -4
- package/dist/indexer/navigation-goto.d.ts.map +1 -1
- package/dist/indexer/navigation-goto.js +2075 -137
- package/dist/indexer/navigation-goto.js.map +1 -1
- package/dist/indexer/navigation-local.d.ts +18 -2
- package/dist/indexer/navigation-local.d.ts.map +1 -1
- package/dist/indexer/navigation-local.js +498 -61
- package/dist/indexer/navigation-local.js.map +1 -1
- package/dist/indexer/navigation-php.d.ts +66 -0
- package/dist/indexer/navigation-php.d.ts.map +1 -1
- package/dist/indexer/navigation-php.js +287 -4
- package/dist/indexer/navigation-php.js.map +1 -1
- package/dist/indexer/navigation-references.d.ts +72 -5
- package/dist/indexer/navigation-references.d.ts.map +1 -1
- package/dist/indexer/navigation-references.js +620 -54
- package/dist/indexer/navigation-references.js.map +1 -1
- package/dist/indexer/navigation-resolve.d.ts +33 -2
- package/dist/indexer/navigation-resolve.d.ts.map +1 -1
- package/dist/indexer/navigation-resolve.js +446 -193
- package/dist/indexer/navigation-resolve.js.map +1 -1
- package/dist/indexer/navigation.d.ts +28 -2
- package/dist/indexer/navigation.d.ts.map +1 -1
- package/dist/indexer/navigation.js +1082 -151
- package/dist/indexer/navigation.js.map +1 -1
- package/dist/indexer/php-namespace-symbols.d.ts +66 -0
- package/dist/indexer/php-namespace-symbols.d.ts.map +1 -0
- package/dist/indexer/php-namespace-symbols.js +342 -0
- package/dist/indexer/php-namespace-symbols.js.map +1 -0
- package/dist/indexer/reference-context.d.ts +2 -0
- package/dist/indexer/reference-context.d.ts.map +1 -1
- package/dist/indexer/reference-context.js +4 -0
- package/dist/indexer/reference-context.js.map +1 -1
- package/dist/indexer/scope-nodes.d.ts +92 -13
- package/dist/indexer/scope-nodes.d.ts.map +1 -1
- package/dist/indexer/scope-nodes.js +212 -20
- package/dist/indexer/scope-nodes.js.map +1 -1
- package/dist/indexer/scope-types.d.ts +25 -1
- package/dist/indexer/scope-types.d.ts.map +1 -1
- package/dist/indexer/scope.d.ts.map +1 -1
- package/dist/indexer/scope.js +894 -45
- package/dist/indexer/scope.js.map +1 -1
- package/dist/indexer/shared-owner-identity.d.ts +53 -0
- package/dist/indexer/shared-owner-identity.d.ts.map +1 -0
- package/dist/indexer/shared-owner-identity.js +460 -0
- package/dist/indexer/shared-owner-identity.js.map +1 -0
- package/dist/indexer/shared.d.ts +1 -1
- package/dist/indexer/shared.d.ts.map +1 -1
- package/dist/indexer/shared.js +1 -1
- package/dist/indexer/shared.js.map +1 -1
- package/dist/indexer/star-import-precedence.d.ts +114 -0
- package/dist/indexer/star-import-precedence.d.ts.map +1 -0
- package/dist/indexer/star-import-precedence.js +396 -0
- package/dist/indexer/star-import-precedence.js.map +1 -0
- package/dist/indexer/symbols.d.ts +3 -1
- package/dist/indexer/symbols.d.ts.map +1 -1
- package/dist/indexer/symbols.js +58 -18
- package/dist/indexer/symbols.js.map +1 -1
- package/dist/indexer/ts-callables.d.ts +51 -0
- package/dist/indexer/ts-callables.d.ts.map +1 -0
- package/dist/indexer/ts-callables.js +264 -0
- package/dist/indexer/ts-callables.js.map +1 -0
- package/dist/indexer/types.d.ts +23 -1
- package/dist/indexer/types.d.ts.map +1 -1
- package/dist/indexer/unused-exports.d.ts +13 -0
- package/dist/indexer/unused-exports.d.ts.map +1 -0
- package/dist/indexer/unused-exports.js +159 -0
- package/dist/indexer/unused-exports.js.map +1 -0
- package/dist/indexer/workspace-symbols.d.ts.map +1 -1
- package/dist/indexer/workspace-symbols.js +3 -2
- package/dist/indexer/workspace-symbols.js.map +1 -1
- package/dist/indexer.d.ts +2 -2
- package/dist/indexer.d.ts.map +1 -1
- package/dist/indexer.js +1 -1
- package/dist/indexer.js.map +1 -1
- package/dist/languages/callable-arity.d.ts +202 -0
- package/dist/languages/callable-arity.d.ts.map +1 -0
- package/dist/languages/callable-arity.js +1182 -0
- package/dist/languages/callable-arity.js.map +1 -0
- package/dist/languages/definitions/c-family.d.ts.map +1 -1
- package/dist/languages/definitions/c-family.js +30 -1
- package/dist/languages/definitions/c-family.js.map +1 -1
- package/dist/languages/definitions/c.d.ts +4 -0
- package/dist/languages/definitions/c.d.ts.map +1 -1
- package/dist/languages/definitions/c.js +19 -0
- 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 +12 -0
- 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 +2 -8
- package/dist/languages/definitions/csharp.js.map +1 -1
- package/dist/languages/definitions/go.d.ts.map +1 -1
- package/dist/languages/definitions/go.js +3 -0
- package/dist/languages/definitions/go.js.map +1 -1
- package/dist/languages/definitions/javascript.d.ts.map +1 -1
- package/dist/languages/definitions/javascript.js +10 -1
- package/dist/languages/definitions/javascript.js.map +1 -1
- package/dist/languages/definitions/js-family.d.ts +1 -1
- package/dist/languages/definitions/js-family.d.ts.map +1 -1
- package/dist/languages/definitions/js-family.js +7 -1
- package/dist/languages/definitions/js-family.js.map +1 -1
- package/dist/languages/definitions/php.d.ts.map +1 -1
- package/dist/languages/definitions/php.js +5 -1
- package/dist/languages/definitions/php.js.map +1 -1
- package/dist/languages/definitions/typescript.d.ts.map +1 -1
- package/dist/languages/definitions/typescript.js +8 -1
- package/dist/languages/definitions/typescript.js.map +1 -1
- package/dist/languages/definitions/zig.d.ts.map +1 -1
- package/dist/languages/definitions/zig.js +2 -0
- package/dist/languages/definitions/zig.js.map +1 -1
- package/dist/mcp/handlers.js +14 -7
- package/dist/mcp/handlers.js.map +1 -1
- package/dist/review/candidates.d.ts.map +1 -1
- package/dist/review/candidates.js +1 -1
- package/dist/review/candidates.js.map +1 -1
- package/dist/review/deleted.d.ts +3 -3
- package/dist/review/deleted.d.ts.map +1 -1
- package/dist/review/deleted.js +82 -32
- package/dist/review/deleted.js.map +1 -1
- package/dist/review/report.d.ts +1 -0
- package/dist/review/report.d.ts.map +1 -1
- package/dist/review/report.js +1 -1
- package/dist/review/report.js.map +1 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +1 -0
- package/dist/review.js.map +1 -1
- package/dist/sql/navigation.d.ts.map +1 -1
- package/dist/sql/navigation.js +1 -0
- package/dist/sql/navigation.js.map +1 -1
- package/dist/sql/source-graph.d.ts.map +1 -1
- package/dist/sql/source-graph.js +2 -2
- package/dist/sql/source-graph.js.map +1 -1
- package/dist/sqlite/schema.d.ts +1 -1
- package/dist/sqlite/schema.d.ts.map +1 -1
- package/dist/sqlite/schema.js +8 -2
- package/dist/sqlite/schema.js.map +1 -1
- package/dist/sqlite/write.js +2 -2
- package/dist/sqlite/write.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util/bloom-filter.d.ts +7 -1
- package/dist/util/bloom-filter.d.ts.map +1 -1
- package/dist/util/bloom-filter.js +12 -2
- package/dist/util/bloom-filter.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/graph-edges.d.ts +19 -1
- package/dist/util/graph-edges.d.ts.map +1 -1
- package/dist/util/graph-edges.js +30 -4
- package/dist/util/graph-edges.js.map +1 -1
- package/dist/util/identifiers.d.ts +15 -0
- package/dist/util/identifiers.d.ts.map +1 -1
- package/dist/util/identifiers.js +35 -0
- package/dist/util/identifiers.js.map +1 -1
- package/dist/util/member-access-tables.d.ts +129 -0
- package/dist/util/member-access-tables.d.ts.map +1 -0
- package/dist/util/member-access-tables.js +285 -0
- package/dist/util/member-access-tables.js.map +1 -0
- package/dist/util/member-access.d.ts +17 -0
- package/dist/util/member-access.d.ts.map +1 -1
- package/dist/util/member-access.js +138 -93
- package/dist/util/member-access.js.map +1 -1
- package/dist/util/resolution/cargo-targets.d.ts +11 -0
- package/dist/util/resolution/cargo-targets.d.ts.map +1 -1
- package/dist/util/resolution/cargo-targets.js +174 -13
- package/dist/util/resolution/cargo-targets.js.map +1 -1
- package/dist/util/resolution/csharp.d.ts +33 -1
- package/dist/util/resolution/csharp.d.ts.map +1 -1
- package/dist/util/resolution/csharp.js +145 -30
- package/dist/util/resolution/csharp.js.map +1 -1
- package/dist/util/resolution/php.d.ts.map +1 -1
- package/dist/util/resolution/php.js +35 -8
- package/dist/util/resolution/php.js.map +1 -1
- package/dist/util/resolution/python.d.ts +9 -0
- package/dist/util/resolution/python.d.ts.map +1 -1
- package/dist/util/resolution/python.js +46 -0
- 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 +95 -26
- package/dist/util/resolution/rust.js.map +1 -1
- package/dist/util/resolution-candidates.d.ts +5 -0
- package/dist/util/resolution-candidates.d.ts.map +1 -1
- package/dist/util/resolution-candidates.js +16 -3
- package/dist/util/resolution-candidates.js.map +1 -1
- package/dist/util/resolution.d.ts +2 -1
- package/dist/util/resolution.d.ts.map +1 -1
- package/dist/util/resolution.js +96 -5
- package/dist/util/resolution.js.map +1 -1
- package/dist/util/specifiers.d.ts +20 -0
- package/dist/util/specifiers.d.ts.map +1 -1
- package/dist/util/specifiers.js +39 -93
- package/dist/util/specifiers.js.map +1 -1
- package/docs/mcp.md +3 -2
- package/package.json +3 -3
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
import { supportForFileWithoutHeaderSample } from "../languages.js";
|
|
2
2
|
import { ensureParsedContext } from "./parse-context.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getCompilationUnitPeers, IMPLICIT_UNIT_LANGUAGES } from "./compilation-units.js";
|
|
4
|
+
import { getReverseNeighbors, graphAdjacencyFor } from "../graphs/adjacency.js";
|
|
5
|
+
import { isGoExportedMemberName } from "./declaration-visibility.js";
|
|
6
|
+
import { memberSyntaxNamesFreeFunction } from "../util/member-access-tables.js";
|
|
7
|
+
import { phpObjectCreationKeyword } from "../graphs/symbol-graph-detailed/receiver-calls.js";
|
|
8
|
+
import { findCsharpPartialTypeEquivalents, innermostNamespaceImport, resolveMemberAccessDefinition, resolvePhpObjectCreationTarget, resolveRubySuperDefinition, sharedOwnerMemberUnitComplete, supportsReceiverMemberNavigation, } from "./navigation-goto.js";
|
|
9
|
+
import { findClosestBinding, findClosestScopeBinding, findDeclarationNameNode, getOrBuildScopeIndex, toModuleRef, } from "./navigation-local.js";
|
|
10
|
+
import { typescriptCallableCandidatesInContainer } from "./ts-callables.js";
|
|
11
|
+
import { isExplicitMethodCall, scopeNodesFor } from "./scope-nodes.js";
|
|
12
|
+
import { AMBIGUOUS_CPP_OVERLOAD_REASON } from "./ambiguous-resolution.js";
|
|
13
|
+
import { effectiveExplicitBinding, findRubyReopenedConstantParts, isExpandedStarBinding, resolveStarImportedDefinition, resolveStarImportedNamespace, } from "./star-import-precedence.js";
|
|
5
14
|
import { createNavigationProvenance, okGoToResult } from "./navigation-provenance.js";
|
|
6
|
-
import { getPhpQualifiedReference, inferPhpQualifiedReferenceImportType, normalizePhpQualifiedReference, } from "./navigation-php.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
15
|
+
import { getPhpQualifiedReference, inferPhpQualifiedReferenceImportType, isPhpCaseInsensitiveSymbolKind, normalizePhpQualifiedReference, phpLastIdentifierSegment, } from "./navigation-php.js";
|
|
16
|
+
import { ensurePhpNamespaceSymbolIndex, phpReferenceRoleMatchesKind } from "./php-namespace-symbols.js";
|
|
17
|
+
import { buildIndexedCandidateCoverage, buildPhpQualifiedNames, cppCanonicalStructuralExport, describeReferenceStrategies, collectVerifiedNamedNodeReferences, isMemberAccessPropertyRange, getCachedScope, exportFromIdentifier, getCachedReferenceCandidateFiles, getCandidateReferenceNames, hasExpandedNamedImport, pythonParentPackageNamespacePaths, importBindingDeclarationRangeKeys, importBindingIdentityVerificationSites, importBindingReferenceSites, rangeIdentityKey, referenceSiteKey, } from "./navigation-references.js";
|
|
18
|
+
import { directModuleValueEntry, resolveExport, resolveImported, resolveModuleExports, resolvePhpExportByImportType, } from "./navigation-resolve.js";
|
|
9
19
|
import { extractEnclosingBlock, extractLineContext, rangeContains, sameDef } from "./reference-context.js";
|
|
10
20
|
import { DEFAULT_REF_CONTEXT_LINES } from "./shared.js";
|
|
11
|
-
import {} from "./scope.js";
|
|
12
21
|
import {} from "../types.js";
|
|
13
22
|
import { loadNearestTsconfigFor, resolveImportSpecifier } from "../util/resolution.js";
|
|
14
23
|
import { fileIdentityKey } from "../util/paths.js";
|
|
15
24
|
import { sliceText, toRange } from "../util/ast.js";
|
|
25
|
+
import { foldPhpIdentifierCase } from "../util/identifiers.js";
|
|
16
26
|
import { getMemberAccessParts, isMemberAccessNode, isMemberObjectIdentifier, isMemberReferencePropertyIdentifier, isReceiverNameNode, } from "../util/member-access.js";
|
|
27
|
+
import { cppOutOfLineOwnerPath, cppOutOfLineMemberName, cppOutOfLineMemberDeclarationNode, cppQualifiedNameSegments, } from "../graphs/symbol-graph-detailed/receiver-calls.js";
|
|
28
|
+
import { cppCallableShapeForNode, cppEquivalentCallableBindings } from "./cpp-callables.js";
|
|
29
|
+
import { resolveCppExportedCallables, resolveCppQualifiedMemberContainer } from "./navigation-cpp.js";
|
|
17
30
|
import { SymbolKind, } from "./types.js";
|
|
18
31
|
import { findSqlReferences, goToSqlDefinition } from "../sql/navigation.js";
|
|
32
|
+
import { createLoadingParsedFileProvider, phpImportTypeAtPosition, resolveBareName, settleNameResolution, withParsedFiles, } from "./name-resolution.js";
|
|
33
|
+
import { resolveCppQualifiedName } from "./name-lookup-policies/c-family.js";
|
|
19
34
|
export { resolveExport, resolveImported } from "./navigation-resolve.js";
|
|
35
|
+
const CPP_MEMBER_CONTAINER_TYPES = new Set(["class_specifier", "struct_specifier", "union_specifier"]);
|
|
36
|
+
const MAX_REFERENCE_NAMESPACE_DEPTH = 8;
|
|
37
|
+
const MAX_REFERENCE_NAMESPACE_PATHS = 64;
|
|
20
38
|
export async function goToDefinition(index, req, parsedContext) {
|
|
21
39
|
const { file, line, column } = req;
|
|
22
40
|
const mod = index.byFile.get(fileIdentityKey(file));
|
|
@@ -30,11 +48,20 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
30
48
|
const sup = context.sup;
|
|
31
49
|
const source = context.source;
|
|
32
50
|
const tree = context.tree;
|
|
51
|
+
if (sup.id === "php")
|
|
52
|
+
await ensurePhpNamespaceSymbolIndex(index);
|
|
33
53
|
const pos = {
|
|
34
54
|
row: Math.max(0, line - 1),
|
|
35
55
|
column: Math.max(0, column - 1),
|
|
36
56
|
};
|
|
37
57
|
let node = tree.rootNode.descendantForPosition(pos, pos);
|
|
58
|
+
// A position at the start of `b` in `a?.b` also touches the end of the `?.` token, which the
|
|
59
|
+
// parser reports first. The use is the name that starts at the position.
|
|
60
|
+
if (node?.type === "optional_chain" && node.parent) {
|
|
61
|
+
const startsHere = node.parent.namedChildren.find((child) => child.startPosition.row === pos.row && child.startPosition.column === pos.column);
|
|
62
|
+
if (startsHere)
|
|
63
|
+
node = startsHere;
|
|
64
|
+
}
|
|
38
65
|
if (node && node.type === "variable_declarator") {
|
|
39
66
|
const value = node.childForFieldName("value");
|
|
40
67
|
if (value && value.type === "call_expression") {
|
|
@@ -52,6 +79,21 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
52
79
|
node = node.parent;
|
|
53
80
|
if (!node)
|
|
54
81
|
return { status: "not_found", reason: "No node at position" };
|
|
82
|
+
if (sup.id === "ruby" && node.type === "super") {
|
|
83
|
+
const target = await resolveRubySuperDefinition(index, mod, node, source, sup);
|
|
84
|
+
if (!target)
|
|
85
|
+
return { status: "not_found", reason: "No matching Ruby superclass method" };
|
|
86
|
+
return okGoToResult(index, target, { resolution: "member-access", confidence: "medium" });
|
|
87
|
+
}
|
|
88
|
+
if (sup.id === "php") {
|
|
89
|
+
const keyword = phpObjectCreationKeyword(node, source, sup);
|
|
90
|
+
if (keyword) {
|
|
91
|
+
const created = resolvePhpObjectCreationTarget(index, mod, keyword, source, sup);
|
|
92
|
+
if (!created)
|
|
93
|
+
return { status: "not_found", reason: "No matching PHP class" };
|
|
94
|
+
return okGoToResult(index, created, { resolution: "member-access", confidence: "medium" });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
55
97
|
const shorthandId = sup.nodeTypes.shorthandPropertyIdentifier ?? [];
|
|
56
98
|
const isId = sup.nodeTypes.identifier.includes(node.type) || shorthandId.includes(node.type);
|
|
57
99
|
let name = isId ? sliceText(node, source) : null;
|
|
@@ -62,6 +104,9 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
62
104
|
name = sliceText(declNameNode, source);
|
|
63
105
|
}
|
|
64
106
|
}
|
|
107
|
+
const phpImportType = sup.id === "php"
|
|
108
|
+
? (phpImportTypeAtPosition(mod.imports, pos.row, pos.column) ?? inferPhpQualifiedReferenceImportType(node))
|
|
109
|
+
: undefined;
|
|
65
110
|
if (node && sup.supportsExportFromReferences && index.projectRoot) {
|
|
66
111
|
const exportFrom = exportFromIdentifier(index, file, toRange(node), context);
|
|
67
112
|
if (exportFrom?.entry) {
|
|
@@ -93,28 +138,60 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
93
138
|
}
|
|
94
139
|
}
|
|
95
140
|
if (sup.supportsCrossModuleSymbols) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
node
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
141
|
+
let memberAccessNode = null;
|
|
142
|
+
if (node.parent && isMemberAccessNode(sup, node.parent)) {
|
|
143
|
+
memberAccessNode = node.parent;
|
|
144
|
+
}
|
|
145
|
+
else if (node.parent?.type === "template_function" &&
|
|
146
|
+
node.parent.parent &&
|
|
147
|
+
isMemberAccessNode(sup, node.parent.parent)) {
|
|
148
|
+
memberAccessNode = node.parent.parent;
|
|
149
|
+
}
|
|
150
|
+
if (sup.id === "cpp") {
|
|
151
|
+
while (memberAccessNode?.parent && isMemberAccessNode(sup, memberAccessNode.parent)) {
|
|
152
|
+
memberAccessNode = memberAccessNode.parent;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// A receiverless call (Java `hit()`) reuses the member-call node with the name in both slots;
|
|
156
|
+
// it is a bare name, so the shared lookup (implicit members, imports, package) decides it.
|
|
157
|
+
const receiverless = !!memberAccessNode && isReceiverlessMemberCall(sup, memberAccessNode);
|
|
158
|
+
const scopeIndex = memberAccessNode ? getOrBuildScopeIndex(index, file, source, sup, mod, tree) : null;
|
|
159
|
+
const memberAccessResult = !receiverless &&
|
|
160
|
+
!isExplicitMethodCall(scopeNodesFor(sup.id), node) &&
|
|
161
|
+
(await resolveMemberAccessDefinition({
|
|
162
|
+
index,
|
|
163
|
+
mod,
|
|
164
|
+
node,
|
|
165
|
+
source,
|
|
166
|
+
tree,
|
|
167
|
+
sup,
|
|
168
|
+
...(scopeIndex
|
|
169
|
+
? {
|
|
170
|
+
resolveLexicalBinding: (receiver) => {
|
|
171
|
+
if (!isReceiverNameNode(sup, receiver.type))
|
|
172
|
+
return null;
|
|
173
|
+
const receiverName = sliceText(receiver, source);
|
|
174
|
+
const binding = findClosestScopeBinding(scopeIndex, receiverName, receiver, sup);
|
|
175
|
+
if (binding?.kind === "importDefault" ||
|
|
176
|
+
binding?.kind === "importNamed" ||
|
|
177
|
+
binding?.kind === "namespace") {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
return findClosestBinding(scopeIndex, file, receiverName, receiver, sup, source, tree);
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
: {}),
|
|
184
|
+
}));
|
|
115
185
|
if (memberAccessResult) {
|
|
116
186
|
return memberAccessResult;
|
|
117
187
|
}
|
|
188
|
+
if (sup.id === "cpp" && scopeIndex && memberAccessNode) {
|
|
189
|
+
const files = createLoadingParsedFileProvider(index, { file, parsed: context });
|
|
190
|
+
const qualifiedName = cppQualifiedNameSegments(memberAccessNode, source).join("::");
|
|
191
|
+
const qualified = await withParsedFiles(files, () => resolveCppQualifiedName({ index, mod, file, parsed: context, scopeIndex, files, node, name: qualifiedName }));
|
|
192
|
+
if (qualified)
|
|
193
|
+
return qualified;
|
|
194
|
+
}
|
|
118
195
|
if (isUnresolvedReceiverMemberProperty(sup, node)) {
|
|
119
196
|
return { status: "not_found", reason: "No matching receiver member definition" };
|
|
120
197
|
}
|
|
@@ -122,23 +199,14 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
122
199
|
if (sup.id === "php" && phpQualifiedReference && index.projectRoot) {
|
|
123
200
|
const normalizedQualifiedReference = normalizePhpQualifiedReference(phpQualifiedReference, source, tree, node);
|
|
124
201
|
if (normalizedQualifiedReference?.includes("\\")) {
|
|
125
|
-
const
|
|
202
|
+
const qualifiedImportType = phpImportType;
|
|
126
203
|
const resolvedTarget = await resolveImportSpecifier(index.projectRoot, file, normalizedQualifiedReference, "php", {
|
|
127
|
-
...(
|
|
204
|
+
...(qualifiedImportType ? { phpImportType: qualifiedImportType } : {}),
|
|
128
205
|
});
|
|
129
206
|
if (typeof resolvedTarget === "string") {
|
|
130
207
|
const exportedName = normalizedQualifiedReference.split("\\").filter(Boolean).pop() ?? null;
|
|
131
208
|
if (exportedName) {
|
|
132
|
-
|
|
133
|
-
if (phpImportType === "function") {
|
|
134
|
-
preferredKind = SymbolKind.Function;
|
|
135
|
-
}
|
|
136
|
-
else if (phpImportType === "class") {
|
|
137
|
-
preferredKind = SymbolKind.Class;
|
|
138
|
-
}
|
|
139
|
-
const hit = resolveExport(index, resolvedTarget, exportedName, {
|
|
140
|
-
...(preferredKind ? { preferredKind } : {}),
|
|
141
|
-
});
|
|
209
|
+
const hit = resolvePhpExportByImportType(index, resolvedTarget, exportedName, qualifiedImportType);
|
|
142
210
|
if (hit?.kind === "resolved") {
|
|
143
211
|
return okGoToResult(index, hit.def, {
|
|
144
212
|
via: { importedFrom: resolvedTarget, exportedName },
|
|
@@ -152,24 +220,26 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
152
220
|
}
|
|
153
221
|
if (name) {
|
|
154
222
|
const scopeIndex = getOrBuildScopeIndex(index, file, source, sup, mod, tree);
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
223
|
+
const files = createLoadingParsedFileProvider(index, { file, parsed: context });
|
|
224
|
+
const use = {
|
|
225
|
+
index,
|
|
226
|
+
mod,
|
|
227
|
+
file,
|
|
228
|
+
parsed: context,
|
|
229
|
+
scopeIndex,
|
|
230
|
+
files,
|
|
231
|
+
node,
|
|
232
|
+
name,
|
|
233
|
+
...(phpImportType ? { phpImportType } : {}),
|
|
234
|
+
};
|
|
235
|
+
const resolution = await withParsedFiles(files, () => resolveBareName(use));
|
|
236
|
+
const settled = await settleNameResolution(use, resolution, {
|
|
237
|
+
recoverIncludedStar: (lookupName, cNamespace) => recoverIncludedCallableStar(index, mod, sup.id, lookupName, cNamespace, node, source),
|
|
238
|
+
});
|
|
239
|
+
if (settled)
|
|
240
|
+
return settled;
|
|
168
241
|
}
|
|
169
|
-
const localAtPosition = mod.locals.find((local) =>
|
|
170
|
-
row: line,
|
|
171
|
-
column: column,
|
|
172
|
-
}));
|
|
242
|
+
const localAtPosition = mod.locals.find((local) => local.range.start.index === node.startIndex && local.range.end.index === node.endIndex);
|
|
173
243
|
if (localAtPosition) {
|
|
174
244
|
return okGoToResult(index, localAtPosition, {
|
|
175
245
|
resolution: "exact",
|
|
@@ -181,9 +251,23 @@ export async function goToDefinition(index, req, parsedContext) {
|
|
|
181
251
|
reason: "No matching local or imported definition",
|
|
182
252
|
};
|
|
183
253
|
}
|
|
254
|
+
/** Whether a member-access node has no receiver distinct from its member name. */
|
|
255
|
+
function isReceiverlessMemberCall(sup, access) {
|
|
256
|
+
// Java `<T>hit()` has no `object` field; the generic parts fall back to the type arguments.
|
|
257
|
+
if (access.type === "method_invocation")
|
|
258
|
+
return !access.childForFieldName("object");
|
|
259
|
+
const { object, property } = getMemberAccessParts(sup, access);
|
|
260
|
+
return !!property && (!object || object.startIndex === property.startIndex);
|
|
261
|
+
}
|
|
262
|
+
function swiftNavigationMemberAccess(sup, node) {
|
|
263
|
+
if (sup.id !== "swift" || node.parent?.type !== "navigation_suffix")
|
|
264
|
+
return null;
|
|
265
|
+
const access = node.parent.parent;
|
|
266
|
+
return access && isMemberAccessNode(sup, access) ? access : null;
|
|
267
|
+
}
|
|
184
268
|
function isUnresolvedReceiverMemberProperty(sup, node) {
|
|
185
|
-
const parent = node.parent;
|
|
186
|
-
if (!parent || !supportsReceiverMemberNavigation(sup.id) || !isMemberAccessNode(sup, parent)) {
|
|
269
|
+
const parent = swiftNavigationMemberAccess(sup, node) ?? node.parent;
|
|
270
|
+
if (!parent || (!supportsReceiverMemberNavigation(sup.id) && sup.id !== "c") || !isMemberAccessNode(sup, parent)) {
|
|
187
271
|
return false;
|
|
188
272
|
}
|
|
189
273
|
const { object, property } = getMemberAccessParts(sup, parent);
|
|
@@ -195,6 +279,7 @@ function isUnresolvedReceiverMemberProperty(sup, node) {
|
|
|
195
279
|
// Namespace and nested-type qualification still resolve through the language
|
|
196
280
|
// paths below; only value-receiver members must not fall back to a bare name.
|
|
197
281
|
if (parent.type === "qualified_name" ||
|
|
282
|
+
parent.type === "alias_qualified_name" ||
|
|
198
283
|
parent.type === "qualified_identifier" ||
|
|
199
284
|
parent.type === "qualified_type" ||
|
|
200
285
|
parent.type === "scoped_identifier" ||
|
|
@@ -232,6 +317,110 @@ export async function findUsageReferences(index, req, opts) {
|
|
|
232
317
|
export async function findRenameReferences(index, def, opts) {
|
|
233
318
|
return findReferencesInternal(index, { def }, opts, "rename");
|
|
234
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Proven equivalent callable definition family for one definition site.
|
|
322
|
+
*
|
|
323
|
+
* Returns the incoming definition first — enriched to its indexed SymbolDef when the definition
|
|
324
|
+
* file's module.locals holds an exact identity match (same file, kind, localName, and full range
|
|
325
|
+
* span), restoring metadata such as `isMember` — followed by every equivalent
|
|
326
|
+
* declaration/definition that reference collection itself proves: same-scope prototype/definition
|
|
327
|
+
* pairs (C and C++), C prototypes linked to definitions through an include, namespace-qualified
|
|
328
|
+
* equivalents, the in-class declaration for out-of-line
|
|
329
|
+
* member definitions, and out-of-line definitions for in-class member declarations linked through
|
|
330
|
+
* the export index. Matching stays conservative: candidates must already exist in the definition
|
|
331
|
+
* file's scope bindings or the export index with a proven signature; no name-only or arity-only
|
|
332
|
+
* equivalence is introduced, and overload sets are never collapsed.
|
|
333
|
+
*
|
|
334
|
+
* `parsedContext` is optional; when omitted the definition file is parsed on demand. Definitions
|
|
335
|
+
* outside C/C++ return just the enriched definition.
|
|
336
|
+
*/
|
|
337
|
+
/**
|
|
338
|
+
* Two included declarations of one C/C++ function are one callable, using
|
|
339
|
+
* {@link getCppEquivalentCallableDefinitions}. Different signatures stay an
|
|
340
|
+
* overload set and are chosen by call arity. Non-callables (typedefs, structs)
|
|
341
|
+
* are left to the star-import ambiguity result.
|
|
342
|
+
*/
|
|
343
|
+
export async function recoverIncludedCallableStar(index, mod, languageId, name, cNamespace, node, source) {
|
|
344
|
+
const candidates = [];
|
|
345
|
+
for (const imp of mod.imports) {
|
|
346
|
+
if (isExpandedStarBinding(imp, mod.imports) || imp.kind !== "star")
|
|
347
|
+
continue;
|
|
348
|
+
const def = resolveStarImportedDefinition(index, imp, name, languageId, cNamespace);
|
|
349
|
+
if (def)
|
|
350
|
+
candidates.push({ imp, def });
|
|
351
|
+
}
|
|
352
|
+
const functions = candidates.filter((candidate) => candidate.def.kind === SymbolKind.Function && !candidate.def.cTag);
|
|
353
|
+
if (functions.length < 2)
|
|
354
|
+
return null;
|
|
355
|
+
const familyOf = new Map();
|
|
356
|
+
const family = async (def) => {
|
|
357
|
+
const key = referenceSiteKey(def.file, def.range);
|
|
358
|
+
const cached = familyOf.get(key);
|
|
359
|
+
if (cached)
|
|
360
|
+
return cached;
|
|
361
|
+
const defs = await getCppEquivalentCallableDefinitions(index, def);
|
|
362
|
+
familyOf.set(key, defs);
|
|
363
|
+
return defs;
|
|
364
|
+
};
|
|
365
|
+
const parent = functions.map((_, candidateIndex) => candidateIndex);
|
|
366
|
+
const find = (start) => {
|
|
367
|
+
let current = start;
|
|
368
|
+
while (parent[current] !== current) {
|
|
369
|
+
const next = parent[current];
|
|
370
|
+
parent[current] = parent[next] ?? next;
|
|
371
|
+
current = next;
|
|
372
|
+
}
|
|
373
|
+
return current;
|
|
374
|
+
};
|
|
375
|
+
const unite = (left, right) => {
|
|
376
|
+
const leftRoot = find(left);
|
|
377
|
+
const rightRoot = find(right);
|
|
378
|
+
if (leftRoot !== rightRoot)
|
|
379
|
+
parent[rightRoot] = leftRoot;
|
|
380
|
+
};
|
|
381
|
+
for (let left = 0; left < functions.length; left += 1) {
|
|
382
|
+
const defs = await family(functions[left].def);
|
|
383
|
+
for (let right = left + 1; right < functions.length; right += 1) {
|
|
384
|
+
if (defs.some((item) => sameDef(item, functions[right].def, index.languageExtensions)))
|
|
385
|
+
unite(left, right);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const roots = new Set(functions.map((_, candidateIndex) => find(candidateIndex)));
|
|
389
|
+
if (roots.size === 1) {
|
|
390
|
+
const chosen = functions[0];
|
|
391
|
+
const importedFrom = toModuleRef(chosen.imp.resolved);
|
|
392
|
+
return okGoToResult(index, chosen.def, {
|
|
393
|
+
via: { ...(importedFrom ? { importedFrom } : {}), exportedName: name },
|
|
394
|
+
resolution: "import-star",
|
|
395
|
+
confidence: "medium",
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
const parsedByFile = new Map();
|
|
399
|
+
for (const candidate of functions) {
|
|
400
|
+
const key = fileIdentityKey(candidate.def.file);
|
|
401
|
+
if (parsedByFile.has(key))
|
|
402
|
+
continue;
|
|
403
|
+
try {
|
|
404
|
+
parsedByFile.set(key, await ensureParsedContext(candidate.def.file, index.parsed?.get(key), index.languageExtensions));
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return languageId === "cpp"
|
|
408
|
+
? { status: "not_found", reason: AMBIGUOUS_CPP_OVERLOAD_REASON }
|
|
409
|
+
: { status: "not_found", reason: "No matching local or imported definition" };
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const selected = resolveCppExportedCallables(index, functions.map((candidate) => candidate.def), node, source, (targetFile) => parsedByFile.get(fileIdentityKey(targetFile)) ?? null);
|
|
413
|
+
if (selected) {
|
|
414
|
+
return okGoToResult(index, selected, { resolution: "exact", confidence: "high" });
|
|
415
|
+
}
|
|
416
|
+
return languageId === "cpp"
|
|
417
|
+
? { status: "not_found", reason: AMBIGUOUS_CPP_OVERLOAD_REASON }
|
|
418
|
+
: { status: "not_found", reason: "No matching local or imported definition" };
|
|
419
|
+
}
|
|
420
|
+
export async function getCppEquivalentCallableDefinitions(index, def, parsedContext) {
|
|
421
|
+
const family = await cppEquivalentCallableFamily(index, def, parsedContext);
|
|
422
|
+
return [family.definition, ...family.equivalents];
|
|
423
|
+
}
|
|
235
424
|
async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
236
425
|
let def = null;
|
|
237
426
|
let provenance;
|
|
@@ -260,6 +449,17 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
260
449
|
if (!def) {
|
|
261
450
|
return { status: "not_found", reason: "Could not resolve definition" };
|
|
262
451
|
}
|
|
452
|
+
if (def.cTag) {
|
|
453
|
+
const canonical = await goToDefinition(index, {
|
|
454
|
+
file: def.file,
|
|
455
|
+
line: def.range.start.line,
|
|
456
|
+
column: def.range.start.column,
|
|
457
|
+
});
|
|
458
|
+
if (canonical.status === "ok") {
|
|
459
|
+
def = canonical.definition;
|
|
460
|
+
provenance = canonical.provenance;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
263
463
|
const maxReferences = typeof opts?.maxReferences === "number" && opts.maxReferences > 0 ? opts.maxReferences : undefined;
|
|
264
464
|
const sqlReferences = await findSqlReferences(index, def, {
|
|
265
465
|
includeDefinition: collectionMode === "all",
|
|
@@ -293,16 +493,23 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
293
493
|
};
|
|
294
494
|
const parsedDef = index.parsed?.get(fileIdentityKey(definitionFile));
|
|
295
495
|
const parsedContext = await ensureParsedContext(definitionFile, parsedDef, index.languageExtensions);
|
|
496
|
+
let cNamespace;
|
|
497
|
+
if (parsedContext.sup.id === "c")
|
|
498
|
+
cNamespace = def.cTag ? "tag" : "ordinary";
|
|
499
|
+
const exportOptions = cNamespace ? { cNamespace } : undefined;
|
|
296
500
|
const mod = index.byFile.get(fileIdentityKey(definitionFile));
|
|
297
501
|
if (!mod)
|
|
298
502
|
return { status: "not_found", reason: "Module not found" };
|
|
299
|
-
const scope = getCachedScope(index, definitionFile, mod, parsedContext);
|
|
300
503
|
const refs = [];
|
|
301
504
|
const seenRefs = new Map();
|
|
302
505
|
const collectionLimit = maxReferences !== undefined ? maxReferences + 1 : undefined;
|
|
303
506
|
const hasReachedCollectionLimit = () => collectionLimit !== undefined && refs.length >= collectionLimit;
|
|
304
507
|
const remainingCollectionSlots = () => collectionLimit !== undefined ? Math.max(0, collectionLimit - refs.length) : undefined;
|
|
305
|
-
const
|
|
508
|
+
const referenceMetadataRank = (ref) => {
|
|
509
|
+
if (ref.via?.importBinding === "imported")
|
|
510
|
+
return 2;
|
|
511
|
+
return ref.via?.namespaceMember ? 1 : 0;
|
|
512
|
+
};
|
|
306
513
|
const pushRef = (ref) => {
|
|
307
514
|
if (!includeReference(ref))
|
|
308
515
|
return;
|
|
@@ -310,7 +517,7 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
310
517
|
const existingIndex = seenRefs.get(key);
|
|
311
518
|
if (existingIndex !== undefined) {
|
|
312
519
|
const existing = refs[existingIndex];
|
|
313
|
-
if (
|
|
520
|
+
if (referenceMetadataRank(ref) > referenceMetadataRank(existing)) {
|
|
314
521
|
refs[existingIndex] = ref;
|
|
315
522
|
}
|
|
316
523
|
return;
|
|
@@ -320,29 +527,128 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
320
527
|
seenRefs.set(key, refs.length);
|
|
321
528
|
refs.push(ref);
|
|
322
529
|
};
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
530
|
+
const family = await cppEquivalentCallableFamily(index, def, parsedContext);
|
|
531
|
+
const definition = family.definition;
|
|
532
|
+
const referenceDef = family.referenceDef;
|
|
533
|
+
const localBinding = family.localBinding;
|
|
534
|
+
pushRef({ file: definitionFile, range: definition.range });
|
|
535
|
+
const receiverMemberDefinition = isReceiverMemberDefinition(definition, parsedContext, !!family.receiverOwner);
|
|
536
|
+
const csharpPartialEquivalents = parsedContext.sup.id === "csharp" &&
|
|
537
|
+
!definition.isMember &&
|
|
538
|
+
(definition.kind === SymbolKind.Class ||
|
|
539
|
+
definition.kind === SymbolKind.Interface ||
|
|
540
|
+
definition.kind === SymbolKind.TypeAlias)
|
|
541
|
+
? await findCsharpPartialTypeEquivalents(index, definition)
|
|
542
|
+
: [];
|
|
543
|
+
const rubyReopen = parsedContext.sup.id === "ruby" ? findRubyReopenedConstantParts(index, definition) : undefined;
|
|
544
|
+
const equivalentDefinitions = [...family.equivalents, ...csharpPartialEquivalents, ...(rubyReopen?.parts ?? [])];
|
|
545
|
+
for (const equivalent of equivalentDefinitions) {
|
|
546
|
+
pushRef({ file: equivalent.file, range: equivalent.range });
|
|
547
|
+
}
|
|
548
|
+
const matchesReferenceDefinition = (candidate) => sameDef(candidate, definition, index.languageExtensions) ||
|
|
549
|
+
equivalentDefinitions.some((equivalent) => sameDef(candidate, equivalent, index.languageExtensions));
|
|
550
|
+
const exportedNames = [];
|
|
551
|
+
for (const candidate of [definition, ...equivalentDefinitions]) {
|
|
552
|
+
const candidateModule = index.byFile.get(fileIdentityKey(candidate.file));
|
|
553
|
+
for (const entry of candidateModule?.exports ?? []) {
|
|
554
|
+
if (entry.type === "local" &&
|
|
555
|
+
sameDef(entry.target, candidate, index.languageExtensions) &&
|
|
556
|
+
!exportedNames.includes(entry.exportedAs)) {
|
|
557
|
+
exportedNames.push(entry.exportedAs);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (!exportedNames.length && !receiverMemberDefinition) {
|
|
562
|
+
exportedNames.push(definition.localName);
|
|
563
|
+
}
|
|
564
|
+
const exportedNameSet = new Set(exportedNames);
|
|
565
|
+
const phpQualifiedNames = await buildPhpQualifiedNames(index, definitionFile, definition);
|
|
566
|
+
const scansReceiverReferences = shouldScanVerifiedReferences(definition, parsedContext, receiverMemberDefinition);
|
|
567
|
+
const scansNamespaceReferences = parsedContext.sup.id === "csharp" &&
|
|
568
|
+
!definition.isMember &&
|
|
569
|
+
(definition.kind === SymbolKind.Class ||
|
|
570
|
+
definition.kind === SymbolKind.Interface ||
|
|
571
|
+
definition.kind === SymbolKind.TypeAlias);
|
|
572
|
+
let requiresTypeScriptOverloadVerifiedScan = false;
|
|
573
|
+
if ((parsedContext.sup.id === "ts" || parsedContext.sup.id === "tsx") &&
|
|
574
|
+
definition.kind === SymbolKind.Function &&
|
|
575
|
+
!receiverMemberDefinition &&
|
|
576
|
+
localBinding?.sameScopeFunctionBindings) {
|
|
577
|
+
const start = definition.range.start.index ?? 0;
|
|
578
|
+
const end = definition.range.end.index ?? start;
|
|
579
|
+
const overloadBindings = typescriptCallableCandidatesInContainer(localBinding.sameScopeFunctionBindings, parsedContext.tree, (binding) => binding.def, start, end);
|
|
580
|
+
requiresTypeScriptOverloadVerifiedScan = overloadBindings.length > 1;
|
|
581
|
+
}
|
|
582
|
+
const requiresSameFileVerifiedScan = ((parsedContext.sup.id === "c" || parsedContext.sup.id === "cpp") &&
|
|
583
|
+
definition.kind === SymbolKind.Function &&
|
|
584
|
+
!receiverMemberDefinition) ||
|
|
585
|
+
scansNamespaceReferences ||
|
|
586
|
+
requiresTypeScriptOverloadVerifiedScan;
|
|
587
|
+
let sameFileVerifiedScanExecuted = false;
|
|
588
|
+
const receiverProofUnavailableFiles = new Map();
|
|
589
|
+
let memberCallOccurrencesNeedVerification = false;
|
|
590
|
+
if (localBinding &&
|
|
591
|
+
localBinding.occurrencesComplete !== false &&
|
|
592
|
+
!requiresSameFileVerifiedScan &&
|
|
593
|
+
!scansReceiverReferences &&
|
|
594
|
+
!requiresTypeScriptOverloadVerifiedScan) {
|
|
595
|
+
const verifyMemberCalls = memberSyntaxNamesFreeFunction(parsedContext.sup.id);
|
|
328
596
|
for (const occurrence of localBinding.occurrences) {
|
|
329
597
|
if (hasReachedCollectionLimit())
|
|
330
598
|
break;
|
|
599
|
+
// A scope occurrence is not proof of a member call. Languages that invoke a free
|
|
600
|
+
// function that way verify the site; an unresolvable receiver stays unavailable.
|
|
601
|
+
if (verifyMemberCalls && isMemberAccessPropertyRange(parsedContext, occurrence)) {
|
|
602
|
+
memberCallOccurrencesNeedVerification = true;
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
331
605
|
pushRef({ file: definitionFile, range: occurrence });
|
|
332
606
|
}
|
|
333
607
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
608
|
+
if (memberCallOccurrencesNeedVerification && !hasReachedCollectionLimit()) {
|
|
609
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, definitionFile, referenceDef.localName, referenceDef, (params, parsed) => goToDefinition(index, params, parsed), remainingCollectionSlots(), verifiedReferenceFilter(definitionFile), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
610
|
+
for (const { range, provenance, via } of ranges) {
|
|
611
|
+
if (hasReachedCollectionLimit())
|
|
612
|
+
break;
|
|
613
|
+
pushRef({ file: definitionFile, range, ...(via ? { via } : {}), ...(provenance ? { provenance } : {}) });
|
|
338
614
|
}
|
|
339
615
|
}
|
|
340
|
-
if (
|
|
341
|
-
|
|
616
|
+
if (requiresSameFileVerifiedScan && !hasReachedCollectionLimit()) {
|
|
617
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, definitionFile, referenceDef.localName, referenceDef, (params, parsed) => goToDefinition(index, params, parsed), remainingCollectionSlots(), verifiedReferenceFilter(definitionFile), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
618
|
+
sameFileVerifiedScanExecuted = true;
|
|
619
|
+
for (const { range, provenance, via } of ranges) {
|
|
620
|
+
if (hasReachedCollectionLimit())
|
|
621
|
+
break;
|
|
622
|
+
pushRef({
|
|
623
|
+
file: definitionFile,
|
|
624
|
+
range,
|
|
625
|
+
...(via ? { via } : {}),
|
|
626
|
+
...(provenance ? { provenance } : {}),
|
|
627
|
+
});
|
|
628
|
+
}
|
|
342
629
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
630
|
+
let candidateFiles = [
|
|
631
|
+
...new Map([referenceDef, ...equivalentDefinitions]
|
|
632
|
+
.flatMap((candidate) => getCachedReferenceCandidateFiles(index, candidate, exportedNames, !!phpQualifiedNames.length, parsedContext.sup.id))
|
|
633
|
+
.map((candidateFile) => [fileIdentityKey(candidateFile), candidateFile])).values(),
|
|
634
|
+
].sort((left, right) => left.localeCompare(right));
|
|
635
|
+
// Candidates that share a compilation unit with the definition (or an equivalent
|
|
636
|
+
// declaration) can name it without an import edge; the per-candidate scan below treats
|
|
637
|
+
// them as bare-name reference sources in addition to the import-derived branches.
|
|
638
|
+
const unitPeerKeys = new Set();
|
|
639
|
+
for (const candidate of [referenceDef, ...equivalentDefinitions]) {
|
|
640
|
+
for (const unitPeer of getCompilationUnitPeers(index, candidate.file, parsedContext.sup.id === "csharp" ? { csharpQualifiedName: true } : undefined).files) {
|
|
641
|
+
unitPeerKeys.add(fileIdentityKey(unitPeer));
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
// A bloom filter holds each candidate file's identifiers in that file's own spelling, and a
|
|
645
|
+
// probe can only test one spelling. PHP resolves class, interface, trait, enum, and function
|
|
646
|
+
// names case-insensitively, so `new \App\sErViCe()` must still match a `Service` definition.
|
|
647
|
+
// `buildBloomFilterFromSource` stores every PHP file's identifiers both in their own spelling
|
|
648
|
+
// and ASCII-case-folded, so folding the probe's last identifier segment here narrows those
|
|
649
|
+
// kinds exactly instead of skipping narrowing and walking every indexed PHP file. Variables,
|
|
650
|
+
// properties, and constants stay case-sensitive and probe with their own spelling.
|
|
651
|
+
const phpCaseInsensitiveDefinition = phpQualifiedNames.length && isPhpCaseInsensitiveSymbolKind(definition.kind);
|
|
346
652
|
if (index.bloomFilters && phpQualifiedNames.length) {
|
|
347
653
|
candidateFiles = candidateFiles.filter((candidateFile) => {
|
|
348
654
|
const module = index.byFile.get(fileIdentityKey(candidateFile));
|
|
@@ -355,12 +661,62 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
355
661
|
const normalizeIdentifier = supportForFileWithoutHeaderSample(candidateFile, index.languageExtensions)?.normalizeIdentifier ??
|
|
356
662
|
((name) => name);
|
|
357
663
|
const aliases = getCandidateReferenceNames(module, definitionFile, exportedNameSet);
|
|
358
|
-
|
|
359
|
-
|
|
664
|
+
const probeNames = aliases.length ? aliases : [...exportedNames, ...phpQualifiedNames];
|
|
665
|
+
if (phpCaseInsensitiveDefinition) {
|
|
666
|
+
return probeNames.some((candidateName) => filter.mightContain(foldPhpIdentifierCase(normalizeIdentifier(phpLastIdentifierSegment(candidateName)))));
|
|
360
667
|
}
|
|
361
|
-
return
|
|
668
|
+
return probeNames.some((candidateName) => filter.mightContain(normalizeIdentifier(phpLastIdentifierSegment(candidateName))));
|
|
362
669
|
});
|
|
363
670
|
}
|
|
671
|
+
// A file reached only through a dynamic import, or another construct that never creates a
|
|
672
|
+
// modeled ImportBinding, still leaves a real file-dependency edge behind. Without this, such
|
|
673
|
+
// a file is never a scan candidate at all, so a genuine same-name use inside it is silently
|
|
674
|
+
// invisible instead of making coverage `partial` — exactly the gap F3 forbids. Member
|
|
675
|
+
// definitions already get every file scanned below, so this only adds files for the narrower,
|
|
676
|
+
// import-graph-driven search.
|
|
677
|
+
if (!definition.isMember && !scansReceiverReferences) {
|
|
678
|
+
const candidateFileKeys = new Set(candidateFiles.map((file) => fileIdentityKey(file)));
|
|
679
|
+
const adjacency = index.graphAdjacency ?? graphAdjacencyFor(index.graph);
|
|
680
|
+
const graphLinkedOrphans = new Map();
|
|
681
|
+
for (const candidate of [definition, ...equivalentDefinitions]) {
|
|
682
|
+
for (const importer of getReverseNeighbors(adjacency, candidate.file)) {
|
|
683
|
+
const key = fileIdentityKey(importer);
|
|
684
|
+
if (key === fileIdentityKey(definitionFile) || candidateFileKeys.has(key))
|
|
685
|
+
continue;
|
|
686
|
+
graphLinkedOrphans.set(key, importer);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// A star import can expose a namespace reexport rather than the member definition itself.
|
|
690
|
+
// Include direct star importers of that package so their namespace member use is verified.
|
|
691
|
+
const namespaceTargetKeys = new Set([definition, ...equivalentDefinitions].map((candidate) => fileIdentityKey(candidate.file)));
|
|
692
|
+
for (const namespaceOwner of index.byFile.values()) {
|
|
693
|
+
const reexportsDefinitionAsNamespace = namespaceOwner.exports.some((entry) => entry.type === "namespaceReexport" && namespaceTargetKeys.has(fileIdentityKey(entry.fromModule)));
|
|
694
|
+
if (!reexportsDefinitionAsNamespace)
|
|
695
|
+
continue;
|
|
696
|
+
const namespaceOwnerKey = fileIdentityKey(namespaceOwner.file);
|
|
697
|
+
if (namespaceOwnerKey !== fileIdentityKey(definitionFile) && !candidateFileKeys.has(namespaceOwnerKey)) {
|
|
698
|
+
graphLinkedOrphans.set(namespaceOwnerKey, namespaceOwner.file);
|
|
699
|
+
}
|
|
700
|
+
for (const importer of getReverseNeighbors(adjacency, namespaceOwner.file)) {
|
|
701
|
+
const key = fileIdentityKey(importer);
|
|
702
|
+
if (key === fileIdentityKey(definitionFile) || candidateFileKeys.has(key))
|
|
703
|
+
continue;
|
|
704
|
+
const importerModule = index.byFile.get(key);
|
|
705
|
+
const importsNamespaceOwner = importerModule?.imports.some((candidate) => candidate.kind === "star" &&
|
|
706
|
+
typeof candidate.resolved === "string" &&
|
|
707
|
+
fileIdentityKey(candidate.resolved) === namespaceOwnerKey);
|
|
708
|
+
if (importsNamespaceOwner)
|
|
709
|
+
graphLinkedOrphans.set(key, importer);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
for (const [key, file] of graphLinkedOrphans) {
|
|
713
|
+
candidateFiles.push(file);
|
|
714
|
+
candidateFileKeys.add(key);
|
|
715
|
+
unitPeerKeys.add(key);
|
|
716
|
+
}
|
|
717
|
+
if (graphLinkedOrphans.size)
|
|
718
|
+
candidateFiles.sort((left, right) => left.localeCompare(right));
|
|
719
|
+
}
|
|
364
720
|
for (const fileId of candidateFiles) {
|
|
365
721
|
if (hasReachedCollectionLimit())
|
|
366
722
|
break;
|
|
@@ -392,10 +748,10 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
392
748
|
if (!exportedNameSet.has(entry.sourceSpecifier))
|
|
393
749
|
continue;
|
|
394
750
|
const resolved = resolveExport(index, entry.fromModule, entry.sourceSpecifier);
|
|
395
|
-
if (resolved?.kind === "resolved" && !
|
|
751
|
+
if (resolved?.kind === "resolved" && !matchesReferenceDefinition(resolved.def))
|
|
396
752
|
continue;
|
|
397
753
|
const remainingReferences = remainingCollectionSlots();
|
|
398
|
-
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, entry.sourceSpecifier,
|
|
754
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, entry.sourceSpecifier, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile));
|
|
399
755
|
for (const { range, provenance, via } of ranges) {
|
|
400
756
|
if (hasReachedCollectionLimit())
|
|
401
757
|
break;
|
|
@@ -408,6 +764,8 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
408
764
|
for (const imp of module.imports) {
|
|
409
765
|
if (hasReachedCollectionLimit())
|
|
410
766
|
break;
|
|
767
|
+
if (cNamespace && imp.kind === "named" && (imp.cNamespace ?? "ordinary") !== cNamespace)
|
|
768
|
+
continue;
|
|
411
769
|
const targetFile = typeof imp.resolved === "string" ? imp.resolved : undefined;
|
|
412
770
|
const bindingSites = importBindingReferenceSites(imp);
|
|
413
771
|
let verifiedBindingMatches;
|
|
@@ -415,6 +773,11 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
415
773
|
if (verifiedBindingMatches !== undefined)
|
|
416
774
|
return verifiedBindingMatches;
|
|
417
775
|
verifiedBindingMatches = false;
|
|
776
|
+
if (imp.kind === "named" &&
|
|
777
|
+
imp.mechanism === "php" &&
|
|
778
|
+
!phpReferenceRoleMatchesKind(imp.phpImportType ?? "class", definition.kind)) {
|
|
779
|
+
return verifiedBindingMatches;
|
|
780
|
+
}
|
|
418
781
|
const parsed = await ensureCandidateParsed();
|
|
419
782
|
for (const verificationSite of importBindingIdentityVerificationSites(imp)) {
|
|
420
783
|
const resolved = await goToDefinition(index, {
|
|
@@ -422,7 +785,7 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
422
785
|
line: verificationSite.range.start.line,
|
|
423
786
|
column: verificationSite.range.start.column,
|
|
424
787
|
}, parsed);
|
|
425
|
-
if (resolved.status === "ok" &&
|
|
788
|
+
if (resolved.status === "ok" && matchesReferenceDefinition(resolved.definition)) {
|
|
426
789
|
verifiedBindingMatches = true;
|
|
427
790
|
break;
|
|
428
791
|
}
|
|
@@ -443,20 +806,95 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
443
806
|
via: { import: imp, importBinding: site.importBinding },
|
|
444
807
|
});
|
|
445
808
|
}
|
|
809
|
+
if (!hasReachedCollectionLimit() && imp.kind === "named") {
|
|
810
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, imp.local, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingCollectionSlots(), verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile));
|
|
811
|
+
for (const { range, provenance, via } of ranges) {
|
|
812
|
+
if (hasReachedCollectionLimit())
|
|
813
|
+
break;
|
|
814
|
+
pushRef({
|
|
815
|
+
file: fileId,
|
|
816
|
+
range,
|
|
817
|
+
via: { import: imp, ...(via ?? {}) },
|
|
818
|
+
...(provenance ? { provenance } : {}),
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
}
|
|
446
822
|
continue;
|
|
447
823
|
}
|
|
824
|
+
const cjsTargetModule = imp.kind === "namespace" && imp.mechanism === "cjs" ? index.byFile.get(fileIdentityKey(targetFile)) : undefined;
|
|
825
|
+
const cjsExportedName = cjsTargetModule && directModuleValueEntry(cjsTargetModule)?.exportedAs;
|
|
448
826
|
for (const exportedName of exportedNames) {
|
|
449
827
|
if (hasReachedCollectionLimit())
|
|
450
828
|
break;
|
|
451
|
-
|
|
452
|
-
|
|
829
|
+
const cjsModuleValue = cjsExportedName === exportedName;
|
|
830
|
+
if (imp.kind === "namespace" && !cjsModuleValue) {
|
|
831
|
+
if (!isGoExportedMemberName(supportForFileWithoutHeaderSample(fileId, index.languageExtensions)?.id, exportedName)) {
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
const hit = resolveExport(index, targetFile, exportedName, exportOptions);
|
|
453
835
|
const matchesDef = hit?.kind === "resolved"
|
|
454
|
-
?
|
|
455
|
-
: imp.kind === "namespace" &&
|
|
456
|
-
|
|
836
|
+
? matchesReferenceDefinition(hit.def)
|
|
837
|
+
: imp.kind === "namespace" &&
|
|
838
|
+
[definition, ...equivalentDefinitions].some((candidate) => fileIdentityKey(targetFile) === fileIdentityKey(candidate.file));
|
|
839
|
+
// Python binds the first segment of an unaliased dotted import, while an alias
|
|
840
|
+
// binds the whole module. Other namespaces use their local name directly.
|
|
841
|
+
const namespaceSearchName = imp.mechanism === "python" && imp.from.includes(".") && !imp.explicitAlias ? imp.from : imp.localNS;
|
|
842
|
+
if (!matchesDef) {
|
|
843
|
+
const targetModule = index.byFile.get(fileIdentityKey(targetFile));
|
|
844
|
+
if (!targetModule?.exports.some((entry) => entry.type === "namespaceReexport" || entry.type === "exportStar")) {
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
// A namespace re-export exposes a member at paths such as W.helpers.helper,
|
|
848
|
+
// not as a bare export of the intermediate module. Follow only export-proven
|
|
849
|
+
// namespace edges, then verify each use through the same goto resolver.
|
|
850
|
+
const namespacePaths = [
|
|
851
|
+
{ file: targetFile, name: namespaceSearchName, depth: 0 },
|
|
852
|
+
];
|
|
853
|
+
for (let pathIndex = 0; pathIndex < namespacePaths.length; pathIndex++) {
|
|
854
|
+
if (pathIndex >= MAX_REFERENCE_NAMESPACE_PATHS) {
|
|
855
|
+
receiverProofUnavailableFiles.set(fileIdentityKey(fileId), fileId);
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
const namespacePath = namespacePaths[pathIndex];
|
|
859
|
+
if (namespacePath.depth) {
|
|
860
|
+
const nestedHit = resolveExport(index, namespacePath.file, exportedName, {
|
|
861
|
+
allowLocalFallback: false,
|
|
862
|
+
...(exportOptions ?? {}),
|
|
863
|
+
});
|
|
864
|
+
if (nestedHit?.kind === "resolved" && matchesReferenceDefinition(nestedHit.def)) {
|
|
865
|
+
const parsed = await ensureCandidateParsed();
|
|
866
|
+
const ranges = await collectNamespaceMemberRefs(fileId, namespacePath.name, exportedName, parsed, index.languageExtensions, imp, module.imports);
|
|
867
|
+
for (const range of ranges) {
|
|
868
|
+
if (hasReachedCollectionLimit())
|
|
869
|
+
break;
|
|
870
|
+
const proof = await goToDefinition(index, { file: fileId, line: range.start.line, column: range.start.column }, parsed);
|
|
871
|
+
if (proof.status !== "ok" || !matchesReferenceDefinition(proof.definition))
|
|
872
|
+
continue;
|
|
873
|
+
pushRef({ file: fileId, range, via: { import: imp, namespaceMember: exportedName } });
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
const exports = resolveModuleExports(index, namespacePath.file, { allowLocalFallback: false });
|
|
878
|
+
if (namespacePath.depth >= MAX_REFERENCE_NAMESPACE_DEPTH) {
|
|
879
|
+
if ([...exports.values()].some((entry) => entry.kind === "namespace")) {
|
|
880
|
+
receiverProofUnavailableFiles.set(fileIdentityKey(fileId), fileId);
|
|
881
|
+
}
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
for (const [alias, entry] of exports) {
|
|
885
|
+
if (entry.kind !== "namespace")
|
|
886
|
+
continue;
|
|
887
|
+
namespacePaths.push({
|
|
888
|
+
file: entry.file,
|
|
889
|
+
name: `${namespacePath.name}.${alias}`,
|
|
890
|
+
depth: namespacePath.depth + 1,
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
}
|
|
457
894
|
continue;
|
|
895
|
+
}
|
|
458
896
|
const parsed = await ensureCandidateParsed();
|
|
459
|
-
const ranges = await collectNamespaceMemberRefs(fileId,
|
|
897
|
+
const ranges = await collectNamespaceMemberRefs(fileId, namespaceSearchName, exportedName, parsed, index.languageExtensions, imp, module.imports);
|
|
460
898
|
for (const range of ranges) {
|
|
461
899
|
if (hasReachedCollectionLimit())
|
|
462
900
|
break;
|
|
@@ -468,51 +906,130 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
468
906
|
}
|
|
469
907
|
}
|
|
470
908
|
else if (imp.kind === "star") {
|
|
471
|
-
const result = resolveImported(index, imp, exportedName);
|
|
472
|
-
const matchesDef = !!result && !("namespace" in result) &&
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
909
|
+
const result = resolveImported(index, imp, exportedName, exportOptions);
|
|
910
|
+
const matchesDef = !!result && !("namespace" in result) && matchesReferenceDefinition(result);
|
|
911
|
+
const matchesStructural = cppCanonicalStructuralExport(index, targetFile, exportedName, definition, parsedContext.sup.id);
|
|
912
|
+
if (matchesDef || matchesStructural) {
|
|
913
|
+
if (hasExpandedNamedImport(module, targetFile, exportedName)) {
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const remainingReferences = remainingCollectionSlots();
|
|
917
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, parsedContext.sup.id === "cpp" || parsedContext.sup.id === "ruby"
|
|
918
|
+
? (exportedName.split("::").pop() ?? exportedName)
|
|
919
|
+
: exportedName, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
920
|
+
for (const { range, provenance, via } of ranges) {
|
|
921
|
+
if (hasReachedCollectionLimit())
|
|
922
|
+
break;
|
|
923
|
+
pushRef({
|
|
924
|
+
file: fileId,
|
|
925
|
+
range,
|
|
926
|
+
via: { import: imp, ...(via ?? {}) },
|
|
927
|
+
...(provenance ? { provenance } : {}),
|
|
928
|
+
});
|
|
929
|
+
}
|
|
476
930
|
continue;
|
|
477
931
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
932
|
+
// A star import can publish a namespace such as a package submodule. Resolve that
|
|
933
|
+
// namespace under the same precedence as navigation before attributing its member use.
|
|
934
|
+
const namespaceExports = resolveModuleExports(index, targetFile);
|
|
935
|
+
const parsed = await ensureCandidateParsed();
|
|
936
|
+
for (const [namespaceName, namespaceResult] of namespaceExports) {
|
|
937
|
+
if (namespaceResult.kind !== "namespace")
|
|
938
|
+
continue;
|
|
939
|
+
if (![definition, ...equivalentDefinitions].some((candidate) => fileIdentityKey(namespaceResult.file) === fileIdentityKey(candidate.file))) {
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const namespaceDecision = resolveStarImportedNamespace(index, module, parsed.sup.id, namespaceName);
|
|
943
|
+
if (namespaceDecision.status !== "resolved" || namespaceDecision.imp !== imp)
|
|
944
|
+
continue;
|
|
945
|
+
const ranges = await collectNamespaceMemberRefs(fileId, namespaceName, exportedName, parsed, index.languageExtensions, undefined, module.imports);
|
|
946
|
+
for (const range of ranges) {
|
|
947
|
+
if (hasReachedCollectionLimit())
|
|
948
|
+
break;
|
|
949
|
+
pushRef({ file: fileId, range, via: { import: imp, namespaceMember: exportedName } });
|
|
950
|
+
}
|
|
489
951
|
}
|
|
490
952
|
}
|
|
491
953
|
else {
|
|
492
954
|
let exported = exportedName;
|
|
955
|
+
const importedLocalName = imp.kind === "namespace" ? imp.localNS : imp.local;
|
|
493
956
|
if (imp.kind === "named") {
|
|
494
957
|
exported = imp.imported;
|
|
495
958
|
}
|
|
496
959
|
else if (imp.kind === "default") {
|
|
497
960
|
exported = "default";
|
|
498
961
|
}
|
|
499
|
-
const hit = resolveExport(index, targetFile, exported);
|
|
500
|
-
let matchesDef = hit?.kind === "resolved" &&
|
|
962
|
+
const hit = resolveExport(index, targetFile, exported, exportOptions);
|
|
963
|
+
let matchesDef = hit?.kind === "resolved" && matchesReferenceDefinition(hit.def);
|
|
964
|
+
let attributedByProof = matchesDef;
|
|
501
965
|
if (!matchesDef && bindingSites.length) {
|
|
502
966
|
matchesDef = await bindingMatchesDefinition();
|
|
967
|
+
attributedByProof = matchesDef;
|
|
968
|
+
}
|
|
969
|
+
if (!matchesDef &&
|
|
970
|
+
cppCanonicalStructuralExport(index, targetFile, exported, definition, parsedContext.sup.id)) {
|
|
971
|
+
// Recover candidates, but prove each overload call through goToDefinition.
|
|
972
|
+
// Structural visibility alone cannot attribute the import token.
|
|
973
|
+
matchesDef = true;
|
|
974
|
+
}
|
|
975
|
+
// A python `from pkg import name` binds `name` from the package's own namespace.
|
|
976
|
+
// Usually that is a real re-exported symbol (handled above); when the package has no
|
|
977
|
+
// such export, Python's own import system falls back to treating `name` as an
|
|
978
|
+
// implicit submodule attribute instead. Reuse the namespace-style dotted scan the
|
|
979
|
+
// `imp.kind === "namespace"` branch above runs, rather than the bare-identifier scan
|
|
980
|
+
// this branch runs next, so a same-name use through the bound local still counts.
|
|
981
|
+
if (!matchesDef && imp.kind === "named" && imp.mechanism === "python") {
|
|
982
|
+
const importedResult = resolveImported(index, imp, exported, exportOptions);
|
|
983
|
+
const submoduleFile = importedResult && "namespace" in importedResult ? importedResult.namespace : undefined;
|
|
984
|
+
if (submoduleFile &&
|
|
985
|
+
[definition, ...equivalentDefinitions].some((candidate) => fileIdentityKey(submoduleFile) === fileIdentityKey(candidate.file))) {
|
|
986
|
+
const parsed = await ensureCandidateParsed();
|
|
987
|
+
const ranges = await collectNamespaceMemberRefs(fileId, imp.local, exportedName, parsed, index.languageExtensions, undefined, module.imports);
|
|
988
|
+
for (const range of ranges) {
|
|
989
|
+
if (hasReachedCollectionLimit())
|
|
990
|
+
break;
|
|
991
|
+
pushRef({ file: fileId, range, via: { import: imp, namespaceMember: exportedName } });
|
|
992
|
+
}
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
503
995
|
}
|
|
504
|
-
if (!matchesDef)
|
|
996
|
+
if (!matchesDef) {
|
|
997
|
+
// The requested export slot itself does not exist at all (as opposed to existing
|
|
998
|
+
// and structurally naming a different, already-proven definition): the binding may
|
|
999
|
+
// still be a whole-module handle onto this exact file under a shape resolution does
|
|
1000
|
+
// not model (a misclassified default import, for example). Verify every same-name
|
|
1001
|
+
// occurrence directly instead of silently treating the file as clean.
|
|
1002
|
+
if (!hasReachedCollectionLimit() &&
|
|
1003
|
+
hit?.kind !== "resolved" &&
|
|
1004
|
+
[definition, ...equivalentDefinitions].some((candidate) => fileIdentityKey(targetFile) === fileIdentityKey(candidate.file))) {
|
|
1005
|
+
const remainingReferences = remainingCollectionSlots();
|
|
1006
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, exportedName, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
1007
|
+
for (const { range, provenance, via } of ranges) {
|
|
1008
|
+
if (hasReachedCollectionLimit())
|
|
1009
|
+
break;
|
|
1010
|
+
pushRef({
|
|
1011
|
+
file: fileId,
|
|
1012
|
+
range,
|
|
1013
|
+
via: { import: imp, ...(via ?? {}) },
|
|
1014
|
+
...(provenance ? { provenance } : {}),
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
505
1018
|
continue;
|
|
506
|
-
for (const site of bindingSites) {
|
|
507
|
-
pushRef({
|
|
508
|
-
file: fileId,
|
|
509
|
-
range: site.range,
|
|
510
|
-
via: { import: imp, importBinding: site.importBinding },
|
|
511
|
-
});
|
|
512
1019
|
}
|
|
513
|
-
if (
|
|
1020
|
+
if (attributedByProof) {
|
|
1021
|
+
for (const site of bindingSites) {
|
|
1022
|
+
pushRef({
|
|
1023
|
+
file: fileId,
|
|
1024
|
+
range: site.range,
|
|
1025
|
+
via: { import: imp, importBinding: site.importBinding },
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const scansQualifiedCppImport = parsedContext.sup.id === "cpp" && imp.kind === "named" && imp.local.includes("::");
|
|
1030
|
+
if (imp.kind === "named" || fileIdentityKey(targetFile) !== fileIdentityKey(definitionFile)) {
|
|
514
1031
|
const remainingReferences = remainingCollectionSlots();
|
|
515
|
-
const ranges = await collectVerifiedNamedNodeReferences(index, fileId,
|
|
1032
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, scansQualifiedCppImport ? (importedLocalName.split("::").pop() ?? importedLocalName) : importedLocalName, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
516
1033
|
for (const { range, provenance, via } of ranges) {
|
|
517
1034
|
if (hasReachedCollectionLimit())
|
|
518
1035
|
break;
|
|
@@ -527,7 +1044,7 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
527
1044
|
}
|
|
528
1045
|
const parsed = await ensureCandidateParsed();
|
|
529
1046
|
const resolvedScope = await ensureScope();
|
|
530
|
-
const localName = parsed.sup.normalizeIdentifier(
|
|
1047
|
+
const localName = parsed.sup.normalizeIdentifier(importedLocalName);
|
|
531
1048
|
const declarationKeys = importBindingDeclarationRangeKeys(module);
|
|
532
1049
|
const bindings = resolvedScope.bindings.get(localName) ?? [];
|
|
533
1050
|
for (const binding of bindings) {
|
|
@@ -544,34 +1061,67 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
544
1061
|
}
|
|
545
1062
|
}
|
|
546
1063
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
1064
|
+
// A unit peer names the definition directly (Go and JVM package siblings, C# namespace
|
|
1065
|
+
// peers, Swift module siblings), with no import binding to attribute. The single bare-name
|
|
1066
|
+
// scan keeps reference sites in agreement with what bare-name resolution can prove.
|
|
1067
|
+
if (!definition.isMember &&
|
|
1068
|
+
fileIdentityKey(fileId) !== fileIdentityKey(definitionFile) &&
|
|
1069
|
+
unitPeerKeys.has(fileIdentityKey(fileId)) &&
|
|
1070
|
+
!hasReachedCollectionLimit()) {
|
|
1071
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, referenceDef.localName, definition, (params, parsed) => goToDefinition(index, params, parsed), remainingCollectionSlots(), verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
1072
|
+
for (const { range, provenance, via } of ranges) {
|
|
550
1073
|
if (hasReachedCollectionLimit())
|
|
551
1074
|
break;
|
|
552
|
-
|
|
553
|
-
|
|
1075
|
+
pushRef({ file: fileId, range, ...(via ? { via } : {}), ...(provenance ? { provenance } : {}) });
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
// Only the exact dotted submodule path can refer to this definition through a
|
|
1079
|
+
// parent-package import. Other same-name uses are proven unrelated.
|
|
1080
|
+
if (parsedContext.sup.id === "python" && !definition.isMember && !hasReachedCollectionLimit()) {
|
|
1081
|
+
for (const { namespace, importBinding } of pythonParentPackageNamespacePaths(module, definitionFile)) {
|
|
1082
|
+
const parsed = await ensureCandidateParsed();
|
|
1083
|
+
const ranges = await collectNamespaceMemberRefs(fileId, namespace, referenceDef.localName, parsed, index.languageExtensions, importBinding, module.imports);
|
|
1084
|
+
for (const range of ranges) {
|
|
554
1085
|
if (hasReachedCollectionLimit())
|
|
555
1086
|
break;
|
|
556
|
-
|
|
1087
|
+
const hit = await goToDefinition(index, { file: fileId, line: range.start.line, column: range.start.column }, parsed);
|
|
1088
|
+
if (hit.status === "ok") {
|
|
1089
|
+
if (matchesReferenceDefinition(hit.definition))
|
|
1090
|
+
pushRef({ file: fileId, range });
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
receiverProofUnavailableFiles.set(fileIdentityKey(fileId), fileId);
|
|
1094
|
+
}
|
|
557
1095
|
}
|
|
558
1096
|
}
|
|
559
1097
|
}
|
|
1098
|
+
if (phpQualifiedNames.length) {
|
|
1099
|
+
const remainingReferences = remainingCollectionSlots();
|
|
1100
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, referenceDef.localName, referenceDef, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile));
|
|
1101
|
+
for (const { range, provenance, via } of ranges) {
|
|
1102
|
+
if (hasReachedCollectionLimit())
|
|
1103
|
+
break;
|
|
1104
|
+
pushRef({ file: fileId, range, ...(via ? { via } : {}), ...(provenance ? { provenance } : {}) });
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
560
1107
|
}
|
|
561
1108
|
const receiverScannedFiles = [];
|
|
562
|
-
if (
|
|
1109
|
+
if (scansReceiverReferences) {
|
|
563
1110
|
for (const fileId of Array.from(index.byFile.values(), (module) => module.file).sort((left, right) => left.localeCompare(right))) {
|
|
564
1111
|
if (hasReachedCollectionLimit())
|
|
565
1112
|
break;
|
|
566
1113
|
receiverScannedFiles.push(fileId);
|
|
567
1114
|
const filter = index.bloomFilters?.get(fileIdentityKey(fileId));
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
1115
|
+
const candidateSupport = supportForFileWithoutHeaderSample(fileId, index.languageExtensions);
|
|
1116
|
+
// Bloom filters store folded PHP identifiers in addition to their source spelling.
|
|
1117
|
+
const normalizedName = candidateSupport?.normalizeIdentifier(referenceDef.localName) ?? referenceDef.localName;
|
|
1118
|
+
const canonicalName = candidateSupport?.id === "php" && isPhpCaseInsensitiveSymbolKind(definition.kind)
|
|
1119
|
+
? foldPhpIdentifierCase(normalizedName)
|
|
1120
|
+
: normalizedName;
|
|
571
1121
|
if (filter && !filter.mightContain(canonicalName))
|
|
572
1122
|
continue;
|
|
573
1123
|
const remainingReferences = remainingCollectionSlots();
|
|
574
|
-
const ranges = await collectVerifiedNamedNodeReferences(index, fileId,
|
|
1124
|
+
const ranges = await collectVerifiedNamedNodeReferences(index, fileId, referenceDef.localName, referenceDef, (params, parsed) => goToDefinition(index, params, parsed), remainingReferences, verifiedReferenceFilter(fileId), (unavailableFile) => receiverProofUnavailableFiles.set(fileIdentityKey(unavailableFile), unavailableFile), equivalentDefinitions);
|
|
575
1125
|
for (const { range, provenance, via } of ranges) {
|
|
576
1126
|
if (hasReachedCollectionLimit())
|
|
577
1127
|
break;
|
|
@@ -612,44 +1162,385 @@ async function findReferencesInternal(index, req, opts, collectionMode) {
|
|
|
612
1162
|
}
|
|
613
1163
|
}
|
|
614
1164
|
const scannedFiles = [definitionFile, ...candidateFiles, ...receiverScannedFiles];
|
|
1165
|
+
// Top-level implicit-unit names and C# partial / Swift shared-owner members are both bounded
|
|
1166
|
+
// by the source-unit relation; an unproven boundary leaves their reference set partial.
|
|
1167
|
+
const implicitUnitComplete = !definition.isMember && IMPLICIT_UNIT_LANGUAGES[parsedContext.sup.id]
|
|
1168
|
+
? getCompilationUnitPeers(index, definitionFile, parsedContext.sup.id === "csharp" ? { csharpQualifiedName: true } : undefined).complete
|
|
1169
|
+
: await sharedOwnerMemberUnitComplete(index, definition);
|
|
615
1170
|
const referenceCoverage = buildIndexedCandidateCoverage({
|
|
616
1171
|
index,
|
|
617
|
-
def,
|
|
1172
|
+
def: definition,
|
|
1173
|
+
languageId: parsedContext.sup.id,
|
|
618
1174
|
exportedNames,
|
|
619
1175
|
candidateFiles,
|
|
620
1176
|
scannedFiles,
|
|
621
1177
|
truncated,
|
|
1178
|
+
strategies: describeReferenceStrategies({
|
|
1179
|
+
languageId: parsedContext.sup.id,
|
|
1180
|
+
phpQualifiedNames,
|
|
1181
|
+
sameFileOccurrence: {
|
|
1182
|
+
// C/C++ callable siblings and reopened C# namespace regions can refer to a
|
|
1183
|
+
// declaration without sharing its lexical scope. Verify those uses through
|
|
1184
|
+
// navigation; parameters and local variables remain lexical-only.
|
|
1185
|
+
applicable: requiresSameFileVerifiedScan,
|
|
1186
|
+
executed: sameFileVerifiedScanExecuted,
|
|
1187
|
+
},
|
|
1188
|
+
// An unproven compilation-unit boundary means the peer universe may extend beyond the
|
|
1189
|
+
// enumerated files, so coverage must not imply that every possible consumer was scanned.
|
|
1190
|
+
...(implicitUnitComplete !== null
|
|
1191
|
+
? { implicitUnitPeers: { applicable: true, executed: implicitUnitComplete } }
|
|
1192
|
+
: {}),
|
|
1193
|
+
}),
|
|
1194
|
+
strategyUnavailableFiles: [
|
|
1195
|
+
...receiverProofUnavailableFiles.values(),
|
|
1196
|
+
...(rubyReopen?.incomplete ? [definition.file] : []),
|
|
1197
|
+
],
|
|
622
1198
|
});
|
|
623
1199
|
return {
|
|
624
1200
|
status: "ok",
|
|
625
|
-
definition
|
|
1201
|
+
definition,
|
|
626
1202
|
references: refs,
|
|
627
1203
|
referenceCoverage,
|
|
628
1204
|
...(provenance ? { provenance } : {}),
|
|
629
1205
|
};
|
|
630
1206
|
}
|
|
631
|
-
function
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
1207
|
+
function syntaxNodeForDefinition(parsedContext, def) {
|
|
1208
|
+
const position = {
|
|
1209
|
+
row: def.range.start.line - 1,
|
|
1210
|
+
column: def.range.start.column - 1,
|
|
1211
|
+
};
|
|
1212
|
+
return parsedContext.tree.rootNode.descendantForPosition(position, position);
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Restores indexed metadata for definitions that arrive without it — impact fabricates reference
|
|
1216
|
+
* defs from changed-symbol projections, dropping fields such as `isMember`. Matching is exact
|
|
1217
|
+
* identity against the definition file's module.locals: same kind, localName, and full range span.
|
|
1218
|
+
* Definitions without byte indices or without a matching local are returned unchanged.
|
|
1219
|
+
*/
|
|
1220
|
+
function indexedDefinitionByIdentity(index, def) {
|
|
1221
|
+
const mod = index.byFile.get(fileIdentityKey(def.file));
|
|
1222
|
+
if (!mod)
|
|
1223
|
+
return def;
|
|
1224
|
+
const startIndex = def.range.start.index;
|
|
1225
|
+
const endIndex = def.range.end.index;
|
|
1226
|
+
if (startIndex === undefined || endIndex === undefined)
|
|
1227
|
+
return def;
|
|
1228
|
+
return (mod.locals.find((candidate) => candidate.kind === def.kind &&
|
|
1229
|
+
candidate.localName === def.localName &&
|
|
1230
|
+
candidate.range.start.index === startIndex &&
|
|
1231
|
+
candidate.range.end.index === endIndex) ?? def);
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Reverse include edges for one index. Rebuilt only when the index object is
|
|
1235
|
+
* new, matching the WeakMap caches in navigation-references.ts.
|
|
1236
|
+
*/
|
|
1237
|
+
const cIncludedByCache = new WeakMap();
|
|
1238
|
+
function cIncludedBy(index) {
|
|
1239
|
+
const cached = cIncludedByCache.get(index);
|
|
1240
|
+
if (cached)
|
|
1241
|
+
return cached;
|
|
1242
|
+
const includedBy = new Map();
|
|
1243
|
+
for (const moduleEntry of index.byFile.values()) {
|
|
1244
|
+
const includerKey = fileIdentityKey(moduleEntry.file);
|
|
1245
|
+
for (const imp of moduleEntry.imports) {
|
|
1246
|
+
if (typeof imp.resolved !== "string")
|
|
1247
|
+
continue;
|
|
1248
|
+
const includedKey = fileIdentityKey(imp.resolved);
|
|
1249
|
+
const includers = includedBy.get(includedKey);
|
|
1250
|
+
if (includers)
|
|
1251
|
+
includers.push(includerKey);
|
|
1252
|
+
else
|
|
1253
|
+
includedBy.set(includedKey, [includerKey]);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
const stored = new Map();
|
|
1257
|
+
for (const [key, includers] of includedBy)
|
|
1258
|
+
stored.set(key, includers);
|
|
1259
|
+
cIncludedByCache.set(index, stored);
|
|
1260
|
+
return stored;
|
|
1261
|
+
}
|
|
1262
|
+
/** Indexed files linked to `startFile` by `#include` in either direction, excluding the file itself. */
|
|
1263
|
+
function cIncludeLinkedModules(index, startFile) {
|
|
1264
|
+
const startKey = fileIdentityKey(startFile);
|
|
1265
|
+
const includedBy = cIncludedBy(index);
|
|
1266
|
+
const linked = new Set();
|
|
1267
|
+
const walk = (origin, neighbors) => {
|
|
1268
|
+
const pending = [origin];
|
|
1269
|
+
const seen = new Set([origin]);
|
|
1270
|
+
while (pending.length) {
|
|
1271
|
+
const current = pending.pop();
|
|
1272
|
+
for (const neighbor of neighbors(current)) {
|
|
1273
|
+
if (seen.has(neighbor))
|
|
1274
|
+
continue;
|
|
1275
|
+
seen.add(neighbor);
|
|
1276
|
+
linked.add(neighbor);
|
|
1277
|
+
pending.push(neighbor);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
walk(startKey, (key) => {
|
|
1282
|
+
const moduleEntry = index.byFile.get(key);
|
|
1283
|
+
if (!moduleEntry)
|
|
1284
|
+
return [];
|
|
1285
|
+
const included = [];
|
|
1286
|
+
for (const imp of moduleEntry.imports) {
|
|
1287
|
+
if (typeof imp.resolved === "string")
|
|
1288
|
+
included.push(fileIdentityKey(imp.resolved));
|
|
1289
|
+
}
|
|
1290
|
+
return included;
|
|
1291
|
+
});
|
|
1292
|
+
walk(startKey, (key) => includedBy.get(key) ?? []);
|
|
1293
|
+
linked.delete(startKey);
|
|
1294
|
+
const modules = [];
|
|
1295
|
+
for (const key of linked) {
|
|
1296
|
+
const moduleEntry = index.byFile.get(key);
|
|
1297
|
+
if (moduleEntry)
|
|
1298
|
+
modules.push(moduleEntry);
|
|
1299
|
+
}
|
|
1300
|
+
return modules;
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* C prototype and definition of one signature, joined only when one file includes
|
|
1304
|
+
* the other. Two translation units that merely share an unrelated header stay apart,
|
|
1305
|
+
* and `static` functions are not exports so they never join the family.
|
|
1306
|
+
*/
|
|
1307
|
+
async function cIncludeLinkedCallableEquivalents(index, def, definitionNameNode) {
|
|
1308
|
+
if (def.kind !== SymbolKind.Function || def.cTag)
|
|
1309
|
+
return [];
|
|
1310
|
+
const expected = cppCallableShapeForNode(definitionNameNode);
|
|
1311
|
+
if (!expected)
|
|
1312
|
+
return [];
|
|
1313
|
+
const origin = index.byFile.get(fileIdentityKey(def.file));
|
|
1314
|
+
const exported = origin?.exports.some((entry) => entry.type === "local" && sameDef(entry.target, def, index.languageExtensions));
|
|
1315
|
+
if (!exported)
|
|
1316
|
+
return [];
|
|
1317
|
+
const equivalents = new Map();
|
|
1318
|
+
for (const moduleEntry of cIncludeLinkedModules(index, def.file)) {
|
|
1319
|
+
const candidates = [];
|
|
1320
|
+
for (const entry of moduleEntry.exports) {
|
|
1321
|
+
if (entry.type !== "local")
|
|
1322
|
+
continue;
|
|
1323
|
+
if (entry.exportedAs !== def.localName || entry.target.localName !== def.localName)
|
|
1324
|
+
continue;
|
|
1325
|
+
if (entry.target.kind !== SymbolKind.Function || entry.target.cTag)
|
|
1326
|
+
continue;
|
|
1327
|
+
candidates.push(entry.target);
|
|
1328
|
+
}
|
|
1329
|
+
if (!candidates.length)
|
|
1330
|
+
continue;
|
|
1331
|
+
let candidateParsed;
|
|
1332
|
+
try {
|
|
1333
|
+
candidateParsed = await ensureParsedContext(moduleEntry.file, index.parsed?.get(fileIdentityKey(moduleEntry.file)), index.languageExtensions);
|
|
1334
|
+
}
|
|
1335
|
+
catch {
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
if (candidateParsed.sup.id !== "c")
|
|
1339
|
+
continue;
|
|
1340
|
+
for (const candidate of candidates) {
|
|
1341
|
+
if (sameDef(candidate, def, index.languageExtensions))
|
|
1342
|
+
continue;
|
|
1343
|
+
const candidateNode = syntaxNodeForDefinition(candidateParsed, candidate);
|
|
1344
|
+
if (cppCallableShapeForNode(candidateNode)?.signature !== expected.signature)
|
|
1345
|
+
continue;
|
|
1346
|
+
equivalents.set(referenceSiteKey(candidate.file, candidate.range), candidate);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return [...equivalents.values()];
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Single calculation behind reference collection and getCppEquivalentCallableDefinitions: resolves
|
|
1353
|
+
* the receiver owner, the normalized reference name, the definition-site scope binding, and the
|
|
1354
|
+
* proven equivalent definition family for one callable definition site.
|
|
1355
|
+
*/
|
|
1356
|
+
async function cppEquivalentCallableFamily(index, def, parsedContext) {
|
|
1357
|
+
const definition = indexedDefinitionByIdentity(index, def);
|
|
1358
|
+
const mod = index.byFile.get(fileIdentityKey(definition.file));
|
|
1359
|
+
if (!mod) {
|
|
1360
|
+
return { definition, referenceDef: definition, receiverOwner: null, localBinding: undefined, equivalents: [] };
|
|
1361
|
+
}
|
|
1362
|
+
const context = parsedContext ??
|
|
1363
|
+
(await ensureParsedContext(definition.file, index.parsed?.get(fileIdentityKey(definition.file)), index.languageExtensions));
|
|
1364
|
+
const definitionNameNode = syntaxNodeForDefinition(context, definition);
|
|
1365
|
+
const receiverOwner = await cppOutOfLineReceiverOwner(index, mod, definition, context, definitionNameNode);
|
|
1366
|
+
const memberName = receiverOwner ? cppOutOfLineMemberName(definitionNameNode, context.source, context.sup) : null;
|
|
1367
|
+
const referenceDef = memberName && memberName !== definition.localName ? { ...definition, localName: memberName } : definition;
|
|
1368
|
+
const normalizedLocalName = context.sup.normalizeIdentifier(referenceDef.localName);
|
|
1369
|
+
const scope = getCachedScope(index, definition.file, mod, context);
|
|
1370
|
+
const localBindings = scope.bindings.get(normalizedLocalName) ?? [];
|
|
1371
|
+
const localBinding = localBindings.find((binding) => binding.def && binding.def.start.index === definition.range.start.index);
|
|
1372
|
+
let sameFileFunctionBindings = localBindings;
|
|
1373
|
+
if (context.sup.id === "cpp") {
|
|
1374
|
+
sameFileFunctionBindings = localBinding ? cppEquivalentCallableBindings(localBinding) : [];
|
|
1375
|
+
}
|
|
1376
|
+
const sameFileFunctionEquivalentDefinitions = (context.sup.id === "c" || context.sup.id === "cpp") && definition.kind === SymbolKind.Function
|
|
1377
|
+
? sameFileFunctionBindings.flatMap((binding) => {
|
|
1378
|
+
const bindingRange = binding.def;
|
|
1379
|
+
if (!bindingRange || bindingRange.start.index === definition.range.start.index)
|
|
1380
|
+
return [];
|
|
1381
|
+
const local = mod.locals.find((candidate) => candidate.kind === SymbolKind.Function &&
|
|
1382
|
+
candidate.localName === definition.localName &&
|
|
1383
|
+
candidate.range.start.index === bindingRange.start.index &&
|
|
1384
|
+
candidate.range.end.index === bindingRange.end.index);
|
|
1385
|
+
return local ? [local] : [];
|
|
1386
|
+
})
|
|
1387
|
+
: [];
|
|
1388
|
+
let equivalents;
|
|
1389
|
+
if (receiverOwner) {
|
|
1390
|
+
equivalents = await cppOutOfLineEquivalentDefinitions(index, referenceDef, context, definitionNameNode, receiverOwner);
|
|
1391
|
+
}
|
|
1392
|
+
else if (definition.isMember && context.sup.id === "cpp") {
|
|
1393
|
+
equivalents = await cppInClassMemberEquivalentDefinitions(index, definition, context, definitionNameNode);
|
|
1394
|
+
}
|
|
1395
|
+
else if (context.sup.id === "cpp") {
|
|
1396
|
+
equivalents = [
|
|
1397
|
+
...sameFileFunctionEquivalentDefinitions,
|
|
1398
|
+
...(await cppNamespaceFunctionEquivalentDefinitions(index, definition, context, definitionNameNode)),
|
|
1399
|
+
];
|
|
1400
|
+
}
|
|
1401
|
+
else if (context.sup.id === "c" && definition.kind === SymbolKind.Function && !definition.cTag) {
|
|
1402
|
+
const linked = await cIncludeLinkedCallableEquivalents(index, definition, definitionNameNode);
|
|
1403
|
+
const seen = new Set(sameFileFunctionEquivalentDefinitions.map((item) => referenceSiteKey(item.file, item.range)));
|
|
1404
|
+
equivalents = [
|
|
1405
|
+
...sameFileFunctionEquivalentDefinitions,
|
|
1406
|
+
...linked.filter((item) => !seen.has(referenceSiteKey(item.file, item.range))),
|
|
1407
|
+
];
|
|
1408
|
+
}
|
|
1409
|
+
else {
|
|
1410
|
+
equivalents = sameFileFunctionEquivalentDefinitions;
|
|
1411
|
+
}
|
|
1412
|
+
return { definition, referenceDef, receiverOwner, localBinding, equivalents };
|
|
1413
|
+
}
|
|
1414
|
+
async function cppOutOfLineReceiverOwner(index, mod, def, parsedContext, definitionNameNode) {
|
|
1415
|
+
if (parsedContext.sup.id !== "cpp" || def.kind !== SymbolKind.Function)
|
|
1416
|
+
return null;
|
|
1417
|
+
const ownerPath = cppOutOfLineOwnerPath(definitionNameNode, parsedContext.source, parsedContext.sup);
|
|
1418
|
+
return ownerPath ? await resolveCppQualifiedMemberContainer(index, mod, ownerPath) : null;
|
|
1419
|
+
}
|
|
1420
|
+
async function cppOutOfLineEquivalentDefinitions(index, def, parsedContext, definitionNameNode, owner) {
|
|
1421
|
+
const ownerModule = index.byFile.get(fileIdentityKey(owner.file));
|
|
1422
|
+
if (!ownerModule)
|
|
1423
|
+
return [];
|
|
1424
|
+
const ownerParsed = await ensureParsedContext(owner.file, index.parsed?.get(fileIdentityKey(owner.file)), index.languageExtensions);
|
|
1425
|
+
const ownerNameNode = syntaxNodeForDefinition(ownerParsed, owner);
|
|
1426
|
+
const declaration = cppOutOfLineMemberDeclarationNode(definitionNameNode, def.localName, ownerNameNode, ownerParsed.source, parsedContext.sup);
|
|
1427
|
+
if (!declaration)
|
|
1428
|
+
return [];
|
|
1429
|
+
const normalizedName = parsedContext.sup.normalizeIdentifier(def.localName);
|
|
1430
|
+
return ownerModule.locals.filter((candidate) => parsedContext.sup.normalizeIdentifier(candidate.localName) === normalizedName &&
|
|
1431
|
+
candidate.range.start.index === declaration.nameNode.startIndex);
|
|
1432
|
+
}
|
|
1433
|
+
async function cppInClassMemberEquivalentDefinitions(index, def, parsedContext, definitionNameNode) {
|
|
1434
|
+
if (def.kind !== SymbolKind.Function)
|
|
1435
|
+
return [];
|
|
1436
|
+
const ownerSegments = [];
|
|
1437
|
+
let current = definitionNameNode.parent;
|
|
1438
|
+
while (current) {
|
|
1439
|
+
if (CPP_MEMBER_CONTAINER_TYPES.has(current.type) || current.type === "namespace_definition") {
|
|
1440
|
+
const name = current.childForFieldName("name");
|
|
1441
|
+
if (!name)
|
|
1442
|
+
return [];
|
|
1443
|
+
ownerSegments.unshift(cppQualifiedNameSegments(name, parsedContext.source));
|
|
1444
|
+
}
|
|
1445
|
+
current = current.parent;
|
|
1446
|
+
}
|
|
1447
|
+
const owners = ownerSegments.flat();
|
|
1448
|
+
if (!owners.length)
|
|
1449
|
+
return [];
|
|
1450
|
+
const qualifiedName = [...owners, def.localName].join("::");
|
|
1451
|
+
const expectedShape = cppCallableShapeForNode(definitionNameNode);
|
|
1452
|
+
if (!expectedShape)
|
|
1453
|
+
return [];
|
|
1454
|
+
const equivalents = new Map();
|
|
1455
|
+
for (const module of index.byFile.values()) {
|
|
1456
|
+
for (const entry of module.exports) {
|
|
1457
|
+
if (entry.type !== "local" ||
|
|
1458
|
+
entry.exportedAs !== qualifiedName ||
|
|
1459
|
+
entry.target.kind !== SymbolKind.Function ||
|
|
1460
|
+
sameDef(entry.target, def, index.languageExtensions)) {
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
const candidateParsed = await ensureParsedContext(entry.target.file, index.parsed?.get(fileIdentityKey(entry.target.file)), index.languageExtensions);
|
|
1464
|
+
const candidateNode = syntaxNodeForDefinition(candidateParsed, entry.target);
|
|
1465
|
+
const candidateShape = cppCallableShapeForNode(candidateNode);
|
|
1466
|
+
if (!candidateShape)
|
|
1467
|
+
continue;
|
|
1468
|
+
let explicitSpecialization = false;
|
|
1469
|
+
let current = candidateNode;
|
|
1470
|
+
while (current) {
|
|
1471
|
+
if (current.type === "template_declaration" &&
|
|
1472
|
+
/^\s*template\s*<\s*>/u.test(sliceText(current, candidateParsed.source))) {
|
|
1473
|
+
explicitSpecialization = true;
|
|
1474
|
+
break;
|
|
1475
|
+
}
|
|
1476
|
+
current = current.parent;
|
|
1477
|
+
}
|
|
1478
|
+
const arityMatches = candidateShape.minArity === expectedShape.minArity && candidateShape.maxArity === expectedShape.maxArity;
|
|
1479
|
+
if (candidateShape.signature !== expectedShape.signature && !(explicitSpecialization && arityMatches)) {
|
|
1480
|
+
continue;
|
|
1481
|
+
}
|
|
1482
|
+
equivalents.set(referenceSiteKey(entry.target.file, entry.target.range), entry.target);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
return [...equivalents.values()];
|
|
1486
|
+
}
|
|
1487
|
+
function shouldScanVerifiedReferences(def, parsedContext, receiverMemberDefinition) {
|
|
1488
|
+
if (parsedContext.sup.id === "php" && !isPhpCaseInsensitiveSymbolKind(def.kind))
|
|
635
1489
|
return false;
|
|
636
|
-
return
|
|
1490
|
+
return supportsReceiverMemberNavigation(parsedContext.sup.id) && receiverMemberDefinition;
|
|
637
1491
|
}
|
|
638
|
-
function
|
|
639
|
-
|
|
1492
|
+
async function cppNamespaceFunctionEquivalentDefinitions(index, def, parsedContext, definitionNameNode) {
|
|
1493
|
+
if (parsedContext.sup.id !== "cpp" || def.kind !== SymbolKind.Function)
|
|
1494
|
+
return [];
|
|
1495
|
+
const ownerPath = cppOutOfLineOwnerPath(definitionNameNode, parsedContext.source, parsedContext.sup);
|
|
1496
|
+
const namespacePath = [];
|
|
1497
|
+
if (!ownerPath) {
|
|
1498
|
+
let current = definitionNameNode.parent;
|
|
1499
|
+
while (current) {
|
|
1500
|
+
if (CPP_MEMBER_CONTAINER_TYPES.has(current.type))
|
|
1501
|
+
return [];
|
|
1502
|
+
if (current.type === "namespace_definition") {
|
|
1503
|
+
const name = current.childForFieldName("name");
|
|
1504
|
+
if (!name)
|
|
1505
|
+
return [];
|
|
1506
|
+
namespacePath.unshift(cppQualifiedNameSegments(name, parsedContext.source));
|
|
1507
|
+
}
|
|
1508
|
+
current = current.parent;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const owners = ownerPath ?? namespacePath.flat();
|
|
1512
|
+
if (!owners.length)
|
|
1513
|
+
return [];
|
|
1514
|
+
const memberName = cppOutOfLineMemberName(definitionNameNode, parsedContext.source, parsedContext.sup) ?? def.localName;
|
|
1515
|
+
const qualifiedName = [...owners, memberName].join("::");
|
|
1516
|
+
const expectedShape = cppCallableShapeForNode(definitionNameNode);
|
|
1517
|
+
if (!expectedShape)
|
|
1518
|
+
return [];
|
|
1519
|
+
const equivalents = new Map();
|
|
1520
|
+
for (const module of index.byFile.values()) {
|
|
1521
|
+
for (const entry of module.exports) {
|
|
1522
|
+
if (entry.type !== "local" ||
|
|
1523
|
+
entry.exportedAs !== qualifiedName ||
|
|
1524
|
+
entry.target.kind !== SymbolKind.Function ||
|
|
1525
|
+
sameDef(entry.target, def, index.languageExtensions)) {
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
const candidateParsed = await ensureParsedContext(entry.target.file, index.parsed?.get(fileIdentityKey(entry.target.file)), index.languageExtensions);
|
|
1529
|
+
const candidateNode = syntaxNodeForDefinition(candidateParsed, entry.target);
|
|
1530
|
+
if (cppCallableShapeForNode(candidateNode)?.signature !== expectedShape.signature)
|
|
1531
|
+
continue;
|
|
1532
|
+
equivalents.set(referenceSiteKey(entry.target.file, entry.target.range), entry.target);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
return [...equivalents.values()];
|
|
640
1536
|
}
|
|
641
|
-
function isReceiverMemberDefinition(def, parsedContext) {
|
|
642
|
-
if (def.isMember)
|
|
1537
|
+
function isReceiverMemberDefinition(def, parsedContext, hasCppOutOfLineOwner) {
|
|
1538
|
+
if (def.isMember || hasCppOutOfLineOwner)
|
|
643
1539
|
return true;
|
|
644
|
-
if (def.kind !== SymbolKind.Function)
|
|
1540
|
+
if (def.kind !== SymbolKind.Function)
|
|
645
1541
|
return false;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const position = {
|
|
649
|
-
row: start.line - 1,
|
|
650
|
-
column: start.column - 1,
|
|
651
|
-
};
|
|
652
|
-
let current = parsedContext.tree.rootNode.descendantForPosition(position, position);
|
|
1542
|
+
let current = syntaxNodeForDefinition(parsedContext, def);
|
|
1543
|
+
let sawCppFunction = false;
|
|
653
1544
|
let sawRustImplFunction = false;
|
|
654
1545
|
while (current) {
|
|
655
1546
|
if (current.type === "method_definition" ||
|
|
@@ -659,33 +1550,73 @@ function isReceiverMemberDefinition(def, parsedContext) {
|
|
|
659
1550
|
current.type === "method") {
|
|
660
1551
|
return true;
|
|
661
1552
|
}
|
|
1553
|
+
if (parsedContext.sup.id === "cpp") {
|
|
1554
|
+
if (current.type === "function_definition")
|
|
1555
|
+
sawCppFunction = true;
|
|
1556
|
+
if (sawCppFunction && CPP_MEMBER_CONTAINER_TYPES.has(current.type))
|
|
1557
|
+
return true;
|
|
1558
|
+
}
|
|
662
1559
|
if (parsedContext.sup.id === "rust" && current.type === "function_item") {
|
|
663
1560
|
sawRustImplFunction = true;
|
|
664
1561
|
}
|
|
665
|
-
if (sawRustImplFunction && current.type === "impl_item")
|
|
1562
|
+
if (sawRustImplFunction && current.type === "impl_item")
|
|
666
1563
|
return true;
|
|
667
|
-
|
|
668
|
-
if (current.type === "function_declaration" || current.type === "program") {
|
|
1564
|
+
if (current.type === "function_declaration" || current.type === "program")
|
|
669
1565
|
return false;
|
|
670
|
-
}
|
|
671
1566
|
current = current.parent;
|
|
672
1567
|
}
|
|
673
1568
|
return false;
|
|
674
1569
|
}
|
|
675
|
-
export async function collectNamespaceMemberRefs(file, ns, member, parsedContext, languageExtensions) {
|
|
1570
|
+
export async function collectNamespaceMemberRefs(file, ns, member, parsedContext, languageExtensions, importBinding, imports) {
|
|
676
1571
|
const parsed = parsedContext ?? (await ensureParsedContext(file, undefined, languageExtensions));
|
|
677
1572
|
const sup = parsed.sup;
|
|
678
1573
|
const source = parsed.source;
|
|
679
1574
|
const tree = parsed.tree;
|
|
680
1575
|
const ranges = [];
|
|
1576
|
+
// Identifier equality follows the language rule, so C# `@X::@Target` matches alias `X` member `Target`.
|
|
1577
|
+
const normalize = sup.normalizeIdentifier;
|
|
1578
|
+
const normalizedNs = normalize(ns);
|
|
1579
|
+
const normalizedMember = normalize(member);
|
|
1580
|
+
let effectivePythonBinding;
|
|
1581
|
+
if (sup.id === "python" && importBinding && imports) {
|
|
1582
|
+
let bindingName;
|
|
1583
|
+
if (importBinding.kind === "namespace")
|
|
1584
|
+
bindingName = importBinding.localNS;
|
|
1585
|
+
else if (importBinding.kind === "named" || importBinding.kind === "default")
|
|
1586
|
+
bindingName = importBinding.local;
|
|
1587
|
+
if (bindingName) {
|
|
1588
|
+
const normalizedBindingName = normalize(bindingName);
|
|
1589
|
+
effectivePythonBinding = effectiveExplicitBinding(imports, sup.id, (binding) => {
|
|
1590
|
+
if (binding.kind === "namespace")
|
|
1591
|
+
return normalize(binding.localNS) === normalizedBindingName;
|
|
1592
|
+
return ((binding.kind === "named" || binding.kind === "default") && normalize(binding.local) === normalizedBindingName);
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
681
1596
|
const walk = (node) => {
|
|
682
1597
|
if (isMemberAccessNode(sup, node)) {
|
|
683
1598
|
const { object: obj, property: prop } = getMemberAccessParts(sup, node);
|
|
684
|
-
if (obj && prop &&
|
|
1599
|
+
if (obj && prop && isMemberReferencePropertyIdentifier(sup, prop.type)) {
|
|
685
1600
|
const objectName = sliceText(obj, source);
|
|
686
1601
|
const propertyName = sliceText(prop, source);
|
|
687
|
-
|
|
688
|
-
|
|
1602
|
+
// A python multi-segment dotted import (`import a.b`) binds only the first segment;
|
|
1603
|
+
// the source only ever repeats the whole dotted phrase to reach the resolved leaf
|
|
1604
|
+
// module again, so `ns` can be that literal phrase and `obj` a compound chain rather
|
|
1605
|
+
// than the single bare identifier every other caller passes.
|
|
1606
|
+
const objectMatches = normalizedNs.includes(".")
|
|
1607
|
+
? normalize(objectName) === normalizedNs
|
|
1608
|
+
: isMemberObjectIdentifier(obj.type) && normalize(objectName) === normalizedNs;
|
|
1609
|
+
if (objectMatches && normalize(propertyName) === normalizedMember) {
|
|
1610
|
+
const inPythonBindingScope = sup.id !== "python" || !effectivePythonBinding || effectivePythonBinding === importBinding;
|
|
1611
|
+
const inAliasScope = inPythonBindingScope &&
|
|
1612
|
+
(sup.id !== "csharp" ||
|
|
1613
|
+
!importBinding ||
|
|
1614
|
+
!imports ||
|
|
1615
|
+
importBinding.kind !== "namespace" ||
|
|
1616
|
+
!importBinding.localRange ||
|
|
1617
|
+
innermostNamespaceImport(imports, objectName, obj, normalize) === importBinding);
|
|
1618
|
+
if (inAliasScope)
|
|
1619
|
+
ranges.push(toRange(prop));
|
|
689
1620
|
}
|
|
690
1621
|
}
|
|
691
1622
|
}
|