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.
Files changed (430) hide show
  1. package/README.md +3 -3
  2. package/dist/_shared/graph/types.d.ts +31 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.d.ts.map +1 -1
  5. package/dist/_shared/language-detection.js +11 -1
  6. package/dist/_shared/language-detection.js.map +1 -1
  7. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  8. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  9. package/dist/_shared/lbug/schema-constants.js +6 -0
  10. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  11. package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
  12. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  13. package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
  14. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  15. package/dist/cli/ai-context.d.ts +31 -1
  16. package/dist/cli/ai-context.js +18 -16
  17. package/dist/cli/analyze-config.js +11 -0
  18. package/dist/cli/analyze.d.ts +14 -0
  19. package/dist/cli/analyze.js +98 -0
  20. package/dist/cli/embedding-dims.d.ts +33 -0
  21. package/dist/cli/embedding-dims.js +39 -0
  22. package/dist/cli/eval-server.d.ts +8 -0
  23. package/dist/cli/eval-server.js +242 -2
  24. package/dist/cli/help-i18n.js +19 -0
  25. package/dist/cli/i18n/en.d.ts +15 -1
  26. package/dist/cli/i18n/en.js +15 -1
  27. package/dist/cli/i18n/resources.d.ts +29 -1
  28. package/dist/cli/i18n/zh-CN.d.ts +14 -0
  29. package/dist/cli/i18n/zh-CN.js +15 -1
  30. package/dist/cli/index.js +89 -1
  31. package/dist/cli/mcp.d.ts +6 -1
  32. package/dist/cli/mcp.js +26 -1
  33. package/dist/cli/optional-grammars.d.ts +6 -8
  34. package/dist/cli/optional-grammars.js +8 -11
  35. package/dist/cli/setup.d.ts +3 -1
  36. package/dist/cli/setup.js +67 -17
  37. package/dist/cli/skill-gen.js +2 -1
  38. package/dist/cli/tool.d.ts +19 -1
  39. package/dist/cli/tool.js +96 -3
  40. package/dist/core/embeddings/hf-env.d.ts +0 -66
  41. package/dist/core/embeddings/http-client.d.ts +7 -0
  42. package/dist/core/embeddings/http-client.js +5 -3
  43. package/dist/core/embeddings/server-mapping.d.ts +1 -1
  44. package/dist/core/embeddings/server-mapping.js +7 -3
  45. package/dist/core/graph/import-cycles.d.ts +10 -0
  46. package/dist/core/graph/import-cycles.js +103 -0
  47. package/dist/core/group/cross-impact.d.ts +2 -1
  48. package/dist/core/group/cross-impact.js +5 -1
  49. package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
  50. package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
  51. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  52. package/dist/core/group/extractors/http-route-extractor.js +22 -4
  53. package/dist/core/group/extractors/include-extractor.js +22 -13
  54. package/dist/core/group/sync.d.ts +27 -1
  55. package/dist/core/group/sync.js +0 -0
  56. package/dist/core/incremental/subgraph-extract.js +18 -1
  57. package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
  58. package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
  59. package/dist/core/ingestion/cfg/collect.d.ts +51 -0
  60. package/dist/core/ingestion/cfg/collect.js +77 -0
  61. package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
  62. package/dist/core/ingestion/cfg/control-dependence.js +182 -0
  63. package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
  64. package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
  65. package/dist/core/ingestion/cfg/emit.d.ts +293 -0
  66. package/dist/core/ingestion/cfg/emit.js +646 -0
  67. package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
  68. package/dist/core/ingestion/cfg/post-dominators.js +176 -0
  69. package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
  70. package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
  71. package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
  72. package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
  73. package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
  74. package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
  75. package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
  76. package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
  77. package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
  78. package/dist/core/ingestion/cfg/traversal-result.js +2 -0
  79. package/dist/core/ingestion/cfg/types.d.ts +274 -0
  80. package/dist/core/ingestion/cfg/types.js +13 -0
  81. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
  82. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
  83. package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
  84. package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
  85. package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
  86. package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
  87. package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
  88. package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
  89. package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
  90. package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
  91. package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
  92. package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
  93. package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
  94. package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
  95. package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
  96. package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
  97. package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
  98. package/dist/core/ingestion/cfg/visitors/go.js +638 -0
  99. package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
  100. package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
  101. package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
  102. package/dist/core/ingestion/cfg/visitors/java.js +812 -0
  103. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
  104. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
  105. package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
  106. package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
  107. package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
  108. package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
  109. package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
  110. package/dist/core/ingestion/cfg/visitors/php.js +721 -0
  111. package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
  112. package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
  113. package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
  114. package/dist/core/ingestion/cfg/visitors/python.js +558 -0
  115. package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
  116. package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
  117. package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
  118. package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
  119. package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
  120. package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
  121. package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
  122. package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
  123. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
  124. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
  125. package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
  126. package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
  127. package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
  128. package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
  129. package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
  130. package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
  131. package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
  132. package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
  133. package/dist/core/ingestion/import-resolvers/utils.js +2 -0
  134. package/dist/core/ingestion/language-provider.d.ts +11 -0
  135. package/dist/core/ingestion/languages/c-cpp.js +6 -1
  136. package/dist/core/ingestion/languages/cobol.js +4 -0
  137. package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
  138. package/dist/core/ingestion/languages/cpp/captures.js +50 -1
  139. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
  140. package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
  141. package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
  142. package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
  143. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
  144. package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
  145. package/dist/core/ingestion/languages/cpp/query.js +23 -0
  146. package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
  147. package/dist/core/ingestion/languages/csharp.js +2 -0
  148. package/dist/core/ingestion/languages/dart.js +2 -0
  149. package/dist/core/ingestion/languages/go.js +2 -0
  150. package/dist/core/ingestion/languages/java.js +3 -0
  151. package/dist/core/ingestion/languages/kotlin/query.js +3 -2
  152. package/dist/core/ingestion/languages/kotlin.js +3 -0
  153. package/dist/core/ingestion/languages/php.js +2 -0
  154. package/dist/core/ingestion/languages/python.js +2 -0
  155. package/dist/core/ingestion/languages/ruby.js +2 -0
  156. package/dist/core/ingestion/languages/rust.js +2 -0
  157. package/dist/core/ingestion/languages/swift.js +2 -0
  158. package/dist/core/ingestion/languages/typescript.js +5 -0
  159. package/dist/core/ingestion/languages/vue.js +6 -0
  160. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
  161. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  162. package/dist/core/ingestion/method-types.d.ts +2 -0
  163. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  164. package/dist/core/ingestion/model/symbol-table.js +1 -0
  165. package/dist/core/ingestion/mro-processor.js +109 -0
  166. package/dist/core/ingestion/parsing-processor.js +23 -0
  167. package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
  168. package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
  169. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  170. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  171. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
  172. package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
  173. package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
  174. package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
  175. package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
  176. package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
  177. package/dist/core/ingestion/pipeline.d.ts +92 -10
  178. package/dist/core/ingestion/pipeline.js +11 -2
  179. package/dist/core/ingestion/scope-extractor.js +12 -2
  180. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
  181. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
  182. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
  183. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
  184. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
  185. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
  186. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
  187. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
  188. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
  189. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
  190. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
  191. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
  192. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
  193. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
  194. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
  195. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
  196. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
  197. package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
  198. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  199. package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
  200. package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
  201. package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
  202. package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
  203. package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
  204. package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
  205. package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
  206. package/dist/core/ingestion/taint/call-summary-model.js +25 -0
  207. package/dist/core/ingestion/taint/emit.d.ts +125 -0
  208. package/dist/core/ingestion/taint/emit.js +208 -0
  209. package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
  210. package/dist/core/ingestion/taint/interproc-emit.js +88 -0
  211. package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
  212. package/dist/core/ingestion/taint/interproc-solver.js +312 -0
  213. package/dist/core/ingestion/taint/match.d.ts +153 -0
  214. package/dist/core/ingestion/taint/match.js +278 -0
  215. package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
  216. package/dist/core/ingestion/taint/path-codec.js +190 -0
  217. package/dist/core/ingestion/taint/propagate.d.ts +216 -0
  218. package/dist/core/ingestion/taint/propagate.js +659 -0
  219. package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
  220. package/dist/core/ingestion/taint/site-safety.js +98 -0
  221. package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
  222. package/dist/core/ingestion/taint/source-sink-config.js +35 -12
  223. package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
  224. package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
  225. package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
  226. package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
  227. package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
  228. package/dist/core/ingestion/taint/summary-harvest.js +537 -0
  229. package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
  230. package/dist/core/ingestion/taint/summary-model.js +86 -0
  231. package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
  232. package/dist/core/ingestion/taint/typescript-model.js +102 -0
  233. package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
  234. package/dist/core/ingestion/utils/env.d.ts +7 -0
  235. package/dist/core/ingestion/utils/env.js +12 -0
  236. package/dist/core/ingestion/utils/method-props.js +1 -0
  237. package/dist/core/ingestion/workers/parse-worker.d.ts +13 -0
  238. package/dist/core/ingestion/workers/parse-worker.js +76 -17
  239. package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
  240. package/dist/core/ingestion/workers/worker-pool.js +15 -2
  241. package/dist/core/lbug/csv-generator.d.ts +51 -3
  242. package/dist/core/lbug/csv-generator.js +369 -255
  243. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  244. package/dist/core/lbug/lbug-adapter.js +346 -84
  245. package/dist/core/lbug/lbug-config.d.ts +19 -0
  246. package/dist/core/lbug/lbug-config.js +29 -0
  247. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  248. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  249. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  250. package/dist/core/lbug/pool-adapter.js +90 -1
  251. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  252. package/dist/core/lbug/rel-pair-routing.js +140 -0
  253. package/dist/core/lbug/schema.d.ts +2 -2
  254. package/dist/core/lbug/schema.js +3 -0
  255. package/dist/core/logger.d.ts +0 -5
  256. package/dist/core/run-analyze.d.ts +96 -0
  257. package/dist/core/run-analyze.js +207 -3
  258. package/dist/core/tree-sitter/parser-loader.js +5 -4
  259. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  260. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  261. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  262. package/dist/core/wiki/generator.js +3 -1
  263. package/dist/core/wiki/graph-queries.d.ts +6 -0
  264. package/dist/core/wiki/graph-queries.js +9 -1
  265. package/dist/mcp/http-transport.d.ts +134 -0
  266. package/dist/mcp/http-transport.js +503 -0
  267. package/dist/mcp/local/local-backend.d.ts +110 -24
  268. package/dist/mcp/local/local-backend.js +1225 -19
  269. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  270. package/dist/mcp/local/pdg-impact.js +1972 -0
  271. package/dist/mcp/resources.js +13 -1
  272. package/dist/mcp/tools.d.ts +12 -0
  273. package/dist/mcp/tools.js +214 -7
  274. package/dist/server/analyze-launch.d.ts +29 -0
  275. package/dist/server/analyze-launch.js +137 -0
  276. package/dist/server/analyze-upload.d.ts +33 -0
  277. package/dist/server/analyze-upload.js +123 -0
  278. package/dist/server/analyze-worker.d.ts +17 -1
  279. package/dist/server/api.d.ts +17 -0
  280. package/dist/server/api.js +132 -168
  281. package/dist/server/git-clone.d.ts +43 -2
  282. package/dist/server/git-clone.js +211 -16
  283. package/dist/server/mcp-http.d.ts +5 -6
  284. package/dist/server/mcp-http.js +9 -82
  285. package/dist/server/middleware.d.ts +40 -0
  286. package/dist/server/middleware.js +92 -0
  287. package/dist/server/private-ip.d.ts +1 -0
  288. package/dist/server/private-ip.js +15 -0
  289. package/dist/server/upload-ingest.d.ts +56 -0
  290. package/dist/server/upload-ingest.js +276 -0
  291. package/dist/server/upload-paths.d.ts +37 -0
  292. package/dist/server/upload-paths.js +57 -0
  293. package/dist/server/upload-sweep.d.ts +20 -0
  294. package/dist/server/upload-sweep.js +57 -0
  295. package/dist/storage/git.js +5 -8
  296. package/dist/storage/parse-cache.d.ts +22 -1
  297. package/dist/storage/parse-cache.js +41 -10
  298. package/dist/storage/repo-manager.d.ts +121 -10
  299. package/dist/storage/repo-manager.js +43 -5
  300. package/dist/types/pipeline.d.ts +9 -0
  301. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  302. package/hooks/claude/gitnexus-hook.cjs +110 -13
  303. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  304. package/package.json +8 -2
  305. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  306. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  307. package/scripts/cross-platform-tests.ts +1 -0
  308. package/skills/gitnexus-debugging.md +16 -4
  309. package/skills/gitnexus-exploring.md +3 -3
  310. package/skills/gitnexus-guide.md +33 -0
  311. package/skills/gitnexus-pdg-query.md +89 -0
  312. package/skills/gitnexus-refactoring.md +1 -1
  313. package/skills/gitnexus-taint-analysis.md +178 -0
  314. package/vendor/tree-sitter-c/package.json +1 -1
  315. package/vendor/tree-sitter-dart/package.json +1 -1
  316. package/vendor/tree-sitter-kotlin/package.json +1 -1
  317. package/vendor/tree-sitter-proto/package.json +1 -1
  318. package/vendor/tree-sitter-swift/package.json +1 -1
  319. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  320. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  321. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  322. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  323. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  324. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  325. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  326. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  327. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  328. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  329. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  330. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  331. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  332. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  333. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  334. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  335. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  336. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  337. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  338. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  339. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  340. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  341. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  342. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  343. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  344. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  345. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  346. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  347. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  348. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  349. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  350. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  351. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  352. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  353. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  354. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  355. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  356. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  357. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  358. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  359. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  360. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  361. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  362. package/web/assets/index-BvYev1UJ.js +635 -0
  363. package/web/assets/index-_lgn7hs5.css +2 -0
  364. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  365. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  366. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  367. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  368. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  369. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  370. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  371. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  372. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  373. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  374. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  375. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  376. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  377. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  378. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  379. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  380. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  381. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  382. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  383. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  384. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  385. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  386. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  387. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  388. package/web/index.html +13 -15
  389. package/scripts/materialize-vendor-grammars.cjs +0 -97
  390. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  391. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  392. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  393. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  394. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  395. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  396. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  397. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  398. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  399. package/web/assets/chunk-CilyBKbf.js +0 -1
  400. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  401. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  402. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  403. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  404. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  405. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  406. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  407. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  408. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  409. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  410. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  411. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  412. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  413. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  414. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  415. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  416. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  417. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  418. package/web/assets/index-BKWA-m7o.css +0 -2
  419. package/web/assets/index-CG6q8eTs.js +0 -626
  420. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  421. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  422. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  423. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  424. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  425. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  426. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  427. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  428. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  429. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  430. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -0,0 +1,584 @@
