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,626 @@
|
|
|
1
|
+
import { CallSiteFactAccumulator } 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_definition',
|
|
5
|
+
'method_declaration',
|
|
6
|
+
'anonymous_function',
|
|
7
|
+
'arrow_function',
|
|
8
|
+
]);
|
|
9
|
+
export class PhpHarvester {
|
|
10
|
+
fnNode;
|
|
11
|
+
bindings = [];
|
|
12
|
+
/** PHP is function-scoped: one flat table, name → binding index. */
|
|
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/new node id → bindings whose declarator/assignment VALUE is exactly
|
|
20
|
+
* that call. Registered before the value walk, consumed by {@link visitCall} /
|
|
21
|
+
* {@link visitNew} (mirrors the Java 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
|
+
this.declareUseClause(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
|
+
/** The function/closure body node (a `compound_statement`, or an expression). */
|
|
38
|
+
bodyOf(fnNode) {
|
|
39
|
+
return fnNode.childForFieldName('body') ?? undefined;
|
|
40
|
+
}
|
|
41
|
+
// ── phase 1: declaration pre-scan ────────────────────────────────────────
|
|
42
|
+
declare(name, declNode, kind) {
|
|
43
|
+
if (!name || this.table.has(name))
|
|
44
|
+
return;
|
|
45
|
+
this.table.set(name, this.bindings.length);
|
|
46
|
+
this.bindings.push({
|
|
47
|
+
name,
|
|
48
|
+
declLine: declNode.startPosition.row + 1,
|
|
49
|
+
declColumn: declNode.startPosition.column,
|
|
50
|
+
kind,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** The `$name` text of a parameter's `name` field (a `variable_name` or `by_ref`). */
|
|
54
|
+
paramVarName(param) {
|
|
55
|
+
const name = param.childForFieldName('name');
|
|
56
|
+
if (!name)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (name.type === 'by_ref') {
|
|
59
|
+
return name.namedChildren.find((c) => c.type === 'variable_name');
|
|
60
|
+
}
|
|
61
|
+
return name.type === 'variable_name' ? name : undefined;
|
|
62
|
+
}
|
|
63
|
+
declareParams(fnNode) {
|
|
64
|
+
const params = fnNode.childForFieldName('parameters');
|
|
65
|
+
if (!params)
|
|
66
|
+
return;
|
|
67
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
68
|
+
const p = params.namedChild(i);
|
|
69
|
+
if (!p)
|
|
70
|
+
continue;
|
|
71
|
+
if (p.type !== 'simple_parameter' &&
|
|
72
|
+
p.type !== 'variadic_parameter' &&
|
|
73
|
+
p.type !== 'property_promotion_parameter') {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const varName = this.paramVarName(p);
|
|
77
|
+
if (varName)
|
|
78
|
+
this.declare(varName.text, varName, 'param');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** `anonymous_function ... use ($a, &$b)` — each captured var binds in the closure. */
|
|
82
|
+
declareUseClause(fnNode) {
|
|
83
|
+
if (fnNode.type !== 'anonymous_function')
|
|
84
|
+
return;
|
|
85
|
+
const clause = fnNode.namedChildren.find((c) => c.type === 'anonymous_function_use_clause');
|
|
86
|
+
if (!clause)
|
|
87
|
+
return;
|
|
88
|
+
for (const v of this.useClauseVars(clause))
|
|
89
|
+
this.declare(v.text, v, 'param');
|
|
90
|
+
}
|
|
91
|
+
/** The captured `variable_name`s of a `use (...)` clause (unwrapping `by_ref`). */
|
|
92
|
+
useClauseVars(clause) {
|
|
93
|
+
const out = [];
|
|
94
|
+
for (let i = 0; i < clause.namedChildCount; i++) {
|
|
95
|
+
const c = clause.namedChild(i);
|
|
96
|
+
if (!c)
|
|
97
|
+
continue;
|
|
98
|
+
if (c.type === 'variable_name')
|
|
99
|
+
out.push(c);
|
|
100
|
+
else if (c.type === 'by_ref') {
|
|
101
|
+
const inner = c.namedChildren.find((x) => x.type === 'variable_name');
|
|
102
|
+
if (inner)
|
|
103
|
+
out.push(inner);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Walk the function body once, declaring every assigned / foreach / catch
|
|
110
|
+
* variable into the FLAT function scope (PHP has no block scoping). Nested
|
|
111
|
+
* function/closure bodies are NOT descended (opaque).
|
|
112
|
+
*/
|
|
113
|
+
prescan(node) {
|
|
114
|
+
const t = node.type;
|
|
115
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
116
|
+
return;
|
|
117
|
+
switch (t) {
|
|
118
|
+
case 'assignment_expression': {
|
|
119
|
+
const left = node.childForFieldName('left');
|
|
120
|
+
if (left)
|
|
121
|
+
this.declareLvalue(left);
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case 'augmented_assignment_expression': {
|
|
125
|
+
const left = node.childForFieldName('left');
|
|
126
|
+
if (left && left.type === 'variable_name')
|
|
127
|
+
this.declare(left.text, left, 'var');
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'update_expression': {
|
|
131
|
+
const arg = node.childForFieldName('argument');
|
|
132
|
+
if (arg && arg.type === 'variable_name')
|
|
133
|
+
this.declare(arg.text, arg, 'var');
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'foreach_statement': {
|
|
137
|
+
for (const v of this.foreachTargets(node))
|
|
138
|
+
this.declare(v.text, v, 'var');
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'catch_clause': {
|
|
142
|
+
const name = node.childForFieldName('name');
|
|
143
|
+
if (name && name.type === 'variable_name')
|
|
144
|
+
this.declare(name.text, name, 'catch');
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
default:
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
151
|
+
const c = node.namedChild(i);
|
|
152
|
+
if (c)
|
|
153
|
+
this.prescan(c);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Declare the variable(s) named by an assignment lvalue: a plain
|
|
158
|
+
* `variable_name`, or a `list_literal` destructure (`[$a,$b]` / `list($a,$b)`,
|
|
159
|
+
* possibly keyed `["x" => $e]`). Member / subscript targets bind nothing.
|
|
160
|
+
*/
|
|
161
|
+
declareLvalue(left) {
|
|
162
|
+
if (left.type === 'variable_name') {
|
|
163
|
+
this.declare(left.text, left, 'var');
|
|
164
|
+
}
|
|
165
|
+
else if (left.type === 'list_literal') {
|
|
166
|
+
for (const v of this.listTargets(left))
|
|
167
|
+
this.declare(v.text, v, 'var');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** Every `variable_name` bound by a `list_literal` (including keyed entries). */
|
|
171
|
+
listTargets(list) {
|
|
172
|
+
const out = [];
|
|
173
|
+
const walk = (n) => {
|
|
174
|
+
if (n.type === 'variable_name') {
|
|
175
|
+
out.push(n);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Keyed (`"x" => $e`) entries and nested lists descend; non-variable keys
|
|
179
|
+
// (the string/int key) are not lvalues and carry no `variable_name`.
|
|
180
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
181
|
+
const c = n.namedChild(i);
|
|
182
|
+
if (c)
|
|
183
|
+
walk(c);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
187
|
+
const c = list.namedChild(i);
|
|
188
|
+
if (c)
|
|
189
|
+
walk(c);
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The bound variable(s) of a `foreach ($it as [$k =>] $v)`: the value (and key)
|
|
195
|
+
* `variable_name`s. The structure is positional — the FIRST named child is the
|
|
196
|
+
* iterable, then either a bare `variable_name` (value) or a `pair` ($k => $v).
|
|
197
|
+
*/
|
|
198
|
+
foreachTargets(stmt) {
|
|
199
|
+
const out = [];
|
|
200
|
+
// Skip the iterable (first named child); collect value / pair targets after.
|
|
201
|
+
for (let i = 1; i < stmt.namedChildCount; i++) {
|
|
202
|
+
const c = stmt.namedChild(i);
|
|
203
|
+
if (!c)
|
|
204
|
+
continue;
|
|
205
|
+
if (c.type === 'variable_name')
|
|
206
|
+
out.push(c);
|
|
207
|
+
else if (c.type === 'pair') {
|
|
208
|
+
for (let j = 0; j < c.namedChildCount; j++) {
|
|
209
|
+
const v = c.namedChild(j);
|
|
210
|
+
if (v?.type === 'variable_name')
|
|
211
|
+
out.push(v);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// `body` (compound_statement / colon_block) is not a target — it has its
|
|
215
|
+
// own non-variable_name/non-pair type, so it is skipped here.
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
// ── phase 2: per-statement fact extraction ───────────────────────────────
|
|
220
|
+
/** Def/use facts for one statement (or construct-header expression) node. */
|
|
221
|
+
facts(node) {
|
|
222
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
223
|
+
this.walkValue(node, acc);
|
|
224
|
+
return acc.finish();
|
|
225
|
+
}
|
|
226
|
+
/** Facts for an expression whose WHOLE evaluation is conditional (case tests). */
|
|
227
|
+
factsConditional(node) {
|
|
228
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
229
|
+
this.conditional(() => this.walkValue(node, acc));
|
|
230
|
+
return acc.finish();
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Def-ONLY facts for a value-position assignment carrier (`$x = match($v) {…}`,
|
|
234
|
+
* #2207): just the LHS target(s), attached to the continuation block the match
|
|
235
|
+
* arms rejoin. The match condition + arm-value USES are already harvested onto
|
|
236
|
+
* the branch's own blocks (visitMatch), so this must NOT re-walk the RHS. A
|
|
237
|
+
* member/subscript target (`$this->x = match …`) has no scalar def → undefined.
|
|
238
|
+
*/
|
|
239
|
+
assignmentDefFacts(assignExpr) {
|
|
240
|
+
const acc = new FactAccumulator(assignExpr.startPosition.row + 1);
|
|
241
|
+
const left = assignExpr.childForFieldName('left');
|
|
242
|
+
if (left) {
|
|
243
|
+
const lv = this.unwrapParen(left);
|
|
244
|
+
if (lv.type === 'variable_name')
|
|
245
|
+
this.def(lv, acc);
|
|
246
|
+
else if (lv.type === 'list_literal')
|
|
247
|
+
for (const v of this.listTargets(lv))
|
|
248
|
+
this.def(v, acc);
|
|
249
|
+
}
|
|
250
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
251
|
+
}
|
|
252
|
+
/** Facts for a `foreach ($it as [$k =>] $v)` head: targets bind, iterable used. */
|
|
253
|
+
foreachHeadFacts(stmt) {
|
|
254
|
+
const acc = new FactAccumulator(stmt.startPosition.row + 1);
|
|
255
|
+
const iterable = stmt.namedChild(0);
|
|
256
|
+
if (iterable)
|
|
257
|
+
this.walkValue(iterable, acc);
|
|
258
|
+
for (const v of this.foreachTargets(stmt))
|
|
259
|
+
this.def(v, acc);
|
|
260
|
+
return acc.finish();
|
|
261
|
+
}
|
|
262
|
+
/** ENTRY-block facts for the function's parameters (defs only). */
|
|
263
|
+
paramFacts() {
|
|
264
|
+
const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
|
|
265
|
+
const params = this.fnNode.childForFieldName('parameters');
|
|
266
|
+
if (params) {
|
|
267
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
268
|
+
const p = params.namedChild(i);
|
|
269
|
+
if (!p)
|
|
270
|
+
continue;
|
|
271
|
+
if (p.type !== 'simple_parameter' &&
|
|
272
|
+
p.type !== 'variadic_parameter' &&
|
|
273
|
+
p.type !== 'property_promotion_parameter') {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const varName = this.paramVarName(p);
|
|
277
|
+
if (varName)
|
|
278
|
+
this.def(varName, acc);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// A closure's `use (...)` captures are live on entry too — model as defs.
|
|
282
|
+
if (this.fnNode.type === 'anonymous_function') {
|
|
283
|
+
const clause = this.fnNode.namedChildren.find((c) => c.type === 'anonymous_function_use_clause');
|
|
284
|
+
if (clause)
|
|
285
|
+
for (const v of this.useClauseVars(clause))
|
|
286
|
+
this.def(v, acc);
|
|
287
|
+
}
|
|
288
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
289
|
+
}
|
|
290
|
+
/** Def fact for a `catch (T $e)` parameter — prepend to the handler entry block. */
|
|
291
|
+
catchParamFacts(catchClause) {
|
|
292
|
+
const name = catchClause.childForFieldName('name');
|
|
293
|
+
if (!name || name.type !== 'variable_name')
|
|
294
|
+
return undefined;
|
|
295
|
+
const acc = new FactAccumulator(catchClause.startPosition.row + 1);
|
|
296
|
+
this.def(name, acc);
|
|
297
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
298
|
+
}
|
|
299
|
+
resolve(nameNode) {
|
|
300
|
+
const name = nameNode.text;
|
|
301
|
+
const idx = this.table.get(name);
|
|
302
|
+
if (idx !== undefined)
|
|
303
|
+
return idx;
|
|
304
|
+
let syn = this.synthetic.get(name);
|
|
305
|
+
if (syn === undefined) {
|
|
306
|
+
syn = this.bindings.length;
|
|
307
|
+
this.synthetic.set(name, syn);
|
|
308
|
+
this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
|
|
309
|
+
}
|
|
310
|
+
return syn;
|
|
311
|
+
}
|
|
312
|
+
def(nameNode, acc) {
|
|
313
|
+
if (this.conditionalDepth > 0)
|
|
314
|
+
acc.addMayDef(this.resolve(nameNode));
|
|
315
|
+
else
|
|
316
|
+
acc.addDef(this.resolve(nameNode));
|
|
317
|
+
}
|
|
318
|
+
use(nameNode, acc) {
|
|
319
|
+
acc.addUse(this.resolve(nameNode));
|
|
320
|
+
}
|
|
321
|
+
/** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
|
|
322
|
+
conditional(fn) {
|
|
323
|
+
this.conditionalDepth++;
|
|
324
|
+
try {
|
|
325
|
+
fn();
|
|
326
|
+
}
|
|
327
|
+
finally {
|
|
328
|
+
this.conditionalDepth--;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Strip parenthesized wrappers around an lvalue (`($x) = 1`). */
|
|
332
|
+
unwrapParen(node) {
|
|
333
|
+
let n = node;
|
|
334
|
+
let hops = 8;
|
|
335
|
+
while (n.type === 'parenthesized_expression' && hops-- > 0) {
|
|
336
|
+
const inner = n.namedChildren.find((c) => c.type !== 'comment');
|
|
337
|
+
if (!inner)
|
|
338
|
+
break;
|
|
339
|
+
n = inner;
|
|
340
|
+
}
|
|
341
|
+
return n;
|
|
342
|
+
}
|
|
343
|
+
/** Value-position walk: collect uses; route def positions to the lvalue handler. */
|
|
344
|
+
walkValue(node, acc) {
|
|
345
|
+
const t = node.type;
|
|
346
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId) {
|
|
347
|
+
// Opaque nested function / closure — captured reads/writes are invisible.
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
switch (t) {
|
|
351
|
+
case 'variable_name':
|
|
352
|
+
this.use(node, acc);
|
|
353
|
+
return;
|
|
354
|
+
case 'assignment_expression': {
|
|
355
|
+
const left = node.childForFieldName('left');
|
|
356
|
+
const right = node.childForFieldName('right');
|
|
357
|
+
if (left) {
|
|
358
|
+
const lv = this.unwrapParen(left);
|
|
359
|
+
if (lv.type === 'variable_name') {
|
|
360
|
+
const snap = acc.defSnapshot();
|
|
361
|
+
this.def(lv, acc);
|
|
362
|
+
if (right)
|
|
363
|
+
this.registerResultDefs(right, acc.defsSince(snap));
|
|
364
|
+
}
|
|
365
|
+
else if (lv.type === 'list_literal') {
|
|
366
|
+
// Destructure: every target binds; non-variable keys are uses.
|
|
367
|
+
for (const v of this.listTargets(lv))
|
|
368
|
+
this.def(v, acc);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
this.walkValue(lv, acc); // member / subscript target — uses only
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (right)
|
|
375
|
+
this.walkValue(right, acc);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
case 'augmented_assignment_expression': {
|
|
379
|
+
const left = node.childForFieldName('left');
|
|
380
|
+
const right = node.childForFieldName('right');
|
|
381
|
+
if (left) {
|
|
382
|
+
const lv = this.unwrapParen(left);
|
|
383
|
+
if (lv.type === 'variable_name') {
|
|
384
|
+
this.def(lv, acc);
|
|
385
|
+
this.use(lv, acc); // compound assign reads too
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
this.walkValue(lv, acc);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (right)
|
|
392
|
+
this.walkValue(right, acc);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
case 'update_expression': {
|
|
396
|
+
const arg = node.childForFieldName('argument');
|
|
397
|
+
const lv = arg ? this.unwrapParen(arg) : null;
|
|
398
|
+
if (lv?.type === 'variable_name') {
|
|
399
|
+
this.def(lv, acc);
|
|
400
|
+
this.use(lv, acc);
|
|
401
|
+
}
|
|
402
|
+
else if (arg) {
|
|
403
|
+
this.walkValue(arg, acc);
|
|
404
|
+
}
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
case 'binary_expression': {
|
|
408
|
+
const left = node.childForFieldName('left');
|
|
409
|
+
const right = node.childForFieldName('right');
|
|
410
|
+
const op = node.childForFieldName('operator')?.text ?? '';
|
|
411
|
+
if (left)
|
|
412
|
+
this.walkValue(left, acc);
|
|
413
|
+
if (right) {
|
|
414
|
+
if (op === '&&' || op === '||' || op === '??' || op === 'and' || op === 'or') {
|
|
415
|
+
this.conditional(() => this.walkValue(right, acc));
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
this.walkValue(right, acc);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
case 'conditional_expression': {
|
|
424
|
+
const cond = node.childForFieldName('condition');
|
|
425
|
+
const body = node.childForFieldName('body');
|
|
426
|
+
const alt = node.childForFieldName('alternative');
|
|
427
|
+
if (cond)
|
|
428
|
+
this.walkValue(cond, acc);
|
|
429
|
+
if (body)
|
|
430
|
+
this.conditional(() => this.walkValue(body, acc));
|
|
431
|
+
if (alt)
|
|
432
|
+
this.conditional(() => this.walkValue(alt, acc));
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
case 'function_call_expression':
|
|
436
|
+
this.visitCall(node, acc, 'function');
|
|
437
|
+
return;
|
|
438
|
+
case 'member_call_expression':
|
|
439
|
+
case 'nullsafe_member_call_expression':
|
|
440
|
+
this.visitCall(node, acc, 'member');
|
|
441
|
+
return;
|
|
442
|
+
case 'scoped_call_expression':
|
|
443
|
+
this.visitCall(node, acc, 'scoped');
|
|
444
|
+
return;
|
|
445
|
+
case 'object_creation_expression':
|
|
446
|
+
this.visitNew(node, acc);
|
|
447
|
+
return;
|
|
448
|
+
case 'member_access_expression':
|
|
449
|
+
case 'nullsafe_member_access_expression': {
|
|
450
|
+
// `$o->p` — value read of the object root only (the property name is not
|
|
451
|
+
// a scalar binding); record the innermost identifier-rooted member read.
|
|
452
|
+
this.walkChain(node, acc);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
default:
|
|
456
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
457
|
+
const c = node.namedChild(i);
|
|
458
|
+
if (c)
|
|
459
|
+
this.walkValue(c, acc);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// ── taint-site harvest ───────────────────────────────────────────────────
|
|
464
|
+
/**
|
|
465
|
+
* When `value`'s root (after stripping parens) is a call / object-creation
|
|
466
|
+
* node, remember its site should carry `resultDefs: defs`.
|
|
467
|
+
*/
|
|
468
|
+
registerResultDefs(value, defs) {
|
|
469
|
+
if (defs.length === 0)
|
|
470
|
+
return;
|
|
471
|
+
const root = this.unwrapParen(value);
|
|
472
|
+
if (root.type === 'function_call_expression' ||
|
|
473
|
+
root.type === 'member_call_expression' ||
|
|
474
|
+
root.type === 'nullsafe_member_call_expression' ||
|
|
475
|
+
root.type === 'scoped_call_expression' ||
|
|
476
|
+
root.type === 'object_creation_expression') {
|
|
477
|
+
this.resultDefTargets.set(root.id, [...defs]);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Call-site handler for the three PHP call shapes:
|
|
482
|
+
* - `function`: `function_call_expression` (`function` field = name, no receiver)
|
|
483
|
+
* - `member`: `member_call_expression` (`object` receiver, `name` method)
|
|
484
|
+
* - `scoped`: `scoped_call_expression` (`scope` class, `name` method)
|
|
485
|
+
* Reproduces the same uses the default descent recorded plus the call site.
|
|
486
|
+
*/
|
|
487
|
+
visitCall(node, acc, shape) {
|
|
488
|
+
const argsNode = node.childForFieldName('arguments');
|
|
489
|
+
// `node` IS the call expression — the SAME node the scope-extractor anchors
|
|
490
|
+
// `@reference.call.*` (its `atRange`) on (KTD7).
|
|
491
|
+
const siteIdx = acc.openCallSite('call', [
|
|
492
|
+
node.startPosition.row + 1,
|
|
493
|
+
node.startPosition.column,
|
|
494
|
+
]);
|
|
495
|
+
acc.pushFrame(siteIdx);
|
|
496
|
+
if (shape === 'function') {
|
|
497
|
+
const fnNode = node.childForFieldName('function');
|
|
498
|
+
if (fnNode) {
|
|
499
|
+
if (fnNode.type === 'name' || fnNode.type === 'qualified_name') {
|
|
500
|
+
acc.setSiteCallee(siteIdx, fnNode.text);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
// dynamic callee (`$fn()`, `($obj->cb)()`) — record uses, no static path
|
|
504
|
+
this.walkValue(fnNode, acc);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else if (shape === 'member') {
|
|
509
|
+
const objectNode = node.childForFieldName('object');
|
|
510
|
+
const nameNode = node.childForFieldName('name');
|
|
511
|
+
let receiverPath;
|
|
512
|
+
if (objectNode) {
|
|
513
|
+
const chain = this.walkChain(objectNode, acc);
|
|
514
|
+
receiverPath = chain.path;
|
|
515
|
+
if (chain.rootIdx !== undefined)
|
|
516
|
+
acc.setSiteReceiver(siteIdx, chain.rootIdx);
|
|
517
|
+
}
|
|
518
|
+
if (nameNode && nameNode.type === 'name') {
|
|
519
|
+
const callee = receiverPath !== undefined ? `${receiverPath}.${nameNode.text}` : nameNode.text;
|
|
520
|
+
acc.setSiteCallee(siteIdx, callee);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
// scoped: `C::method(...)` — scope is a class name (not a binding).
|
|
525
|
+
const scopeNode = node.childForFieldName('scope');
|
|
526
|
+
const nameNode = node.childForFieldName('name');
|
|
527
|
+
const scopeText = scopeNode && (scopeNode.type === 'name' || scopeNode.type === 'qualified_name')
|
|
528
|
+
? scopeNode.text
|
|
529
|
+
: undefined;
|
|
530
|
+
if (nameNode && nameNode.type === 'name') {
|
|
531
|
+
const callee = scopeText !== undefined ? `${scopeText}.${nameNode.text}` : nameNode.text;
|
|
532
|
+
acc.setSiteCallee(siteIdx, callee);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const resultDefs = this.resultDefTargets.get(node.id);
|
|
536
|
+
if (resultDefs !== undefined)
|
|
537
|
+
acc.setSiteResultDefs(siteIdx, resultDefs);
|
|
538
|
+
this.walkArgs(argsNode, acc);
|
|
539
|
+
acc.popFrame();
|
|
540
|
+
}
|
|
541
|
+
/** Explicit `object_creation_expression` (`new Foo($x)`) handler. */
|
|
542
|
+
visitNew(node, acc) {
|
|
543
|
+
const argsNode = node.childForFieldName('arguments');
|
|
544
|
+
// `node` IS the object_creation_expression — the SAME node the
|
|
545
|
+
// scope-extractor anchors `@reference.call.constructor` (its `atRange`) on.
|
|
546
|
+
const siteIdx = acc.openCallSite('new', [
|
|
547
|
+
node.startPosition.row + 1,
|
|
548
|
+
node.startPosition.column,
|
|
549
|
+
]);
|
|
550
|
+
acc.pushFrame(siteIdx);
|
|
551
|
+
// The class name is the first `name`/`qualified_name` child (not a binding).
|
|
552
|
+
const className = node.namedChildren.find((c) => c.type === 'name' || c.type === 'qualified_name');
|
|
553
|
+
if (className)
|
|
554
|
+
acc.setSiteCallee(siteIdx, className.text.replace(/\s+/g, ''));
|
|
555
|
+
const resultDefs = this.resultDefTargets.get(node.id);
|
|
556
|
+
if (resultDefs !== undefined)
|
|
557
|
+
acc.setSiteResultDefs(siteIdx, resultDefs);
|
|
558
|
+
this.walkArgs(argsNode, acc);
|
|
559
|
+
acc.popFrame();
|
|
560
|
+
}
|
|
561
|
+
/** Walk an `arguments` node, tagging each positional `argument` for occurrences. */
|
|
562
|
+
walkArgs(argsNode, acc) {
|
|
563
|
+
if (!argsNode)
|
|
564
|
+
return;
|
|
565
|
+
let pos = 0;
|
|
566
|
+
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
567
|
+
const arg = argsNode.namedChild(i);
|
|
568
|
+
if (!arg || arg.type === 'comment')
|
|
569
|
+
continue;
|
|
570
|
+
if (arg.type !== 'argument') {
|
|
571
|
+
// A spread (`...$xs`) or other non-`argument` child — still walk for uses.
|
|
572
|
+
this.walkValue(arg, acc);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
acc.setFrameArg(pos);
|
|
576
|
+
this.walkValue(arg, acc);
|
|
577
|
+
pos++;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Member-access chain walk shared by value position and a method-call receiver.
|
|
582
|
+
* Records the chain-root `variable_name` as a use plus at most ONE member-read
|
|
583
|
+
* site — the innermost access — when the root is a variable.
|
|
584
|
+
*/
|
|
585
|
+
walkChain(node, acc) {
|
|
586
|
+
const accesses = [];
|
|
587
|
+
let cur = this.unwrapParen(node);
|
|
588
|
+
for (;;) {
|
|
589
|
+
if (cur.type === 'member_access_expression' ||
|
|
590
|
+
cur.type === 'nullsafe_member_access_expression') {
|
|
591
|
+
const field = cur.childForFieldName('name');
|
|
592
|
+
accesses.unshift(field?.text ?? '');
|
|
593
|
+
const obj = cur.childForFieldName('object');
|
|
594
|
+
if (!obj)
|
|
595
|
+
break;
|
|
596
|
+
cur = this.unwrapParen(obj);
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
let rootIdx;
|
|
603
|
+
let rootSegment;
|
|
604
|
+
if (cur.type === 'variable_name') {
|
|
605
|
+
rootIdx = this.resolve(cur);
|
|
606
|
+
acc.addUse(rootIdx);
|
|
607
|
+
rootSegment = cur.text;
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
this.walkValue(cur, acc);
|
|
611
|
+
}
|
|
612
|
+
const innermost = accesses[0];
|
|
613
|
+
if (rootIdx !== undefined && innermost)
|
|
614
|
+
acc.addMemberRead(rootIdx, innermost);
|
|
615
|
+
const path = rootSegment !== undefined && accesses.every((a) => a !== '')
|
|
616
|
+
? [rootSegment, ...accesses].join('.')
|
|
617
|
+
: undefined;
|
|
618
|
+
return { path, rootIdx };
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Ordered, deduplicating def/use + call-site collector for one statement record.
|
|
623
|
+
* The shared {@link CallSiteFactAccumulator} carries the def/use machinery plus
|
|
624
|
+
* the taint-site harvest.
|
|
625
|
+
*/
|
|
626
|
+
const FactAccumulator = CallSiteFactAccumulator;
|