gitnexus 1.6.8-rc.8 → 1.6.8
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 +3 -3
- package/dist/_shared/graph/types.d.ts +31 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +11 -1
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +6 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +31 -1
- package/dist/cli/ai-context.js +18 -16
- package/dist/cli/analyze-config.js +11 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +98 -0
- package/dist/cli/embedding-dims.d.ts +33 -0
- package/dist/cli/embedding-dims.js +39 -0
- package/dist/cli/eval-server.d.ts +8 -0
- package/dist/cli/eval-server.js +242 -2
- package/dist/cli/help-i18n.js +19 -0
- package/dist/cli/i18n/en.d.ts +15 -1
- package/dist/cli/i18n/en.js +15 -1
- package/dist/cli/i18n/resources.d.ts +29 -1
- package/dist/cli/i18n/zh-CN.d.ts +14 -0
- package/dist/cli/i18n/zh-CN.js +15 -1
- package/dist/cli/index.js +89 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/setup.d.ts +3 -1
- package/dist/cli/setup.js +67 -17
- package/dist/cli/skill-gen.js +2 -1
- package/dist/cli/tool.d.ts +19 -1
- package/dist/cli/tool.js +96 -3
- package/dist/core/embeddings/hf-env.d.ts +0 -66
- package/dist/core/embeddings/http-client.d.ts +7 -0
- package/dist/core/embeddings/http-client.js +5 -3
- package/dist/core/embeddings/server-mapping.d.ts +1 -1
- package/dist/core/embeddings/server-mapping.js +7 -3
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +5 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +22 -4
- package/dist/core/group/extractors/include-extractor.js +22 -13
- package/dist/core/group/sync.d.ts +27 -1
- package/dist/core/group/sync.js +0 -0
- package/dist/core/incremental/subgraph-extract.js +18 -1
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
- package/dist/core/ingestion/cfg/collect.d.ts +51 -0
- package/dist/core/ingestion/cfg/collect.js +77 -0
- package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
- package/dist/core/ingestion/cfg/control-dependence.js +182 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
- package/dist/core/ingestion/cfg/emit.d.ts +293 -0
- package/dist/core/ingestion/cfg/emit.js +646 -0
- package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
- package/dist/core/ingestion/cfg/post-dominators.js +176 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
- package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
- package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +274 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
- package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
- package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
- package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
- package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/go.js +638 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
- package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
- package/dist/core/ingestion/cfg/visitors/java.js +812 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
- package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
- package/dist/core/ingestion/cfg/visitors/php.js +721 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
- package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
- package/dist/core/ingestion/cfg/visitors/python.js +558 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
- package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
- package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
- package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
- package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
- package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
- package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
- package/dist/core/ingestion/import-resolvers/utils.js +2 -0
- package/dist/core/ingestion/language-provider.d.ts +23 -2
- package/dist/core/ingestion/languages/c-cpp.js +17 -5
- package/dist/core/ingestion/languages/cobol.js +4 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
- package/dist/core/ingestion/languages/cpp/captures.js +50 -1
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
- package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
- package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
- package/dist/core/ingestion/languages/csharp.js +2 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go.js +2 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +8 -1
- package/dist/core/ingestion/languages/php.js +2 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/ruby.js +2 -0
- package/dist/core/ingestion/languages/rust.js +2 -0
- package/dist/core/ingestion/languages/swift.js +2 -0
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/languages/vue.js +6 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/mro-processor.js +109 -0
- package/dist/core/ingestion/parsing-processor.js +44 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/index.js +2 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
- package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
- package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
- package/dist/core/ingestion/pipeline.d.ts +92 -10
- package/dist/core/ingestion/pipeline.js +11 -2
- package/dist/core/ingestion/scope-extractor.js +12 -2
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
- package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
- package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
- package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
- package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
- package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
- package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
- package/dist/core/ingestion/taint/call-summary-model.js +25 -0
- package/dist/core/ingestion/taint/emit.d.ts +125 -0
- package/dist/core/ingestion/taint/emit.js +208 -0
- package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
- package/dist/core/ingestion/taint/interproc-emit.js +88 -0
- package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
- package/dist/core/ingestion/taint/interproc-solver.js +312 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +659 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
- package/dist/core/ingestion/taint/source-sink-config.js +35 -12
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
- package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
- package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
- package/dist/core/ingestion/taint/summary-harvest.js +537 -0
- package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
- package/dist/core/ingestion/taint/summary-model.js +86 -0
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
- package/dist/core/ingestion/utils/env.d.ts +7 -0
- package/dist/core/ingestion/utils/env.js +12 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
- package/dist/core/ingestion/workers/parse-worker.js +81 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
- package/dist/core/ingestion/workers/worker-pool.js +43 -16
- package/dist/core/lbug/csv-generator.d.ts +51 -3
- package/dist/core/lbug/csv-generator.js +369 -255
- package/dist/core/lbug/lbug-adapter.d.ts +58 -18
- package/dist/core/lbug/lbug-adapter.js +346 -84
- package/dist/core/lbug/lbug-config.d.ts +19 -0
- package/dist/core/lbug/lbug-config.js +29 -0
- package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
- package/dist/core/lbug/pdg-emit-sink.js +358 -0
- package/dist/core/lbug/pool-adapter.d.ts +35 -0
- package/dist/core/lbug/pool-adapter.js +90 -1
- package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
- package/dist/core/lbug/rel-pair-routing.js +140 -0
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +3 -0
- package/dist/core/logger.d.ts +0 -5
- package/dist/core/run-analyze.d.ts +96 -0
- package/dist/core/run-analyze.js +207 -3
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/core/wiki/generator.js +3 -1
- package/dist/core/wiki/graph-queries.d.ts +6 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.d.ts +110 -24
- package/dist/mcp/local/local-backend.js +1225 -19
- package/dist/mcp/local/pdg-impact.d.ts +384 -0
- package/dist/mcp/local/pdg-impact.js +1972 -0
- package/dist/mcp/resources.js +13 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.js +214 -7
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -1
- package/dist/server/api.d.ts +17 -0
- package/dist/server/api.js +132 -168
- package/dist/server/git-clone.d.ts +43 -2
- package/dist/server/git-clone.js +211 -16
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +40 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +37 -0
- package/dist/server/upload-paths.js +57 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/git.js +5 -8
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +44 -10
- package/dist/storage/repo-manager.d.ts +121 -10
- package/dist/storage/repo-manager.js +43 -5
- package/dist/types/pipeline.d.ts +9 -0
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
- package/hooks/claude/gitnexus-hook.cjs +110 -13
- package/hooks/claude/hook-db-lock-probe.cjs +513 -26
- package/package.json +8 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/scripts/cross-platform-tests.ts +1 -0
- package/skills/gitnexus-debugging.md +16 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-guide.md +33 -0
- package/skills/gitnexus-pdg-query.md +89 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/skills/gitnexus-taint-analysis.md +178 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
- package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
- package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
- package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
- package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
- package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
- package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
- package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
- package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
- package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
- package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
- package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
- package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
- package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
- package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
- package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
- package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
- package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
- package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
- package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
- package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
- package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
- package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
- package/web/assets/index-BvYev1UJ.js +635 -0
- package/web/assets/index-_lgn7hs5.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
- package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
- package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
- package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
- package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
- package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
- package/web/index.html +13 -15
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
- package/web/assets/chunk-CilyBKbf.js +0 -1
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
- package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
- package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
- package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
- package/web/assets/index-BKWA-m7o.css +0 -2
- package/web/assets/index-CG6q8eTs.js +0 -626
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
- /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
import { CallSiteFactAccumulator as FactAccumulator, finalizeChain } from './call-site-harvest.js';
|
|
2
|
+
/** Node types that own a nested CFG — their subtrees are opaque to harvesting. */
|
|
3
|
+
const NESTED_FUNCTION_TYPES = new Set([
|
|
4
|
+
'function_declaration',
|
|
5
|
+
'init_declaration',
|
|
6
|
+
'deinit_declaration',
|
|
7
|
+
'lambda_literal',
|
|
8
|
+
]);
|
|
9
|
+
export class SwiftHarvester {
|
|
10
|
+
fnNode;
|
|
11
|
+
bindings = [];
|
|
12
|
+
/** Single function-scope name → binding index (v1: no block scope). */
|
|
13
|
+
table = new Map();
|
|
14
|
+
synthetic = new Map();
|
|
15
|
+
fnId;
|
|
16
|
+
/** >0 while walking a conditionally-evaluated subexpression — defs become may-defs. */
|
|
17
|
+
conditionalDepth = 0;
|
|
18
|
+
/**
|
|
19
|
+
* `call_expression` node id → binding indices its single-target result is
|
|
20
|
+
* assigned to (`let x = f()` / `x = g()` ⇒ `[x]`). Populated just before the
|
|
21
|
+
* value walk reaches the call (see {@link registerResultDefs}) and consumed by
|
|
22
|
+
* {@link visitCall}. Mirrors the Kotlin / Go / Python harvesters' map.
|
|
23
|
+
*/
|
|
24
|
+
resultDefTargets = new Map();
|
|
25
|
+
constructor(fnNode) {
|
|
26
|
+
this.fnNode = fnNode;
|
|
27
|
+
this.fnId = fnNode.id;
|
|
28
|
+
this.declareParams(fnNode);
|
|
29
|
+
const body = this.bodyOf(fnNode);
|
|
30
|
+
if (body)
|
|
31
|
+
this.prescan(body);
|
|
32
|
+
}
|
|
33
|
+
/** The completed binding table — pass to `CfgBuilder.finish`. */
|
|
34
|
+
bindingTable() {
|
|
35
|
+
return this.bindings;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The function/closure body `statements` node. A `function_declaration` /
|
|
39
|
+
* `init_declaration` / `deinit_declaration` wraps it in a `function_body`; a
|
|
40
|
+
* `lambda_literal` carries the `statements` directly.
|
|
41
|
+
*/
|
|
42
|
+
bodyOf(fnNode) {
|
|
43
|
+
const fb = fnNode.childForFieldName('body') ??
|
|
44
|
+
fnNode.namedChildren.find((c) => c.type === 'function_body');
|
|
45
|
+
if (fb && fb.type === 'function_body') {
|
|
46
|
+
return fb.namedChildren.find((c) => c.type === 'statements') ?? fb;
|
|
47
|
+
}
|
|
48
|
+
// lambda_literal — its `statements` is a direct named child.
|
|
49
|
+
return fnNode.namedChildren.find((c) => c.type === 'statements');
|
|
50
|
+
}
|
|
51
|
+
// ── phase 1: declaration pre-scan ────────────────────────────────────────
|
|
52
|
+
declare(nameNode, kind) {
|
|
53
|
+
const name = nameNode.text;
|
|
54
|
+
if (!name || name === '_' || this.table.has(name))
|
|
55
|
+
return;
|
|
56
|
+
this.table.set(name, this.bindings.length);
|
|
57
|
+
this.bindings.push({
|
|
58
|
+
name,
|
|
59
|
+
declLine: nameNode.startPosition.row + 1,
|
|
60
|
+
declColumn: nameNode.startPosition.column,
|
|
61
|
+
kind,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Declare every parameter binder of a fn / init / closure. */
|
|
65
|
+
declareParams(fnNode) {
|
|
66
|
+
for (const p of fnNode.namedChildren) {
|
|
67
|
+
if (p.type === 'parameter') {
|
|
68
|
+
const name = p.childForFieldName('name');
|
|
69
|
+
if (name && name.type === 'simple_identifier')
|
|
70
|
+
this.declare(name, 'param');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Closure params live in lambda_function_type → lambda_function_type_parameters.
|
|
74
|
+
const lambdaType = fnNode.namedChildren.find((c) => c.type === 'lambda_function_type');
|
|
75
|
+
if (lambdaType)
|
|
76
|
+
this.declareClosureParams(lambdaType);
|
|
77
|
+
}
|
|
78
|
+
declareClosureParams(lambdaType) {
|
|
79
|
+
for (const params of lambdaType.namedChildren) {
|
|
80
|
+
if (params.type !== 'lambda_function_type_parameters')
|
|
81
|
+
continue;
|
|
82
|
+
for (const id of params.namedChildren) {
|
|
83
|
+
if (id.type === 'simple_identifier')
|
|
84
|
+
this.declare(id, 'param');
|
|
85
|
+
else if (id.type === 'lambda_parameter') {
|
|
86
|
+
const name = id.childForFieldName('name') ??
|
|
87
|
+
id.namedChildren.find((c) => c.type === 'simple_identifier');
|
|
88
|
+
if (name)
|
|
89
|
+
this.declare(name, 'param');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Pre-scan the function body once, declaring every bound name. Recurses into
|
|
96
|
+
* compound expressions but NOT into nested `function_declaration` /
|
|
97
|
+
* `lambda_literal` bodies (opaque).
|
|
98
|
+
*/
|
|
99
|
+
prescan(node) {
|
|
100
|
+
const t = node.type;
|
|
101
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
102
|
+
return;
|
|
103
|
+
switch (t) {
|
|
104
|
+
case 'property_declaration':
|
|
105
|
+
// `let`/`var PAT = …` — declare every `name` pattern's leaves.
|
|
106
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
107
|
+
if (node.fieldNameForChild(i) === 'name') {
|
|
108
|
+
const pat = node.child(i);
|
|
109
|
+
if (pat)
|
|
110
|
+
this.declarePattern(pat);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
case 'for_statement': {
|
|
115
|
+
const pat = node.childForFieldName('item');
|
|
116
|
+
if (pat)
|
|
117
|
+
this.declarePattern(pat);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case 'catch_block': {
|
|
121
|
+
const err = node.childForFieldName('error');
|
|
122
|
+
if (err)
|
|
123
|
+
this.declarePattern(err);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'switch_pattern': {
|
|
127
|
+
// `case let n` / `case (let a, let b)` / `case .some(let v)` — declare
|
|
128
|
+
// the value binding(s) so a body use resolves to a real local.
|
|
129
|
+
const pat = node.namedChildren.find((c) => c.type === 'pattern');
|
|
130
|
+
if (pat)
|
|
131
|
+
this.declarePattern(pat);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
default:
|
|
135
|
+
// Optional binding (`if let` / `while let` / `guard let`): a
|
|
136
|
+
// `value_binding_pattern` condition followed by a `bound_identifier`.
|
|
137
|
+
if (t === 'if_statement' || t === 'while_statement' || t === 'guard_statement') {
|
|
138
|
+
this.declareOptionalBindings(node);
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
143
|
+
const c = node.namedChild(i);
|
|
144
|
+
if (c)
|
|
145
|
+
this.prescan(c);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** Declare the bindings of each optional binding in a condition. */
|
|
149
|
+
declareOptionalBindings(node) {
|
|
150
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
151
|
+
const child = node.child(i);
|
|
152
|
+
if (!child)
|
|
153
|
+
continue;
|
|
154
|
+
// `if/guard let v = e` — a direct `bound_identifier` field.
|
|
155
|
+
if (node.fieldNameForChild(i) === 'bound_identifier') {
|
|
156
|
+
this.declare(child, 'let');
|
|
157
|
+
}
|
|
158
|
+
else if (child.type === 'pattern') {
|
|
159
|
+
// `if/guard case PAT = e` (e.g. `case .some(let v)`): the binder is nested
|
|
160
|
+
// in a `pattern` condition child, not a direct `bound_identifier`, so it
|
|
161
|
+
// was missed and resolved to a synthetic global. declarePattern finds its
|
|
162
|
+
// bound leaves (#2206).
|
|
163
|
+
this.declarePattern(child);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Declare every `simple_identifier` leaf of a binding pattern. Handles the
|
|
169
|
+
* common Swift pattern shapes: a `bound_identifier` simple pattern and tuple
|
|
170
|
+
* destructuring (`(a, b)`), which nests `pattern` children. `_` (the wildcard)
|
|
171
|
+
* binds nothing.
|
|
172
|
+
*/
|
|
173
|
+
declarePattern(pat) {
|
|
174
|
+
const bound = pat.childForFieldName?.('bound_identifier');
|
|
175
|
+
if (bound && bound.type === 'simple_identifier') {
|
|
176
|
+
this.declare(bound, 'let');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (pat.type === 'simple_identifier') {
|
|
180
|
+
this.declare(pat, 'let');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Tuple / nested pattern — recurse into child patterns / identifiers.
|
|
184
|
+
for (let i = 0; i < pat.namedChildCount; i++) {
|
|
185
|
+
const c = pat.namedChild(i);
|
|
186
|
+
if (!c)
|
|
187
|
+
continue;
|
|
188
|
+
if (c.type === 'pattern')
|
|
189
|
+
this.declarePattern(c);
|
|
190
|
+
else if (c.type === 'simple_identifier')
|
|
191
|
+
this.declare(c, 'let');
|
|
192
|
+
else if (c.type === 'value_binding_pattern')
|
|
193
|
+
continue;
|
|
194
|
+
else
|
|
195
|
+
this.declarePattern(c);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// ── phase 2: per-statement fact extraction ───────────────────────────────
|
|
199
|
+
/** Def/use facts for one statement (or construct-header expression) node. */
|
|
200
|
+
facts(node) {
|
|
201
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
202
|
+
this.walkValue(node, acc);
|
|
203
|
+
return acc.finish();
|
|
204
|
+
}
|
|
205
|
+
/** Facts for an expression whose WHOLE evaluation is conditional (guards/tests). */
|
|
206
|
+
factsConditional(node) {
|
|
207
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
208
|
+
this.conditional(() => this.walkValue(node, acc));
|
|
209
|
+
return acc.finish();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Def-ONLY facts for a value-position binding carrier (`let x = if … / switch …`,
|
|
213
|
+
* #2207): just the declared name pattern's leaves, attached to the continuation
|
|
214
|
+
* block the branch arms rejoin. The condition + arm-value USES are already
|
|
215
|
+
* harvested onto the branch's own blocks (visitIf / visitSwitch), so this must
|
|
216
|
+
* NOT re-walk the value — only the `name`-field pattern leaves are defs here.
|
|
217
|
+
*/
|
|
218
|
+
bindingDefFacts(stmt) {
|
|
219
|
+
const acc = new FactAccumulator(stmt.startPosition.row + 1);
|
|
220
|
+
for (let i = 0; i < stmt.childCount; i++) {
|
|
221
|
+
if (stmt.fieldNameForChild(i) === 'name') {
|
|
222
|
+
const pat = stmt.child(i);
|
|
223
|
+
if (pat)
|
|
224
|
+
this.defPattern(pat, acc);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* MAY-def facts for a `switch_pattern`'s value bindings (`case let n` /
|
|
231
|
+
* `case .some(let v)`). The binding only takes effect when the case matches,
|
|
232
|
+
* so it is a may-def on the dispatch block — propagated into the case body
|
|
233
|
+
* where the bound name is read.
|
|
234
|
+
*/
|
|
235
|
+
switchPatternFacts(switchPattern) {
|
|
236
|
+
const acc = new FactAccumulator(switchPattern.startPosition.row + 1);
|
|
237
|
+
const pat = switchPattern.namedChildren.find((c) => c.type === 'pattern');
|
|
238
|
+
if (pat)
|
|
239
|
+
this.conditional(() => this.defPattern(pat, acc));
|
|
240
|
+
return acc.finish();
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Facts for a `for item in COLLECTION` head: the loop pattern's leaves are
|
|
244
|
+
* defs, the iterated collection a use. The `where` guard (if any) is harvested
|
|
245
|
+
* conditionally.
|
|
246
|
+
*/
|
|
247
|
+
forHeadFacts(stmt) {
|
|
248
|
+
const acc = new FactAccumulator(stmt.startPosition.row + 1);
|
|
249
|
+
const collection = stmt.childForFieldName('collection');
|
|
250
|
+
const item = stmt.childForFieldName('item');
|
|
251
|
+
if (collection)
|
|
252
|
+
this.walkValue(collection, acc);
|
|
253
|
+
if (item)
|
|
254
|
+
this.defPattern(item, acc);
|
|
255
|
+
const where = stmt.namedChildren.find((c) => c.type === 'where_clause');
|
|
256
|
+
if (where)
|
|
257
|
+
this.conditional(() => this.walkValue(where, acc));
|
|
258
|
+
return acc.finish();
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Facts for an `if`/`while`/`guard` condition: optional bindings bind their
|
|
262
|
+
* pattern (a def — a may-def when `conditional`), and the condition expression
|
|
263
|
+
* children are uses. The construct's `condition` / `bound_identifier` fields are
|
|
264
|
+
* interleaved, so we walk all children and classify them.
|
|
265
|
+
*/
|
|
266
|
+
conditionFacts(stmt, conditional) {
|
|
267
|
+
const acc = new FactAccumulator(stmt.startPosition.row + 1);
|
|
268
|
+
const run = () => {
|
|
269
|
+
for (let i = 0; i < stmt.childCount; i++) {
|
|
270
|
+
const field = stmt.fieldNameForChild(i);
|
|
271
|
+
const child = stmt.child(i);
|
|
272
|
+
if (!child)
|
|
273
|
+
continue;
|
|
274
|
+
if (field === 'bound_identifier')
|
|
275
|
+
this.def(child, acc);
|
|
276
|
+
else if (field === 'condition') {
|
|
277
|
+
// `value_binding_pattern` (`let`) and the `=` operator carry no uses.
|
|
278
|
+
if (child.type === 'value_binding_pattern')
|
|
279
|
+
continue;
|
|
280
|
+
if (!child.isNamed)
|
|
281
|
+
continue;
|
|
282
|
+
// `if/guard case PAT = e` (e.g. `case .some(let v)`): the `pattern` child
|
|
283
|
+
// BINDS — its leaves are defs (a may-def when conditional), not uses, so
|
|
284
|
+
// a tainted subject propagates to the binding (#2206). The matched
|
|
285
|
+
// subject and any other condition child are uses.
|
|
286
|
+
if (child.type === 'pattern')
|
|
287
|
+
this.defPattern(child, acc);
|
|
288
|
+
else
|
|
289
|
+
this.walkValue(child, acc);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
if (conditional)
|
|
294
|
+
this.conditional(run);
|
|
295
|
+
else
|
|
296
|
+
run();
|
|
297
|
+
return acc.finish();
|
|
298
|
+
}
|
|
299
|
+
/** ENTRY-block facts for the parameters (defs only). */
|
|
300
|
+
paramFacts() {
|
|
301
|
+
const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
|
|
302
|
+
for (const p of this.fnNode.namedChildren) {
|
|
303
|
+
if (p.type === 'parameter') {
|
|
304
|
+
const name = p.childForFieldName('name');
|
|
305
|
+
if (name && name.type === 'simple_identifier')
|
|
306
|
+
this.def(name, acc);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const lambdaType = this.fnNode.namedChildren.find((c) => c.type === 'lambda_function_type');
|
|
310
|
+
if (lambdaType) {
|
|
311
|
+
for (const params of lambdaType.namedChildren) {
|
|
312
|
+
if (params.type !== 'lambda_function_type_parameters')
|
|
313
|
+
continue;
|
|
314
|
+
for (const id of params.namedChildren) {
|
|
315
|
+
if (id.type === 'simple_identifier')
|
|
316
|
+
this.def(id, acc);
|
|
317
|
+
else if (id.type === 'lambda_parameter') {
|
|
318
|
+
const name = id.childForFieldName('name') ??
|
|
319
|
+
id.namedChildren.find((c) => c.type === 'simple_identifier');
|
|
320
|
+
if (name)
|
|
321
|
+
this.def(name, acc);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
327
|
+
}
|
|
328
|
+
/** Def fact for a `catch let e` error pattern — prepend to the handler entry block. */
|
|
329
|
+
catchErrorFacts(catchBlock) {
|
|
330
|
+
const err = catchBlock.childForFieldName('error');
|
|
331
|
+
if (!err)
|
|
332
|
+
return undefined;
|
|
333
|
+
const acc = new FactAccumulator(catchBlock.startPosition.row + 1);
|
|
334
|
+
this.defPattern(err, acc);
|
|
335
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
336
|
+
}
|
|
337
|
+
resolve(nameNode) {
|
|
338
|
+
const name = nameNode.text;
|
|
339
|
+
const idx = this.table.get(name);
|
|
340
|
+
if (idx !== undefined)
|
|
341
|
+
return idx;
|
|
342
|
+
let syn = this.synthetic.get(name);
|
|
343
|
+
if (syn === undefined) {
|
|
344
|
+
syn = this.bindings.length;
|
|
345
|
+
this.synthetic.set(name, syn);
|
|
346
|
+
this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
|
|
347
|
+
}
|
|
348
|
+
return syn;
|
|
349
|
+
}
|
|
350
|
+
def(nameNode, acc) {
|
|
351
|
+
if (nameNode.text === '_')
|
|
352
|
+
return; // blank target defines nothing
|
|
353
|
+
if (this.conditionalDepth > 0)
|
|
354
|
+
acc.addMayDef(this.resolve(nameNode));
|
|
355
|
+
else
|
|
356
|
+
acc.addDef(this.resolve(nameNode));
|
|
357
|
+
}
|
|
358
|
+
use(nameNode, acc) {
|
|
359
|
+
if (nameNode.text === '_')
|
|
360
|
+
return;
|
|
361
|
+
acc.addUse(this.resolve(nameNode));
|
|
362
|
+
}
|
|
363
|
+
/** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
|
|
364
|
+
conditional(fn) {
|
|
365
|
+
this.conditionalDepth++;
|
|
366
|
+
try {
|
|
367
|
+
fn();
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
this.conditionalDepth--;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Def each `simple_identifier` leaf of a binding pattern (the def-position
|
|
375
|
+
* analogue of {@link declarePattern}). Tuple destructuring recurses; `_` binds
|
|
376
|
+
* nothing.
|
|
377
|
+
*/
|
|
378
|
+
defPattern(pat, acc) {
|
|
379
|
+
const bound = pat.childForFieldName?.('bound_identifier');
|
|
380
|
+
if (bound && bound.type === 'simple_identifier') {
|
|
381
|
+
this.def(bound, acc);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (pat.type === 'simple_identifier') {
|
|
385
|
+
this.def(pat, acc);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
for (let i = 0; i < pat.namedChildCount; i++) {
|
|
389
|
+
const c = pat.namedChild(i);
|
|
390
|
+
if (!c)
|
|
391
|
+
continue;
|
|
392
|
+
if (c.type === 'pattern')
|
|
393
|
+
this.defPattern(c, acc);
|
|
394
|
+
else if (c.type === 'simple_identifier')
|
|
395
|
+
this.def(c, acc);
|
|
396
|
+
else if (c.type === 'value_binding_pattern')
|
|
397
|
+
continue;
|
|
398
|
+
else
|
|
399
|
+
this.defPattern(c, acc);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/** Value-position walk: collect uses; route def positions to the pattern handler. */
|
|
403
|
+
walkValue(node, acc) {
|
|
404
|
+
const t = node.type;
|
|
405
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
406
|
+
return; // opaque
|
|
407
|
+
switch (t) {
|
|
408
|
+
case 'simple_identifier':
|
|
409
|
+
this.use(node, acc);
|
|
410
|
+
return;
|
|
411
|
+
case 'property_declaration': {
|
|
412
|
+
// Walk each `value` for uses, then def each `name` pattern's leaves.
|
|
413
|
+
const names = [];
|
|
414
|
+
const values = [];
|
|
415
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
416
|
+
const field = node.fieldNameForChild(i);
|
|
417
|
+
const child = node.child(i);
|
|
418
|
+
if (!child)
|
|
419
|
+
continue;
|
|
420
|
+
if (field === 'value' || field === 'computed_value')
|
|
421
|
+
values.push(child);
|
|
422
|
+
else if (field === 'name')
|
|
423
|
+
names.push(child);
|
|
424
|
+
}
|
|
425
|
+
// Register result-defs BEFORE the value walk so the call the walk reaches
|
|
426
|
+
// carries them — single-name `let x = f()` only (a destructuring or
|
|
427
|
+
// multi-binder `let (a, b) = …` / `let p = 1, q = 2` attaches nothing).
|
|
428
|
+
const single = this.singlePatternBinder(names);
|
|
429
|
+
if (single && values.length === 1)
|
|
430
|
+
this.registerResultDefs(values[0], [single]);
|
|
431
|
+
for (const value of values)
|
|
432
|
+
this.walkValue(value, acc);
|
|
433
|
+
for (const pat of names)
|
|
434
|
+
this.defPattern(pat, acc);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
case 'assignment': {
|
|
438
|
+
const target = node.childForFieldName('target');
|
|
439
|
+
const result = node.childForFieldName('result');
|
|
440
|
+
const op = node.childForFieldName('operator')?.text ?? '=';
|
|
441
|
+
const lv = target ? this.unwrapAssignable(target) : undefined;
|
|
442
|
+
const scalar = lv && lv.type === 'simple_identifier' ? lv : undefined;
|
|
443
|
+
// A plain `x = <call>` attaches `resultDefs: [x]`; a compound `+=` does
|
|
444
|
+
// not (the prior value flows in too).
|
|
445
|
+
if (scalar && op === '=' && result)
|
|
446
|
+
this.registerResultDefs(result, [scalar]);
|
|
447
|
+
if (result)
|
|
448
|
+
this.walkValue(result, acc);
|
|
449
|
+
if (lv) {
|
|
450
|
+
if (scalar) {
|
|
451
|
+
this.def(scalar, acc);
|
|
452
|
+
if (op !== '=')
|
|
453
|
+
this.use(scalar, acc); // compound assign reads too
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
// `self.x = …`, `a[i] = …` — root is a use only (not a scalar def).
|
|
457
|
+
this.walkValue(lv, acc);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
case 'call_expression':
|
|
463
|
+
// A Swift call (`foo(a)`, `obj.method(x)`, `a.b.c()`, `Foo(...)`). Records
|
|
464
|
+
// a taint site (callee path, receiver, per-arg occurrences, result defs)
|
|
465
|
+
// while reproducing the uses the old default descent recorded. Swift has
|
|
466
|
+
// no `new` — every site is `kind: 'call'`.
|
|
467
|
+
this.visitCall(node, acc);
|
|
468
|
+
return;
|
|
469
|
+
case 'navigation_expression': {
|
|
470
|
+
// `a.b` value read — the chain-root identifier is a use plus at most one
|
|
471
|
+
// member-read site (the innermost access); the suffix name is not a scalar
|
|
472
|
+
// binding. Mirrors the Kotlin / Go value-position member-read semantics.
|
|
473
|
+
this.walkChain(node, acc, false);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
case 'try_expression': {
|
|
477
|
+
// `try expr` / `try? expr` / `try! expr` — the wrapped expression's uses.
|
|
478
|
+
const expr = node.childForFieldName('expr');
|
|
479
|
+
if (expr)
|
|
480
|
+
this.walkValue(expr, acc);
|
|
481
|
+
else
|
|
482
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
483
|
+
const c = node.namedChild(i);
|
|
484
|
+
if (c && c.type !== 'try_operator')
|
|
485
|
+
this.walkValue(c, acc);
|
|
486
|
+
}
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
case 'conjunction_expression':
|
|
490
|
+
case 'disjunction_expression': {
|
|
491
|
+
// `a && b` / `a || b` — the right operand is conditionally evaluated.
|
|
492
|
+
const lhs = node.childForFieldName('lhs');
|
|
493
|
+
const rhs = node.childForFieldName('rhs');
|
|
494
|
+
if (lhs)
|
|
495
|
+
this.walkValue(lhs, acc);
|
|
496
|
+
else if (node.namedChildCount > 0)
|
|
497
|
+
this.walkValue(node.namedChild(0), acc);
|
|
498
|
+
if (rhs)
|
|
499
|
+
this.conditional(() => this.walkValue(rhs, acc));
|
|
500
|
+
else if (node.namedChildCount > 1) {
|
|
501
|
+
this.conditional(() => this.walkValue(node.namedChild(node.namedChildCount - 1), acc));
|
|
502
|
+
}
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
case 'value_binding_pattern':
|
|
506
|
+
case 'type_identifier':
|
|
507
|
+
case 'user_type':
|
|
508
|
+
// Binding keyword / type position — no scalar value uses.
|
|
509
|
+
return;
|
|
510
|
+
default:
|
|
511
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
512
|
+
const c = node.namedChild(i);
|
|
513
|
+
if (c)
|
|
514
|
+
this.walkValue(c, acc);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/** Strip a `directly_assignable_expression` wrapper around an lvalue. */
|
|
519
|
+
unwrapAssignable(node) {
|
|
520
|
+
let n = node;
|
|
521
|
+
let hops = 4;
|
|
522
|
+
while (n.type === 'directly_assignable_expression' && hops-- > 0) {
|
|
523
|
+
const inner = n.namedChild(0);
|
|
524
|
+
if (!inner)
|
|
525
|
+
break;
|
|
526
|
+
n = inner;
|
|
527
|
+
}
|
|
528
|
+
return n;
|
|
529
|
+
}
|
|
530
|
+
// ── taint-site harvest ───────────────────────────────────────────────────
|
|
531
|
+
/**
|
|
532
|
+
* The sole `bound_identifier` binder of a single `name` pattern, or undefined
|
|
533
|
+
* when there are multiple `name` patterns or the pattern is a tuple / wildcard
|
|
534
|
+
* destructuring (`let (a, b) = …`). Used to gate single-target result-defs.
|
|
535
|
+
*/
|
|
536
|
+
singlePatternBinder(names) {
|
|
537
|
+
if (names.length !== 1)
|
|
538
|
+
return undefined;
|
|
539
|
+
const pat = names[0];
|
|
540
|
+
const bound = pat.childForFieldName?.('bound_identifier');
|
|
541
|
+
if (bound && bound.type === 'simple_identifier' && bound.text !== '_')
|
|
542
|
+
return bound;
|
|
543
|
+
if (pat.type === 'simple_identifier' && pat.text !== '_')
|
|
544
|
+
return pat;
|
|
545
|
+
return undefined;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* When `value`'s root (after unwrapping) is a `call_expression`, remember that
|
|
549
|
+
* call site should carry `resultDefs` — the binding indices of `targets`
|
|
550
|
+
* (def-position identifiers). Consumed by {@link visitCall} once the value walk
|
|
551
|
+
* reaches the node. Single-target only; the blank target (`_`) binds nothing.
|
|
552
|
+
*/
|
|
553
|
+
registerResultDefs(value, targets) {
|
|
554
|
+
const root = this.unwrapAssignable(value);
|
|
555
|
+
if (root.type !== 'call_expression')
|
|
556
|
+
return;
|
|
557
|
+
const defs = [];
|
|
558
|
+
for (const target of targets) {
|
|
559
|
+
if (target.type !== 'simple_identifier' || target.text === '_')
|
|
560
|
+
continue;
|
|
561
|
+
defs.push(this.resolve(target));
|
|
562
|
+
}
|
|
563
|
+
if (defs.length > 0)
|
|
564
|
+
this.resultDefTargets.set(root.id, defs);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* The callee node of a `call_expression` — the first named child that is NOT
|
|
568
|
+
* the trailing `call_suffix` (a bare `simple_identifier` for a free / init
|
|
569
|
+
* call, or a `navigation_expression` for a member / chained call).
|
|
570
|
+
*/
|
|
571
|
+
calleeOf(call) {
|
|
572
|
+
for (let i = 0; i < call.namedChildCount; i++) {
|
|
573
|
+
const c = call.namedChild(i);
|
|
574
|
+
if (c && c.type !== 'call_suffix')
|
|
575
|
+
return c;
|
|
576
|
+
}
|
|
577
|
+
return undefined;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Open + populate a call site for a Swift `call_expression`. `node` IS the
|
|
581
|
+
* `call_expression` — the SAME node the scope query anchors `@reference.call.*`
|
|
582
|
+
* on (its `atRange`), so the resolved-id join lands by exact position (see file
|
|
583
|
+
* header ANCHOR ALIGNMENT). Swift has no `new`, so every site is `kind: 'call'`.
|
|
584
|
+
*/
|
|
585
|
+
visitCall(node, acc) {
|
|
586
|
+
const calleeNode = this.calleeOf(node);
|
|
587
|
+
const siteIdx = acc.openCallSite('call', [
|
|
588
|
+
node.startPosition.row + 1,
|
|
589
|
+
node.startPosition.column,
|
|
590
|
+
]);
|
|
591
|
+
acc.pushFrame(siteIdx);
|
|
592
|
+
if (calleeNode) {
|
|
593
|
+
const callee = this.unwrapAssignable(calleeNode);
|
|
594
|
+
if (callee.type === 'simple_identifier') {
|
|
595
|
+
// A bare free / init call — the callee NAME is a statement-level use but
|
|
596
|
+
// NOT a value occurrence in any enclosing argument.
|
|
597
|
+
if (callee.text !== '_')
|
|
598
|
+
acc.addUseWithoutOccurrence(this.resolve(callee));
|
|
599
|
+
acc.setSiteCallee(siteIdx, callee.text);
|
|
600
|
+
}
|
|
601
|
+
else if (callee.type === 'navigation_expression') {
|
|
602
|
+
// skipFinalRead: the final `.name` IS the callee, carried by the path.
|
|
603
|
+
const chain = this.walkChain(callee, acc, true);
|
|
604
|
+
if (chain.path !== undefined)
|
|
605
|
+
acc.setSiteCallee(siteIdx, chain.path);
|
|
606
|
+
if (chain.rootIdx !== undefined)
|
|
607
|
+
acc.setSiteReceiver(siteIdx, chain.rootIdx);
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
// Call-rooted chains (`f()()`), parenthesized callables, `self.x`-rooted —
|
|
611
|
+
// the walk still records uses and nested sites; no static callee path.
|
|
612
|
+
this.walkValue(callee, acc);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
const resultDefs = this.resultDefTargets.get(node.id);
|
|
616
|
+
if (resultDefs !== undefined)
|
|
617
|
+
acc.setSiteResultDefs(siteIdx, resultDefs);
|
|
618
|
+
const suffix = node.namedChildren.find((c) => c.type === 'call_suffix');
|
|
619
|
+
if (suffix)
|
|
620
|
+
this.walkArguments(suffix, acc);
|
|
621
|
+
acc.popFrame();
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Walk a `call_suffix`'s `value_arguments`, tagging each positional / labeled
|
|
625
|
+
* argument's occurrence position. A trailing closure (`lambda_literal`) is a
|
|
626
|
+
* nested function body — opaque (excluded by {@link NESTED_FUNCTION_TYPES}), so
|
|
627
|
+
* it is not an argument occurrence here.
|
|
628
|
+
*/
|
|
629
|
+
walkArguments(suffix, acc) {
|
|
630
|
+
const args = suffix.namedChildren.find((c) => c.type === 'value_arguments');
|
|
631
|
+
if (!args)
|
|
632
|
+
return;
|
|
633
|
+
let pos = 0;
|
|
634
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
635
|
+
const arg = args.namedChild(i);
|
|
636
|
+
if (!arg || arg.type !== 'value_argument')
|
|
637
|
+
continue;
|
|
638
|
+
acc.setFrameArg(pos);
|
|
639
|
+
// A labeled arg (`name: value`) records only the VALUE occurrence — the
|
|
640
|
+
// `value_argument_label` is dropped. An `&inout` value walks its `target`
|
|
641
|
+
// identifier for the use. Swift has no call-site spread operator.
|
|
642
|
+
const value = arg.childForFieldName('value');
|
|
643
|
+
if (value)
|
|
644
|
+
this.walkValue(value, acc);
|
|
645
|
+
pos++;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* `navigation_expression` chain walk shared by value position and callee
|
|
650
|
+
* position. Records the chain-root identifier as a use plus at most ONE
|
|
651
|
+
* member-read site — the INNERMOST access — when the root is an identifier;
|
|
652
|
+
* `skipFinalRead` suppresses it when that access is the callee (carried by the
|
|
653
|
+
* dotted path instead). Mirrors the Kotlin / Go / Python harvesters' walkChain.
|
|
654
|
+
* A non-identifier root (`self`/literal/call) launders no static path/receiver.
|
|
655
|
+
*/
|
|
656
|
+
walkChain(node, acc, skipFinalRead) {
|
|
657
|
+
const accesses = [];
|
|
658
|
+
let cur = this.unwrapAssignable(node);
|
|
659
|
+
for (;;) {
|
|
660
|
+
if (cur.type === 'navigation_expression') {
|
|
661
|
+
const suffix = cur.childForFieldName('suffix');
|
|
662
|
+
const name = suffix?.childForFieldName('suffix');
|
|
663
|
+
accesses.unshift(name?.text ?? '');
|
|
664
|
+
const operand = cur.childForFieldName('target');
|
|
665
|
+
if (!operand)
|
|
666
|
+
break;
|
|
667
|
+
cur = this.unwrapAssignable(operand);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// The shared terminal: root-use record + innermost member-read + path-join.
|
|
674
|
+
return finalizeChain(acc, cur, accesses, skipFinalRead, (t) => t === 'simple_identifier', {
|
|
675
|
+
resolve: (n) => this.resolve(n),
|
|
676
|
+
walkRoot: (n) => this.walkValue(n, acc),
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|