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,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic-escape pass for CDG soundness (#2197 U1).
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM. Control dependence is computed over the post-dominator tree
|
|
5
|
+
* (control-dependence.ts), which is only sound when EXIT is reverse-reachable
|
|
6
|
+
* from every entry-reachable block (post-dominators.ts §
|
|
7
|
+
* {@link isExitReachableFromAllBlocks}). Loop visitors keep that invariant by
|
|
8
|
+
* giving every loop a structural `header → loopExit` `cond-false` edge — so an
|
|
9
|
+
* ordinary `while`/`for` always has a path to EXIT. The `goto` handlers
|
|
10
|
+
* (C/C++/C#/Go), however, wire an UNCONDITIONAL back-edge as plain `seq` with no
|
|
11
|
+
* such escape:
|
|
12
|
+
*
|
|
13
|
+
* void handler(int a){ start: if (a > 0) { work(); } goto start; }
|
|
14
|
+
*
|
|
15
|
+
* Here every body block sits in a trapping cycle (`start … goto start`) with no
|
|
16
|
+
* path to EXIT, so EXIT is non-reverse-reachable and {@link emitFileCdg} (the
|
|
17
|
+
* soundness gate) WITHHOLDS all control dependence for the whole function —
|
|
18
|
+
* silent CDG coverage loss for an entire (common) class of functions.
|
|
19
|
+
*
|
|
20
|
+
* THE FIX (nontermination-sensitive control dependence — Ranganath et al.,
|
|
21
|
+
* TOPLAS 2007). For a genuinely exit-unreachable *cycle* (an infinite loop), add
|
|
22
|
+
* an ANALYSIS-ONLY virtual escape edge from the cycle's controlling branch to
|
|
23
|
+
* EXIT, making the post-dom tree well-defined again. The synthetic edge is inert
|
|
24
|
+
* in the Ferrante walk (EXIT post-dominates its source, so the post-dom guard
|
|
25
|
+
* skips it) — it only restores reverse-reachability so the REAL control points
|
|
26
|
+
* inside the loop get their dependences.
|
|
27
|
+
*
|
|
28
|
+
* ANALYSIS-ONLY (load-bearing — KTD7). The pass NEVER mutates the input. The
|
|
29
|
+
* persisted CFG / REACHING_DEF graph and the byte-identical-off golden depend on
|
|
30
|
+
* `cfg.edges` staying faithful, so the augmentation lives on a shallow-cloned
|
|
31
|
+
* {@link FunctionCfg} whose `edges` is `[...cfg.edges, ...synthetic]`. Because
|
|
32
|
+
* both {@link computePostDominators} AND {@link computeControlDependence}
|
|
33
|
+
* (its Ferrante walk + `buildArmSenses`) re-read `cfg.edges` directly, the
|
|
34
|
+
* augmented view must be passed to BOTH — feeding only an augmented post-dom
|
|
35
|
+
* tree would leave the walk on the un-augmented edges (KTD7).
|
|
36
|
+
*
|
|
37
|
+
* PURE AND DETERMINISTIC (mirrors post-dominators.ts / reaching-defs.ts). The
|
|
38
|
+
* SCC routine sorts every adjacency list and emits SCCs root-deterministically,
|
|
39
|
+
* so the chosen representative — hence the augmented edge set and any downstream
|
|
40
|
+
* snapshot — is identical across runs.
|
|
41
|
+
*
|
|
42
|
+
* WHICH SCCs ARE BRIDGED (KTD2 / KTD6, and the anti-masking guarantee R2). The
|
|
43
|
+
* decision is gated on the WHOLE entry-reachable trapped region (the union of
|
|
44
|
+
* the entry-reachable blocks that cannot reach EXIT): the pass bridges only when
|
|
45
|
+
* that region contains at least one *control point* — a block with ≥2 successors
|
|
46
|
+
* (a branch terminator). A region with a control point is a real, recoverable
|
|
47
|
+
* loop (a `goto`-cycle always carries the `if` predicate from its guard); a
|
|
48
|
+
* region with NO control point is a branch-less infinite spin that carries no
|
|
49
|
+
* control dependence to recover AND is indistinguishable from a genuine
|
|
50
|
+
* CFG-construction anomaly (e.g. a disconnected EXIT block), so it is
|
|
51
|
+
* deliberately LEFT UNBRIDGED — the existing soundness gate then skips the
|
|
52
|
+
* function and surfaces the skip (R2 / R3). In practice a branch-less trapping
|
|
53
|
+
* region never comes from a real loop visitor (loops emit the structural escape
|
|
54
|
+
* edge) — it signals a construction error, exactly what we must not paper over.
|
|
55
|
+
*
|
|
56
|
+
* When the region is bridged, EACH exit-less SCC gets one synthetic escape edge
|
|
57
|
+
* from its *controlling representative*: the entry-reachable member with a branch
|
|
58
|
+
* terminator (≥2 successors), highest out-degree, lowest-index tie-break. That
|
|
59
|
+
* branch is the predicate deciding stay-in-loop vs. leave, the faithful escape
|
|
60
|
+
* representative; attaching the escape anywhere else invents or drops CDG edges
|
|
61
|
+
* while still passing the AC2 post-dominance property test, so the choice is
|
|
62
|
+
* pinned by an exact-edge-set test, not `CDG>0`. When an exit-less SCC has NO
|
|
63
|
+
* internal branch (e.g. the body of an irreducible loop whose control point sits
|
|
64
|
+
* OUTSIDE the cycle), its escape attaches to the lowest-index member — the
|
|
65
|
+
* choice is semantically immaterial (the SCC has no internal control point so it
|
|
66
|
+
* contributes no internal CDG), and a deterministic index keeps snapshots
|
|
67
|
+
* stable. This per-SCC bridging restores reverse-reachability for the whole
|
|
68
|
+
* region in one batch, then the gate re-checks (KTD2).
|
|
69
|
+
*
|
|
70
|
+
* GRANULARITY OF A MIXED cycle + dead-end FUNCTION. {@link emitFileCdg} is
|
|
71
|
+
* all-or-nothing per function: it computes CDG only when EXIT is reverse-
|
|
72
|
+
* reachable from EVERY entry-reachable block. So if a function contains a
|
|
73
|
+
* recoverable goto-cycle AND a *separate* residual block that is still
|
|
74
|
+
* exit-unreachable after all escapes (a dangling/dead-end block not in any
|
|
75
|
+
* bridgeable cycle), the pass restores the cycle but the residual block keeps
|
|
76
|
+
* EXIT non-reverse-reachable → the WHOLE function is still skipped and surfaced.
|
|
77
|
+
* We do NOT bridge the residual (that would mask the construction error), and we
|
|
78
|
+
* do NOT emit partial per-cycle CDG (the emit layer has no partial mode). This
|
|
79
|
+
* is the documented, intentional trade-off: recover the common goto-cycle case;
|
|
80
|
+
* surface anything with a genuine residual anomaly rather than guess.
|
|
81
|
+
*/
|
|
82
|
+
import { isExitReachableFromAllBlocks, type PostDomTree } from './post-dominators.js';
|
|
83
|
+
import type { FunctionCfg } from './types.js';
|
|
84
|
+
/**
|
|
85
|
+
* Strongly-connected components of a CFG via an ITERATIVE Tarjan over the
|
|
86
|
+
* forward edges. Pure and deterministic: nodes are visited in ascending index
|
|
87
|
+
* and every successor list is iterated in sorted order, so the component
|
|
88
|
+
* partition (and the per-component member order) is identical across runs.
|
|
89
|
+
*
|
|
90
|
+
* Returns `compOf[b]` = the component id of block `b`, plus `members[c]` = the
|
|
91
|
+
* (ascending-index) members of component `c`. Component ids are assigned in
|
|
92
|
+
* Tarjan completion order (a reverse-topological order over the condensation),
|
|
93
|
+
* which is deterministic but not relied upon — callers key on `compOf`.
|
|
94
|
+
*/
|
|
95
|
+
export interface SccResult {
|
|
96
|
+
readonly compOf: readonly number[];
|
|
97
|
+
readonly members: readonly (readonly number[])[];
|
|
98
|
+
}
|
|
99
|
+
export declare function computeScc(succ: readonly number[][], n: number): SccResult;
|
|
100
|
+
/**
|
|
101
|
+
* Restore EXIT reverse-reachability for genuine exit-unreachable cycles so the
|
|
102
|
+
* post-dom / CDG pass runs on a well-defined tree, WITHOUT masking construction
|
|
103
|
+
* errors or perturbing sound functions. See the module doc for the full
|
|
104
|
+
* contract.
|
|
105
|
+
*
|
|
106
|
+
* Returns the input `cfg` UNCHANGED (referential no-op) when EXIT is already
|
|
107
|
+
* reverse-reachable from every entry-reachable block — terminating functions and
|
|
108
|
+
* properly-escaped loops are byte-identical (zero synthetic edges). Otherwise
|
|
109
|
+
* returns a SHALLOW-CLONED {@link FunctionCfg} whose `edges` is the original
|
|
110
|
+
* edges followed by the synthetic escapes; the input's `edges` is never mutated.
|
|
111
|
+
*
|
|
112
|
+
* Pass the returned view to BOTH {@link computePostDominators} and
|
|
113
|
+
* {@link computeControlDependence} (KTD7).
|
|
114
|
+
*/
|
|
115
|
+
export declare function augmentForPostDom(cfg: FunctionCfg): FunctionCfg;
|
|
116
|
+
/**
|
|
117
|
+
* Convenience: `true` iff {@link augmentForPostDom} returned a DIFFERENT object
|
|
118
|
+
* (i.e. at least one synthetic escape edge was added). Useful for tests
|
|
119
|
+
* asserting the no-op path. Reference equality is exact: the no-op path returns
|
|
120
|
+
* the input unchanged.
|
|
121
|
+
*/
|
|
122
|
+
export declare function wasAugmented(cfg: FunctionCfg, view: FunctionCfg): boolean;
|
|
123
|
+
export { isExitReachableFromAllBlocks };
|
|
124
|
+
export type { PostDomTree };
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic-escape pass for CDG soundness (#2197 U1).
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM. Control dependence is computed over the post-dominator tree
|
|
5
|
+
* (control-dependence.ts), which is only sound when EXIT is reverse-reachable
|
|
6
|
+
* from every entry-reachable block (post-dominators.ts §
|
|
7
|
+
* {@link isExitReachableFromAllBlocks}). Loop visitors keep that invariant by
|
|
8
|
+
* giving every loop a structural `header → loopExit` `cond-false` edge — so an
|
|
9
|
+
* ordinary `while`/`for` always has a path to EXIT. The `goto` handlers
|
|
10
|
+
* (C/C++/C#/Go), however, wire an UNCONDITIONAL back-edge as plain `seq` with no
|
|
11
|
+
* such escape:
|
|
12
|
+
*
|
|
13
|
+
* void handler(int a){ start: if (a > 0) { work(); } goto start; }
|
|
14
|
+
*
|
|
15
|
+
* Here every body block sits in a trapping cycle (`start … goto start`) with no
|
|
16
|
+
* path to EXIT, so EXIT is non-reverse-reachable and {@link emitFileCdg} (the
|
|
17
|
+
* soundness gate) WITHHOLDS all control dependence for the whole function —
|
|
18
|
+
* silent CDG coverage loss for an entire (common) class of functions.
|
|
19
|
+
*
|
|
20
|
+
* THE FIX (nontermination-sensitive control dependence — Ranganath et al.,
|
|
21
|
+
* TOPLAS 2007). For a genuinely exit-unreachable *cycle* (an infinite loop), add
|
|
22
|
+
* an ANALYSIS-ONLY virtual escape edge from the cycle's controlling branch to
|
|
23
|
+
* EXIT, making the post-dom tree well-defined again. The synthetic edge is inert
|
|
24
|
+
* in the Ferrante walk (EXIT post-dominates its source, so the post-dom guard
|
|
25
|
+
* skips it) — it only restores reverse-reachability so the REAL control points
|
|
26
|
+
* inside the loop get their dependences.
|
|
27
|
+
*
|
|
28
|
+
* ANALYSIS-ONLY (load-bearing — KTD7). The pass NEVER mutates the input. The
|
|
29
|
+
* persisted CFG / REACHING_DEF graph and the byte-identical-off golden depend on
|
|
30
|
+
* `cfg.edges` staying faithful, so the augmentation lives on a shallow-cloned
|
|
31
|
+
* {@link FunctionCfg} whose `edges` is `[...cfg.edges, ...synthetic]`. Because
|
|
32
|
+
* both {@link computePostDominators} AND {@link computeControlDependence}
|
|
33
|
+
* (its Ferrante walk + `buildArmSenses`) re-read `cfg.edges` directly, the
|
|
34
|
+
* augmented view must be passed to BOTH — feeding only an augmented post-dom
|
|
35
|
+
* tree would leave the walk on the un-augmented edges (KTD7).
|
|
36
|
+
*
|
|
37
|
+
* PURE AND DETERMINISTIC (mirrors post-dominators.ts / reaching-defs.ts). The
|
|
38
|
+
* SCC routine sorts every adjacency list and emits SCCs root-deterministically,
|
|
39
|
+
* so the chosen representative — hence the augmented edge set and any downstream
|
|
40
|
+
* snapshot — is identical across runs.
|
|
41
|
+
*
|
|
42
|
+
* WHICH SCCs ARE BRIDGED (KTD2 / KTD6, and the anti-masking guarantee R2). The
|
|
43
|
+
* decision is gated on the WHOLE entry-reachable trapped region (the union of
|
|
44
|
+
* the entry-reachable blocks that cannot reach EXIT): the pass bridges only when
|
|
45
|
+
* that region contains at least one *control point* — a block with ≥2 successors
|
|
46
|
+
* (a branch terminator). A region with a control point is a real, recoverable
|
|
47
|
+
* loop (a `goto`-cycle always carries the `if` predicate from its guard); a
|
|
48
|
+
* region with NO control point is a branch-less infinite spin that carries no
|
|
49
|
+
* control dependence to recover AND is indistinguishable from a genuine
|
|
50
|
+
* CFG-construction anomaly (e.g. a disconnected EXIT block), so it is
|
|
51
|
+
* deliberately LEFT UNBRIDGED — the existing soundness gate then skips the
|
|
52
|
+
* function and surfaces the skip (R2 / R3). In practice a branch-less trapping
|
|
53
|
+
* region never comes from a real loop visitor (loops emit the structural escape
|
|
54
|
+
* edge) — it signals a construction error, exactly what we must not paper over.
|
|
55
|
+
*
|
|
56
|
+
* When the region is bridged, EACH exit-less SCC gets one synthetic escape edge
|
|
57
|
+
* from its *controlling representative*: the entry-reachable member with a branch
|
|
58
|
+
* terminator (≥2 successors), highest out-degree, lowest-index tie-break. That
|
|
59
|
+
* branch is the predicate deciding stay-in-loop vs. leave, the faithful escape
|
|
60
|
+
* representative; attaching the escape anywhere else invents or drops CDG edges
|
|
61
|
+
* while still passing the AC2 post-dominance property test, so the choice is
|
|
62
|
+
* pinned by an exact-edge-set test, not `CDG>0`. When an exit-less SCC has NO
|
|
63
|
+
* internal branch (e.g. the body of an irreducible loop whose control point sits
|
|
64
|
+
* OUTSIDE the cycle), its escape attaches to the lowest-index member — the
|
|
65
|
+
* choice is semantically immaterial (the SCC has no internal control point so it
|
|
66
|
+
* contributes no internal CDG), and a deterministic index keeps snapshots
|
|
67
|
+
* stable. This per-SCC bridging restores reverse-reachability for the whole
|
|
68
|
+
* region in one batch, then the gate re-checks (KTD2).
|
|
69
|
+
*
|
|
70
|
+
* GRANULARITY OF A MIXED cycle + dead-end FUNCTION. {@link emitFileCdg} is
|
|
71
|
+
* all-or-nothing per function: it computes CDG only when EXIT is reverse-
|
|
72
|
+
* reachable from EVERY entry-reachable block. So if a function contains a
|
|
73
|
+
* recoverable goto-cycle AND a *separate* residual block that is still
|
|
74
|
+
* exit-unreachable after all escapes (a dangling/dead-end block not in any
|
|
75
|
+
* bridgeable cycle), the pass restores the cycle but the residual block keeps
|
|
76
|
+
* EXIT non-reverse-reachable → the WHOLE function is still skipped and surfaced.
|
|
77
|
+
* We do NOT bridge the residual (that would mask the construction error), and we
|
|
78
|
+
* do NOT emit partial per-cycle CDG (the emit layer has no partial mode). This
|
|
79
|
+
* is the documented, intentional trade-off: recover the common goto-cycle case;
|
|
80
|
+
* surface anything with a genuine residual anomaly rather than guess.
|
|
81
|
+
*/
|
|
82
|
+
import { isExitReachableFromAllBlocks } from './post-dominators.js';
|
|
83
|
+
/**
|
|
84
|
+
* The synthetic escape edge kind. Reuses the existing `cond-false` kind (the
|
|
85
|
+
* same kind every loop's structural `header → loopExit` escape carries — see the
|
|
86
|
+
* module doc), so the augmented view is structurally indistinguishable from a
|
|
87
|
+
* normally-escaped loop and `buildArmSenses`/`labelFor` treat it identically.
|
|
88
|
+
* The edge is analysis-only and never persisted.
|
|
89
|
+
*/
|
|
90
|
+
const SYNTHETIC_ESCAPE_KIND = 'cond-false';
|
|
91
|
+
function reach(start, adj, n) {
|
|
92
|
+
const seen = new Uint8Array(n);
|
|
93
|
+
if (start < 0 || start >= n)
|
|
94
|
+
return seen;
|
|
95
|
+
const stack = [start];
|
|
96
|
+
seen[start] = 1;
|
|
97
|
+
while (stack.length > 0) {
|
|
98
|
+
const b = stack.pop();
|
|
99
|
+
for (const next of adj[b]) {
|
|
100
|
+
if (!seen[next]) {
|
|
101
|
+
seen[next] = 1;
|
|
102
|
+
stack.push(next);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return seen;
|
|
107
|
+
}
|
|
108
|
+
function computeReachability(cfg) {
|
|
109
|
+
const n = cfg.blocks.length;
|
|
110
|
+
const succ = Array.from({ length: n }, () => []);
|
|
111
|
+
const pred = Array.from({ length: n }, () => []);
|
|
112
|
+
for (const e of cfg.edges) {
|
|
113
|
+
if (e.from < 0 || e.from >= n || e.to < 0 || e.to >= n)
|
|
114
|
+
continue;
|
|
115
|
+
succ[e.from].push(e.to);
|
|
116
|
+
pred[e.to].push(e.from);
|
|
117
|
+
}
|
|
118
|
+
// Sorted adjacency — determinism (mirrors post-dominators.ts).
|
|
119
|
+
for (const l of succ)
|
|
120
|
+
l.sort((a, b) => a - b);
|
|
121
|
+
return {
|
|
122
|
+
fromEntry: reach(cfg.entryIndex, succ, n),
|
|
123
|
+
canReachExit: reach(cfg.exitIndex, pred, n),
|
|
124
|
+
succ,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export function computeScc(succ, n) {
|
|
128
|
+
const compOf = new Array(n).fill(-1);
|
|
129
|
+
const members = [];
|
|
130
|
+
const index = new Array(n).fill(-1);
|
|
131
|
+
const lowlink = new Array(n).fill(0);
|
|
132
|
+
const onStack = new Uint8Array(n);
|
|
133
|
+
const tarjanStack = [];
|
|
134
|
+
let nextIndex = 0;
|
|
135
|
+
// Explicit work stack: each frame tracks the node and how far through its
|
|
136
|
+
// (sorted) successor list we have iterated, so recursion depth never blows the
|
|
137
|
+
// JS stack on a large per-function CFG.
|
|
138
|
+
for (let root = 0; root < n; root++) {
|
|
139
|
+
if (index[root] !== -1)
|
|
140
|
+
continue;
|
|
141
|
+
const work = [{ node: root, childIdx: 0 }];
|
|
142
|
+
while (work.length > 0) {
|
|
143
|
+
const frame = work[work.length - 1];
|
|
144
|
+
const v = frame.node;
|
|
145
|
+
if (frame.childIdx === 0) {
|
|
146
|
+
// First visit to v.
|
|
147
|
+
index[v] = nextIndex;
|
|
148
|
+
lowlink[v] = nextIndex;
|
|
149
|
+
nextIndex += 1;
|
|
150
|
+
tarjanStack.push(v);
|
|
151
|
+
onStack[v] = 1;
|
|
152
|
+
}
|
|
153
|
+
const succs = succ[v];
|
|
154
|
+
if (frame.childIdx < succs.length) {
|
|
155
|
+
const w = succs[frame.childIdx];
|
|
156
|
+
frame.childIdx += 1;
|
|
157
|
+
if (index[w] === -1) {
|
|
158
|
+
// Descend into the unvisited child; resume v afterwards.
|
|
159
|
+
work.push({ node: w, childIdx: 0 });
|
|
160
|
+
}
|
|
161
|
+
else if (onStack[w]) {
|
|
162
|
+
if (index[w] < lowlink[v])
|
|
163
|
+
lowlink[v] = index[w];
|
|
164
|
+
}
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// All successors of v processed: propagate lowlink to the parent, and if v
|
|
168
|
+
// is a component root, pop its component off the Tarjan stack.
|
|
169
|
+
if (lowlink[v] === index[v]) {
|
|
170
|
+
const comp = [];
|
|
171
|
+
for (;;) {
|
|
172
|
+
const w = tarjanStack.pop();
|
|
173
|
+
onStack[w] = 0;
|
|
174
|
+
comp.push(w);
|
|
175
|
+
if (w === v)
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
comp.sort((a, b) => a - b); // ascending member order — determinism
|
|
179
|
+
const id = members.length;
|
|
180
|
+
for (const w of comp)
|
|
181
|
+
compOf[w] = id;
|
|
182
|
+
members.push(comp);
|
|
183
|
+
}
|
|
184
|
+
work.pop();
|
|
185
|
+
if (work.length > 0) {
|
|
186
|
+
const parent = work[work.length - 1].node;
|
|
187
|
+
if (lowlink[v] < lowlink[parent])
|
|
188
|
+
lowlink[parent] = lowlink[v];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { compOf, members };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Restore EXIT reverse-reachability for genuine exit-unreachable cycles so the
|
|
196
|
+
* post-dom / CDG pass runs on a well-defined tree, WITHOUT masking construction
|
|
197
|
+
* errors or perturbing sound functions. See the module doc for the full
|
|
198
|
+
* contract.
|
|
199
|
+
*
|
|
200
|
+
* Returns the input `cfg` UNCHANGED (referential no-op) when EXIT is already
|
|
201
|
+
* reverse-reachable from every entry-reachable block — terminating functions and
|
|
202
|
+
* properly-escaped loops are byte-identical (zero synthetic edges). Otherwise
|
|
203
|
+
* returns a SHALLOW-CLONED {@link FunctionCfg} whose `edges` is the original
|
|
204
|
+
* edges followed by the synthetic escapes; the input's `edges` is never mutated.
|
|
205
|
+
*
|
|
206
|
+
* Pass the returned view to BOTH {@link computePostDominators} and
|
|
207
|
+
* {@link computeControlDependence} (KTD7).
|
|
208
|
+
*/
|
|
209
|
+
export function augmentForPostDom(cfg) {
|
|
210
|
+
const n = cfg.blocks.length;
|
|
211
|
+
const { entryIndex, exitIndex } = cfg;
|
|
212
|
+
if (n === 0 || entryIndex < 0 || entryIndex >= n || exitIndex < 0 || exitIndex >= n) {
|
|
213
|
+
return cfg; // degenerate — leave to the existing gate
|
|
214
|
+
}
|
|
215
|
+
const { fromEntry, canReachExit, succ } = computeReachability(cfg);
|
|
216
|
+
// No-op fast path: every entry-reachable block already reaches EXIT.
|
|
217
|
+
let allReach = true;
|
|
218
|
+
for (let b = 0; b < n; b++) {
|
|
219
|
+
if (fromEntry[b] && !canReachExit[b]) {
|
|
220
|
+
allReach = false;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (allReach)
|
|
225
|
+
return cfg;
|
|
226
|
+
// Anti-masking gate (R2): only bridge when the entry-reachable TRAPPED REGION
|
|
227
|
+
// (the union of entry-reachable blocks that cannot reach EXIT) holds at least
|
|
228
|
+
// one control point — a block with ≥2 successors. A branch-less trapped region
|
|
229
|
+
// is a degenerate spin / construction anomaly we refuse to mask; the existing
|
|
230
|
+
// soundness gate skips it and surfaces the skip. A real `goto`-cycle always
|
|
231
|
+
// carries its guard's `if`, so it is recovered; a disconnected/dangling EXIT
|
|
232
|
+
// (no branch anywhere in the trap) is left to skip. See the module doc.
|
|
233
|
+
let regionHasControlPoint = false;
|
|
234
|
+
for (let b = 0; b < n; b++) {
|
|
235
|
+
if (fromEntry[b] && !canReachExit[b] && succ[b].length >= 2) {
|
|
236
|
+
regionHasControlPoint = true;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (!regionHasControlPoint)
|
|
241
|
+
return cfg;
|
|
242
|
+
// Condense into SCCs over the real edges.
|
|
243
|
+
const { members } = computeScc(succ, n);
|
|
244
|
+
// Bridge EACH exit-less SCC (a trapping cycle: no member can reach EXIT, so
|
|
245
|
+
// `canReachExit` is false for the whole SCC). `canReachExit` already encodes
|
|
246
|
+
// the transitive closure, so a single member's flag answers it for the SCC.
|
|
247
|
+
const synthetic = [];
|
|
248
|
+
for (const comp of members) {
|
|
249
|
+
if (comp.length === 0)
|
|
250
|
+
continue;
|
|
251
|
+
const rep = comp[0]; // ascending-order members → comp[0] is the lowest index
|
|
252
|
+
if (canReachExit[rep])
|
|
253
|
+
continue; // SCC escapes to EXIT — nothing to bridge
|
|
254
|
+
// Only genuine CYCLES trap. A singleton SCC with no self-edge is an ordinary
|
|
255
|
+
// acyclic block (ENTRY / the spine) that is exit-unreachable only because it
|
|
256
|
+
// FEEDS a trap downstream; it gets its path to EXIT for free once the trap is
|
|
257
|
+
// bridged, so it is never bridged on its own.
|
|
258
|
+
const isCycle = comp.length > 1 || cfg.edges.some((e) => e.from === rep && e.to === rep);
|
|
259
|
+
if (!isCycle)
|
|
260
|
+
continue;
|
|
261
|
+
// Controlling representative: the entry-reachable member with a branch
|
|
262
|
+
// terminator (≥2 successors), highest out-degree, lowest-index tie-break.
|
|
263
|
+
// When the SCC has no internal branch (its control point sits outside, e.g.
|
|
264
|
+
// an irreducible loop body), fall back to the lowest-index member — the
|
|
265
|
+
// choice is immaterial (no internal control point ⇒ no internal CDG) and a
|
|
266
|
+
// deterministic index keeps snapshots stable (KTD6).
|
|
267
|
+
let controller = -1;
|
|
268
|
+
let bestOutDeg = 1; // require ≥2 to qualify as a branch
|
|
269
|
+
for (const b of comp) {
|
|
270
|
+
if (!fromEntry[b])
|
|
271
|
+
continue;
|
|
272
|
+
const outDeg = succ[b].length;
|
|
273
|
+
if (outDeg >= 2 && outDeg > bestOutDeg) {
|
|
274
|
+
bestOutDeg = outDeg;
|
|
275
|
+
controller = b;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (controller === -1) {
|
|
279
|
+
// No internal branch — attach at the lowest entry-reachable member (or the
|
|
280
|
+
// lowest member if none is entry-reachable, a defensive fallback).
|
|
281
|
+
controller = comp.find((b) => fromEntry[b]) ?? rep;
|
|
282
|
+
}
|
|
283
|
+
synthetic.push({ from: controller, to: exitIndex, kind: SYNTHETIC_ESCAPE_KIND });
|
|
284
|
+
}
|
|
285
|
+
if (synthetic.length === 0)
|
|
286
|
+
return cfg; // nothing bridgeable — gate will skip
|
|
287
|
+
// Shallow clone with the augmented edge set; the input's `edges` is untouched.
|
|
288
|
+
return { ...cfg, edges: [...cfg.edges, ...synthetic] };
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Convenience: `true` iff {@link augmentForPostDom} returned a DIFFERENT object
|
|
292
|
+
* (i.e. at least one synthetic escape edge was added). Useful for tests
|
|
293
|
+
* asserting the no-op path. Reference equality is exact: the no-op path returns
|
|
294
|
+
* the input unchanged.
|
|
295
|
+
*/
|
|
296
|
+
export function wasAugmented(cfg, view) {
|
|
297
|
+
return view !== cfg;
|
|
298
|
+
}
|
|
299
|
+
// Re-export so callers can build the augmented view and gate it in one import.
|
|
300
|
+
export { isExitReachableFromAllBlocks };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraversalResult (issue #2081, M1).
|
|
3
|
+
*
|
|
4
|
+
* Visiting a statement (or a statement sequence) returns the block its control
|
|
5
|
+
* flow ENTERS through, plus the set of blocks whose **normal** control flows
|
|
6
|
+
* out the bottom (the "dangling exits") — to be wired to the entry of whatever
|
|
7
|
+
* comes next. Abnormal exits (return/break/continue/throw) are wired directly
|
|
8
|
+
* to their targets during the walk and are NOT part of `exits`.
|
|
9
|
+
*
|
|
10
|
+
* A statement that cannot fall through (e.g. ends in `return`/`throw`, or both
|
|
11
|
+
* branches of an `if` return) yields an empty `exits` array.
|
|
12
|
+
*/
|
|
13
|
+
export interface TraversalResult {
|
|
14
|
+
/** Block index control enters this statement/sequence through. */
|
|
15
|
+
readonly entry: number;
|
|
16
|
+
/** Block indices whose normal control falls out the bottom (may be empty). */
|
|
17
|
+
readonly exits: readonly number[];
|
|
18
|
+
}
|
|
19
|
+
/** A sequence of statements that produced no blocks (e.g. an empty body). */
|
|
20
|
+
export declare const emptyTraversal: (entry: number) => TraversalResult;
|