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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
2
|
import * as fs from 'node:fs/promises';
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
3
|
import { glob } from 'glob';
|
|
5
4
|
import Parser from 'tree-sitter';
|
|
6
5
|
import Cpp from 'tree-sitter-cpp';
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
import { requireVendoredGrammar } from '../../tree-sitter/vendored-grammars.js';
|
|
7
|
+
// `tree-sitter-c` is vendored (#2116), loaded from `vendor/` by absolute path
|
|
8
|
+
// (NEVER copied into node_modules — see vendored-grammars.ts / #2111). Load it
|
|
9
|
+
// via a guarded call rather than a top-level `import C from 'tree-sitter-c'`,
|
|
10
|
+
// which would throw ERR_MODULE_NOT_FOUND at module-load and crash analyze
|
|
11
|
+
// (#2091/#2093). It may be absent on a platform without a prebuild; when the
|
|
11
12
|
// binding is absent, `getLanguageForFile` returns null for `.c`/`.h` so C
|
|
12
13
|
// include-extraction is skipped (C++ is unaffected — its binding always ships).
|
|
13
|
-
const _require = createRequire(import.meta.url);
|
|
14
14
|
let C = null;
|
|
15
15
|
try {
|
|
16
|
-
C =
|
|
16
|
+
C = requireVendoredGrammar('tree-sitter-c');
|
|
17
17
|
}
|
|
18
18
|
catch {
|
|
19
19
|
/* C grammar unavailable — C include extraction degrades to a no-op. */
|
|
@@ -27,7 +27,7 @@ import { logger } from '../../logger.js';
|
|
|
27
27
|
/**
|
|
28
28
|
* Cross-repo C/C++ `#include` dependency extractor.
|
|
29
29
|
*
|
|
30
|
-
* **Provider side:** registers every `.h/.hpp/.hxx/.hh` file in the repo
|
|
30
|
+
* **Provider side:** registers every `.h/.hpp/.hxx/.hh/.cuh` file in the repo
|
|
31
31
|
* as a provider contract with `include::<relative-path>`.
|
|
32
32
|
*
|
|
33
33
|
* **Consumer side:** parses all C/C++ source/header files for `#include "…"`
|
|
@@ -40,12 +40,19 @@ import { logger } from '../../logger.js';
|
|
|
40
40
|
* exact contract-id equality in `runExactMatch`.
|
|
41
41
|
*/
|
|
42
42
|
// ---------- constants ----------
|
|
43
|
-
const HEADER_EXTENSIONS = new Set(['.h', '.hpp', '.hxx', '.hh']);
|
|
44
|
-
// Source = headers (provider-eligible) ∪ implementation files (.c/.cpp/.cc/.cxx).
|
|
43
|
+
const HEADER_EXTENSIONS = new Set(['.h', '.hpp', '.hxx', '.hh', '.cuh']);
|
|
44
|
+
// Source = headers (provider-eligible) ∪ implementation files (.c/.cpp/.cc/.cxx/.cu).
|
|
45
45
|
// Spread keeps the subset relationship explicit so a future contributor adding
|
|
46
46
|
// a new header extension to HEADER_EXTENSIONS does not have to remember to
|
|
47
47
|
// also add it here.
|
|
48
|
-
const SOURCE_EXTENSIONS = new Set([
|
|
48
|
+
const SOURCE_EXTENSIONS = new Set([
|
|
49
|
+
...HEADER_EXTENSIONS,
|
|
50
|
+
'.c',
|
|
51
|
+
'.cpp',
|
|
52
|
+
'.cc',
|
|
53
|
+
'.cxx',
|
|
54
|
+
'.cu',
|
|
55
|
+
]);
|
|
49
56
|
const INCLUDE_QUERY_SRC = '(preproc_include path: (_) @import.source) @import';
|
|
50
57
|
/**
|
|
51
58
|
* Well-known C/C++ standard library headers that can appear in `#include "…"`
|
|
@@ -259,6 +266,8 @@ function getLanguageForFile(filePath) {
|
|
|
259
266
|
case '.hpp':
|
|
260
267
|
case '.hxx':
|
|
261
268
|
case '.hh':
|
|
269
|
+
case '.cu':
|
|
270
|
+
case '.cuh':
|
|
262
271
|
return Cpp;
|
|
263
272
|
default:
|
|
264
273
|
return null;
|
|
@@ -281,7 +290,7 @@ function getLanguageForFile(filePath) {
|
|
|
281
290
|
function isLocalInclude(cleaned, suffixIndex) {
|
|
282
291
|
const candidates = [cleaned];
|
|
283
292
|
if (!/\.[a-zA-Z0-9]+$/.test(cleaned)) {
|
|
284
|
-
for (const ext of
|
|
293
|
+
for (const ext of HEADER_EXTENSIONS)
|
|
285
294
|
candidates.push(cleaned + ext);
|
|
286
295
|
}
|
|
287
296
|
for (const c of candidates) {
|
|
@@ -386,7 +395,7 @@ export class IncludeExtractor {
|
|
|
386
395
|
async extractProvidersGraph(db, repoPath) {
|
|
387
396
|
try {
|
|
388
397
|
const rows = await db(`MATCH (f:File)
|
|
389
|
-
WHERE f.filePath =~ '.*\\\\.(h|hpp|hxx|hh)$'
|
|
398
|
+
WHERE f.filePath =~ '.*\\\\.(h|hpp|hxx|hh|cuh)$'
|
|
390
399
|
RETURN f.filePath AS filePath, f.id AS fileId`);
|
|
391
400
|
// gitnexus analyze stores absolute paths in the File.filePath column.
|
|
392
401
|
// Provider contract IDs MUST be repo-relative — otherwise the consumer
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RegistryEntry } from '../../storage/repo-manager.js';
|
|
2
|
-
import type { GroupConfig, RepoHandle, RepoSnapshot, StoredContract, CrossLink } from './types.js';
|
|
2
|
+
import type { GroupConfig, RepoHandle, RepoSnapshot, StoredContract, CrossLink, GroupManifestLink } from './types.js';
|
|
3
3
|
export interface SyncOptions {
|
|
4
4
|
extractorOverride?: ((repo: RepoHandle) => Promise<StoredContract[]>) | (() => Promise<StoredContract[]>);
|
|
5
5
|
resolveRepoHandle?: (registryName: string, groupPath: string) => Promise<RepoHandle | null>;
|
|
@@ -18,4 +18,30 @@ export interface SyncResult {
|
|
|
18
18
|
repoSnapshots: Record<string, RepoSnapshot>;
|
|
19
19
|
}
|
|
20
20
|
export declare function stableRepoPoolId(entry: RegistryEntry, allEntries: RegistryEntry[]): string;
|
|
21
|
+
/** A batch of manifest links whose referenced in-group repos fit one resident window. */
|
|
22
|
+
export interface ManifestWindow {
|
|
23
|
+
links: GroupManifestLink[];
|
|
24
|
+
/** In-group repos (group paths) this window's links reference; size ≤ maxResident. */
|
|
25
|
+
repos: Set<string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Partition manifest links into windows so each window references at most
|
|
29
|
+
* `maxResident` distinct in-group repos. Manifest resolution then materializes
|
|
30
|
+
* only one window's repos at a time, bounding peak pool residency regardless of
|
|
31
|
+
* group size (PR #2191 review, Finding 3 — windowed deferred resolution).
|
|
32
|
+
*
|
|
33
|
+
* Each link references ≤2 in-group repos, so every link fits a window when
|
|
34
|
+
* `maxResident ≥ 2`. Links are pre-sorted by their referenced-repo key so links
|
|
35
|
+
* sharing a repo land in contiguous windows — combined with release-not-close
|
|
36
|
+
* pooling, a hub repo stays warm across the windows that reference it (its
|
|
37
|
+
* lease is released, not closed, so the next window's initLbug fast-paths it).
|
|
38
|
+
* Every link lands in EXACTLY one window (a true partition): downstream
|
|
39
|
+
* dedupeCrossLinks dedupes cross-links but not contracts, so a link in two
|
|
40
|
+
* windows would emit duplicate contracts nothing absorbs.
|
|
41
|
+
*
|
|
42
|
+
* Repos not in `knownRepos` (dangling / unresolved) add 0 to a window's repo
|
|
43
|
+
* budget — the link is still placed (so it yields synthetic-UID contracts), it
|
|
44
|
+
* just consumes no residency.
|
|
45
|
+
*/
|
|
46
|
+
export declare function partitionManifestWindows(links: GroupManifestLink[], knownRepos: Set<string>, maxResident: number): ManifestWindow[];
|
|
21
47
|
export declare function syncGroup(config: GroupConfig, opts?: SyncOptions): Promise<SyncResult>;
|
package/dist/core/group/sync.js
CHANGED
|
Binary file
|
|
@@ -49,6 +49,21 @@
|
|
|
49
49
|
*/
|
|
50
50
|
import { createKnowledgeGraph } from '../graph/graph.js';
|
|
51
51
|
const isGraphWide = (label) => label === 'Community' || label === 'Process';
|
|
52
|
+
/**
|
|
53
|
+
* Relationship types whose VALIDITY is a whole-program property, not a
|
|
54
|
+
* function of their endpoints' files (#2084 M4 U6). `TAINT_PATH` (cross-
|
|
55
|
+
* function taint) can be invalidated by a change to an INTERMEDIATE function
|
|
56
|
+
* on a third file, so the endpoint-writability rule below would skip a stale
|
|
57
|
+
* A→C edge. These are always extracted (and the orchestrator delete-alls them
|
|
58
|
+
* first, like Community/Process) so they rebuild from the fresh graph.
|
|
59
|
+
*/
|
|
60
|
+
// `CALL_SUMMARY` (PDG FU-C) is intra-procedural (a callee's RETURN-VALUE ASCENT
|
|
61
|
+
// depends only on its OWN body), but the orchestrator delete-alls it on an
|
|
62
|
+
// incremental `--pdg` writeback to keep the emit path single — so it must be
|
|
63
|
+
// re-included from the FULL fresh graph (which the emit phase recomputes every
|
|
64
|
+
// run) or an unchanged function's summary would be lost. Cheap: one self-loop
|
|
65
|
+
// edge per return-flowing function.
|
|
66
|
+
const isGraphWideRelType = (type) => type === 'TAINT_PATH' || type === 'CALL_SUMMARY';
|
|
52
67
|
/**
|
|
53
68
|
* Build a Map<nodeId, filePath> for every File-bound node in the graph.
|
|
54
69
|
* Graph-wide nodes (Community/Process) have no filePath and are filtered.
|
|
@@ -74,7 +89,9 @@ export const extractChangedSubgraph = (fullGraph, toWriteSet) => {
|
|
|
74
89
|
}
|
|
75
90
|
});
|
|
76
91
|
fullGraph.forEachRelationship((r) => {
|
|
77
|
-
if (writableNodeIds.has(r.sourceId) ||
|
|
92
|
+
if (writableNodeIds.has(r.sourceId) ||
|
|
93
|
+
writableNodeIds.has(r.targetId) ||
|
|
94
|
+
isGraphWideRelType(r.type)) {
|
|
78
95
|
sub.addRelationship(r);
|
|
79
96
|
}
|
|
80
97
|
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CfgBuilder (issue #2081, M1) — the language-agnostic accumulator.
|
|
3
|
+
*
|
|
4
|
+
* A per-language `CfgVisitor` drives this: it creates blocks as it walks
|
|
5
|
+
* statements, wires edges (including back-edges and break/continue/return/throw
|
|
6
|
+
* targets resolved via {@link ControlFlowContext}), and calls {@link finish} to
|
|
7
|
+
* produce the serializable {@link FunctionCfg}. The builder owns the synthetic
|
|
8
|
+
* ENTRY (index 0) and EXIT blocks and de-duplicates identical edges so repeated
|
|
9
|
+
* `connect` calls (common when wiring a set of dangling exits) stay idempotent.
|
|
10
|
+
*
|
|
11
|
+
* It has no knowledge of any AST — it is exercised directly in unit tests with
|
|
12
|
+
* hand-built block sequences, which is how the classic CFG hazards are pinned
|
|
13
|
+
* before the tree-sitter visitor (U2) drives it.
|
|
14
|
+
*/
|
|
15
|
+
import type { BasicBlockData, BindingEntry, CfgEdgeKind, FunctionCfg, StatementFacts } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Hard ceiling on CFG recursive-descent scope-entry depth (#2195). A language
|
|
18
|
+
* `CfgVisitor` wraps each nested block scope in {@link CfgBuilder.withNesting} (its
|
|
19
|
+
* `visitBody` / `visitSeq` choke points), so the live count tracks scope entries,
|
|
20
|
+
* not statement width. NOTE the count is ~2× LEXICAL nesting for block-bodied
|
|
21
|
+
* constructs (visitBody → visitSeq both enter), so the effective lexical ceiling
|
|
22
|
+
* is ~250 levels for block bodies (~500 for single-statement bodies / bare
|
|
23
|
+
* blocks). Real source nests ≤ ~50 deep, so this fires only on machine-generated
|
|
24
|
+
* / adversarial input. Both effective ceilings sit far below the engine's native
|
|
25
|
+
* stack limit (~1.2k+ nesting even on the raised worker `stackSizeMb`), so the
|
|
26
|
+
* bail is a DETERMINISTIC, language-independent {@link CfgNestingDepthError}
|
|
27
|
+
* rather than a nondeterministic `RangeError` thrown somewhere mid-walk.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MAX_CFG_NESTING_DEPTH = 500;
|
|
30
|
+
/**
|
|
31
|
+
* Thrown by the visitor nesting-depth guard ({@link CfgBuilder.enterNesting})
|
|
32
|
+
* when lexical nesting exceeds {@link MAX_CFG_NESTING_DEPTH}. `collectFunctionCfgs`
|
|
33
|
+
* catches it and counts the function under `skipped.tooDeeplyNested`, isolating
|
|
34
|
+
* the bail to one function instead of risking a worker-wide stack overflow.
|
|
35
|
+
*/
|
|
36
|
+
export declare class CfgNestingDepthError extends Error {
|
|
37
|
+
readonly limit: number;
|
|
38
|
+
constructor(limit: number);
|
|
39
|
+
}
|
|
40
|
+
export declare class CfgBuilder {
|
|
41
|
+
private readonly filePath;
|
|
42
|
+
private readonly functionStartLine;
|
|
43
|
+
private readonly functionEndLine;
|
|
44
|
+
/** Start column of the owning function — disambiguates same-line functions
|
|
45
|
+
* in the BasicBlock ids (see {@link FunctionCfg.functionStartColumn}).
|
|
46
|
+
* Defaults to 0 for hand-built test CFGs that don't model columns. */
|
|
47
|
+
private readonly functionStartColumn;
|
|
48
|
+
private readonly blocks;
|
|
49
|
+
private readonly edges;
|
|
50
|
+
private readonly edgeKeys;
|
|
51
|
+
/** Live recursive-descent nesting depth — see {@link enterNesting}. */
|
|
52
|
+
private nesting;
|
|
53
|
+
readonly entryIndex: number;
|
|
54
|
+
readonly exitIndex: number;
|
|
55
|
+
constructor(filePath: string, functionStartLine: number, functionEndLine: number,
|
|
56
|
+
/** Start column of the owning function — disambiguates same-line functions
|
|
57
|
+
* in the BasicBlock ids (see {@link FunctionCfg.functionStartColumn}).
|
|
58
|
+
* Defaults to 0 for hand-built test CFGs that don't model columns. */
|
|
59
|
+
functionStartColumn?: number);
|
|
60
|
+
/** Create a block and return its index. */
|
|
61
|
+
newBlock(startLine: number, endLine: number, text: string, kind?: BasicBlockData['kind'], facts?: StatementFacts): number;
|
|
62
|
+
/** Add a single edge (idempotent on from+to+kind). */
|
|
63
|
+
edge(from: number, to: number, kind: CfgEdgeKind): void;
|
|
64
|
+
/** Wire a set of dangling exits to a single target block with one kind. */
|
|
65
|
+
connect(exits: readonly number[], to: number, kind?: CfgEdgeKind): void;
|
|
66
|
+
/** Extend a block's end line as more statements accrue to it. */
|
|
67
|
+
extendBlock(index: number, endLine: number, appendText?: string, facts?: StatementFacts): void;
|
|
68
|
+
/**
|
|
69
|
+
* Attach a facts-only statement record to a block WITHOUT touching its text
|
|
70
|
+
* or line span (#2082 M2 U1) — bench fingerprints and CFG snapshots include
|
|
71
|
+
* block text, so harvesting must never perturb it (ENTRY-block param defs
|
|
72
|
+
* are the canonical use; records that must precede a walked body get their
|
|
73
|
+
* own facts-only block instead, see the catch-param handling in visitTry).
|
|
74
|
+
*/
|
|
75
|
+
attachFacts(index: number, facts: StatementFacts): void;
|
|
76
|
+
get blockCount(): number;
|
|
77
|
+
/**
|
|
78
|
+
* Run `fn` inside ONE nested block scope (#2195) — the single choke every
|
|
79
|
+
* visitor's `visitBody` / `visitSeq` funnels through. Enters on the way in and
|
|
80
|
+
* exits in a `finally`, so the live depth is balanced on every return AND every
|
|
81
|
+
* throw and the enter/exit can never drift out of pair (the reason this is one
|
|
82
|
+
* helper, not 24 hand-paired call sites). Throws {@link CfgNestingDepthError}
|
|
83
|
+
* when nesting exceeds {@link MAX_CFG_NESTING_DEPTH} — a proactive, deterministic
|
|
84
|
+
* bail before the native stack can overflow on a pathologically nested function.
|
|
85
|
+
*
|
|
86
|
+
* A block-bodied construct passes through BOTH visitBody and visitSeq, so it
|
|
87
|
+
* costs TWO scopes per lexical level: the effective structural ceiling is
|
|
88
|
+
* ~MAX_CFG_NESTING_DEPTH/2 (~250) lexical levels for block bodies (~500 for
|
|
89
|
+
* single-statement bodies / bare blocks, which hit only one of the two). Still
|
|
90
|
+
* an order of magnitude below the native limit and far above real code (≤ ~50).
|
|
91
|
+
*/
|
|
92
|
+
withNesting<T>(fn: () => T): T;
|
|
93
|
+
/**
|
|
94
|
+
* Increment the nesting counter, throwing {@link CfgNestingDepthError} past the
|
|
95
|
+
* cap. Prefer {@link withNesting}, which pairs the exit in a `finally`; this is
|
|
96
|
+
* exposed for direct depth-accounting tests only.
|
|
97
|
+
*/
|
|
98
|
+
enterNesting(): void;
|
|
99
|
+
/** Decrement the nesting counter — the partner of {@link enterNesting}. */
|
|
100
|
+
exitNesting(): void;
|
|
101
|
+
/** Produce the serializable CFG. Caller is responsible for having wired the
|
|
102
|
+
* function's dangling exits to {@link exitIndex} before calling.
|
|
103
|
+
*
|
|
104
|
+
* Pass `bindings` (the function's binding table, possibly empty) to emit
|
|
105
|
+
* statement facts (#2082 M2 U1) — every block then carries a `statements`
|
|
106
|
+
* array. Omit it (hand-built test CFGs, pre-M2 producers) and both fields
|
|
107
|
+
* are absent, which the reaching-defs solver reports as `no-facts`. */
|
|
108
|
+
finish(bindings?: readonly BindingEntry[]): FunctionCfg;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Block indices reachable from `entryIndex` by following edges. Backs the
|
|
112
|
+
* reachability property tests (R9) over hand-built and visitor-produced CFGs.
|
|
113
|
+
*/
|
|
114
|
+
export declare const reachableBlocks: (cfg: FunctionCfg) => Set<number>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hard ceiling on CFG recursive-descent scope-entry depth (#2195). A language
|
|
3
|
+
* `CfgVisitor` wraps each nested block scope in {@link CfgBuilder.withNesting} (its
|
|
4
|
+
* `visitBody` / `visitSeq` choke points), so the live count tracks scope entries,
|
|
5
|
+
* not statement width. NOTE the count is ~2× LEXICAL nesting for block-bodied
|
|
6
|
+
* constructs (visitBody → visitSeq both enter), so the effective lexical ceiling
|
|
7
|
+
* is ~250 levels for block bodies (~500 for single-statement bodies / bare
|
|
8
|
+
* blocks). Real source nests ≤ ~50 deep, so this fires only on machine-generated
|
|
9
|
+
* / adversarial input. Both effective ceilings sit far below the engine's native
|
|
10
|
+
* stack limit (~1.2k+ nesting even on the raised worker `stackSizeMb`), so the
|
|
11
|
+
* bail is a DETERMINISTIC, language-independent {@link CfgNestingDepthError}
|
|
12
|
+
* rather than a nondeterministic `RangeError` thrown somewhere mid-walk.
|
|
13
|
+
*/
|
|
14
|
+
export const MAX_CFG_NESTING_DEPTH = 500;
|
|
15
|
+
/**
|
|
16
|
+
* Thrown by the visitor nesting-depth guard ({@link CfgBuilder.enterNesting})
|
|
17
|
+
* when lexical nesting exceeds {@link MAX_CFG_NESTING_DEPTH}. `collectFunctionCfgs`
|
|
18
|
+
* catches it and counts the function under `skipped.tooDeeplyNested`, isolating
|
|
19
|
+
* the bail to one function instead of risking a worker-wide stack overflow.
|
|
20
|
+
*/
|
|
21
|
+
export class CfgNestingDepthError extends Error {
|
|
22
|
+
limit;
|
|
23
|
+
constructor(limit) {
|
|
24
|
+
super(`CFG nesting depth exceeded ${limit}`);
|
|
25
|
+
this.limit = limit;
|
|
26
|
+
this.name = 'CfgNestingDepthError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class CfgBuilder {
|
|
30
|
+
filePath;
|
|
31
|
+
functionStartLine;
|
|
32
|
+
functionEndLine;
|
|
33
|
+
functionStartColumn;
|
|
34
|
+
blocks = [];
|
|
35
|
+
edges = [];
|
|
36
|
+
edgeKeys = new Set();
|
|
37
|
+
/** Live recursive-descent nesting depth — see {@link enterNesting}. */
|
|
38
|
+
nesting = 0;
|
|
39
|
+
entryIndex;
|
|
40
|
+
exitIndex;
|
|
41
|
+
constructor(filePath, functionStartLine, functionEndLine,
|
|
42
|
+
/** Start column of the owning function — disambiguates same-line functions
|
|
43
|
+
* in the BasicBlock ids (see {@link FunctionCfg.functionStartColumn}).
|
|
44
|
+
* Defaults to 0 for hand-built test CFGs that don't model columns. */
|
|
45
|
+
functionStartColumn = 0) {
|
|
46
|
+
this.filePath = filePath;
|
|
47
|
+
this.functionStartLine = functionStartLine;
|
|
48
|
+
this.functionEndLine = functionEndLine;
|
|
49
|
+
this.functionStartColumn = functionStartColumn;
|
|
50
|
+
this.entryIndex = this.newBlock(functionStartLine, functionStartLine, '', 'entry');
|
|
51
|
+
this.exitIndex = this.newBlock(functionEndLine, functionEndLine, '', 'exit');
|
|
52
|
+
}
|
|
53
|
+
/** Create a block and return its index. */
|
|
54
|
+
newBlock(startLine, endLine, text, kind = 'normal', facts) {
|
|
55
|
+
this.blocks.push({
|
|
56
|
+
startLine,
|
|
57
|
+
endLine,
|
|
58
|
+
textParts: text ? [text] : [],
|
|
59
|
+
kind,
|
|
60
|
+
statements: facts ? [facts] : [],
|
|
61
|
+
});
|
|
62
|
+
return this.blocks.length - 1;
|
|
63
|
+
}
|
|
64
|
+
/** Add a single edge (idempotent on from+to+kind). */
|
|
65
|
+
edge(from, to, kind) {
|
|
66
|
+
const key = `${from}->${to}:${kind}`;
|
|
67
|
+
if (this.edgeKeys.has(key))
|
|
68
|
+
return;
|
|
69
|
+
this.edgeKeys.add(key);
|
|
70
|
+
this.edges.push({ from, to, kind });
|
|
71
|
+
}
|
|
72
|
+
/** Wire a set of dangling exits to a single target block with one kind. */
|
|
73
|
+
connect(exits, to, kind = 'seq') {
|
|
74
|
+
for (const from of exits)
|
|
75
|
+
this.edge(from, to, kind);
|
|
76
|
+
}
|
|
77
|
+
/** Extend a block's end line as more statements accrue to it. */
|
|
78
|
+
extendBlock(index, endLine, appendText, facts) {
|
|
79
|
+
const b = this.blocks[index];
|
|
80
|
+
if (!b)
|
|
81
|
+
return;
|
|
82
|
+
if (endLine > b.endLine)
|
|
83
|
+
b.endLine = endLine;
|
|
84
|
+
if (appendText)
|
|
85
|
+
b.textParts.push(appendText);
|
|
86
|
+
if (facts)
|
|
87
|
+
b.statements.push(facts);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Attach a facts-only statement record to a block WITHOUT touching its text
|
|
91
|
+
* or line span (#2082 M2 U1) — bench fingerprints and CFG snapshots include
|
|
92
|
+
* block text, so harvesting must never perturb it (ENTRY-block param defs
|
|
93
|
+
* are the canonical use; records that must precede a walked body get their
|
|
94
|
+
* own facts-only block instead, see the catch-param handling in visitTry).
|
|
95
|
+
*/
|
|
96
|
+
attachFacts(index, facts) {
|
|
97
|
+
const b = this.blocks[index];
|
|
98
|
+
if (!b)
|
|
99
|
+
return;
|
|
100
|
+
b.statements.push(facts);
|
|
101
|
+
}
|
|
102
|
+
get blockCount() {
|
|
103
|
+
return this.blocks.length;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Run `fn` inside ONE nested block scope (#2195) — the single choke every
|
|
107
|
+
* visitor's `visitBody` / `visitSeq` funnels through. Enters on the way in and
|
|
108
|
+
* exits in a `finally`, so the live depth is balanced on every return AND every
|
|
109
|
+
* throw and the enter/exit can never drift out of pair (the reason this is one
|
|
110
|
+
* helper, not 24 hand-paired call sites). Throws {@link CfgNestingDepthError}
|
|
111
|
+
* when nesting exceeds {@link MAX_CFG_NESTING_DEPTH} — a proactive, deterministic
|
|
112
|
+
* bail before the native stack can overflow on a pathologically nested function.
|
|
113
|
+
*
|
|
114
|
+
* A block-bodied construct passes through BOTH visitBody and visitSeq, so it
|
|
115
|
+
* costs TWO scopes per lexical level: the effective structural ceiling is
|
|
116
|
+
* ~MAX_CFG_NESTING_DEPTH/2 (~250) lexical levels for block bodies (~500 for
|
|
117
|
+
* single-statement bodies / bare blocks, which hit only one of the two). Still
|
|
118
|
+
* an order of magnitude below the native limit and far above real code (≤ ~50).
|
|
119
|
+
*/
|
|
120
|
+
withNesting(fn) {
|
|
121
|
+
this.enterNesting();
|
|
122
|
+
try {
|
|
123
|
+
return fn();
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
this.exitNesting();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Increment the nesting counter, throwing {@link CfgNestingDepthError} past the
|
|
131
|
+
* cap. Prefer {@link withNesting}, which pairs the exit in a `finally`; this is
|
|
132
|
+
* exposed for direct depth-accounting tests only.
|
|
133
|
+
*/
|
|
134
|
+
enterNesting() {
|
|
135
|
+
if (++this.nesting > MAX_CFG_NESTING_DEPTH)
|
|
136
|
+
throw new CfgNestingDepthError(MAX_CFG_NESTING_DEPTH);
|
|
137
|
+
}
|
|
138
|
+
/** Decrement the nesting counter — the partner of {@link enterNesting}. */
|
|
139
|
+
exitNesting() {
|
|
140
|
+
this.nesting--;
|
|
141
|
+
}
|
|
142
|
+
/** Produce the serializable CFG. Caller is responsible for having wired the
|
|
143
|
+
* function's dangling exits to {@link exitIndex} before calling.
|
|
144
|
+
*
|
|
145
|
+
* Pass `bindings` (the function's binding table, possibly empty) to emit
|
|
146
|
+
* statement facts (#2082 M2 U1) — every block then carries a `statements`
|
|
147
|
+
* array. Omit it (hand-built test CFGs, pre-M2 producers) and both fields
|
|
148
|
+
* are absent, which the reaching-defs solver reports as `no-facts`. */
|
|
149
|
+
finish(bindings) {
|
|
150
|
+
const withFacts = bindings !== undefined;
|
|
151
|
+
return {
|
|
152
|
+
filePath: this.filePath,
|
|
153
|
+
functionStartLine: this.functionStartLine,
|
|
154
|
+
functionEndLine: this.functionEndLine,
|
|
155
|
+
functionStartColumn: this.functionStartColumn,
|
|
156
|
+
entryIndex: this.entryIndex,
|
|
157
|
+
exitIndex: this.exitIndex,
|
|
158
|
+
blocks: this.blocks.map((b, index) => ({
|
|
159
|
+
index,
|
|
160
|
+
startLine: b.startLine,
|
|
161
|
+
endLine: b.endLine,
|
|
162
|
+
text: b.textParts.join('\n'),
|
|
163
|
+
kind: b.kind,
|
|
164
|
+
...(withFacts ? { statements: b.statements } : {}),
|
|
165
|
+
})),
|
|
166
|
+
edges: [...this.edges],
|
|
167
|
+
...(withFacts ? { bindings } : {}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Block indices reachable from `entryIndex` by following edges. Backs the
|
|
173
|
+
* reachability property tests (R9) over hand-built and visitor-produced CFGs.
|
|
174
|
+
*/
|
|
175
|
+
export const reachableBlocks = (cfg) => {
|
|
176
|
+
const adj = new Map();
|
|
177
|
+
for (const e of cfg.edges) {
|
|
178
|
+
const list = adj.get(e.from);
|
|
179
|
+
if (list)
|
|
180
|
+
list.push(e.to);
|
|
181
|
+
else
|
|
182
|
+
adj.set(e.from, [e.to]);
|
|
183
|
+
}
|
|
184
|
+
const seen = new Set([cfg.entryIndex]);
|
|
185
|
+
const stack = [cfg.entryIndex];
|
|
186
|
+
while (stack.length) {
|
|
187
|
+
const n = stack.pop();
|
|
188
|
+
for (const next of adj.get(n) ?? []) {
|
|
189
|
+
if (!seen.has(next)) {
|
|
190
|
+
seen.add(next);
|
|
191
|
+
stack.push(next);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return seen;
|
|
196
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collectFunctionCfgs (issue #2081, M1).
|
|
3
|
+
*
|
|
4
|
+
* Walks a parsed file's tree-sitter tree and builds one {@link FunctionCfg} per
|
|
5
|
+
* CFG-bearing function via the language's {@link CfgVisitor}. Runs IN THE PARSE
|
|
6
|
+
* WORKER (where the AST lives — KTD1/KTD7); the result rides on
|
|
7
|
+
* `ParsedFile.cfgSideChannel` across the worker→main boundary.
|
|
8
|
+
*
|
|
9
|
+
* Nested functions are enumerated independently — each gets its own CFG, and
|
|
10
|
+
* appears as an opaque straight-line block in its enclosing function's CFG (the
|
|
11
|
+
* visitor does not descend into nested function bodies). `maxFunctionLines`
|
|
12
|
+
* bounds per-function cost: a function whose source span exceeds the cap is
|
|
13
|
+
* skipped (and counted) rather than walked, so a pathological mega-function
|
|
14
|
+
* cannot blow up worker time/memory. A cap of `0` means no limit.
|
|
15
|
+
*/
|
|
16
|
+
import type { SyntaxNode } from '../utils/ast-helpers.js';
|
|
17
|
+
import type { CfgVisitor, FunctionCfg } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Default per-function source-line cap used by the worker when the `--pdg` run
|
|
20
|
+
* does not specify `pdgMaxFunctionLines`. A function longer than this (almost
|
|
21
|
+
* always minified/generated code) is skipped rather than walked — its CFG is
|
|
22
|
+
* both expensive and low-value. Overridable via `PipelineOptions.pdgMaxFunctionLines`.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_PDG_MAX_FUNCTION_LINES = 2000;
|
|
25
|
+
/**
|
|
26
|
+
* CFG-bearing functions skipped during the walk, bucketed by reason (#2195).
|
|
27
|
+
* Surfaced per-language in the parse telemetry (parsing-processor.ts) so a CFG
|
|
28
|
+
* coverage gap is observable, not silent. All-zero ⇒ nothing skipped.
|
|
29
|
+
*/
|
|
30
|
+
export interface CfgSkipCounts {
|
|
31
|
+
/** Source span exceeded `maxFunctionLines` (minified / generated code). */
|
|
32
|
+
readonly tooManyLines: number;
|
|
33
|
+
/**
|
|
34
|
+
* Recursive-descent nesting hit {@link MAX_CFG_NESTING_DEPTH} — a proactive,
|
|
35
|
+
* deterministic bail (see {@link CfgNestingDepthError}) before a worker stack
|
|
36
|
+
* overflow.
|
|
37
|
+
*/
|
|
38
|
+
readonly tooDeeplyNested: number;
|
|
39
|
+
/**
|
|
40
|
+
* `buildFunctionCfg` threw an unexpected error. Caught PER FUNCTION so one
|
|
41
|
+
* malformed function no longer drops the whole file's CFGs (the throw used to
|
|
42
|
+
* escape to the worker's language-group catch).
|
|
43
|
+
*/
|
|
44
|
+
readonly buildError: number;
|
|
45
|
+
}
|
|
46
|
+
export interface CollectedCfgs {
|
|
47
|
+
readonly cfgs: readonly FunctionCfg[];
|
|
48
|
+
/** Per-reason skip counts (#2195). */
|
|
49
|
+
readonly skipped: CfgSkipCounts;
|
|
50
|
+
}
|
|
51
|
+
export declare function collectFunctionCfgs(root: SyntaxNode, visitor: CfgVisitor<SyntaxNode>, filePath: string, maxFunctionLines?: number, lineOffset?: number): CollectedCfgs;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { CfgNestingDepthError } from './cfg-builder.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default per-function source-line cap used by the worker when the `--pdg` run
|
|
4
|
+
* does not specify `pdgMaxFunctionLines`. A function longer than this (almost
|
|
5
|
+
* always minified/generated code) is skipped rather than walked — its CFG is
|
|
6
|
+
* both expensive and low-value. Overridable via `PipelineOptions.pdgMaxFunctionLines`.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_PDG_MAX_FUNCTION_LINES = 2000;
|
|
9
|
+
/**
|
|
10
|
+
* Convert a CFG built from an EXTRACTED sub-document's AST (script-relative
|
|
11
|
+
* tree-sitter rows) into the enclosing file's coordinates by adding `offset` to
|
|
12
|
+
* every source-line field. Needed for embedded scripts — a Vue SFC `<script>`
|
|
13
|
+
* block parses at row 0 but lives at `lineOffset` in the `.vue` file, and every
|
|
14
|
+
* other worker-emitted graph node is already file-relative; without this, the
|
|
15
|
+
* CFG's `functionStartLine` would never join its Function/Method graph node
|
|
16
|
+
* (inter-procedural taint silently resolves nothing) and BasicBlock source
|
|
17
|
+
* lines would point at the wrong `.vue` line. A 0 offset returns the input
|
|
18
|
+
* unchanged (the common case: `.ts`/`.js`/etc. parse at the file root), keeping
|
|
19
|
+
* non-embedded languages byte-identical. Synthetic bindings keep `declLine` 0.
|
|
20
|
+
*/
|
|
21
|
+
function shiftCfgLines(cfg, offset) {
|
|
22
|
+
if (offset === 0)
|
|
23
|
+
return cfg;
|
|
24
|
+
return {
|
|
25
|
+
...cfg,
|
|
26
|
+
functionStartLine: cfg.functionStartLine + offset,
|
|
27
|
+
functionEndLine: cfg.functionEndLine + offset,
|
|
28
|
+
blocks: cfg.blocks.map((b) => ({
|
|
29
|
+
...b,
|
|
30
|
+
startLine: b.startLine + offset,
|
|
31
|
+
endLine: b.endLine + offset,
|
|
32
|
+
statements: b.statements?.map((s) => ({ ...s, line: s.line + offset })),
|
|
33
|
+
})),
|
|
34
|
+
bindings: cfg.bindings?.map((bd) => bd.declLine > 0 ? { ...bd, declLine: bd.declLine + offset } : bd),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function collectFunctionCfgs(root, visitor, filePath, maxFunctionLines = 0, lineOffset = 0) {
|
|
38
|
+
const cfgs = [];
|
|
39
|
+
let tooManyLines = 0;
|
|
40
|
+
let tooDeeplyNested = 0;
|
|
41
|
+
let buildError = 0;
|
|
42
|
+
const stack = [root];
|
|
43
|
+
while (stack.length) {
|
|
44
|
+
const node = stack.pop();
|
|
45
|
+
if (visitor.isFunction(node)) {
|
|
46
|
+
const lines = node.endPosition.row - node.startPosition.row + 1;
|
|
47
|
+
if (maxFunctionLines > 0 && lines > maxFunctionLines) {
|
|
48
|
+
tooManyLines++;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Isolate the per-function build: a proactive deep-nesting bail
|
|
52
|
+
// (CfgNestingDepthError) or any other visitor throw is counted and
|
|
53
|
+
// skipped HERE, so it can't escape to the worker's language-group catch
|
|
54
|
+
// and silently drop every remaining function's CFG (#2195).
|
|
55
|
+
try {
|
|
56
|
+
const cfg = visitor.buildFunctionCfg(node, filePath);
|
|
57
|
+
if (cfg)
|
|
58
|
+
cfgs.push(shiftCfgLines(cfg, lineOffset));
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
if (err instanceof CfgNestingDepthError)
|
|
62
|
+
tooDeeplyNested++;
|
|
63
|
+
else
|
|
64
|
+
buildError++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Descend regardless (a skipped mega-function may still contain small
|
|
69
|
+
// nested functions that are worth a CFG of their own).
|
|
70
|
+
for (let i = node.namedChildCount - 1; i >= 0; i--) {
|
|
71
|
+
const child = node.namedChild(i);
|
|
72
|
+
if (child)
|
|
73
|
+
stack.push(child);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { cfgs, skipped: { tooManyLines, tooDeeplyNested, buildError } };
|
|
77
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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 { type PostDomTree } from './post-dominators.js';
|
|
33
|
+
import type { FunctionCfg } from './types.js';
|
|
34
|
+
export type CdgLabel = 'T' | 'F';
|
|
35
|
+
export interface ControlDepEdge {
|
|
36
|
+
/** The branch block whose outcome controls `dependentBlock`. */
|
|
37
|
+
readonly controllerBlock: number;
|
|
38
|
+
/** The block that executes only because `controllerBlock` took `label`. */
|
|
39
|
+
readonly dependentBlock: number;
|
|
40
|
+
/** Branch sense of the controlling CFG edge — see {@link branchSense}. */
|
|
41
|
+
readonly label: CdgLabel;
|
|
42
|
+
}
|
|
43
|
+
export interface ControlDepResult {
|
|
44
|
+
/** Deduped, sorted (controller, dependent, label) control-dependence edges. */
|
|
45
|
+
readonly edges: readonly ControlDepEdge[];
|
|
46
|
+
/**
|
|
47
|
+
* True when the `maxEdges` ceiling was reached; `edges` is then a
|
|
48
|
+
* deterministic prefix (CFG-edge iteration order, sorted), never a silent
|
|
49
|
+
* drop. Mirrors {@link computeReachingDefs}'s `truncated`.
|
|
50
|
+
*/
|
|
51
|
+
readonly truncated: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute control-dependence edges for one function's CFG. `postDom` may be
|
|
55
|
+
* supplied to reuse an already-built tree; otherwise it is computed. See the
|
|
56
|
+
* module doc for the purity/determinism contract.
|
|
57
|
+
*/
|
|
58
|
+
export declare function computeControlDependence(cfg: FunctionCfg, postDom?: PostDomTree, maxEdges?: number): ControlDepResult;
|