1
+ import { CfgBuilder } from '../cfg-builder.js';
2
+ import { CCppHarvester } from './c-cpp-harvest.js';
3
+ /** C function node — only `function_definition` owns a CFG-bearing body. */
4
+ const C_FUNCTION_TYPES = new Set(['function_definition']);
5
+ /** C++ adds the lambda as a CFG-bearing function. */
6
+ const CPP_FUNCTION_TYPES = new Set(['function_definition', 'lambda_expression']);
7
+ /** Statement node types that break a basic block (everything else coalesces). */
8
+ const C_CONTROL_FLOW_TYPES = new Set([
9
+ 'if_statement',
10
+ 'while_statement',
11
+ 'do_statement',
12
+ 'for_statement',
13
+ 'switch_statement',
14
+ 'return_statement',
15
+ 'break_statement',
16
+ 'continue_statement',
17
+ 'goto_statement',
18
+ 'labeled_statement',
19
+ 'compound_statement',
20
+ ]);
21
+ /** C++ control-flow node types (C set ∪ exceptions ∪ range-for). */
22
+ const CPP_CONTROL_FLOW_TYPES = new Set([
23
+ ...C_CONTROL_FLOW_TYPES,
24
+ 'for_range_loop',
25
+ 'try_statement',
26
+ 'throw_statement',
27
+ 'co_return_statement',
28
+ ]);
29
+ const LOOP_OR_SWITCH_TYPES = new Set([
30
+ 'while_statement',
31
+ 'do_statement',
32
+ 'for_statement',
33
+ 'for_range_loop',
34
+ 'switch_statement',
35
+ ]);
36
+ const startLineOf = (n) => n.startPosition.row + 1;
37
+ const endLineOf = (n) => n.endPosition.row + 1;
38
+ /**
39
+ * Per-function C walk state. One instance per function so the jump-target stack,
40
+ * exception-handler stack, and label tables are scoped to that function.
41
+ *
42
+ * Designed to be EXTENDED by the C++ walk: the dispatch table is open via the
43
+ * protected {@link visitStmt} override hook, so C++ adds its node types without
44
+ * any language conditional in the C core.
45
+ */
46
+ class CCfgWalk {
47
+ builder;
48
+ harvest;
49
+ jumps = [];
50
+ /** Stack of exception-handler entry blocks (catch) a `throw` jumps to. */
51
+ handlers = [];
52
+ /** label name → its `labeled_statement` body's entry block (resolved on demand). */
53
+ labelBlocks = new Map();
54
+ /** Pending gotos to a label not yet seen: label → list of source blocks. */
55
+ pendingGotos = new Map();
56
+ /** Set of node types that break a block, used by {@link visitSeq}. */
57
+ controlFlowTypes;
58
+ constructor(builder, harvest, controlFlowTypes) {
59
+ this.builder = builder;
60
+ this.harvest = harvest;
61
+ this.controlFlowTypes = controlFlowTypes;
62
+ }
63
+ /** Statements of a block node, ignoring comments. */
64
+ statementsOf(block) {
65
+ return block.namedChildren.filter((c) => c.type !== 'comment');
66
+ }
67
+ /** The `body` block of a node (field, or the first compound_statement child). */
68
+ bodyBlockOf(node) {
69
+ return (node.childForFieldName('body') ??
70
+ node.namedChildren.find((c) => c.type === 'compound_statement'));
71
+ }
72
+ /** Visit a body that may be a `compound_statement` or a single statement. */
73
+ visitBody(node) {
74
+ return this.builder.withNesting(() => {
75
+ if (!node)
76
+ return null;
77
+ if (node.type === 'compound_statement')
78
+ return this.visitSeq(this.statementsOf(node));
79
+ return this.visitStmt(node);
80
+ });
81
+ }
82
+ /** Wire a sequence of statements, coalescing straight-line runs into blocks. */
83
+ visitSeq(stmts) {
84
+ return this.builder.withNesting(() => {
85
+ let entry;
86
+ let dangling = [];
87
+ let openSimple;
88
+ for (const stmt of stmts) {
89
+ if (this.controlFlowTypes.has(stmt.type)) {
90
+ openSimple = undefined; // close any open straight-line block
91
+ const res = this.visitStmt(stmt);
92
+ if (res === null)
93
+ continue; // transparent (empty nested block)
94
+ if (entry === undefined)
95
+ entry = res.entry;
96
+ else
97
+ this.builder.connect(dangling, res.entry, 'seq');
98
+ dangling = [...res.exits];
99
+ }
100
+ else {
101
+ if (openSimple === undefined) {
102
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
103
+ if (entry === undefined)
104
+ entry = idx;
105
+ else
106
+ this.builder.connect(dangling, idx, 'seq');
107
+ openSimple = idx;
108
+ dangling = [idx];
109
+ }
110
+ else {
111
+ this.builder.extendBlock(openSimple, endLineOf(stmt), stmt.text, this.harvest.facts(stmt));
112
+ }
113
+ }
114
+ }
115
+ if (entry === undefined)
116
+ return null;
117
+ return { entry, exits: dangling };
118
+ });
119
+ }
120
+ /** Dispatch one statement to its handler. Non-null except for empty blocks. */
121
+ visitStmt(stmt) {
122
+ switch (stmt.type) {
123
+ case 'if_statement':
124
+ return this.visitIf(stmt);
125
+ case 'while_statement':
126
+ return this.visitWhile(stmt);
127
+ case 'do_statement':
128
+ return this.visitDoWhile(stmt);
129
+ case 'for_statement':
130
+ return this.visitFor(stmt);
131
+ case 'switch_statement':
132
+ return this.visitSwitch(stmt);
133
+ case 'return_statement':
134
+ return this.visitReturn(stmt);
135
+ case 'break_statement':
136
+ return this.visitBreak(stmt);
137
+ case 'continue_statement':
138
+ return this.visitContinue(stmt);
139
+ case 'goto_statement':
140
+ return this.visitGoto(stmt);
141
+ case 'labeled_statement':
142
+ return this.visitLabeled(stmt);
143
+ case 'compound_statement':
144
+ return this.visitSeq(this.statementsOf(stmt));
145
+ default:
146
+ return this.visitExtra(stmt) ?? this.visitSimple(stmt);
147
+ }
148
+ }
149
+ /**
150
+ * Extension hook for node types the C core does not handle (C++ try/catch/
151
+ * throw/for-range). Returns `undefined` to fall through to {@link visitSimple}.
152
+ * The C core has none, so this is a no-op here.
153
+ */
154
+ visitExtra(_stmt) {
155
+ return undefined;
156
+ }
157
+ visitSimple(stmt) {
158
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
159
+ return { entry: idx, exits: [idx] };
160
+ }
161
+ visitReturn(stmt) {
162
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
163
+ this.builder.edge(idx, this.builder.exitIndex, 'return');
164
+ return { entry: idx, exits: [] };
165
+ }
166
+ visitBreak(stmt) {
167
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
168
+ const target = this.nearestBreakTarget();
169
+ this.builder.edge(idx, target ?? this.builder.exitIndex, 'break');
170
+ return { entry: idx, exits: [] };
171
+ }
172
+ visitContinue(stmt) {
173
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
174
+ const target = this.nearestContinueTarget();
175
+ this.builder.edge(idx, target ?? this.builder.exitIndex, 'continue');
176
+ return { entry: idx, exits: [] };
177
+ }
178
+ /** Nearest enclosing loop/switch `break` target, or undefined (→ EXIT). */
179
+ nearestBreakTarget() {
180
+ return this.jumps.length ? this.jumps[this.jumps.length - 1].breakTo : undefined;
181
+ }
182
+ /** Nearest enclosing loop `continue` target (switches don't catch continue). */
183
+ nearestContinueTarget() {
184
+ for (let i = this.jumps.length - 1; i >= 0; i--) {
185
+ if (this.jumps[i].kind === 'loop')
186
+ return this.jumps[i].continueTo;
187
+ }
188
+ return undefined;
189
+ }
190
+ /** `goto label;` — route to the label block if known, else defer / EXIT. */
191
+ visitGoto(stmt) {
192
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
193
+ const label = this.labelOf(stmt);
194
+ if (label === undefined) {
195
+ // Computed goto (`goto *p;`) or malformed — route to EXIT (single-exit).
196
+ this.builder.edge(idx, this.builder.exitIndex, 'seq');
197
+ return { entry: idx, exits: [] };
198
+ }
199
+ const target = this.labelBlocks.get(label);
200
+ if (target !== undefined) {
201
+ this.builder.edge(idx, target, 'seq'); // backward goto: label already built
202
+ }
203
+ else {
204
+ // Forward goto — wire once the label is created (or to EXIT at finish()).
205
+ const list = this.pendingGotos.get(label);
206
+ if (list)
207
+ list.push(idx);
208
+ else
209
+ this.pendingGotos.set(label, [idx]);
210
+ }
211
+ return { entry: idx, exits: [] };
212
+ }
213
+ visitLabeled(stmt) {
214
+ const label = this.labelOf(stmt);
215
+ // The labeled statement's body is the trailing named child (no `body` field
216
+ // on labeled_statement in C/C++).
217
+ const body = stmt.namedChildren.find((c) => c.type !== 'statement_identifier' && c.type !== 'comment') ??
218
+ null;
219
+ const res = this.visitBody(body);
220
+ if (label !== undefined) {
221
+ const entry = res?.entry ?? this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
222
+ this.labelBlocks.set(label, entry);
223
+ // Resolve any forward gotos that were waiting on this label.
224
+ const pending = this.pendingGotos.get(label);
225
+ if (pending) {
226
+ for (const from of pending)
227
+ this.builder.edge(from, entry, 'seq');
228
+ this.pendingGotos.delete(label);
229
+ }
230
+ if (!res)
231
+ return { entry, exits: [entry] };
232
+ }
233
+ return res;
234
+ }
235
+ visitIf(stmt) {
236
+ const cond = stmt.childForFieldName('condition') ?? stmt;
237
+ const condBlock = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.harvest.facts(cond));
238
+ const exits = [];
239
+ const thenRes = this.visitBody(stmt.childForFieldName('consequence'));
240
+ if (thenRes) {
241
+ this.builder.edge(condBlock, thenRes.entry, 'cond-true');
242
+ exits.push(...thenRes.exits);
243
+ }
244
+ else {
245
+ exits.push(condBlock); // empty then — true path falls through
246
+ }
247
+ const elseNode = this.elseBodyOf(stmt);
248
+ if (elseNode) {
249
+ const elseRes = this.visitBody(elseNode);
250
+ if (elseRes) {
251
+ this.builder.edge(condBlock, elseRes.entry, 'cond-false');
252
+ exits.push(...elseRes.exits);
253
+ }
254
+ else {
255
+ exits.push(condBlock);
256
+ }
257
+ }
258
+ else {
259
+ exits.push(condBlock); // no else — false path falls through to the join
260
+ }
261
+ return { entry: condBlock, exits: [...new Set(exits)] };
262
+ }
263
+ /** The else body node (unwraps an `else_clause` wrapper if present). */
264
+ elseBodyOf(ifStmt) {
265
+ const alt = ifStmt.childForFieldName('alternative');
266
+ if (!alt)
267
+ return undefined;
268
+ if (alt.type === 'else_clause') {
269
+ return alt.childForFieldName('body') ?? alt.namedChildren[0];
270
+ }
271
+ return alt; // an `else if` is the nested if_statement directly
272
+ }
273
+ visitWhile(stmt) {
274
+ const cond = stmt.childForFieldName('condition') ?? stmt;
275
+ const header = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.harvest.facts(cond));
276
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
277
+ this.jumps.push({ kind: 'loop', breakTo: loopExit, continueTo: header });
278
+ const body = this.visitBody(this.bodyBlockOf(stmt));
279
+ this.jumps.pop();
280
+ if (body) {
281
+ this.builder.edge(header, body.entry, 'cond-true');
282
+ this.builder.connect(body.exits, header, 'loop-back');
283
+ }
284
+ else {
285
+ this.builder.edge(header, header, 'loop-back'); // empty body re-tests
286
+ }
287
+ // Always emit the structural exit edge — even `while (1)` keeps EXIT
288
+ // reverse-reachable for the post-dominator / CDG pass.
289
+ this.builder.edge(header, loopExit, 'cond-false');
290
+ return { entry: header, exits: [loopExit] };
291
+ }
292
+ visitDoWhile(stmt) {
293
+ const cond = stmt.childForFieldName('condition') ?? stmt;
294
+ const condBlock = this.builder.newBlock(startLineOf(cond), endLineOf(cond), cond.text, 'normal', this.harvest.facts(cond));
295
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
296
+ this.jumps.push({ kind: 'loop', breakTo: loopExit, continueTo: condBlock });
297
+ const body = this.visitBody(this.bodyBlockOf(stmt));
298
+ this.jumps.pop();
299
+ const backTarget = body ? body.entry : condBlock;
300
+ if (body)
301
+ this.builder.connect(body.exits, condBlock, 'seq');
302
+ this.builder.edge(condBlock, backTarget, 'loop-back'); // cond true → run body again
303
+ this.builder.edge(condBlock, loopExit, 'cond-false');
304
+ return { entry: backTarget, exits: [loopExit] };
305
+ }
306
+ visitFor(stmt) {
307
+ const init = stmt.childForFieldName('initializer');
308
+ const cond = stmt.childForFieldName('condition');
309
+ const incr = stmt.childForFieldName('update');
310
+ const header = this.builder.newBlock(startLineOf(stmt), cond ? endLineOf(cond) : startLineOf(stmt), cond ? cond.text : 'for(;;)', 'normal', cond ? this.harvest.facts(cond) : undefined);
311
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
312
+ let incrBlock = header;
313
+ if (incr) {
314
+ incrBlock = this.builder.newBlock(startLineOf(incr), endLineOf(incr), incr.text, 'normal', this.harvest.facts(incr));
315
+ this.builder.edge(incrBlock, header, 'loop-back');
316
+ }
317
+ this.jumps.push({ kind: 'loop', breakTo: loopExit, continueTo: incrBlock });
318
+ const body = this.visitBody(this.bodyBlockOf(stmt));
319
+ this.jumps.pop();
320
+ if (body) {
321
+ this.builder.edge(header, body.entry, 'cond-true');
322
+ this.builder.connect(body.exits, incrBlock, incr ? 'seq' : 'loop-back');
323
+ }
324
+ else {
325
+ this.builder.edge(header, incrBlock, 'cond-true');
326
+ if (!incr)
327
+ this.builder.edge(header, header, 'loop-back');
328
+ }
329
+ // Structural exit edge — `for (;;) {}` (no condition) still keeps EXIT
330
+ // reverse-reachable so CDG is not silently skipped for the function.
331
+ this.builder.edge(header, loopExit, 'cond-false');
332
+ let entry = header;
333
+ if (init) {
334
+ const initBlock = this.builder.newBlock(startLineOf(init), endLineOf(init), init.text, 'normal', this.harvest.facts(init));
335
+ this.builder.edge(initBlock, header, 'seq');
336
+ entry = initBlock;
337
+ }
338
+ return { entry, exits: [loopExit] };
339
+ }
340
+ visitSwitch(stmt) {
341
+ const value = stmt.childForFieldName('condition') ?? stmt;
342
+ const dispatch = this.builder.newBlock(startLineOf(stmt), endLineOf(value), value.text, 'normal', this.harvest.facts(value));
343
+ const switchExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
344
+ this.jumps.push({ kind: 'switch', breakTo: switchExit, continueTo: -1 });
345
+ const body = stmt.childForFieldName('body');
346
+ // C/C++ uses ONE `case_statement` node for both `case X:` and `default:`;
347
+ // a default has no `value` field.
348
+ const cases = body ? body.namedChildren.filter((c) => c.type === 'case_statement') : [];
349
+ // `case X:` test expressions live in no block — harvest their uses onto the
350
+ // dispatch block as may-defs/uses (sound over-approx of in-order evaluation).
351
+ for (const c of cases) {
352
+ const caseValue = c.childForFieldName('value');
353
+ if (caseValue)
354
+ this.builder.attachFacts(dispatch, this.harvest.factsConditional(caseValue));
355
+ }
356
+ const caseResults = cases.map((c) => this.visitSeq(this.caseStatements(c)));
357
+ const hasDefault = cases.some((c) => !c.childForFieldName('value'));
358
+ const entryOf = new Array(cases.length);
359
+ let after = switchExit;
360
+ for (let i = cases.length - 1; i >= 0; i--) {
361
+ entryOf[i] = caseResults[i]?.entry ?? after;
362
+ after = entryOf[i];
363
+ }
364
+ for (let i = 0; i < cases.length; i++) {
365
+ this.builder.edge(dispatch, entryOf[i], 'switch-case');
366
+ }
367
+ if (!hasDefault)
368
+ this.builder.edge(dispatch, switchExit, 'switch-case'); // no-match path
369
+ for (let i = 0; i < cases.length; i++) {
370
+ const res = caseResults[i];
371
+ if (!res)
372
+ continue;
373
+ const fallTarget = i + 1 < cases.length ? entryOf[i + 1] : switchExit;
374
+ this.builder.connect(res.exits, fallTarget, 'fallthrough');
375
+ }
376
+ this.jumps.pop();
377
+ return { entry: dispatch, exits: [switchExit] };
378
+ }
379
+ /** A case's body statements (everything but the `value` test and comments). */
380
+ caseStatements(caseNode) {
381
+ const value = caseNode.childForFieldName('value');
382
+ return caseNode.namedChildren.filter((c) => c.id !== value?.id && c.type !== 'comment');
383
+ }
384
+ /** Nearest enclosing exception handler, or the function EXIT. */
385
+ currentHandler() {
386
+ return this.handlers.length ? this.handlers[this.handlers.length - 1] : this.builder.exitIndex;
387
+ }
388
+ labelOf(stmt) {
389
+ const id = stmt.childForFieldName('label') ??
390
+ stmt.namedChildren.find((c) => c.type === 'statement_identifier');
391
+ return id?.text;
392
+ }
393
+ /**
394
+ * Drain any forward gotos whose label never appeared in the function (a label
395
+ * defined in a header macro, or malformed source) — route them to EXIT so the
396
+ * graph stays single-exit. Logs via console.warn (the builder's warn path)
397
+ * so a dropped jump is never silent (R4). Called once after the body walk.
398
+ */
399
+ finishGotos() {
400
+ for (const [label, froms] of this.pendingGotos) {
401
+ // eslint-disable-next-line no-console
402
+ console.warn(`[cfg] unresolved goto label "${label}" routed to EXIT (${froms.length} site(s))`);
403
+ for (const from of froms)
404
+ this.builder.edge(from, this.builder.exitIndex, 'seq');
405
+ }
406
+ this.pendingGotos.clear();
407
+ }
408
+ }
409
+ /**
410
+ * C++ walk — extends the C core with exception flow and the range-for loop.
411
+ * These node types never appear in a C parse, so no language conditional is
412
+ * needed; the C core dispatches them through {@link visitExtra}.
413
+ */
414
+ class CppCfgWalk extends CCfgWalk {
415
+ visitExtra(stmt) {
416
+ switch (stmt.type) {
417
+ case 'for_range_loop':
418
+ return this.visitForRange(stmt);
419
+ case 'try_statement':
420
+ return this.visitTry(stmt);
421
+ case 'throw_statement':
422
+ return this.visitThrow(stmt);
423
+ case 'co_return_statement':
424
+ // A coroutine `co_return` terminates the coroutine like an ordinary
425
+ // return: edge to EXIT, no fallthrough (`co_await`/`co_yield` are plain
426
+ // expressions that continue, so they need no control-flow handling).
427
+ return this.visitReturn(stmt);
428
+ default:
429
+ return undefined;
430
+ }
431
+ }
432
+ visitThrow(stmt) {
433
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
434
+ this.builder.edge(idx, this.currentHandler(), 'throw');
435
+ return { entry: idx, exits: [] };
436
+ }
437
+ visitForRange(stmt) {
438
+ // Header text is synthesized; facts come from the declarator (def) + the
439
+ // iterated expression (use) directly.
440
+ const header = this.builder.newBlock(startLineOf(stmt), startLineOf(stmt), this.forRangeHeaderText(stmt), 'normal', this.harvest.forRangeHeadFacts(stmt));
441
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
442
+ this.jumps.push({ kind: 'loop', breakTo: loopExit, continueTo: header });
443
+ const body = this.visitBody(this.bodyBlockOf(stmt));
444
+ this.jumps.pop();
445
+ if (body) {
446
+ this.builder.edge(header, body.entry, 'cond-true');
447
+ this.builder.connect(body.exits, header, 'loop-back');
448
+ }
449
+ else {
450
+ this.builder.edge(header, header, 'loop-back');
451
+ }
452
+ this.builder.edge(header, loopExit, 'cond-false');
453
+ return { entry: header, exits: [loopExit] };
454
+ }
455
+ forRangeHeaderText(stmt) {
456
+ const decl = stmt.childForFieldName('declarator')?.text ?? '';
457
+ const right = stmt.childForFieldName('right')?.text ?? '';
458
+ return decl || right ? `for(${decl} : ${right})` : 'for(… : …)';
459
+ }
460
+ /**
461
+ * try / catch (C++ has no `finally`). Conservative exceptional flow: every
462
+ * block created while walking the protected body edges to the (first) catch
463
+ * handler — an exception may fire mid-block, and a branched body must still
464
+ * reach the handler from any interior block (matching the TS visitTry
465
+ * over-approximation). Multiple `catch` clauses: a body throw routes to EVERY
466
+ * handler (the runtime type match is dynamic), and each handler's normal
467
+ * completion joins the post-try continuation.
468
+ */
469
+ visitTry(stmt) {
470
+ const bodyNode = stmt.childForFieldName('body');
471
+ const catchClauses = [];
472
+ for (let i = 0; i < stmt.namedChildCount; i++) {
473
+ const c = stmt.namedChild(i);
474
+ if (c?.type === 'catch_clause')
475
+ catchClauses.push(c);
476
+ }
477
+ // Build each catch handler. The handler entry is the catch-param binding
478
+ // block (a facts-only block) in front of the body, so the exception's
479
+ // binding happens exactly once on handler entry.
480
+ const handlerEntries = [];
481
+ const handlerExits = [];
482
+ for (const clause of catchClauses) {
483
+ const clauseBody = this.bodyBlockOf(clause);
484
+ let res = clauseBody ? this.visitSeq(this.statementsOf(clauseBody)) : null;
485
+ if (res === null) {
486
+ // Empty catch body still CATCHES — synthesize one block so the
487
+ // exception lands somewhere and the post-try code stays reachable.
488
+ const idx = this.builder.newBlock(startLineOf(clause), endLineOf(clause), '');
489
+ res = { entry: idx, exits: [idx] };
490
+ }
491
+ const paramFacts = this.harvest.catchParamFacts(clause);
492
+ if (paramFacts) {
493
+ const paramBlock = this.builder.newBlock(startLineOf(clause), startLineOf(clause), '', 'normal', paramFacts);
494
+ this.builder.edge(paramBlock, res.entry, 'seq');
495
+ res = { entry: paramBlock, exits: res.exits };
496
+ }
497
+ handlerEntries.push(res.entry);
498
+ handlerExits.push(...res.exits);
499
+ }
500
+ // The protected body's handler is the FIRST catch (if any), else the outer.
501
+ const tryHandler = handlerEntries[0] ?? this.currentHandler();
502
+ const protectedStart = this.builder.blockCount;
503
+ this.handlers.push(tryHandler);
504
+ const bodyRes = bodyNode ? this.visitSeq(this.statementsOf(bodyNode)) : null;
505
+ this.handlers.pop();
506
+ // Conservative exceptional edges: every protected-region block → EVERY handler
507
+ // entry. The runtime catch that matches a thrown type is not statically known,
508
+ // so over-approximate to ALL clauses — wiring only the first (tryHandler)
509
+ // orphaned `catch` clauses 2..N, dropping their control/data flow entirely
510
+ // (the binding `catch(T2 e)` and the handler body became unreachable). Mirrors
511
+ // the Swift multi-catch handling.
512
+ if (catchClauses.length > 0) {
513
+ for (let b = protectedStart; b < this.builder.blockCount; b++) {
514
+ for (const handler of handlerEntries)
515
+ this.builder.edge(b, handler, 'throw');
516
+ }
517
+ }
518
+ const exits = [];
519
+ if (bodyRes)
520
+ exits.push(...bodyRes.exits);
521
+ exits.push(...handlerExits);
522
+ // No catch clause at all — an exception re-propagates to the outer handler.
523
+ if (catchClauses.length === 0 && bodyRes) {
524
+ // (A bare `try {}` with no catch is ill-formed C++, but stay robust.)
525
+ this.builder.connect(bodyRes.exits, this.currentHandler(), 'throw');
526
+ }
527
+ const entry = bodyRes?.entry ?? handlerEntries[0];
528
+ if (entry === undefined)
529
+ return null;
530
+ return { entry, exits: [...new Set(exits)] };
531
+ }
532
+ }
533
+ /** Build the CFG for one C/C++ function node, or `undefined` if not modelable. */
534
+ function buildFunctionCfg(fnNode, filePath, functionTypes, controlFlowTypes, WalkClass) {
535
+ try {
536
+ if (!functionTypes.has(fnNode.type))
537
+ return undefined;
538
+ const startLine = startLineOf(fnNode);
539
+ const endLine = endLineOf(fnNode);
540
+ const startColumn = fnNode.startPosition.column;
541
+ // The body is a compound_statement (field `body`, or first such child).
542
+ const body = fnNode.childForFieldName('body') ??
543
+ fnNode.namedChildren.find((c) => c.type === 'compound_statement');
544
+ if (!body || body.type !== 'compound_statement')
545
+ return undefined; // declaration / no body
546
+ const builder = new CfgBuilder(filePath, startLine, endLine, startColumn);
547
+ const harvest = new CCppHarvester(fnNode);
548
+ const paramFacts = harvest.paramFacts();
549
+ if (paramFacts)
550
+ builder.attachFacts(builder.entryIndex, paramFacts);
551
+ const walk = new WalkClass(builder, harvest, controlFlowTypes);
552
+ const res = walk.visitSeq(body.namedChildren.filter((c) => c.type !== 'comment'));
553
+ walk.finishGotos();
554
+ if (!res) {
555
+ builder.edge(builder.entryIndex, builder.exitIndex, 'seq'); // empty body
556
+ return builder.finish(harvest.bindingTable());
557
+ }
558
+ builder.edge(builder.entryIndex, res.entry, 'seq');
559
+ builder.connect(res.exits, builder.exitIndex, 'seq'); // normal fall-off → EXIT
560
+ return builder.finish(harvest.bindingTable());
561
+ }
562
+ catch (err) {
563
+ // Never throw out of buildFunctionCfg — a malformed AST shape must skip only
564
+ // this one function's CFG, never drop the whole file's language group (R4).
565
+ // eslint-disable-next-line no-console
566
+ console.warn(`[cfg] C/C++ buildFunctionCfg skipped a function in ${filePath}: ${String(err)}`);
567
+ return undefined;
568
+ }
569
+ }
570
+ /** The C CFG visitor. */
571
+ export function createCCfgVisitor() {
572
+ return {
573
+ isFunction: (node) => C_FUNCTION_TYPES.has(node.type),
574
+ buildFunctionCfg: (fnNode, filePath) => buildFunctionCfg(fnNode, filePath, C_FUNCTION_TYPES, C_CONTROL_FLOW_TYPES, CCfgWalk),
575
+ };
576
+ }
577
+ /** The C++ CFG visitor (C core + exceptions + range-for + lambdas). */
578
+ export function createCppCfgVisitor() {
579
+ return {
580
+ isFunction: (node) => CPP_FUNCTION_TYPES.has(node.type),
581
+ buildFunctionCfg: (fnNode, filePath) => buildFunctionCfg(fnNode, filePath, CPP_FUNCTION_TYPES, CPP_CONTROL_FLOW_TYPES, CppCfgWalk),
582
+ };
583
+ }
584
+ export { C_FUNCTION_TYPES, CPP_FUNCTION_TYPES };