gitnexus 1.6.8-rc.9 → 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 +11 -0
- package/dist/core/ingestion/languages/c-cpp.js +6 -1
- 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 +3 -0
- 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 +23 -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/parse-worker.d.ts +13 -0
- package/dist/core/ingestion/workers/parse-worker.js +76 -17
- package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
- package/dist/core/ingestion/workers/worker-pool.js +15 -2
- 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.d.ts +17 -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 +41 -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,739 @@
|
|
|
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(['function_definition', 'lambda']);
|
|
4
|
+
/** LHS pattern containers whose identifier/splat leaves are assignment targets. */
|
|
5
|
+
const PATTERN_LIST_TYPES = new Set(['pattern_list', 'tuple_pattern', 'list_pattern']);
|
|
6
|
+
export class PythonHarvester {
|
|
7
|
+
fnNode;
|
|
8
|
+
bindings = [];
|
|
9
|
+
/** Single function-scope name → binding index (Python has no block scope). */
|
|
10
|
+
table = new Map();
|
|
11
|
+
synthetic = new Map();
|
|
12
|
+
/** Names declared `global`/`nonlocal` — resolve to the synthetic module binding. */
|
|
13
|
+
globalNames = new Set();
|
|
14
|
+
fnId;
|
|
15
|
+
/** >0 while walking a conditionally-evaluated subexpression — defs become may-defs. */
|
|
16
|
+
conditionalDepth = 0;
|
|
17
|
+
/**
|
|
18
|
+
* `call` node id → binding indices its single-target result is assigned to
|
|
19
|
+
* (`x = f()` ⇒ `[x]`). Populated just before the value walk reaches the call
|
|
20
|
+
* (see {@link registerResultDefs}) and consumed by {@link visitCall}. Mirrors
|
|
21
|
+
* the Go harvester's `resultDefTargets`.
|
|
22
|
+
*/
|
|
23
|
+
resultDefTargets = new Map();
|
|
24
|
+
constructor(fnNode) {
|
|
25
|
+
this.fnNode = fnNode;
|
|
26
|
+
this.fnId = fnNode.id;
|
|
27
|
+
this.declareParams(fnNode);
|
|
28
|
+
const body = this.bodyOf(fnNode);
|
|
29
|
+
if (body)
|
|
30
|
+
this.prescan(body);
|
|
31
|
+
}
|
|
32
|
+
/** The completed binding table — pass to `CfgBuilder.finish`. */
|
|
33
|
+
bindingTable() {
|
|
34
|
+
return this.bindings;
|
|
35
|
+
}
|
|
36
|
+
/** The function/lambda body node (a `block` for `def`, an expression for `lambda`). */
|
|
37
|
+
bodyOf(fnNode) {
|
|
38
|
+
return fnNode.childForFieldName('body') ?? undefined;
|
|
39
|
+
}
|
|
40
|
+
// ── phase 1: declaration pre-scan ────────────────────────────────────────
|
|
41
|
+
declare(nameNode, kind) {
|
|
42
|
+
const name = nameNode.text;
|
|
43
|
+
if (!name || name === '_' || this.table.has(name) || this.globalNames.has(name))
|
|
44
|
+
return;
|
|
45
|
+
this.table.set(name, this.bindings.length);
|
|
46
|
+
this.bindings.push({
|
|
47
|
+
name,
|
|
48
|
+
declLine: nameNode.startPosition.row + 1,
|
|
49
|
+
declColumn: nameNode.startPosition.column,
|
|
50
|
+
kind,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** Declare every parameter binder (incl. defaults, typed, `*args`, `**kwargs`). */
|
|
54
|
+
declareParams(fnNode) {
|
|
55
|
+
const params = fnNode.childForFieldName('parameters') ??
|
|
56
|
+
fnNode.namedChildren.find((c) => c.type === 'parameters' || c.type === 'lambda_parameters');
|
|
57
|
+
if (!params)
|
|
58
|
+
return;
|
|
59
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
60
|
+
const p = params.namedChild(i);
|
|
61
|
+
if (p)
|
|
62
|
+
this.declareParam(p);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Declare the binder identifier(s) of one parameter node. */
|
|
66
|
+
declareParam(p) {
|
|
67
|
+
switch (p.type) {
|
|
68
|
+
case 'identifier':
|
|
69
|
+
this.declare(p, 'param');
|
|
70
|
+
return;
|
|
71
|
+
case 'default_parameter':
|
|
72
|
+
case 'typed_default_parameter': {
|
|
73
|
+
const name = p.childForFieldName('name');
|
|
74
|
+
if (name)
|
|
75
|
+
this.declareParamBinder(name);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
case 'typed_parameter': {
|
|
79
|
+
// No `name` field — the binder is the first non-`type` named child
|
|
80
|
+
// (an identifier or a splat pattern).
|
|
81
|
+
const typeNode = p.childForFieldName('type');
|
|
82
|
+
for (let i = 0; i < p.namedChildCount; i++) {
|
|
83
|
+
const c = p.namedChild(i);
|
|
84
|
+
if (c && c.id !== typeNode?.id) {
|
|
85
|
+
this.declareParamBinder(c);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
case 'list_splat_pattern':
|
|
92
|
+
case 'dictionary_splat_pattern':
|
|
93
|
+
this.declareParamBinder(p);
|
|
94
|
+
return;
|
|
95
|
+
default:
|
|
96
|
+
// tuple-grouped params and the like — declare any identifier leaves.
|
|
97
|
+
this.declareParamBinder(p);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** Declare a binder that may be an identifier or a `*`/`**` splat pattern. */
|
|
101
|
+
declareParamBinder(node) {
|
|
102
|
+
if (node.type === 'identifier') {
|
|
103
|
+
this.declare(node, 'param');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (node.type === 'list_splat_pattern' || node.type === 'dictionary_splat_pattern') {
|
|
107
|
+
const id = node.namedChild(0);
|
|
108
|
+
if (id?.type === 'identifier')
|
|
109
|
+
this.declare(id, 'param');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Nested grouping — declare identifier descendants up to the next binder.
|
|
113
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
114
|
+
const c = node.namedChild(i);
|
|
115
|
+
if (c?.type === 'identifier')
|
|
116
|
+
this.declare(c, 'param');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Pre-scan the function body once, declaring every in-function name. Recurses
|
|
121
|
+
* into compound statements but NOT into nested `function_definition` / `lambda`
|
|
122
|
+
* bodies (opaque). `global`/`nonlocal` are processed FIRST in a sibling sweep
|
|
123
|
+
* so a later assignment to a global name does not mint a function-local.
|
|
124
|
+
*/
|
|
125
|
+
prescan(node) {
|
|
126
|
+
const t = node.type;
|
|
127
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
128
|
+
return;
|
|
129
|
+
switch (t) {
|
|
130
|
+
case 'global_statement':
|
|
131
|
+
case 'nonlocal_statement': {
|
|
132
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
133
|
+
const c = node.namedChild(i);
|
|
134
|
+
if (c?.type === 'identifier')
|
|
135
|
+
this.globalNames.add(c.text);
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
case 'assignment': {
|
|
140
|
+
const left = node.childForFieldName('left');
|
|
141
|
+
if (left)
|
|
142
|
+
this.declareTargets(left);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case 'augmented_assignment': {
|
|
146
|
+
const left = node.childForFieldName('left');
|
|
147
|
+
if (left)
|
|
148
|
+
this.declareTargets(left);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case 'named_expression': {
|
|
152
|
+
const name = node.childForFieldName('name');
|
|
153
|
+
if (name?.type === 'identifier')
|
|
154
|
+
this.declare(name, 'let');
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'for_statement':
|
|
158
|
+
case 'for_in_clause': {
|
|
159
|
+
const left = node.childForFieldName('left');
|
|
160
|
+
if (left)
|
|
161
|
+
this.declareTargets(left);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case 'with_item': {
|
|
165
|
+
this.declareWithItem(node);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'except_clause':
|
|
169
|
+
case 'except_group_clause': {
|
|
170
|
+
this.declareExceptAlias(node);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
177
|
+
const c = node.namedChild(i);
|
|
178
|
+
if (c)
|
|
179
|
+
this.prescan(c);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Declare identifier/splat leaves of an assignment / loop target pattern. */
|
|
183
|
+
declareTargets(target) {
|
|
184
|
+
const t = target.type;
|
|
185
|
+
if (t === 'identifier') {
|
|
186
|
+
this.declare(target, 'let');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (PATTERN_LIST_TYPES.has(t)) {
|
|
190
|
+
for (let i = 0; i < target.namedChildCount; i++) {
|
|
191
|
+
const c = target.namedChild(i);
|
|
192
|
+
if (c)
|
|
193
|
+
this.declareTargets(c);
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (t === 'list_splat_pattern') {
|
|
198
|
+
const id = target.namedChild(0);
|
|
199
|
+
if (id?.type === 'identifier')
|
|
200
|
+
this.declare(id, 'let');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// attribute / subscript target — not a scalar def (root is a use only).
|
|
204
|
+
}
|
|
205
|
+
/** `with EXPR as TARGET` — declare the alias target(s). */
|
|
206
|
+
declareWithItem(item) {
|
|
207
|
+
const value = item.childForFieldName('value') ?? item.namedChild(0);
|
|
208
|
+
if (value?.type !== 'as_pattern')
|
|
209
|
+
return;
|
|
210
|
+
const alias = value.childForFieldName('alias') ?? this.asPatternTarget(value);
|
|
211
|
+
if (alias)
|
|
212
|
+
this.declareAsTarget(alias);
|
|
213
|
+
}
|
|
214
|
+
/** `except E as e` — declare `e`. */
|
|
215
|
+
declareExceptAlias(clause) {
|
|
216
|
+
for (let i = 0; i < clause.namedChildCount; i++) {
|
|
217
|
+
const c = clause.namedChild(i);
|
|
218
|
+
if (c?.type === 'as_pattern') {
|
|
219
|
+
const alias = c.childForFieldName('alias') ?? this.asPatternTarget(c);
|
|
220
|
+
if (alias)
|
|
221
|
+
this.declareAsTarget(alias, 'catch');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** The `as_pattern_target` child of an `as_pattern` (when no `alias` field). */
|
|
226
|
+
asPatternTarget(asPattern) {
|
|
227
|
+
return asPattern.namedChildren.find((c) => c.type === 'as_pattern_target');
|
|
228
|
+
}
|
|
229
|
+
/** Declare an `as_pattern_target` (or its identifier child) as a binding. */
|
|
230
|
+
declareAsTarget(target, kind = 'let') {
|
|
231
|
+
if (target.type === 'identifier') {
|
|
232
|
+
this.declare(target, kind);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// `as_pattern_target` wraps an identifier (or a tuple pattern).
|
|
236
|
+
const inner = target.namedChild(0);
|
|
237
|
+
if (inner?.type === 'identifier')
|
|
238
|
+
this.declare(inner, kind);
|
|
239
|
+
else if (inner)
|
|
240
|
+
this.declareTargets(inner);
|
|
241
|
+
else
|
|
242
|
+
this.declare(target, kind); // a bare `as_pattern_target` text IS the name
|
|
243
|
+
}
|
|
244
|
+
// ── phase 2: per-statement fact extraction ───────────────────────────────
|
|
245
|
+
/** Def/use facts for one statement (or construct-header expression) node. */
|
|
246
|
+
facts(node) {
|
|
247
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
248
|
+
this.walkValue(node, acc);
|
|
249
|
+
return acc.finish();
|
|
250
|
+
}
|
|
251
|
+
/** Facts for an expression whose WHOLE evaluation is conditional (case tests). */
|
|
252
|
+
factsConditional(node) {
|
|
253
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
254
|
+
this.conditional(() => this.walkValue(node, acc));
|
|
255
|
+
return acc.finish();
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Facts for a `for TARGET in ITER` / `for_in_clause` head: the loop target(s)
|
|
259
|
+
* are defs, the iterated expression is a use.
|
|
260
|
+
*/
|
|
261
|
+
loopHeadFacts(headNode) {
|
|
262
|
+
const acc = new FactAccumulator(headNode.startPosition.row + 1);
|
|
263
|
+
const left = headNode.childForFieldName('left');
|
|
264
|
+
const right = headNode.childForFieldName('right');
|
|
265
|
+
if (right)
|
|
266
|
+
this.walkValue(right, acc);
|
|
267
|
+
if (left)
|
|
268
|
+
this.defTargets(left, acc);
|
|
269
|
+
return acc.finish();
|
|
270
|
+
}
|
|
271
|
+
/** Facts for a `with_item`: the `as` alias is a def, the value an use. */
|
|
272
|
+
withItemFacts(item) {
|
|
273
|
+
const acc = new FactAccumulator(item.startPosition.row + 1);
|
|
274
|
+
const value = item.childForFieldName('value') ?? item.namedChild(0);
|
|
275
|
+
if (!value)
|
|
276
|
+
return acc.finish();
|
|
277
|
+
if (value.type === 'as_pattern') {
|
|
278
|
+
const inner = value.namedChild(0);
|
|
279
|
+
if (inner)
|
|
280
|
+
this.walkValue(inner, acc);
|
|
281
|
+
const alias = value.childForFieldName('alias') ?? this.asPatternTarget(value);
|
|
282
|
+
if (alias)
|
|
283
|
+
this.defAsTarget(alias, acc);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
this.walkValue(value, acc);
|
|
287
|
+
}
|
|
288
|
+
return acc.finish();
|
|
289
|
+
}
|
|
290
|
+
/** Facts for an `except E as e:` header: `e` is a def, `E` a use. */
|
|
291
|
+
exceptHeadFacts(clause) {
|
|
292
|
+
const acc = new FactAccumulator(clause.startPosition.row + 1);
|
|
293
|
+
const block = clause.namedChildren.find((c) => c.type === 'block');
|
|
294
|
+
for (let i = 0; i < clause.namedChildCount; i++) {
|
|
295
|
+
const c = clause.namedChild(i);
|
|
296
|
+
if (!c || c.id === block?.id)
|
|
297
|
+
continue;
|
|
298
|
+
if (c.type === 'as_pattern') {
|
|
299
|
+
const exc = c.namedChild(0);
|
|
300
|
+
if (exc)
|
|
301
|
+
this.walkValue(exc, acc);
|
|
302
|
+
const alias = c.childForFieldName('alias') ?? this.asPatternTarget(c);
|
|
303
|
+
if (alias)
|
|
304
|
+
this.defAsTarget(alias, acc);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
this.walkValue(c, acc);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return acc.finish();
|
|
311
|
+
}
|
|
312
|
+
/** ENTRY-block facts for the parameters (defs only — incl. default-value uses). */
|
|
313
|
+
paramFacts() {
|
|
314
|
+
const params = this.fnNode.childForFieldName('parameters') ??
|
|
315
|
+
this.fnNode.namedChildren.find((c) => c.type === 'parameters' || c.type === 'lambda_parameters');
|
|
316
|
+
if (!params)
|
|
317
|
+
return undefined;
|
|
318
|
+
const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
|
|
319
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
320
|
+
const p = params.namedChild(i);
|
|
321
|
+
if (p)
|
|
322
|
+
this.defParam(p, acc);
|
|
323
|
+
}
|
|
324
|
+
return acc.defCount() || acc.finish().uses.length ? acc.finish() : undefined;
|
|
325
|
+
}
|
|
326
|
+
/** Def the binder(s) of one parameter node and use any default-value expr. */
|
|
327
|
+
defParam(p, acc) {
|
|
328
|
+
switch (p.type) {
|
|
329
|
+
case 'identifier':
|
|
330
|
+
this.def(p, acc);
|
|
331
|
+
return;
|
|
332
|
+
case 'default_parameter':
|
|
333
|
+
case 'typed_default_parameter': {
|
|
334
|
+
const value = p.childForFieldName('value');
|
|
335
|
+
if (value)
|
|
336
|
+
this.walkValue(value, acc);
|
|
337
|
+
const name = p.childForFieldName('name');
|
|
338
|
+
if (name)
|
|
339
|
+
this.defParamBinder(name, acc);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
case 'typed_parameter': {
|
|
343
|
+
const typeNode = p.childForFieldName('type');
|
|
344
|
+
for (let i = 0; i < p.namedChildCount; i++) {
|
|
345
|
+
const c = p.namedChild(i);
|
|
346
|
+
if (c && c.id !== typeNode?.id) {
|
|
347
|
+
this.defParamBinder(c, acc);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
case 'list_splat_pattern':
|
|
354
|
+
case 'dictionary_splat_pattern':
|
|
355
|
+
this.defParamBinder(p, acc);
|
|
356
|
+
return;
|
|
357
|
+
default:
|
|
358
|
+
this.defParamBinder(p, acc);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
defParamBinder(node, acc) {
|
|
362
|
+
if (node.type === 'identifier') {
|
|
363
|
+
this.def(node, acc);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (node.type === 'list_splat_pattern' || node.type === 'dictionary_splat_pattern') {
|
|
367
|
+
const id = node.namedChild(0);
|
|
368
|
+
if (id?.type === 'identifier')
|
|
369
|
+
this.def(id, acc);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
373
|
+
const c = node.namedChild(i);
|
|
374
|
+
if (c?.type === 'identifier')
|
|
375
|
+
this.def(c, acc);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
resolve(nameNode) {
|
|
379
|
+
const name = nameNode.text;
|
|
380
|
+
if (!this.globalNames.has(name)) {
|
|
381
|
+
const idx = this.table.get(name);
|
|
382
|
+
if (idx !== undefined)
|
|
383
|
+
return idx;
|
|
384
|
+
}
|
|
385
|
+
let idx = this.synthetic.get(name);
|
|
386
|
+
if (idx === undefined) {
|
|
387
|
+
idx = this.bindings.length;
|
|
388
|
+
this.synthetic.set(name, idx);
|
|
389
|
+
this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
|
|
390
|
+
}
|
|
391
|
+
return idx;
|
|
392
|
+
}
|
|
393
|
+
def(nameNode, acc) {
|
|
394
|
+
if (nameNode.text === '_')
|
|
395
|
+
return; // blank target defines nothing of interest
|
|
396
|
+
if (this.conditionalDepth > 0)
|
|
397
|
+
acc.addMayDef(this.resolve(nameNode));
|
|
398
|
+
else
|
|
399
|
+
acc.addDef(this.resolve(nameNode));
|
|
400
|
+
}
|
|
401
|
+
use(nameNode, acc) {
|
|
402
|
+
if (nameNode.text === '_')
|
|
403
|
+
return;
|
|
404
|
+
acc.addUse(this.resolve(nameNode));
|
|
405
|
+
}
|
|
406
|
+
/** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
|
|
407
|
+
conditional(fn) {
|
|
408
|
+
this.conditionalDepth++;
|
|
409
|
+
try {
|
|
410
|
+
fn();
|
|
411
|
+
}
|
|
412
|
+
finally {
|
|
413
|
+
this.conditionalDepth--;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Def each identifier/splat leaf of an assignment / loop target pattern; route
|
|
418
|
+
* attribute / subscript targets to the value walk (root identifier is a use).
|
|
419
|
+
*/
|
|
420
|
+
defTargets(target, acc) {
|
|
421
|
+
const t = target.type;
|
|
422
|
+
if (t === 'identifier') {
|
|
423
|
+
this.def(target, acc);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (PATTERN_LIST_TYPES.has(t)) {
|
|
427
|
+
for (let i = 0; i < target.namedChildCount; i++) {
|
|
428
|
+
const c = target.namedChild(i);
|
|
429
|
+
if (c)
|
|
430
|
+
this.defTargets(c, acc);
|
|
431
|
+
}
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (t === 'list_splat_pattern') {
|
|
435
|
+
const id = target.namedChild(0);
|
|
436
|
+
if (id?.type === 'identifier')
|
|
437
|
+
this.def(id, acc);
|
|
438
|
+
else if (id)
|
|
439
|
+
this.defTargets(id, acc);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
// attribute / subscript / call target — uses only (the root identifier).
|
|
443
|
+
this.walkValue(target, acc);
|
|
444
|
+
}
|
|
445
|
+
/** Def an `as_pattern_target` (or its identifier child). */
|
|
446
|
+
defAsTarget(target, acc) {
|
|
447
|
+
if (target.type === 'identifier') {
|
|
448
|
+
this.def(target, acc);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const inner = target.namedChild(0);
|
|
452
|
+
if (inner?.type === 'identifier')
|
|
453
|
+
this.def(inner, acc);
|
|
454
|
+
else if (inner)
|
|
455
|
+
this.defTargets(inner, acc);
|
|
456
|
+
else
|
|
457
|
+
this.def(target, acc);
|
|
458
|
+
}
|
|
459
|
+
/** Value-position walk: collect uses; route def positions to the target handler. */
|
|
460
|
+
walkValue(node, acc) {
|
|
461
|
+
const t = node.type;
|
|
462
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
463
|
+
return; // opaque
|
|
464
|
+
switch (t) {
|
|
465
|
+
case 'identifier':
|
|
466
|
+
this.use(node, acc);
|
|
467
|
+
return;
|
|
468
|
+
case 'assignment': {
|
|
469
|
+
const left = node.childForFieldName('left');
|
|
470
|
+
const right = node.childForFieldName('right');
|
|
471
|
+
// Register result-defs BEFORE walking the value so the nested call site
|
|
472
|
+
// (reached during the value walk) carries them — single identifier
|
|
473
|
+
// target only (`x = f()`); a tuple/attribute LHS attaches nothing.
|
|
474
|
+
if (left?.type === 'identifier' && right)
|
|
475
|
+
this.registerResultDefs(right, [left]);
|
|
476
|
+
if (right)
|
|
477
|
+
this.walkValue(right, acc);
|
|
478
|
+
if (left)
|
|
479
|
+
this.defTargets(left, acc);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
case 'augmented_assignment': {
|
|
483
|
+
const left = node.childForFieldName('left');
|
|
484
|
+
const right = node.childForFieldName('right');
|
|
485
|
+
if (right)
|
|
486
|
+
this.walkValue(right, acc);
|
|
487
|
+
if (left) {
|
|
488
|
+
// `x += v` reads AND writes a plain-identifier lvalue.
|
|
489
|
+
if (left.type === 'identifier') {
|
|
490
|
+
this.use(left, acc);
|
|
491
|
+
this.def(left, acc);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
this.walkValue(left, acc); // attribute/subscript lvalue — use only
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
case 'named_expression': {
|
|
500
|
+
// walrus `(n := v)` — `n` is a def, `v` a use.
|
|
501
|
+
const name = node.childForFieldName('name');
|
|
502
|
+
const value = node.childForFieldName('value');
|
|
503
|
+
if (name?.type === 'identifier' && value)
|
|
504
|
+
this.registerResultDefs(value, [name]);
|
|
505
|
+
if (value)
|
|
506
|
+
this.walkValue(value, acc);
|
|
507
|
+
if (name?.type === 'identifier')
|
|
508
|
+
this.def(name, acc);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
case 'boolean_operator': {
|
|
512
|
+
// `a or b` / `a and b` — the right operand is conditionally evaluated, so
|
|
513
|
+
// any def inside it (a walrus) is a may-def; uses are still recorded.
|
|
514
|
+
const left = node.childForFieldName('left');
|
|
515
|
+
const right = node.childForFieldName('right');
|
|
516
|
+
if (left)
|
|
517
|
+
this.walkValue(left, acc);
|
|
518
|
+
if (right)
|
|
519
|
+
this.conditional(() => this.walkValue(right, acc));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
case 'conditional_expression': {
|
|
523
|
+
// `consequent if condition else alternative`. The condition always
|
|
524
|
+
// evaluates; each arm is conditional (its walrus defs are may-defs).
|
|
525
|
+
const children = node.namedChildren;
|
|
526
|
+
const [consequent, condition, alternative] = children;
|
|
527
|
+
if (condition)
|
|
528
|
+
this.walkValue(condition, acc);
|
|
529
|
+
if (consequent)
|
|
530
|
+
this.conditional(() => this.walkValue(consequent, acc));
|
|
531
|
+
if (alternative)
|
|
532
|
+
this.conditional(() => this.walkValue(alternative, acc));
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
case 'attribute': {
|
|
536
|
+
// `a.b` — value read of the operand root only; the attribute name is not
|
|
537
|
+
// a scalar binding. Records the chain-root use plus at most ONE
|
|
538
|
+
// member-read site (the innermost identifier-rooted access), mirroring
|
|
539
|
+
// the Go harvester's value-position `walkChain`.
|
|
540
|
+
this.walkChain(node, acc, false);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
case 'subscript': {
|
|
544
|
+
// `a[i]` — both the container root and the index are uses.
|
|
545
|
+
const value = node.childForFieldName('value');
|
|
546
|
+
const sub = node.childForFieldName('subscript');
|
|
547
|
+
if (value)
|
|
548
|
+
this.walkValue(value, acc);
|
|
549
|
+
if (sub)
|
|
550
|
+
this.walkValue(sub, acc);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
case 'call':
|
|
554
|
+
// #2227 follow-up: explicit case (previously default-descended) — same
|
|
555
|
+
// uses, plus a taint-site record. Python has no `new` (constructor calls
|
|
556
|
+
// are plain `call`s). Defs/uses stay byte-identical.
|
|
557
|
+
this.visitCall(node, acc);
|
|
558
|
+
return;
|
|
559
|
+
case 'list_comprehension':
|
|
560
|
+
case 'set_comprehension':
|
|
561
|
+
case 'dictionary_comprehension':
|
|
562
|
+
case 'generator_expression': {
|
|
563
|
+
this.walkComprehension(node, acc);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
case 'keyword_argument': {
|
|
567
|
+
// `f(k=v)` — `k` is a parameter name, not a use; only `v` is a use.
|
|
568
|
+
const value = node.childForFieldName('value');
|
|
569
|
+
if (value)
|
|
570
|
+
this.walkValue(value, acc);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
default:
|
|
574
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
575
|
+
const c = node.namedChild(i);
|
|
576
|
+
if (c)
|
|
577
|
+
this.walkValue(c, acc);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* A comprehension (`[body for t in src if g]`): each `for_in_clause` target is
|
|
583
|
+
* a def, its source a use; the `body` and any `if_clause` are uses. Kept INLINE
|
|
584
|
+
* (no separate CFG blocks) per the plan — the target binding is harvested so it
|
|
585
|
+
* is a real def. The `for_in_clause` source is walked in the ENCLOSING context
|
|
586
|
+
* (it reads outer names), the body/filter after the targets are bound.
|
|
587
|
+
*/
|
|
588
|
+
walkComprehension(node, acc) {
|
|
589
|
+
const body = node.childForFieldName('body');
|
|
590
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
591
|
+
const c = node.namedChild(i);
|
|
592
|
+
if (!c)
|
|
593
|
+
continue;
|
|
594
|
+
if (c.type === 'for_in_clause') {
|
|
595
|
+
const left = c.childForFieldName('left');
|
|
596
|
+
const right = c.childForFieldName('right');
|
|
597
|
+
if (right)
|
|
598
|
+
this.walkValue(right, acc);
|
|
599
|
+
if (left)
|
|
600
|
+
this.defTargets(left, acc);
|
|
601
|
+
}
|
|
602
|
+
else if (c.id !== body?.id) {
|
|
603
|
+
// `if_clause` filter (and any other auxiliary clause) — uses only.
|
|
604
|
+
this.walkValue(c, acc);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (body)
|
|
608
|
+
this.walkValue(body, acc);
|
|
609
|
+
}
|
|
610
|
+
// ── taint-site harvest (#2227 follow-up) ─────────────────────────────────
|
|
611
|
+
/**
|
|
612
|
+
* When `value`'s root (after stripping parens) is a `call`, remember that
|
|
613
|
+
* call site should carry `resultDefs` — the binding indices of `targets`
|
|
614
|
+
* (def-position identifiers). Consumed by {@link visitCall} once the value
|
|
615
|
+
* walk reaches the node. Single-target only (the caller restricts to a plain
|
|
616
|
+
* identifier LHS); the blank identifier (`_`) binds nothing and is skipped.
|
|
617
|
+
*/
|
|
618
|
+
registerResultDefs(value, targets) {
|
|
619
|
+
const root = this.unwrapValue(value);
|
|
620
|
+
if (root.type !== 'call')
|
|
621
|
+
return;
|
|
622
|
+
const defs = [];
|
|
623
|
+
for (const target of targets) {
|
|
624
|
+
if (target.type !== 'identifier' || target.text === '_')
|
|
625
|
+
continue;
|
|
626
|
+
defs.push(this.resolve(target));
|
|
627
|
+
}
|
|
628
|
+
if (defs.length > 0)
|
|
629
|
+
this.resultDefTargets.set(root.id, defs);
|
|
630
|
+
}
|
|
631
|
+
/** Strip `parenthesized_expression` wrappers around a value (`(f())`). */
|
|
632
|
+
unwrapValue(node) {
|
|
633
|
+
let n = node;
|
|
634
|
+
let hops = 8;
|
|
635
|
+
while (n.type === 'parenthesized_expression' && hops-- > 0) {
|
|
636
|
+
const inner = n.namedChild(0);
|
|
637
|
+
if (!inner)
|
|
638
|
+
break;
|
|
639
|
+
n = inner;
|
|
640
|
+
}
|
|
641
|
+
return n;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Explicit `call` handler. Records a call site (callee path, receiver, per-arg
|
|
645
|
+
* occurrence entries, result defs, spread marker) while reproducing EXACTLY
|
|
646
|
+
* the uses the old default descent recorded (callee chain root + arguments).
|
|
647
|
+
* Python has no `new` — every site is `kind: 'call'`.
|
|
648
|
+
*/
|
|
649
|
+
visitCall(node, acc) {
|
|
650
|
+
const calleeNode = node.childForFieldName('function');
|
|
651
|
+
const argsNode = node.childForFieldName('arguments');
|
|
652
|
+
// `node` IS the `call` — the SAME node the scope-extractor anchors
|
|
653
|
+
// `@reference.call.free/.member` on (its `atRange`), so the resolved-id join
|
|
654
|
+
// lands by exact position.
|
|
655
|
+
const siteIdx = acc.openCallSite('call', [
|
|
656
|
+
node.startPosition.row + 1,
|
|
657
|
+
node.startPosition.column,
|
|
658
|
+
]);
|
|
659
|
+
acc.pushFrame(siteIdx);
|
|
660
|
+
if (calleeNode) {
|
|
661
|
+
const callee = this.unwrapValue(calleeNode);
|
|
662
|
+
if (callee.type === 'identifier') {
|
|
663
|
+
if (callee.text !== '_')
|
|
664
|
+
acc.addUseWithoutOccurrence(this.resolve(callee));
|
|
665
|
+
acc.setSiteCallee(siteIdx, callee.text);
|
|
666
|
+
}
|
|
667
|
+
else if (callee.type === 'attribute') {
|
|
668
|
+
// skipFinalRead: the final `.attr` IS the callee, carried by the path.
|
|
669
|
+
const chain = this.walkChain(callee, acc, true);
|
|
670
|
+
if (chain.path !== undefined)
|
|
671
|
+
acc.setSiteCallee(siteIdx, chain.path);
|
|
672
|
+
if (chain.rootIdx !== undefined)
|
|
673
|
+
acc.setSiteReceiver(siteIdx, chain.rootIdx);
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
// Call-rooted chains (`a().b()`), subscripts (`d[k]()`) — the walk still
|
|
677
|
+
// records uses and nested sites; the callee path is not statically known.
|
|
678
|
+
this.walkValue(callee, acc);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const resultDefs = this.resultDefTargets.get(node.id);
|
|
682
|
+
if (resultDefs !== undefined)
|
|
683
|
+
acc.setSiteResultDefs(siteIdx, resultDefs);
|
|
684
|
+
if (argsNode) {
|
|
685
|
+
let pos = 0;
|
|
686
|
+
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
687
|
+
const arg = argsNode.namedChild(i);
|
|
688
|
+
if (!arg || arg.type === 'comment')
|
|
689
|
+
continue;
|
|
690
|
+
if (arg.type === 'list_splat' || arg.type === 'dictionary_splat') {
|
|
691
|
+
// `f(*args)` / `f(**kw)` — a spread. Mark the first spread position so
|
|
692
|
+
// the matcher degrades soundly; the inner value still walks.
|
|
693
|
+
acc.setFrameArg(pos);
|
|
694
|
+
acc.setSiteSpread(siteIdx, pos);
|
|
695
|
+
const inner = arg.namedChild(0);
|
|
696
|
+
if (inner)
|
|
697
|
+
this.walkValue(inner, acc);
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
// Positional or `keyword_argument` — the `keyword_argument` case in
|
|
701
|
+
// `walkValue` walks only its `value`, so the key name is not a use.
|
|
702
|
+
acc.setFrameArg(pos);
|
|
703
|
+
this.walkValue(arg, acc);
|
|
704
|
+
}
|
|
705
|
+
pos++;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
acc.popFrame();
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* `attribute` chain walk shared by value position and callee position. Records
|
|
712
|
+
* the chain-root identifier as a use (identical to the old default descent)
|
|
713
|
+
* plus at most ONE member-read site — the INNERMOST access — when the root is
|
|
714
|
+
* an identifier; `skipFinalRead` suppresses it when that access is the callee
|
|
715
|
+
* (carried by the dotted path instead). Mirrors the Go harvester's `walkChain`.
|
|
716
|
+
*/
|
|
717
|
+
walkChain(node, acc, skipFinalRead) {
|
|
718
|
+
const accesses = [];
|
|
719
|
+
let cur = this.unwrapValue(node);
|
|
720
|
+
for (;;) {
|
|
721
|
+
if (cur.type === 'attribute') {
|
|
722
|
+
const field = cur.childForFieldName('attribute');
|
|
723
|
+
accesses.unshift(field?.text ?? '');
|
|
724
|
+
const operand = cur.childForFieldName('object');
|
|
725
|
+
if (!operand)
|
|
726
|
+
break;
|
|
727
|
+
cur = this.unwrapValue(operand);
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// The shared terminal: root-use record + innermost member-read + path-join.
|
|
734
|
+
return finalizeChain(acc, cur, accesses, skipFinalRead, (t) => t === 'identifier', {
|
|
735
|
+
resolve: (n) => this.resolve(n),
|
|
736
|
+
walkRoot: (n) => this.walkValue(n, acc),
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}
|