gitnexus 1.6.8-rc.8 → 1.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/_shared/graph/types.d.ts +31 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +11 -1
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +6 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +31 -1
- package/dist/cli/ai-context.js +18 -16
- package/dist/cli/analyze-config.js +11 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +98 -0
- package/dist/cli/embedding-dims.d.ts +33 -0
- package/dist/cli/embedding-dims.js +39 -0
- package/dist/cli/eval-server.d.ts +8 -0
- package/dist/cli/eval-server.js +242 -2
- package/dist/cli/help-i18n.js +19 -0
- package/dist/cli/i18n/en.d.ts +15 -1
- package/dist/cli/i18n/en.js +15 -1
- package/dist/cli/i18n/resources.d.ts +29 -1
- package/dist/cli/i18n/zh-CN.d.ts +14 -0
- package/dist/cli/i18n/zh-CN.js +15 -1
- package/dist/cli/index.js +89 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/setup.d.ts +3 -1
- package/dist/cli/setup.js +67 -17
- package/dist/cli/skill-gen.js +2 -1
- package/dist/cli/tool.d.ts +19 -1
- package/dist/cli/tool.js +96 -3
- package/dist/core/embeddings/hf-env.d.ts +0 -66
- package/dist/core/embeddings/http-client.d.ts +7 -0
- package/dist/core/embeddings/http-client.js +5 -3
- package/dist/core/embeddings/server-mapping.d.ts +1 -1
- package/dist/core/embeddings/server-mapping.js +7 -3
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +5 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +22 -4
- package/dist/core/group/extractors/include-extractor.js +22 -13
- package/dist/core/group/sync.d.ts +27 -1
- package/dist/core/group/sync.js +0 -0
- package/dist/core/incremental/subgraph-extract.js +18 -1
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
- package/dist/core/ingestion/cfg/collect.d.ts +51 -0
- package/dist/core/ingestion/cfg/collect.js +77 -0
- package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
- package/dist/core/ingestion/cfg/control-dependence.js +182 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
- package/dist/core/ingestion/cfg/emit.d.ts +293 -0
- package/dist/core/ingestion/cfg/emit.js +646 -0
- package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
- package/dist/core/ingestion/cfg/post-dominators.js +176 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
- package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
- package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +274 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
- package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
- package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
- package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
- package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/go.js +638 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
- package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
- package/dist/core/ingestion/cfg/visitors/java.js +812 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
- package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
- package/dist/core/ingestion/cfg/visitors/php.js +721 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
- package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
- package/dist/core/ingestion/cfg/visitors/python.js +558 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
- package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
- package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
- package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
- package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
- package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
- package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
- package/dist/core/ingestion/import-resolvers/utils.js +2 -0
- package/dist/core/ingestion/language-provider.d.ts +23 -2
- package/dist/core/ingestion/languages/c-cpp.js +17 -5
- package/dist/core/ingestion/languages/cobol.js +4 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
- package/dist/core/ingestion/languages/cpp/captures.js +50 -1
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
- package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
- package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
- package/dist/core/ingestion/languages/csharp.js +2 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go.js +2 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +8 -1
- package/dist/core/ingestion/languages/php.js +2 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/ruby.js +2 -0
- package/dist/core/ingestion/languages/rust.js +2 -0
- package/dist/core/ingestion/languages/swift.js +2 -0
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/languages/vue.js +6 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/mro-processor.js +109 -0
- package/dist/core/ingestion/parsing-processor.js +44 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/index.js +2 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
- package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
- package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
- package/dist/core/ingestion/pipeline.d.ts +92 -10
- package/dist/core/ingestion/pipeline.js +11 -2
- package/dist/core/ingestion/scope-extractor.js +12 -2
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
- package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
- package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
- package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
- package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
- package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
- package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
- package/dist/core/ingestion/taint/call-summary-model.js +25 -0
- package/dist/core/ingestion/taint/emit.d.ts +125 -0
- package/dist/core/ingestion/taint/emit.js +208 -0
- package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
- package/dist/core/ingestion/taint/interproc-emit.js +88 -0
- package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
- package/dist/core/ingestion/taint/interproc-solver.js +312 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +659 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
- package/dist/core/ingestion/taint/source-sink-config.js +35 -12
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
- package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
- package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
- package/dist/core/ingestion/taint/summary-harvest.js +537 -0
- package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
- package/dist/core/ingestion/taint/summary-model.js +86 -0
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
- package/dist/core/ingestion/utils/env.d.ts +7 -0
- package/dist/core/ingestion/utils/env.js +12 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
- package/dist/core/ingestion/workers/parse-worker.js +81 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
- package/dist/core/ingestion/workers/worker-pool.js +43 -16
- package/dist/core/lbug/csv-generator.d.ts +51 -3
- package/dist/core/lbug/csv-generator.js +369 -255
- package/dist/core/lbug/lbug-adapter.d.ts +58 -18
- package/dist/core/lbug/lbug-adapter.js +346 -84
- package/dist/core/lbug/lbug-config.d.ts +19 -0
- package/dist/core/lbug/lbug-config.js +29 -0
- package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
- package/dist/core/lbug/pdg-emit-sink.js +358 -0
- package/dist/core/lbug/pool-adapter.d.ts +35 -0
- package/dist/core/lbug/pool-adapter.js +90 -1
- package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
- package/dist/core/lbug/rel-pair-routing.js +140 -0
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +3 -0
- package/dist/core/logger.d.ts +0 -5
- package/dist/core/run-analyze.d.ts +96 -0
- package/dist/core/run-analyze.js +207 -3
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/core/wiki/generator.js +3 -1
- package/dist/core/wiki/graph-queries.d.ts +6 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.d.ts +110 -24
- package/dist/mcp/local/local-backend.js +1225 -19
- package/dist/mcp/local/pdg-impact.d.ts +384 -0
- package/dist/mcp/local/pdg-impact.js +1972 -0
- package/dist/mcp/resources.js +13 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.js +214 -7
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -1
- package/dist/server/api.d.ts +17 -0
- package/dist/server/api.js +132 -168
- package/dist/server/git-clone.d.ts +43 -2
- package/dist/server/git-clone.js +211 -16
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +40 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +37 -0
- package/dist/server/upload-paths.js +57 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/git.js +5 -8
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +44 -10
- package/dist/storage/repo-manager.d.ts +121 -10
- package/dist/storage/repo-manager.js +43 -5
- package/dist/types/pipeline.d.ts +9 -0
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
- package/hooks/claude/gitnexus-hook.cjs +110 -13
- package/hooks/claude/hook-db-lock-probe.cjs +513 -26
- package/package.json +8 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/scripts/cross-platform-tests.ts +1 -0
- package/skills/gitnexus-debugging.md +16 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-guide.md +33 -0
- package/skills/gitnexus-pdg-query.md +89 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/skills/gitnexus-taint-analysis.md +178 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
- package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
- package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
- package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
- package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
- package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
- package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
- package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
- package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
- package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
- package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
- package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
- package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
- package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
- package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
- package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
- package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
- package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
- package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
- package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
- package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
- package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
- package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
- package/web/assets/index-BvYev1UJ.js +635 -0
- package/web/assets/index-_lgn7hs5.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
- package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
- package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
- package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
- package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
- package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
- package/web/index.html +13 -15
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
- package/web/assets/chunk-CilyBKbf.js +0 -1
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
- package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
- package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
- package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
- package/web/assets/index-BKWA-m7o.css +0 -2
- package/web/assets/index-CG6q8eTs.js +0 -626
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
- /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control dependence (#2085 M5 U3) — Ferrante, Ottenstein & Warren §3.1.1
|
|
3
|
+
* semantics. A block `dependent` is control-dependent on a branch block
|
|
4
|
+
* `controller` when `controller` decides whether `dependent` executes: formally,
|
|
5
|
+
* there is a CFG edge `controller → B` such that `dependent` post-dominates `B`
|
|
6
|
+
* but does NOT strictly post-dominate `controller`.
|
|
7
|
+
*
|
|
8
|
+
* Construction — the reverse-CFG dominance-frontier formulation (Cytron,
|
|
9
|
+
* Ferrante, Rosen, Wegman & Zadeck 1991): control dependence IS the dominance
|
|
10
|
+
* frontier of the reverse CFG, so `A ∈ PDF(X)` (the post-dominance frontier)
|
|
11
|
+
* ⟺ `X` is control-dependent on `A`. The PDF is computed bottom-up over the
|
|
12
|
+
* post-dom tree (`PDF_local` from a node's CFG predecessors + `PDF_up` from its
|
|
13
|
+
* post-dom-tree children) in O(N + E + output) — each up-step is charged to a
|
|
14
|
+
* distinct emitted edge, NOT re-walked per CFG edge as the original §3.1.1
|
|
15
|
+
* up-walk did (which was Θ(N²) on a deep post-dom chain). The two formulations
|
|
16
|
+
* enumerate the IDENTICAL full `(controller, dependent, label)` set (verified
|
|
17
|
+
* byte-identical on 3203 CFGs + ~1M-case differential fuzz); LLVM, Joern and WALA
|
|
18
|
+
* use the reverse-DF form. (Only the rare TRUNCATED prefix — when a function
|
|
19
|
+
* exceeds `maxEdges` — differs from the old prefix: it is now a sorted
|
|
20
|
+
* deterministic prefix rather than CFG-edge-iteration order. Both are valid,
|
|
21
|
+
* deterministic subsets; the full untruncated output is unchanged.)
|
|
22
|
+
* The branch SENSE ('T' | 'F') of the controlling edge becomes the edge label
|
|
23
|
+
* (KTD4 / KTD3 — it rides the persisted relation's `reason` column).
|
|
24
|
+
*
|
|
25
|
+
* PURE AND DETERMINISTIC (mirrors post-dominators.ts / reaching-defs.ts): no
|
|
26
|
+
* graph, no logger, importable outside the worker; output is deduped per
|
|
27
|
+
* (controller, dependent, label) and sorted, so snapshot tests and
|
|
28
|
+
* content-derived edge ids are stable. The loop header legitimately appears as
|
|
29
|
+
* control-dependent on ITSELF (`controller === dependent`) — the loop predicate
|
|
30
|
+
* gates its own re-execution; this is standard PDG behavior, not a bug.
|
|
31
|
+
*/
|
|
32
|
+
import { computePostDominators, NO_IPDOM } from './post-dominators.js';
|
|
33
|
+
function buildArmSenses(cfg) {
|
|
34
|
+
const n = cfg.blocks.length;
|
|
35
|
+
const senses = Array.from({ length: n }, () => ({
|
|
36
|
+
hasTrueArm: false,
|
|
37
|
+
hasFalseArm: false,
|
|
38
|
+
}));
|
|
39
|
+
for (const e of cfg.edges) {
|
|
40
|
+
if (e.from < 0 || e.from >= n)
|
|
41
|
+
continue;
|
|
42
|
+
if (e.kind === 'cond-true' || e.kind === 'switch-case')
|
|
43
|
+
senses[e.from].hasTrueArm = true;
|
|
44
|
+
else if (e.kind === 'cond-false')
|
|
45
|
+
senses[e.from].hasFalseArm = true;
|
|
46
|
+
}
|
|
47
|
+
return senses;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The CDG label ('T'|'F') for a control-dependence edge, given the controlling
|
|
51
|
+
* block's arm senses. An explicitly-sensed edge is taken at face value; an
|
|
52
|
+
* ambiguous fall-through edge (`seq`/`loop-back`/`fallthrough`/jump) is the
|
|
53
|
+
* COMPLEMENT of the controller's explicit sibling arm. Per-case `switch` value
|
|
54
|
+
* labels are deferred to #2086 — every `switch-case` is 'T' in M5.
|
|
55
|
+
*/
|
|
56
|
+
function labelFor(kind, controller) {
|
|
57
|
+
if (kind === 'cond-true' || kind === 'switch-case')
|
|
58
|
+
return 'T';
|
|
59
|
+
if (kind === 'cond-false')
|
|
60
|
+
return 'F';
|
|
61
|
+
// Ambiguous structural kind: take the complement of the controller's explicit
|
|
62
|
+
// arm. A block with a true arm reaches here via its false fall-through; a
|
|
63
|
+
// do/while bottom-test (false arm = cond-false) reaches here via its true
|
|
64
|
+
// loop-back. With neither explicit arm (a degenerate / exit-unreachable
|
|
65
|
+
// region — see #2188 F2, where the dependence itself is unsound) the sense is
|
|
66
|
+
// indeterminate; default 'F' since fall-through is the common case.
|
|
67
|
+
if (controller.hasTrueArm)
|
|
68
|
+
return 'F';
|
|
69
|
+
if (controller.hasFalseArm)
|
|
70
|
+
return 'T';
|
|
71
|
+
return 'F';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compute control-dependence edges for one function's CFG. `postDom` may be
|
|
75
|
+
* supplied to reuse an already-built tree; otherwise it is computed. See the
|
|
76
|
+
* module doc for the purity/determinism contract.
|
|
77
|
+
*/
|
|
78
|
+
export function computeControlDependence(cfg, postDom,
|
|
79
|
+
// Output-size ceiling, mirroring computeReachingDefs' `maxFacts` (#2188 review).
|
|
80
|
+
// The reverse-DF set is the bounded (controller, dependent, label) dependence
|
|
81
|
+
// relation, so peak working set ≈ output here (no pre-dedup spike like the old
|
|
82
|
+
// up-walk) — this caps the final edge COUNT, not transient memory. `0` ⇒
|
|
83
|
+
// unbounded. On overflow `edges` is a deterministic SORTED prefix and
|
|
84
|
+
// `truncated` is set — never a silent drop. (The sorted prefix is the prefix
|
|
85
|
+
// CONTENTS may differ from the old up-walk's CFG-edge-iteration prefix at the
|
|
86
|
+
// cap boundary; the FULL untruncated set is byte-identical — see the module doc.)
|
|
87
|
+
maxEdges = 0) {
|
|
88
|
+
const tree = postDom ?? computePostDominators(cfg);
|
|
89
|
+
const { ipdom } = tree;
|
|
90
|
+
const n = cfg.blocks.length;
|
|
91
|
+
const armSenses = buildArmSenses(cfg);
|
|
92
|
+
const cap = maxEdges > 0 ? maxEdges : Infinity;
|
|
93
|
+
// Reverse-CFG post-dominance frontier (Cytron, Ferrante, Rosen, Wegman,
|
|
94
|
+
// Zadeck 1991): control dependence IS the dominance frontier of the reverse
|
|
95
|
+
// CFG. `A ∈ PDF(X)` ⟺ X is control-dependent on A, so emit (controller=A,
|
|
96
|
+
// dependent=X). Computing the PDF bottom-up over the post-dom tree charges
|
|
97
|
+
// each up-step to a DISTINCT emitted entry — O(N+E+output) — instead of the
|
|
98
|
+
// old Ferrante up-walk that re-climbs the ipdom chain per CFG edge (Θ(N²) on
|
|
99
|
+
// a deep post-dom chain). Output is the identical (controller, dependent,
|
|
100
|
+
// label) set (verified byte-identical on 3203 CFGs across all languages +
|
|
101
|
+
// fuzz) and 1-2 orders of magnitude faster. LLVM (ReverseIDFCalculator),
|
|
102
|
+
// Joern (CdgPass) and WALA use the same formulation.
|
|
103
|
+
const children = Array.from({ length: n }, () => []);
|
|
104
|
+
const inEdges = Array.from({ length: n }, () => []);
|
|
105
|
+
for (let b = 0; b < n; b++) {
|
|
106
|
+
const ip = ipdom[b];
|
|
107
|
+
if (ip !== NO_IPDOM && ip >= 0 && ip < n)
|
|
108
|
+
children[ip].push(b);
|
|
109
|
+
}
|
|
110
|
+
for (const e of cfg.edges) {
|
|
111
|
+
if (e.from < 0 || e.from >= n || e.to < 0 || e.to >= n)
|
|
112
|
+
continue;
|
|
113
|
+
inEdges[e.to].push({ from: e.from, kind: e.kind });
|
|
114
|
+
}
|
|
115
|
+
// Post-dom-tree post-order (children before parents). Iterative — the post-dom
|
|
116
|
+
// forest can itself be chain-deep. Roots are the NO_IPDOM nodes (EXIT, plus
|
|
117
|
+
// any exit-unreachable region per #2188 F2). The reverse of a root-first DFS
|
|
118
|
+
// visits every parent AFTER all its descendants.
|
|
119
|
+
const dfs = [];
|
|
120
|
+
for (let r = 0; r < n; r++)
|
|
121
|
+
if (ipdom[r] === NO_IPDOM)
|
|
122
|
+
dfs.push(r);
|
|
123
|
+
const preorder = [];
|
|
124
|
+
while (dfs.length) {
|
|
125
|
+
const x = dfs.pop();
|
|
126
|
+
preorder.push(x);
|
|
127
|
+
for (const c of children[x])
|
|
128
|
+
dfs.push(c);
|
|
129
|
+
}
|
|
130
|
+
const order = preorder.reverse();
|
|
131
|
+
// PDF[X]: controller A → the label SET with which A controls X. A set (not one
|
|
132
|
+
// label) because a controller can reach X via opposite-sense arms (goto-
|
|
133
|
+
// cycles) — the old (a, cur, label) dedup kept both rows.
|
|
134
|
+
const pdf = Array.from({ length: n }, () => new Map());
|
|
135
|
+
const add = (x, a, label) => {
|
|
136
|
+
const set = pdf[x].get(a);
|
|
137
|
+
if (set)
|
|
138
|
+
set.add(label);
|
|
139
|
+
else
|
|
140
|
+
pdf[x].set(a, new Set([label]));
|
|
141
|
+
};
|
|
142
|
+
for (const x of order) {
|
|
143
|
+
// PDF_local: a CFG-predecessor A of X that X does not (immediately) post-
|
|
144
|
+
// dominate. `A !== X && ipdom[A] !== X` is exactly the production
|
|
145
|
+
// `!postDominates(X, A)` for one edge A→X (postDominates(X,A) ⟺ ipdom[A]===X),
|
|
146
|
+
// and it excludes self-edges + NO_IPDOM regions. Sense is read from the
|
|
147
|
+
// CONTROLLER's arms (seq/loop-back fall-through false arms would otherwise
|
|
148
|
+
// mislabel as 'T' — #2188 F1).
|
|
149
|
+
for (const { from: a, kind } of inEdges[x]) {
|
|
150
|
+
if (a !== x && ipdom[a] !== x)
|
|
151
|
+
add(x, a, labelFor(kind, armSenses[a]));
|
|
152
|
+
}
|
|
153
|
+
// PDF_up: inherit each post-dom child's frontier controller (with its label
|
|
154
|
+
// set) when X does not post-dominate it.
|
|
155
|
+
for (const z of children[x]) {
|
|
156
|
+
for (const [a, labels] of pdf[z]) {
|
|
157
|
+
if (ipdom[a] !== x)
|
|
158
|
+
for (const l of labels)
|
|
159
|
+
add(x, a, l);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const out = [];
|
|
164
|
+
for (const x of order) {
|
|
165
|
+
for (const [a, labels] of pdf[x]) {
|
|
166
|
+
for (const label of labels)
|
|
167
|
+
out.push({ controllerBlock: a, dependentBlock: x, label });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
out.sort((x, y) => x.controllerBlock - y.controllerBlock ||
|
|
171
|
+
x.dependentBlock - y.dependentBlock ||
|
|
172
|
+
(x.label < y.label ? -1 : x.label > y.label ? 1 : 0));
|
|
173
|
+
// `maxEdges` is a heap-safety backstop applied to the SORTED set (the DF makes
|
|
174
|
+
// overflow far rarer than the old per-edge walk). Deterministic prefix, never
|
|
175
|
+
// a silent drop; mirrors computeReachingDefs' `truncated`.
|
|
176
|
+
let truncated = false;
|
|
177
|
+
if (cap !== Infinity && out.length > cap) {
|
|
178
|
+
truncated = true;
|
|
179
|
+
out.length = cap;
|
|
180
|
+
}
|
|
181
|
+
return { edges: out, truncated };
|
|
182
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ControlFlowContext (issue #2081 M1; finalizer frames added by #2082 M2 U2).
|
|
3
|
+
*
|
|
4
|
+
* Resolves the targets of `break`/`continue` (plain and labeled) as the visitor
|
|
5
|
+
* descends through loops and switches. Loops and switches push a target frame
|
|
6
|
+
* on entry and pop it on exit; a labeled statement attaches its label to the
|
|
7
|
+
* frame of the construct it labels, so `break outer` / `continue outer` resolve
|
|
8
|
+
* against the right enclosing loop/switch rather than the nearest one.
|
|
9
|
+
*
|
|
10
|
+
* M2 adds FINALIZER frames, interleaved on the SAME stack as loop/switch frames
|
|
11
|
+
* — interleaving is load-bearing: a jump must route through exactly the
|
|
12
|
+
* `finally` bodies lexically BETWEEN it and its target (target-relative
|
|
13
|
+
* threading). A `break` whose loop lives entirely inside the `try` crosses no
|
|
14
|
+
* finally and must keep its direct edge; re-routing it anyway would force the
|
|
15
|
+
* only path to the in-try continuation through the finally, letting a finally
|
|
16
|
+
* redefinition falsely KILL in-loop definitions for the downstream
|
|
17
|
+
* reaching-defs pass (a taint false negative). A parallel stack cannot express
|
|
18
|
+
* that between-ness, which is why the frames live here.
|
|
19
|
+
*/
|
|
20
|
+
import type { CfgBuilder } from './cfg-builder.js';
|
|
21
|
+
import type { CfgEdgeKind } from './types.js';
|
|
22
|
+
/** A `finally` whose body any crossing jump must route through. */
|
|
23
|
+
export interface FinalizerFrame {
|
|
24
|
+
readonly kind: 'finalizer';
|
|
25
|
+
/** Entry block of the finally body. */
|
|
26
|
+
readonly entry: number;
|
|
27
|
+
/**
|
|
28
|
+
* Completion legs registered by jumps that crossed this finally: once the
|
|
29
|
+
* owning try pops the frame, it wires `finally-exits → to` with `kind` for
|
|
30
|
+
* each entry. Mutated by the jump handlers via {@link ControlFlowContext}.
|
|
31
|
+
*/
|
|
32
|
+
readonly pending: {
|
|
33
|
+
to: number;
|
|
34
|
+
kind: CfgEdgeKind;
|
|
35
|
+
}[];
|
|
36
|
+
}
|
|
37
|
+
/** A resolved jump: its ultimate target + the finallys it crosses (inner→outer). */
|
|
38
|
+
export interface JumpResolution {
|
|
39
|
+
readonly target: number;
|
|
40
|
+
readonly finalizers: readonly FinalizerFrame[];
|
|
41
|
+
}
|
|
42
|
+
export declare class ControlFlowContext {
|
|
43
|
+
private readonly stack;
|
|
44
|
+
pushLoop(continueTo: number, breakTo: number, labels?: readonly string[]): void;
|
|
45
|
+
pushSwitch(breakTo: number, labels?: readonly string[]): void;
|
|
46
|
+
/** Push a labeled non-loop statement's break-target frame. */
|
|
47
|
+
pushLabeledBlock(breakTo: number, labels: readonly string[]): void;
|
|
48
|
+
/**
|
|
49
|
+
* Push a finalizer frame and return it — the owning `visitTry` keeps the
|
|
50
|
+
* reference to wire {@link FinalizerFrame.pending} after popping it.
|
|
51
|
+
*/
|
|
52
|
+
pushFinalizer(entry: number): FinalizerFrame;
|
|
53
|
+
pop(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a `break`: the nearest enclosing loop/switch frame (or, with a
|
|
56
|
+
* label, the nearest frame carrying that label) plus every finalizer frame
|
|
57
|
+
* stacked ABOVE it — i.e. exactly the finallys the jump crosses, innermost
|
|
58
|
+
* first. Returns `undefined` if there is no valid target (malformed input or
|
|
59
|
+
* an unmodeled label) — the caller falls back to its conservative routing and
|
|
60
|
+
* threads nothing.
|
|
61
|
+
*/
|
|
62
|
+
resolveBreak(label?: string): JumpResolution | undefined;
|
|
63
|
+
/** Resolve a `continue`: like {@link resolveBreak} but only loop frames match. */
|
|
64
|
+
resolveContinue(label?: string): JumpResolution | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a Java `yield e` (switch-EXPRESSION arm exit): the nearest enclosing
|
|
67
|
+
* SWITCH frame's exit, threading the finalizers stacked above it. Unlike a
|
|
68
|
+
* `break`, a `yield` ALWAYS targets the switch — never an intervening loop — so
|
|
69
|
+
* it cannot match a loop frame (a `yield` inside a loop inside a switch arm
|
|
70
|
+
* still exits the whole switch). Returns `undefined` when there is no enclosing
|
|
71
|
+
* switch (malformed input); the caller falls back to its conservative routing.
|
|
72
|
+
*/
|
|
73
|
+
resolveYield(): JumpResolution | undefined;
|
|
74
|
+
/** Every active finalizer, innermost first — what a `return` must cross. */
|
|
75
|
+
finalizersForReturn(): readonly FinalizerFrame[];
|
|
76
|
+
/**
|
|
77
|
+
* Target block for a `break` (no finalizer info) — see {@link resolveBreak}.
|
|
78
|
+
* Prefer `resolveBreak` + {@link wireJumpThroughFinalizers} in visitors: a
|
|
79
|
+
* target-only lookup silently loses finalizer threading (the M2 soundness
|
|
80
|
+
* fix). Kept for target-shape assertions in tests.
|
|
81
|
+
*/
|
|
82
|
+
breakTarget(label?: string): number | undefined;
|
|
83
|
+
/** Target block for a `continue` — same caveat as {@link breakTarget}. */
|
|
84
|
+
continueTarget(label?: string): number | undefined;
|
|
85
|
+
private resolve;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Wire a jump from `from` to `target`, routing through the finallys it
|
|
89
|
+
* crosses (innermost first). The first leg keeps the bare jump `kind`
|
|
90
|
+
* (preserving the "kind ⟹ source-block terminator" invariant in types.ts);
|
|
91
|
+
* each finally's completion leg is registered as pending on its frame with the
|
|
92
|
+
* matching `finally-*` kind and wired by the owning try via
|
|
93
|
+
* {@link drainFinalizerPending} once the finally's exits are known.
|
|
94
|
+
*
|
|
95
|
+
* Language-agnostic on purpose (#2082 M2): the threading protocol encodes
|
|
96
|
+
* three subtle invariants every future language visitor needs identically —
|
|
97
|
+
* keeping it here means a new visitor cannot drift on any of them.
|
|
98
|
+
*/
|
|
99
|
+
export declare function wireJumpThroughFinalizers(builder: CfgBuilder, from: number, finalizers: readonly FinalizerFrame[], target: number, kind: 'return' | 'break' | 'continue'): void;
|
|
100
|
+
/**
|
|
101
|
+
* Wire a popped finalizer frame's pending completion legs from the finally's
|
|
102
|
+
* exit blocks. A finally that itself always jumps (`finally { return 2; }`)
|
|
103
|
+
* has no exits — its pending legs wire nowhere, matching JS's
|
|
104
|
+
* finally-override semantics.
|
|
105
|
+
*/
|
|
106
|
+
export declare function drainFinalizerPending(builder: CfgBuilder, frame: FinalizerFrame, finallyExits: readonly number[]): void;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export class ControlFlowContext {
|
|
2
|
+
stack = [];
|
|
3
|
+
pushLoop(continueTo, breakTo, labels = []) {
|
|
4
|
+
this.stack.push({ kind: 'loop', continueTo, breakTo, labels });
|
|
5
|
+
}
|
|
6
|
+
pushSwitch(breakTo, labels = []) {
|
|
7
|
+
this.stack.push({ kind: 'switch', breakTo, labels });
|
|
8
|
+
}
|
|
9
|
+
/** Push a labeled non-loop statement's break-target frame. */
|
|
10
|
+
pushLabeledBlock(breakTo, labels) {
|
|
11
|
+
this.stack.push({ kind: 'block', breakTo, labels });
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Push a finalizer frame and return it — the owning `visitTry` keeps the
|
|
15
|
+
* reference to wire {@link FinalizerFrame.pending} after popping it.
|
|
16
|
+
*/
|
|
17
|
+
pushFinalizer(entry) {
|
|
18
|
+
const frame = { kind: 'finalizer', entry, pending: [] };
|
|
19
|
+
this.stack.push(frame);
|
|
20
|
+
return frame;
|
|
21
|
+
}
|
|
22
|
+
pop() {
|
|
23
|
+
this.stack.pop();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a `break`: the nearest enclosing loop/switch frame (or, with a
|
|
27
|
+
* label, the nearest frame carrying that label) plus every finalizer frame
|
|
28
|
+
* stacked ABOVE it — i.e. exactly the finallys the jump crosses, innermost
|
|
29
|
+
* first. Returns `undefined` if there is no valid target (malformed input or
|
|
30
|
+
* an unmodeled label) — the caller falls back to its conservative routing and
|
|
31
|
+
* threads nothing.
|
|
32
|
+
*/
|
|
33
|
+
resolveBreak(label) {
|
|
34
|
+
return this.resolve((f) => label === undefined
|
|
35
|
+
? f.kind !== 'block' // an unlabeled break never targets a labeled block
|
|
36
|
+
: f.labels.includes(label));
|
|
37
|
+
}
|
|
38
|
+
/** Resolve a `continue`: like {@link resolveBreak} but only loop frames match. */
|
|
39
|
+
resolveContinue(label) {
|
|
40
|
+
return this.resolve((f) => f.kind === 'loop' && (label === undefined || f.labels.includes(label)), (f) => f.continueTo);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a Java `yield e` (switch-EXPRESSION arm exit): the nearest enclosing
|
|
44
|
+
* SWITCH frame's exit, threading the finalizers stacked above it. Unlike a
|
|
45
|
+
* `break`, a `yield` ALWAYS targets the switch — never an intervening loop — so
|
|
46
|
+
* it cannot match a loop frame (a `yield` inside a loop inside a switch arm
|
|
47
|
+
* still exits the whole switch). Returns `undefined` when there is no enclosing
|
|
48
|
+
* switch (malformed input); the caller falls back to its conservative routing.
|
|
49
|
+
*/
|
|
50
|
+
resolveYield() {
|
|
51
|
+
return this.resolve((f) => f.kind === 'switch');
|
|
52
|
+
}
|
|
53
|
+
/** Every active finalizer, innermost first — what a `return` must cross. */
|
|
54
|
+
finalizersForReturn() {
|
|
55
|
+
const fins = [];
|
|
56
|
+
for (let i = this.stack.length - 1; i >= 0; i--) {
|
|
57
|
+
const f = this.stack[i];
|
|
58
|
+
if (f.kind === 'finalizer')
|
|
59
|
+
fins.push(f);
|
|
60
|
+
}
|
|
61
|
+
return fins;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Target block for a `break` (no finalizer info) — see {@link resolveBreak}.
|
|
65
|
+
* Prefer `resolveBreak` + {@link wireJumpThroughFinalizers} in visitors: a
|
|
66
|
+
* target-only lookup silently loses finalizer threading (the M2 soundness
|
|
67
|
+
* fix). Kept for target-shape assertions in tests.
|
|
68
|
+
*/
|
|
69
|
+
breakTarget(label) {
|
|
70
|
+
return this.resolveBreak(label)?.target;
|
|
71
|
+
}
|
|
72
|
+
/** Target block for a `continue` — same caveat as {@link breakTarget}. */
|
|
73
|
+
continueTarget(label) {
|
|
74
|
+
return this.resolveContinue(label)?.target;
|
|
75
|
+
}
|
|
76
|
+
resolve(matches, targetOf = (f) => f.breakTo) {
|
|
77
|
+
const crossed = [];
|
|
78
|
+
for (let i = this.stack.length - 1; i >= 0; i--) {
|
|
79
|
+
const f = this.stack[i];
|
|
80
|
+
if (f.kind === 'finalizer') {
|
|
81
|
+
crossed.push(f);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (matches(f))
|
|
85
|
+
return { target: targetOf(f), finalizers: crossed };
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Wire a jump from `from` to `target`, routing through the finallys it
|
|
92
|
+
* crosses (innermost first). The first leg keeps the bare jump `kind`
|
|
93
|
+
* (preserving the "kind ⟹ source-block terminator" invariant in types.ts);
|
|
94
|
+
* each finally's completion leg is registered as pending on its frame with the
|
|
95
|
+
* matching `finally-*` kind and wired by the owning try via
|
|
96
|
+
* {@link drainFinalizerPending} once the finally's exits are known.
|
|
97
|
+
*
|
|
98
|
+
* Language-agnostic on purpose (#2082 M2): the threading protocol encodes
|
|
99
|
+
* three subtle invariants every future language visitor needs identically —
|
|
100
|
+
* keeping it here means a new visitor cannot drift on any of them.
|
|
101
|
+
*/
|
|
102
|
+
export function wireJumpThroughFinalizers(builder, from, finalizers, target, kind) {
|
|
103
|
+
if (finalizers.length === 0) {
|
|
104
|
+
builder.edge(from, target, kind);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const completionKind = `finally-${kind}`;
|
|
108
|
+
builder.edge(from, finalizers[0].entry, kind);
|
|
109
|
+
for (let i = 0; i < finalizers.length; i++) {
|
|
110
|
+
const to = i + 1 < finalizers.length ? finalizers[i + 1].entry : target;
|
|
111
|
+
finalizers[i].pending.push({ to, kind: completionKind });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Wire a popped finalizer frame's pending completion legs from the finally's
|
|
116
|
+
* exit blocks. A finally that itself always jumps (`finally { return 2; }`)
|
|
117
|
+
* has no exits — its pending legs wire nowhere, matching JS's
|
|
118
|
+
* finally-override semantics.
|
|
119
|
+
*/
|
|
120
|
+
export function drainFinalizerPending(builder, frame, finallyExits) {
|
|
121
|
+
for (const p of frame.pending) {
|
|
122
|
+
builder.connect(finallyExits, p.to, p.kind);
|
|
123
|
+
}
|
|
124
|
+
}
|