@backbencher/brain 0.0.0-stage → 0.1.0

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 (319) hide show
  1. package/CHANGELOG.md +298 -0
  2. package/EMBEDDINGS.md +355 -0
  3. package/LICENSE +21 -0
  4. package/README.md +415 -2
  5. package/bin/bb +13 -0
  6. package/dist/analysis-exclusions-7ZJDXOVZ.js +35 -0
  7. package/dist/brain-index-health-KY7K552E.js +17 -0
  8. package/dist/brain-relationship-enrichment-QH7OOHUF.js +558 -0
  9. package/dist/brain.sql-EIM4WS4D.js +29 -0
  10. package/dist/chunk-2BSKD7O3.js +40 -0
  11. package/dist/chunk-2DE27DVC.js +1314 -0
  12. package/dist/chunk-2RRBMNBQ.js +322 -0
  13. package/dist/chunk-2RTN2DFU.js +711 -0
  14. package/dist/chunk-2WXYNLBA.js +29 -0
  15. package/dist/chunk-3CTFIJJB.js +17 -0
  16. package/dist/chunk-3LFTSMIV.js +174 -0
  17. package/dist/chunk-47HKX4AJ.js +930 -0
  18. package/dist/chunk-4H22TLOT.js +543 -0
  19. package/dist/chunk-5SD45FLC.js +818 -0
  20. package/dist/chunk-66A5ZFYA.js +1758 -0
  21. package/dist/chunk-6AIRWAO2.js +247 -0
  22. package/dist/chunk-6WNGD3NN.js +196 -0
  23. package/dist/chunk-7AN7U5IZ.js +371 -0
  24. package/dist/chunk-BHB7BYYI.js +626 -0
  25. package/dist/chunk-BQ3OVQ3P.js +125 -0
  26. package/dist/chunk-CW4XXSNN.js +1479 -0
  27. package/dist/chunk-D2Q4Y47A.js +53 -0
  28. package/dist/chunk-DIYAGQJL.js +34 -0
  29. package/dist/chunk-DYM4FQEE.js +90 -0
  30. package/dist/chunk-EWMWK7WN.js +75 -0
  31. package/dist/chunk-FVVQTSIM.js +3427 -0
  32. package/dist/chunk-FWSL4VG6.js +1290 -0
  33. package/dist/chunk-GBI7V7KY.js +69 -0
  34. package/dist/chunk-GEFFO6O2.js +152 -0
  35. package/dist/chunk-HOWAQXJO.js +236 -0
  36. package/dist/chunk-HQSPJDHI.js +613 -0
  37. package/dist/chunk-IFZNR5UJ.js +2863 -0
  38. package/dist/chunk-J4PMBXQQ.js +336 -0
  39. package/dist/chunk-KAET47ZL.js +125 -0
  40. package/dist/chunk-KCDECRJY.js +440 -0
  41. package/dist/chunk-KLK3PBTO.js +1119 -0
  42. package/dist/chunk-L5TDYKYK.js +76 -0
  43. package/dist/chunk-MLKGABMK.js +9 -0
  44. package/dist/chunk-OWISBAOF.js +61 -0
  45. package/dist/chunk-PJTNGD3Z.js +6924 -0
  46. package/dist/chunk-QLK6ED4Q.js +235 -0
  47. package/dist/chunk-R2GW4F6R.js +19 -0
  48. package/dist/chunk-RCMTFSEF.js +87 -0
  49. package/dist/chunk-RH7KC5HU.js +12050 -0
  50. package/dist/chunk-RM3PY6TG.js +376 -0
  51. package/dist/chunk-ROMM6KMC.js +433 -0
  52. package/dist/chunk-SK6YVHFZ.js +211 -0
  53. package/dist/chunk-SM7RFQRO.js +214 -0
  54. package/dist/chunk-UFE77L67.js +782 -0
  55. package/dist/chunk-UGR4QIGS.js +67 -0
  56. package/dist/chunk-UUNHHX4M.js +13 -0
  57. package/dist/chunk-V44PGPA6.js +2104 -0
  58. package/dist/chunk-VL52PL2T.js +71 -0
  59. package/dist/chunk-VURYFIHW.js +201 -0
  60. package/dist/chunk-XJKJYIPP.js +7436 -0
  61. package/dist/chunk-YI6FF2ZR.js +340 -0
  62. package/dist/cli/index.js +37 -0
  63. package/dist/config-HZAAYDP3.js +10 -0
  64. package/dist/content-search-642F7E5V.js +593 -0
  65. package/dist/database-TCTZDLE5.js +9 -0
  66. package/dist/doctor-GXCKSJOX.js +395 -0
  67. package/dist/edit-engine-KM7MPFEC.js +51 -0
  68. package/dist/engine-42TZFNIZ.js +11 -0
  69. package/dist/engine-LO6L4JLQ.js +18 -0
  70. package/dist/fingerprint-XDXFRWO6.js +33 -0
  71. package/dist/framework-intelligence-DWFCKV44.js +860 -0
  72. package/dist/freshness-3K6VU5OT.js +174 -0
  73. package/dist/graph-engine-PL5YA7BA.js +21 -0
  74. package/dist/graph_request-MM4REP6H.js +350 -0
  75. package/dist/impact_request-WDE47IZ5.js +68 -0
  76. package/dist/index-space-IUUN5WYV.js +15 -0
  77. package/dist/index-status-6BD7UBHR.js +34 -0
  78. package/dist/index.js +159 -0
  79. package/dist/instance-FO6QZRLH.js +19 -0
  80. package/dist/language-detection-DFCAU5DZ.js +11 -0
  81. package/dist/lsp/server.js +4301 -0
  82. package/dist/mcp/server.js +132 -0
  83. package/dist/onboard-DIQZV2NW.js +161 -0
  84. package/dist/override-companion-pass-XR7MHTP7.js +117 -0
  85. package/dist/parallel-indexer-4PW3AFXP.js +88 -0
  86. package/dist/pool-worker.js +1153 -0
  87. package/dist/project-health-ZS5TS2Z6.js +94 -0
  88. package/dist/project-index-5SDPHITE.js +57 -0
  89. package/dist/project-registry-DGZBIZS7.js +355 -0
  90. package/dist/real-bash-analyzer-SXSV67E2.js +2201 -0
  91. package/dist/real-c-analyzer-SY7FTZ6W.js +5942 -0
  92. package/dist/real-clean-analyzer-IGDHHLZK.js +3470 -0
  93. package/dist/real-clojure-analyzer-4OH7IWLB.js +2818 -0
  94. package/dist/real-cpp-analyzer-7LTDRJRJ.js +4101 -0
  95. package/dist/real-csharp-analyzer-KICU3TLH.js +3298 -0
  96. package/dist/real-css-analyzer-HPU277Q6.js +15 -0
  97. package/dist/real-dart-analyzer-7LZ5LCMW.js +3944 -0
  98. package/dist/real-elixir-analyzer-BE3MEVZO.js +2192 -0
  99. package/dist/real-erlang-analyzer-BZMAKYBK.js +1731 -0
  100. package/dist/real-fsharp-analyzer-5QLTOV3E.js +2390 -0
  101. package/dist/real-go-analyzer-POD7MZQR.js +4126 -0
  102. package/dist/real-graphql-analyzer-MAQRZ6QW.js +1442 -0
  103. package/dist/real-groovy-analyzer-MEWSUPMJ.js +2285 -0
  104. package/dist/real-haskell-analyzer-I5L2GR3Y.js +2533 -0
  105. package/dist/real-hcl-analyzer-DBOPXSWJ.js +725 -0
  106. package/dist/real-html-analyzer-O63XZLZD.js +1759 -0
  107. package/dist/real-java-analyzer-CHCW3EKA.js +4677 -0
  108. package/dist/real-javascript-analyzer-QAAJQYZE.js +14 -0
  109. package/dist/real-json-analyzer-UGBR7YQN.js +1640 -0
  110. package/dist/real-julia-analyzer-35Q4GHOZ.js +2085 -0
  111. package/dist/real-kotlin-analyzer-GRAYCWW2.js +3956 -0
  112. package/dist/real-lua-analyzer-5BAPDZDF.js +1957 -0
  113. package/dist/real-makefile-analyzer-YJKAHNAS.js +920 -0
  114. package/dist/real-markdown-analyzer-UKUQZO4F.js +1215 -0
  115. package/dist/real-matlab-analyzer-FVIKQZKG.js +480 -0
  116. package/dist/real-nim-analyzer-M7FAIABG.js +3603 -0
  117. package/dist/real-objective-c-analyzer-XMYQIGQI.js +1518 -0
  118. package/dist/real-perl-analyzer-ZLY6M2DZ.js +1865 -0
  119. package/dist/real-php-analyzer-KI2ZAM7X.js +9368 -0
  120. package/dist/real-powershell-analyzer-B3T5ZP6U.js +2915 -0
  121. package/dist/real-protobuf-analyzer-23OZ75XV.js +867 -0
  122. package/dist/real-python-analyzer-I4TIUB6D.js +4880 -0
  123. package/dist/real-r-analyzer-FJZJXXS6.js +2596 -0
  124. package/dist/real-ruby-analyzer-M3UFIVTQ.js +2429 -0
  125. package/dist/real-rust-analyzer-LVSONPAN.js +3359 -0
  126. package/dist/real-scala-analyzer-CWPI33Q2.js +3293 -0
  127. package/dist/real-scss-analyzer-TGRJQ7TH.js +1515 -0
  128. package/dist/real-solidity-analyzer-4P2VBVWA.js +2608 -0
  129. package/dist/real-sql-analyzer-J7DYZOZR.js +3840 -0
  130. package/dist/real-svelte-analyzer-NHEN2SX5.js +2532 -0
  131. package/dist/real-swift-analyzer-2NSYULWI.js +2311 -0
  132. package/dist/real-toml-analyzer-L3C66L7Q.js +929 -0
  133. package/dist/real-typescript-analyzer-FTC6ETRQ.js +14 -0
  134. package/dist/real-vb-analyzer-ORY7LAQS.js +3145 -0
  135. package/dist/real-vba-analyzer-JH2TTUFI.js +466 -0
  136. package/dist/real-vue-analyzer-OO4FUGBV.js +2680 -0
  137. package/dist/real-xml-analyzer-6CQVR477.js +2405 -0
  138. package/dist/real-yaml-analyzer-J6MQG3YX.js +3528 -0
  139. package/dist/real-zig-analyzer-EFKCPJNU.js +2430 -0
  140. package/dist/regex-search-OPTLKUN5.js +239 -0
  141. package/dist/rules-I453JTRC.js +152 -0
  142. package/dist/scoped-path-MJYWJZQX.js +11 -0
  143. package/dist/setup-show-Y5GB5KXA.js +15 -0
  144. package/dist/setup-wizard-G5YYR5T6.js +24 -0
  145. package/dist/symbol-search-KB4MU4SI.js +16 -0
  146. package/dist/taint-YOTN5X55.js +202 -0
  147. package/dist/taint-analyzer-N7YLZU3N.js +163 -0
  148. package/dist/tool-handlers-G4NAGJIH.js +72 -0
  149. package/dist/tool-registry-BPEJNSZG.js +17 -0
  150. package/dist/tool-validation-RF675A3C.js +32 -0
  151. package/dist/type-inference-4Y7WTMFE.js +13 -0
  152. package/dist/vector-binary-LMY4QGAN.js +19 -0
  153. package/dist/version-LXGNFO37.js +9 -0
  154. package/dist/wasm-NMWO3WXY.js +16 -0
  155. package/docs/EMBEDDINGS.md +132 -0
  156. package/docs/README.md +178 -0
  157. package/docs/data/m10-baseline.json +602 -0
  158. package/docs/data/m10-benchmark-baseline.json +57 -0
  159. package/docs/data/m10-benchmark-last-run.json +127 -0
  160. package/docs/data/m10-final-audit.json +215 -0
  161. package/docs/data/m12-final-audit.json +138 -0
  162. package/docs/data/m12-surface-matrix.json +50 -0
  163. package/docs/data/public-tools.json +1902 -0
  164. package/docs/indexing/DEAD-ASSETS.md +88 -0
  165. package/docs/indexing/INDEXER-REVIEW.md +634 -0
  166. package/docs/indexing/PERFORMANCE-FINDINGS.md +106 -0
  167. package/docs/indexing/README.md +427 -0
  168. package/docs/indexing/discovery-matrix.md +41 -0
  169. package/docs/indexing/embeddings.md +325 -0
  170. package/docs/indexing/environment-variables.md +77 -0
  171. package/docs/indexing/performance.md +323 -0
  172. package/docs/indexing/resume.md +345 -0
  173. package/docs/indexing/troubleshooting.md +391 -0
  174. package/docs/man/bb.1 +190 -0
  175. package/docs/tools/bb_analyze.md +147 -0
  176. package/docs/tools/bb_annotate.md +110 -0
  177. package/docs/tools/bb_annotations.md +106 -0
  178. package/docs/tools/bb_ask.md +101 -0
  179. package/docs/tools/bb_cross_language.md +103 -0
  180. package/docs/tools/bb_doc.md +169 -0
  181. package/docs/tools/bb_edit.md +185 -0
  182. package/docs/tools/bb_graph.md +169 -0
  183. package/docs/tools/bb_health.md +156 -0
  184. package/docs/tools/bb_impact.md +117 -0
  185. package/docs/tools/bb_index.md +108 -0
  186. package/docs/tools/bb_migrate.md +135 -0
  187. package/docs/tools/bb_patterns.md +140 -0
  188. package/docs/tools/bb_search.md +150 -0
  189. package/docs/tools/bb_security.md +100 -0
  190. package/docs/tools/bb_visualize.md +184 -0
  191. package/grammars/README.md +57 -0
  192. package/grammars/THIRD-PARTY-NOTICES.md +50 -0
  193. package/grammars/tree-sitter-c/LICENSE +21 -0
  194. package/grammars/tree-sitter-clojure/LICENSE.md +21 -0
  195. package/grammars/tree-sitter-cpp/LICENSE +21 -0
  196. package/grammars/tree-sitter-csharp/LICENSE +21 -0
  197. package/grammars/tree-sitter-css/LICENSE +21 -0
  198. package/grammars/tree-sitter-css/README.md +21 -0
  199. package/grammars/tree-sitter-dart/LICENSE +20 -0
  200. package/grammars/tree-sitter-dart-upstream/LICENSE +20 -0
  201. package/grammars/tree-sitter-dart-upstream/README.md +18 -0
  202. package/grammars/tree-sitter-elixir/LICENSE +176 -0
  203. package/grammars/tree-sitter-elixir/README.md +11 -0
  204. package/grammars/tree-sitter-fsharp/LICENSE +21 -0
  205. package/grammars/tree-sitter-fsharp/README.md +45 -0
  206. package/grammars/tree-sitter-graphql/LICENSE +21 -0
  207. package/grammars/tree-sitter-graphql/README.md +106 -0
  208. package/grammars/tree-sitter-groovy/LICENSE +21 -0
  209. package/grammars/tree-sitter-groovy/README.md +4 -0
  210. package/grammars/tree-sitter-haskell/LICENSE +21 -0
  211. package/grammars/tree-sitter-haskell/README.md +394 -0
  212. package/grammars/tree-sitter-hcl/CHANGELOG.md +102 -0
  213. package/grammars/tree-sitter-hcl/LICENSE +201 -0
  214. package/grammars/tree-sitter-hcl/README.md +39 -0
  215. package/grammars/tree-sitter-html/LICENSE +21 -0
  216. package/grammars/tree-sitter-html/README.md +21 -0
  217. package/grammars/tree-sitter-julia/LICENSE +21 -0
  218. package/grammars/tree-sitter-julia/README.md +24 -0
  219. package/grammars/tree-sitter-kotlin/LICENSE +9 -0
  220. package/grammars/tree-sitter-lua/LICENSE.md +21 -0
  221. package/grammars/tree-sitter-lua/README.md +29 -0
  222. package/grammars/tree-sitter-make/LICENSE +21 -0
  223. package/grammars/tree-sitter-matlab/LICENSE +19 -0
  224. package/grammars/tree-sitter-matlab/README.md +99 -0
  225. package/grammars/tree-sitter-nim/LICENSE +373 -0
  226. package/grammars/tree-sitter-nim/README.md +46 -0
  227. package/grammars/tree-sitter-objc/LICENSE +21 -0
  228. package/grammars/tree-sitter-objc/README.md +20 -0
  229. package/grammars/tree-sitter-perl/LICENSE +7 -0
  230. package/grammars/tree-sitter-perl/README.md +100 -0
  231. package/grammars/tree-sitter-powershell/LICENSE +21 -0
  232. package/grammars/tree-sitter-powershell/README.md +7 -0
  233. package/grammars/tree-sitter-proto/LICENSE +21 -0
  234. package/grammars/tree-sitter-proto/README.md +105 -0
  235. package/grammars/tree-sitter-r/LICENSE +9 -0
  236. package/grammars/tree-sitter-r/README.md +66 -0
  237. package/grammars/tree-sitter-ruby/LICENSE +22 -0
  238. package/grammars/tree-sitter-scss/LICENSE +21 -0
  239. package/grammars/tree-sitter-scss/README.md +17 -0
  240. package/grammars/tree-sitter-solidity/LICENSE +7 -0
  241. package/grammars/tree-sitter-sql/LICENSE +21 -0
  242. package/grammars/tree-sitter-typescript/LICENSE +21 -0
  243. package/grammars/tree-sitter-vba/LICENSE +21 -0
  244. package/grammars/tree-sitter-vba/README.md +738 -0
  245. package/grammars/tree-sitter-vbnet/LICENSE +21 -0
  246. package/grammars/tree-sitter-vbnet/README.md +322 -0
  247. package/grammars/tree-sitter-xml/LICENSE +19 -0
  248. package/grammars/tree-sitter-yaml/LICENSE +20 -0
  249. package/grammars/tree-sitter-yaml/README.md +21 -0
  250. package/package.json +184 -4
  251. package/wasm/dart.wasm +0 -0
  252. package/wasm/tree-sitter-bash.wasm +0 -0
  253. package/wasm/tree-sitter-c.wasm +0 -0
  254. package/wasm/tree-sitter-c_sharp.wasm +0 -0
  255. package/wasm/tree-sitter-clean.wasm +0 -0
  256. package/wasm/tree-sitter-clojure.wasm +0 -0
  257. package/wasm/tree-sitter-core_schema.wasm +0 -0
  258. package/wasm/tree-sitter-cpp.wasm +0 -0
  259. package/wasm/tree-sitter-css.wasm +0 -0
  260. package/wasm/tree-sitter-dart.wasm +0 -0
  261. package/wasm/tree-sitter-elisp.wasm +0 -0
  262. package/wasm/tree-sitter-elixir.wasm +0 -0
  263. package/wasm/tree-sitter-elm.wasm +0 -0
  264. package/wasm/tree-sitter-embedded_template.wasm +0 -0
  265. package/wasm/tree-sitter-erlang.wasm +0 -0
  266. package/wasm/tree-sitter-fsharp.wasm +0 -0
  267. package/wasm/tree-sitter-fsharp_signature.wasm +0 -0
  268. package/wasm/tree-sitter-go.wasm +0 -0
  269. package/wasm/tree-sitter-graphql.wasm +0 -0
  270. package/wasm/tree-sitter-groovy.wasm +0 -0
  271. package/wasm/tree-sitter-haskell.wasm +0 -0
  272. package/wasm/tree-sitter-hcl.wasm +0 -0
  273. package/wasm/tree-sitter-html.wasm +0 -0
  274. package/wasm/tree-sitter-java.wasm +0 -0
  275. package/wasm/tree-sitter-javascript.wasm +0 -0
  276. package/wasm/tree-sitter-json.wasm +0 -0
  277. package/wasm/tree-sitter-json_schema.wasm +0 -0
  278. package/wasm/tree-sitter-julia.wasm +0 -0
  279. package/wasm/tree-sitter-kotlin.wasm +0 -0
  280. package/wasm/tree-sitter-lua.wasm +0 -0
  281. package/wasm/tree-sitter-make.wasm +0 -0
  282. package/wasm/tree-sitter-markdown.wasm +0 -0
  283. package/wasm/tree-sitter-markdown_inline.wasm +0 -0
  284. package/wasm/tree-sitter-matlab.wasm +0 -0
  285. package/wasm/tree-sitter-nim.wasm +0 -0
  286. package/wasm/tree-sitter-objc.wasm +0 -0
  287. package/wasm/tree-sitter-ocaml.wasm +0 -0
  288. package/wasm/tree-sitter-perl.wasm +0 -0
  289. package/wasm/tree-sitter-php.wasm +0 -0
  290. package/wasm/tree-sitter-php_only.wasm +0 -0
  291. package/wasm/tree-sitter-powershell.wasm +0 -0
  292. package/wasm/tree-sitter-protobuf.wasm +0 -0
  293. package/wasm/tree-sitter-python.wasm +0 -0
  294. package/wasm/tree-sitter-ql.wasm +0 -0
  295. package/wasm/tree-sitter-r.wasm +0 -0
  296. package/wasm/tree-sitter-rescript.wasm +0 -0
  297. package/wasm/tree-sitter-ruby.wasm +0 -0
  298. package/wasm/tree-sitter-rust.wasm +0 -0
  299. package/wasm/tree-sitter-scala.wasm +0 -0
  300. package/wasm/tree-sitter-scss.wasm +0 -0
  301. package/wasm/tree-sitter-solidity.wasm +0 -0
  302. package/wasm/tree-sitter-sql.wasm +0 -0
  303. package/wasm/tree-sitter-svelte.wasm +0 -0
  304. package/wasm/tree-sitter-swift.wasm +0 -0
  305. package/wasm/tree-sitter-systemrdl.wasm +0 -0
  306. package/wasm/tree-sitter-terraform.wasm +0 -0
  307. package/wasm/tree-sitter-tlaplus.wasm +0 -0
  308. package/wasm/tree-sitter-toml.wasm +0 -0
  309. package/wasm/tree-sitter-tsx.wasm +0 -0
  310. package/wasm/tree-sitter-typescript.wasm +0 -0
  311. package/wasm/tree-sitter-vba.wasm +0 -0
  312. package/wasm/tree-sitter-vbnet.wasm +0 -0
  313. package/wasm/tree-sitter-vue.wasm +0 -0
  314. package/wasm/tree-sitter-xml.wasm +0 -0
  315. package/wasm/tree-sitter-yaml.wasm +0 -0
  316. package/wasm/tree-sitter-zig.wasm +0 -0
  317. package/wasm/tree-sitter.wasm +0 -0
  318. package/wasm/tsx.wasm +0 -0
  319. package/wasm/typescript.wasm +0 -0
@@ -0,0 +1,3298 @@
1
+ import {
2
+ findDeclaringParent,
3
+ localEdgeLabel,
4
+ localEdgeName
5
+ } from "./chunk-OWISBAOF.js";
6
+ import {
7
+ ASTEngine
8
+ } from "./chunk-V44PGPA6.js";
9
+ import "./chunk-BQ3OVQ3P.js";
10
+ import "./chunk-SK6YVHFZ.js";
11
+ import "./chunk-2BSKD7O3.js";
12
+ import "./chunk-KAET47ZL.js";
13
+ import "./chunk-KCDECRJY.js";
14
+ import "./chunk-MLKGABMK.js";
15
+
16
+ // src/ast/real-csharp-analyzer.ts
17
+ function csharpCleanTypeLeaf(text) {
18
+ const lt = text.indexOf("<");
19
+ const base = lt > 0 ? text.slice(0, lt) : text;
20
+ const q = base.indexOf("?");
21
+ const noQ = q > 0 ? base.slice(0, q) : base;
22
+ const br = noQ.indexOf("[");
23
+ return (br > 0 ? noQ.slice(0, br) : noQ).trim();
24
+ }
25
+ function isCSharpNameSeparator(ch) {
26
+ return ch === "." || ch === "<" || ch === ">" || ch === "," || ch === "[" || ch === "]";
27
+ }
28
+ function csharpTypeNameText(text) {
29
+ const out = [];
30
+ let pendingSpace = false;
31
+ for (let i = 0; i < text.length; i++) {
32
+ const ch = text[i];
33
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
34
+ if (out.length > 0) pendingSpace = true;
35
+ continue;
36
+ }
37
+ if (pendingSpace) {
38
+ const last = out[out.length - 1];
39
+ if (!isCSharpNameSeparator(last) && !isCSharpNameSeparator(ch)) out.push(" ");
40
+ pendingSpace = false;
41
+ }
42
+ out.push(ch);
43
+ }
44
+ return out.join("");
45
+ }
46
+ var CSHARP_DECLARED_TYPE_NODES = /* @__PURE__ */ new Set([
47
+ "identifier",
48
+ "generic_name",
49
+ "qualified_name",
50
+ "predefined_type",
51
+ "array_type",
52
+ "pointer_type",
53
+ "nullable_type",
54
+ "ref_type",
55
+ "tuple_type",
56
+ // C2a: a `global::`-qualified name with a SINGLE segment is an `alias_qualified_name` — the
57
+ // grammar only wraps it in a `qualified_name` when the path has a dot after the qualifier. The
58
+ // set's two consumers are the return-type and indexer-type fallback scans, so without this the
59
+ // declared-type graph lost the dependency for exactly the qualified spelling it exists to
60
+ // normalise (measured: `public global::Root RetAlias()` published NO `return_type` ref while
61
+ // `public Root RetPlain()` published one — script/m14/tmp/cs-alias-position-battery3.ts).
62
+ "alias_qualified_name"
63
+ ]);
64
+ var CSHARP_SYMBOL_DECLARATIONS = /* @__PURE__ */ new Set([
65
+ "namespace_declaration",
66
+ "file_scoped_namespace_declaration",
67
+ "class_declaration",
68
+ "struct_declaration",
69
+ "interface_declaration",
70
+ "record_declaration",
71
+ "enum_declaration",
72
+ "enum_member_declaration",
73
+ "delegate_declaration",
74
+ "event_declaration",
75
+ "operator_declaration",
76
+ "conversion_operator_declaration",
77
+ "method_declaration",
78
+ "constructor_declaration",
79
+ "property_declaration",
80
+ "indexer_declaration"
81
+ ]);
82
+ function csharpMemberDeclaredTypeText(memberLike) {
83
+ const TYPES = CSHARP_DECLARED_TYPE_NODES;
84
+ const resolveHolder = (holder2, nameFieldChild2) => {
85
+ const tf = holder2?.childForFieldName?.("type");
86
+ if (tf) return String(tf.text ?? "").trim();
87
+ for (const c of holder2?.namedChildren ?? []) {
88
+ if (!c || !TYPES.has(c.type)) continue;
89
+ if (nameFieldChild2 && c.startIndex === nameFieldChild2.startIndex && c.endIndex === nameFieldChild2.endIndex) continue;
90
+ return String(c.text ?? "").trim();
91
+ }
92
+ return null;
93
+ };
94
+ if (memberLike.type === "field_declaration") {
95
+ const vd = memberLike.namedChildren?.find((c) => c.type === "variable_declaration");
96
+ if (vd) {
97
+ const t = resolveHolder(vd, null);
98
+ if (t) return t;
99
+ }
100
+ }
101
+ if (memberLike.type === "variable_declarator") {
102
+ const parentDecl = memberLike.parent;
103
+ if (parentDecl && parentDecl.type === "variable_declaration") {
104
+ const t = resolveHolder(parentDecl, null);
105
+ if (t) return t;
106
+ }
107
+ }
108
+ const nameFieldChild = memberLike.childForFieldName?.("name") ?? null;
109
+ const holder = memberLike.type === "field_declaration" ? memberLike.namedChildren?.find((c) => c.type === "variable_declaration") : memberLike;
110
+ return resolveHolder(holder, nameFieldChild);
111
+ }
112
+ function csharpTargetTypedNewSite(nodeLike) {
113
+ let isElement = false;
114
+ let cur = nodeLike.parent;
115
+ while (cur) {
116
+ if (cur.type === "collection_expression" || cur.type === "collection_element" || cur.type === "expression_element" || cur.type === "initializer_expression" || cur.type === "array_creation_expression") {
117
+ isElement = isElement || cur.type === "collection_element" || cur.type === "expression_element" || cur.type === "collection_expression" || cur.type === "initializer_expression" || cur.type === "array_creation_expression";
118
+ }
119
+ if (cur.type === "object_creation_expression" || cur.type === "implicit_object_creation_expression" || cur.type === "anonymous_object_creation_expression") {
120
+ return null;
121
+ }
122
+ if (cur.type === "invocation_expression" || cur.type === "argument_list" || // ≡ /^(binary|conditional|prefix_unary|postfix_unary|cast|as_|await|coalesce|conditional_access|element_access|member_access)_expression$/ —
123
+ // anchored alternation over the fixed expression-node set: endsWith("_expression") + membership excludes arbitrary *_expression node types (equals-check per disjunct; as_* is startsWith).
124
+ CSHARP_TARGETISH_EXPRESSIONS.has(cur.type)) {
125
+ return null;
126
+ }
127
+ if (cur.type === "variable_declarator" || cur.type === "property_declaration" || cur.type === "indexer_declaration" || cur.type === "field_declaration") {
128
+ return { kind: "declaration", decl: cur, isElement };
129
+ }
130
+ if (cur.type === "assignment_expression") {
131
+ const lhs = cur.childForFieldName?.("left");
132
+ if (!lhs) return null;
133
+ const name = lhs.type === "identifier" ? lhs.text : lhs.childForFieldName?.("name")?.text ?? "";
134
+ return name ? { kind: "assignment", memberName: name, isElement } : null;
135
+ }
136
+ cur = cur.parent;
137
+ }
138
+ return null;
139
+ }
140
+ function csharpResolveTargetTypedNew(nodeLike, memberTypes) {
141
+ const site = csharpTargetTypedNewSite(nodeLike);
142
+ if (!site) return null;
143
+ if (site.kind === "declaration") {
144
+ const declared2 = csharpMemberDeclaredTypeText(site.decl);
145
+ if (!declared2) return null;
146
+ if (declared2 === "var") return null;
147
+ return csharpTargetFromDeclaredType(declared2, site.isElement);
148
+ }
149
+ const declared = memberTypes?.get(site.memberName);
150
+ return declared ? csharpTargetFromDeclaredType(declared, site.isElement) : null;
151
+ }
152
+ function csharpTargetFromDeclaredType(typeText, isElement) {
153
+ let t = csharpTypeSpelling(typeText).trim();
154
+ if (t === "var") return "";
155
+ if (t.endsWith("?")) t = t.slice(0, -1).trim();
156
+ if (isElement) {
157
+ const br = t.indexOf("[");
158
+ if (br > 0) return csharpCleanTypeLeaf(t.slice(0, br));
159
+ const lt = t.indexOf("<");
160
+ if (lt > 0 && t.endsWith(">")) {
161
+ const inner = t.slice(lt + 1, -1);
162
+ const first = inner.split(",")[0].trim();
163
+ return csharpCleanTypeLeaf(first);
164
+ }
165
+ return csharpCleanTypeLeaf(t);
166
+ }
167
+ return csharpCleanTypeLeaf(t);
168
+ }
169
+ var CSHARP_KEYWORDS = /* @__PURE__ */ new Set([
170
+ "if",
171
+ "for",
172
+ "foreach",
173
+ "while",
174
+ "do",
175
+ "switch",
176
+ "case",
177
+ "else",
178
+ "return",
179
+ "throw",
180
+ "using",
181
+ "new",
182
+ "delegate",
183
+ "in",
184
+ "is",
185
+ "as",
186
+ "sizeof",
187
+ "fixed",
188
+ "lock",
189
+ "checked",
190
+ "unchecked",
191
+ "params",
192
+ "ref",
193
+ "out",
194
+ "base",
195
+ "this",
196
+ // CS-B2 (csharp review): `nameof(x)` parses as an invocation_expression
197
+ // with an identifier callee — without this entry every nameof site
198
+ // fabricated a `calls -> nameof` edge (probe-verified). `typeof`/`default`
199
+ // never parse as invocations (dedicated nodes), so only nameof belongs.
200
+ "get",
201
+ "set",
202
+ "nameof"
203
+ ]);
204
+ var CSHARP_TARGETISH_EXPRESSIONS = /* @__PURE__ */ new Set([
205
+ "binary_expression",
206
+ "conditional_expression",
207
+ "prefix_unary_expression",
208
+ "postfix_unary_expression",
209
+ "cast_expression",
210
+ "as_expression",
211
+ "await_expression",
212
+ "coalesce_expression",
213
+ "conditional_access_expression",
214
+ "element_access_expression",
215
+ "member_access_expression"
216
+ ]);
217
+ var CSHARP_BUILTINS = /* @__PURE__ */ new Set([
218
+ // Console output — filtered (like Java's System.out.println)
219
+ "Console.WriteLine",
220
+ "Console.Write",
221
+ "Console.WriteAsync",
222
+ "Console.Error.WriteLine",
223
+ "Console.Error.Write",
224
+ "Console.Error.WriteAsync",
225
+ "Console.Out.WriteLine",
226
+ "Console.Out.Write",
227
+ "Console.Out.WriteAsync",
228
+ // System-level noise
229
+ "Environment.Exit",
230
+ "Environment.GetEnvironmentVariable",
231
+ "Environment.GetEnvironmentVariables",
232
+ "Environment.SetEnvironmentVariable",
233
+ "GC.Collect",
234
+ "GC.SuppressFinalize",
235
+ "GC.WaitForPendingFinalizers",
236
+ "Debug.WriteLine",
237
+ "Debug.Write",
238
+ "Debug.Print",
239
+ "Trace.WriteLine",
240
+ "Trace.Write",
241
+ // Object methods (C# equivalent of Java's Object methods)
242
+ "ToString",
243
+ "GetHashCode",
244
+ "Equals",
245
+ "GetType",
246
+ "ReferenceEquals"
247
+ ]);
248
+ function csharpUsingDirectiveTarget(node) {
249
+ if (!node) return null;
250
+ if (node.hasError) return null;
251
+ const firstNamed = (pred) => {
252
+ for (let i = 0; i < node.namedChildCount; i++) {
253
+ const c = node.namedChild(i);
254
+ if (c && pred(c)) return c;
255
+ }
256
+ return null;
257
+ };
258
+ const nameNode = firstNamed((n) => n.type === "identifier" || n.type === "qualified_name" || n.type === "alias_qualified_name");
259
+ if (!nameNode) return null;
260
+ let eq = null;
261
+ for (let i = 0; i < node.childCount; i++) {
262
+ const c = node.child(i);
263
+ if (c && c.type === "=") {
264
+ eq = c;
265
+ break;
266
+ }
267
+ }
268
+ const aliasNode = eq ? node.childForFieldName?.("name") ?? null : null;
269
+ let targetAfterEq = null;
270
+ if (eq) {
271
+ for (let i = 0; i < node.namedChildCount; i++) {
272
+ const c = node.namedChild(i);
273
+ if (c && c.startIndex >= eq.endIndex) {
274
+ targetAfterEq = c;
275
+ break;
276
+ }
277
+ }
278
+ }
279
+ const targetNode = targetAfterEq ?? firstNamed((n) => n.type === "qualified_name" || n.type === "alias_qualified_name") ?? nameNode;
280
+ const spelled = csharpTypeNameText(csharpTypeSpelling(String(targetNode?.text ?? "")));
281
+ const module = csharpCleanTypeLeaf(spelled);
282
+ if (!module) return null;
283
+ return {
284
+ module: csharpUsingDirectiveModule(targetNode, module),
285
+ typeArguments: csharpTypeExpressionArguments(targetNode),
286
+ targetNode,
287
+ alias: aliasNode ? csharpTypeNameText(String(aliasNode.text ?? "")) : null,
288
+ kind: csharpUsingDirectiveKind(node, aliasNode != null)
289
+ };
290
+ }
291
+ function csharpUsingDirectiveModule(targetNode, fallback) {
292
+ if (targetNode?.type !== "tuple_type") return fallback;
293
+ const parts = [];
294
+ for (const el of targetNode.namedChildren ?? []) {
295
+ if (el?.type !== "tuple_element") continue;
296
+ const ty = el.childForFieldName?.("type") ?? el.namedChild(0);
297
+ if (!ty) continue;
298
+ const leaf = csharpCleanTypeLeaf(csharpTypeNameText(csharpTypeSpelling(String(ty.text ?? ""))));
299
+ if (leaf) parts.push(leaf);
300
+ }
301
+ return parts.length ? `(${parts.join(",")})` : fallback;
302
+ }
303
+ function csharpUsingDirectiveKind(node, hasAlias) {
304
+ let isGlobal = false;
305
+ let isStatic = false;
306
+ for (let i = 0; i < (node?.childCount ?? 0); i++) {
307
+ const c = node.child(i);
308
+ if (!c || c.isNamed) continue;
309
+ if (c.type === "global") isGlobal = true;
310
+ else if (c.type === "static") isStatic = true;
311
+ }
312
+ if (hasAlias) return isGlobal ? "global_alias" : "alias";
313
+ if (isStatic) return isGlobal ? "global_static" : "static";
314
+ return isGlobal ? "global_namespace" : "namespace";
315
+ }
316
+ function csharpTypeExpressionArguments(targetNode) {
317
+ if (!targetNode) return [];
318
+ const out = [];
319
+ const seen = /* @__PURE__ */ new Set();
320
+ const add = (raw) => {
321
+ const name = csharpCleanTypeLeaf(csharpTypeNameText(csharpTypeSpelling(raw)));
322
+ if (!name || name === "var" || name === "dynamic" || name === "nint" || name === "nuint") return;
323
+ if (seen.has(name)) return;
324
+ seen.add(name);
325
+ out.push(name);
326
+ };
327
+ const walkArgument = (n) => {
328
+ if (!n) return;
329
+ const t = n.type;
330
+ if (t === "predefined_type" || t === "implicit_type" || t === "void_keyword") return;
331
+ if (t === "identifier") {
332
+ add(String(n.text ?? ""));
333
+ return;
334
+ }
335
+ if (t === "tuple_type") {
336
+ for (const el of n.namedChildren ?? []) {
337
+ if (el.type !== "tuple_element") continue;
338
+ walkArgument(el.childForFieldName?.("type") ?? el.namedChild(0));
339
+ }
340
+ return;
341
+ }
342
+ if (t === "generic_name") {
343
+ const base = n.namedChild(0);
344
+ if (base) walkArgument(base);
345
+ const args = (n.namedChildren ?? []).find((c) => c.type === "type_argument_list");
346
+ if (args) for (const a of args.namedChildren ?? []) walkArgument(a);
347
+ return;
348
+ }
349
+ if (t === "qualified_name" || t === "alias_qualified_name") {
350
+ const leaf = csharpTypeLeafNode(n);
351
+ if (leaf) {
352
+ add(String(leaf.text ?? ""));
353
+ const owner = n.namedChild(n.namedChildCount - 1);
354
+ if (owner && owner.type === "generic_name") {
355
+ const args = (owner.namedChildren ?? []).find((c) => c.type === "type_argument_list");
356
+ if (args) for (const a of args.namedChildren ?? []) walkArgument(a);
357
+ }
358
+ }
359
+ return;
360
+ }
361
+ for (const c of n.namedChildren ?? []) walkArgument(c);
362
+ };
363
+ const collectFromTarget = (n) => {
364
+ if (!n) return;
365
+ const t = n.type;
366
+ if (t === "generic_name") {
367
+ const args = (n.namedChildren ?? []).find((c) => c.type === "type_argument_list");
368
+ if (args) for (const a of args.namedChildren ?? []) walkArgument(a);
369
+ return;
370
+ }
371
+ if (t === "qualified_name" || t === "alias_qualified_name") {
372
+ const last = n.namedChild(n.namedChildCount - 1);
373
+ if (last && last.type === "generic_name") collectFromTarget(last);
374
+ return;
375
+ }
376
+ if (t === "array_type" || t === "pointer_type" || t === "nullable_type" || t === "ref_type") {
377
+ const inner = n.namedChild(0);
378
+ if (inner) collectFromTarget(inner);
379
+ return;
380
+ }
381
+ if (t === "tuple_type") {
382
+ for (const el of n.namedChildren ?? []) {
383
+ if (el.type !== "tuple_element") continue;
384
+ collectFromTarget(el.childForFieldName?.("type") ?? el.namedChild(0));
385
+ }
386
+ }
387
+ };
388
+ collectFromTarget(targetNode);
389
+ return out;
390
+ }
391
+ var CSHARP_BUILTIN_TYPE_SPELLINGS = /* @__PURE__ */ new Set(["dynamic", "nint", "nuint", "var"]);
392
+ var CSHARP_RENDER_HOSTS = /* @__PURE__ */ new Set(["RenderComponent", "RenderChild"]);
393
+ var DOTNET_CITATION_ROOTS = [
394
+ "System.Text.Json",
395
+ "Newtonsoft.Json",
396
+ "System.Xml",
397
+ "System.Net.Http.Json",
398
+ "Microsoft.AspNetCore.Http.Json",
399
+ "BenchmarkDotNet.Exporters.Csv",
400
+ "BenchmarkDotNet.Exporters.Json"
401
+ ];
402
+ function dotnetCitationRoots(target) {
403
+ const t = String(target ?? "");
404
+ if (t.length === 0) return [];
405
+ return DOTNET_CITATION_ROOTS.filter((root) => t === root || t.startsWith(`${root}.`));
406
+ }
407
+ var CSHARP_CALLABLE_DECLARATIONS = /* @__PURE__ */ new Set([
408
+ "method_declaration",
409
+ "constructor_declaration",
410
+ "delegate_declaration",
411
+ "operator_declaration",
412
+ "conversion_operator_declaration",
413
+ "local_function_statement"
414
+ ]);
415
+ var CSHARP_TYPE_DECLARATIONS = /* @__PURE__ */ new Set([
416
+ "class_declaration",
417
+ "struct_declaration",
418
+ "interface_declaration",
419
+ "record_declaration",
420
+ "enum_declaration"
421
+ ]);
422
+ function csharpTypeSpelling(text) {
423
+ const GLOBAL = "global";
424
+ if (text.length <= GLOBAL.length + 2) return text;
425
+ for (let i2 = 0; i2 < GLOBAL.length; i2++) {
426
+ if (text.charCodeAt(i2) !== GLOBAL.charCodeAt(i2)) return text;
427
+ }
428
+ const isWs = (c) => c === 32 || c === 9 || c === 10 || c === 13;
429
+ let i = GLOBAL.length;
430
+ while (i < text.length && isWs(text.charCodeAt(i))) i++;
431
+ if (text.charCodeAt(i) !== 58 || text.charCodeAt(i + 1) !== 58) return text;
432
+ i += 2;
433
+ while (i < text.length && isWs(text.charCodeAt(i))) i++;
434
+ return i < text.length ? text.slice(i) : text;
435
+ }
436
+ function csharpTypeDeclarationKind(node) {
437
+ switch (node.type) {
438
+ case "class_declaration":
439
+ return ASTEngine.SymbolKind.Class;
440
+ case "record_declaration": {
441
+ for (let i = 0; i < node.childCount; i++) {
442
+ const c = node.child(i);
443
+ if (c && !c.isNamed && c.type === "struct") return ASTEngine.SymbolKind.Struct;
444
+ }
445
+ return ASTEngine.SymbolKind.Class;
446
+ }
447
+ case "struct_declaration":
448
+ return ASTEngine.SymbolKind.Struct;
449
+ case "interface_declaration":
450
+ return ASTEngine.SymbolKind.Interface;
451
+ case "enum_declaration":
452
+ return ASTEngine.SymbolKind.Enum;
453
+ default:
454
+ return null;
455
+ }
456
+ }
457
+ function csharpTypeLeafNode(n) {
458
+ if (!n) return void 0;
459
+ const t = n.type;
460
+ if (t === "identifier") return n;
461
+ if (t === "generic_name" || t === "primary_constructor_base_type") return csharpTypeLeafNode(n.namedChild(0));
462
+ if (t === "qualified_name" || t === "alias_qualified_name") return csharpTypeLeafNode(n.namedChild(n.namedChildCount - 1));
463
+ return void 0;
464
+ }
465
+ function csharpDeclaredTypeLeaves(typeRoot, isBoundTypeParameter) {
466
+ const acc = [];
467
+ const accept = (node, raw) => {
468
+ const name = raw.trim();
469
+ if (!name || CSHARP_BUILTIN_TYPE_SPELLINGS.has(name)) return;
470
+ if (isBoundTypeParameter(node, name)) return;
471
+ acc.push({ node, name });
472
+ };
473
+ const walk = (n) => {
474
+ if (!n) return;
475
+ const t = n.type;
476
+ if (t === "predefined_type" || t === "implicit_type" || t === "void_keyword") return;
477
+ if (t === "identifier") {
478
+ accept(n, String(n.text ?? ""));
479
+ return;
480
+ }
481
+ if (t === "qualified_name" || t === "alias_qualified_name") {
482
+ const leaf = csharpTypeLeafNode(n);
483
+ if (leaf) accept(leaf, String(leaf.text ?? ""));
484
+ const lastSegment = n.namedChild(n.namedChildCount - 1);
485
+ if (lastSegment && lastSegment.type === "generic_name") {
486
+ const args = lastSegment.namedChildren.find((c) => c.type === "type_argument_list");
487
+ if (args) for (const a of args.namedChildren) walk(a);
488
+ }
489
+ return;
490
+ }
491
+ if (t === "generic_name" || t === "primary_constructor_base_type") {
492
+ walk(n.namedChild(0));
493
+ const args = n.namedChildren.find((c) => c.type === "type_argument_list");
494
+ if (args) for (const a of args.namedChildren) walk(a);
495
+ return;
496
+ }
497
+ if (t === "tuple_element") {
498
+ walk(n.childForFieldName("type") ?? n.namedChild(0));
499
+ return;
500
+ }
501
+ for (const c of n.namedChildren) walk(c);
502
+ };
503
+ walk(typeRoot);
504
+ return acc;
505
+ }
506
+ function csharpDeclaredTypeRefs(root) {
507
+ const out = [];
508
+ const emitted = /* @__PURE__ */ new Set();
509
+ const isBoundTypeParameter = (from, name) => {
510
+ let cur = from;
511
+ while (cur) {
512
+ if (cur.type === "class_declaration" || cur.type === "struct_declaration" || cur.type === "interface_declaration" || cur.type === "record_declaration" || cur.type === "method_declaration" || cur.type === "delegate_declaration" || cur.type === "local_function_statement" || cur.type === "operator_declaration" || cur.type === "conversion_operator_declaration") {
513
+ const tp = cur.childForFieldName("type_parameters") ?? cur.namedChildren.find((c) => c.type === "type_parameter_list");
514
+ if (tp) {
515
+ const w = [tp];
516
+ while (w.length > 0) {
517
+ const m = w.pop();
518
+ if ((m.type === "type_parameter" || m.type === "identifier") && m.text.trim() === name) return true;
519
+ for (const c of m.namedChildren) w.push(c);
520
+ }
521
+ }
522
+ }
523
+ cur = cur.parent;
524
+ }
525
+ return false;
526
+ };
527
+ const enclosing = (from, kinds) => {
528
+ let cur = from.parent;
529
+ while (cur) {
530
+ if (kinds.has(cur.type)) {
531
+ const nm = cur.childForFieldName("name")?.text;
532
+ if (nm) return nm;
533
+ }
534
+ cur = cur.parent;
535
+ }
536
+ return "";
537
+ };
538
+ const push = (source, typeNode, relationshipType, declaredOn) => {
539
+ if (!source || !typeNode) return;
540
+ for (const leaf of csharpDeclaredTypeLeaves(typeNode, isBoundTypeParameter)) {
541
+ const line = leaf.node.startPosition.row + 1;
542
+ const key = `${source}\0${leaf.name}\0${line}`;
543
+ if (emitted.has(key)) continue;
544
+ emitted.add(key);
545
+ out.push({ source, target: leaf.name, line, relationshipType, declaredOn });
546
+ }
547
+ };
548
+ const typeRootOf = (n) => {
549
+ if (!n) return null;
550
+ const tf = n.childForFieldName("type");
551
+ if (tf) return tf;
552
+ if (n.type === "field_declaration" || n.type === "event_field_declaration") {
553
+ const vd = n.namedChildren.find((c) => c.type === "variable_declaration");
554
+ return vd ? typeRootOf(vd) : null;
555
+ }
556
+ return null;
557
+ };
558
+ const returnTypeNode = (n) => {
559
+ const tf = n.childForFieldName("type");
560
+ if (tf) return tf;
561
+ const nameChild = n.childForFieldName("name");
562
+ for (const c of n.namedChildren) {
563
+ if (c.type === "modifier" || c.type === "attribute_list" || c.type === "parameter_list" || c.type === "type_parameter_list" || c.type === "block" || c.type === "arrow_expression_clause" || c.type === "where_clause" || c.type === "constructor_initializer" || c.type === "type_parameter_constraints_clause") continue;
564
+ if (nameChild && c.startIndex === nameChild.startIndex && c.endIndex === nameChild.endIndex) continue;
565
+ if (CSHARP_DECLARED_TYPE_NODES.has(c.type)) return c;
566
+ }
567
+ return null;
568
+ };
569
+ const stack = [root];
570
+ while (stack.length > 0) {
571
+ const n = stack.pop();
572
+ switch (n.type) {
573
+ case "field_declaration":
574
+ case "event_field_declaration": {
575
+ const vd = n.namedChildren.find((c) => c.type === "variable_declaration");
576
+ push(enclosing(n, CSHARP_TYPE_DECLARATIONS), typeRootOf(vd), "declared_type", n.type);
577
+ break;
578
+ }
579
+ case "property_declaration":
580
+ case "indexer_declaration":
581
+ case "event_declaration": {
582
+ push(enclosing(n, CSHARP_TYPE_DECLARATIONS), typeRootOf(n), "declared_type", n.type);
583
+ break;
584
+ }
585
+ case "method_declaration":
586
+ case "delegate_declaration":
587
+ case "operator_declaration":
588
+ case "conversion_operator_declaration": {
589
+ const owner = n.childForFieldName("name")?.text ?? enclosing(n, CSHARP_TYPE_DECLARATIONS);
590
+ push(owner, returnTypeNode(n), "return_type", "return_type");
591
+ break;
592
+ }
593
+ case "parameter": {
594
+ push(enclosing(n, CSHARP_CALLABLE_DECLARATIONS), typeRootOf(n), "declared_type", "parameter");
595
+ break;
596
+ }
597
+ case "variable_declaration": {
598
+ if (n.parent?.type === "local_declaration_statement") {
599
+ push(
600
+ enclosing(n, CSHARP_CALLABLE_DECLARATIONS),
601
+ typeRootOf(n),
602
+ "declared_type",
603
+ "local_declaration_statement"
604
+ );
605
+ }
606
+ break;
607
+ }
608
+ }
609
+ for (const c of n.namedChildren) stack.push(c);
610
+ }
611
+ return out;
612
+ }
613
+ var RealCSharpAnalyzer = class {
614
+ analyze(rootNode, content, filePath, context) {
615
+ const symbols = [];
616
+ const relationships = [];
617
+ const imports = [];
618
+ const exports = [];
619
+ const errors = [];
620
+ const symbolMap = /* @__PURE__ */ new Map();
621
+ const classHierarchy = /* @__PURE__ */ new Map();
622
+ const overrideTasks = [];
623
+ const interfaceTasks = [];
624
+ const interfaceMembers = /* @__PURE__ */ new Map();
625
+ const classMembers = /* @__PURE__ */ new Map();
626
+ const typeKinds = /* @__PURE__ */ new Map();
627
+ this.collectDeclaredTypeKinds(rootNode, typeKinds);
628
+ const memberTypes = /* @__PURE__ */ new Map();
629
+ const memberTypeNodes = /* @__PURE__ */ new Map();
630
+ this.collectMemberTypes(rootNode, memberTypes, memberTypeNodes);
631
+ const scopeStack = [];
632
+ let fileScopedNamespace = void 0;
633
+ const stack = [{ node: rootNode }];
634
+ let cyclomaticComplexity = 1;
635
+ while (stack.length > 0) {
636
+ const item = stack.pop();
637
+ const { node, parentContext, isExit } = item;
638
+ if (isExit) {
639
+ if (parentContext) {
640
+ if (scopeStack.length > 0 && scopeStack[scopeStack.length - 1] === parentContext) {
641
+ scopeStack.pop();
642
+ }
643
+ }
644
+ continue;
645
+ }
646
+ if (node.isMissing || node.hasError) {
647
+ if (node.type === "ERROR" || node.type === "MISSING") {
648
+ errors.push({
649
+ message: `Syntax ${node.type} detected.`,
650
+ range: this.nodeToRange(node),
651
+ severity: "warning"
652
+ });
653
+ }
654
+ }
655
+ let newContext = parentContext;
656
+ const type = node.type;
657
+ let pushedScope = false;
658
+ const complexityNodes = /* @__PURE__ */ new Set([
659
+ "if_statement",
660
+ "for_statement",
661
+ "foreach_statement",
662
+ "while_statement",
663
+ // CS-B3 (csharp review): BOTH catch forms parse as `catch_clause`
664
+ // (which CONTAINS an optional `catch_declaration`) — counting the
665
+ // inner declaration counted typed catches but never bare `catch { }`.
666
+ // Count the clause instead (exactly once either way); matches
667
+ // swift's catch_block.
668
+ "case_switch_label",
669
+ "catch_clause",
670
+ "conditional_expression",
671
+ "logical_and_expression",
672
+ "logical_or_expression",
673
+ // CSD2 (re-review 2026-09-04, probe): switch EXPRESSION arms are
674
+ // decision points exactly like case labels — a 3-arm switch
675
+ // expression measured complexity 1 (its legacy statement twin
676
+ // counted every case_switch_label). 42 arms in the first 400 corpus
677
+ // files were systematically undercounted.
678
+ "switch_expression_arm"
679
+ ]);
680
+ if (complexityNodes.has(type)) cyclomaticComplexity++;
681
+ if (type === "using_directive") {
682
+ const nameNode = this.findChild(
683
+ node,
684
+ (n) => n.type === "identifier" || n.type === "qualified_name" || n.type === "alias_qualified_name"
685
+ );
686
+ if (nameNode) {
687
+ const usingTarget = csharpUsingDirectiveTarget(node);
688
+ if (!usingTarget) {
689
+ if (node.hasError) {
690
+ errors.push({
691
+ message: "Syntax ERROR detected in using directive.",
692
+ range: this.nodeToRange(node),
693
+ severity: "warning"
694
+ });
695
+ }
696
+ continue;
697
+ }
698
+ const { module: text, typeArguments, targetNode: nameNode2, alias: usingAlias, kind: usingKind } = usingTarget;
699
+ imports.push({
700
+ module: text,
701
+ source: text,
702
+ imported: [],
703
+ range: this.nodeToRange(node),
704
+ isTypeOnly: false
705
+ });
706
+ relationships.push({
707
+ source: "root",
708
+ target: text,
709
+ type: ASTEngine.RelationshipType.References,
710
+ confidence: 0.9,
711
+ // M59.A7 (#825): the line of the node that NAMES the target — the
712
+ // qualified_name / identifier the using directive writes, which for
713
+ // the alias form (`using A = B.C;`) is the TARGET, never the alias.
714
+ // `nodeNamingToken` descends to the last segment's own node, so a
715
+ // WRAPPED qualified name stamps the line its leaf is written on
716
+ // rather than the line the name starts on.
717
+ line_number: this.nodeLine(this.nodeNamingToken(nameNode2, text) ?? nameNode2),
718
+ // isImport (family contract — c/go emit import deps with isImport)
719
+ // lets the completeness section-B `imports` pin and the tier
720
+ // classifier mark this import_based.
721
+ metadata: {
722
+ isUsingDirective: true,
723
+ isImport: true,
724
+ ...usingAlias ? { isUsingAlias: true, usingAlias } : {}
725
+ }
726
+ });
727
+ for (const arg of typeArguments) {
728
+ if (arg === text) continue;
729
+ relationships.push({
730
+ source: "root",
731
+ target: arg,
732
+ type: ASTEngine.RelationshipType.References,
733
+ confidence: 0.9,
734
+ line_number: this.nodeLine(this.nodeNamingToken(nameNode2, arg) ?? nameNode2),
735
+ metadata: { relationshipType: "using_type_argument" }
736
+ });
737
+ }
738
+ const citationRoots = dotnetCitationRoots(text);
739
+ relationships.push({
740
+ source: "root",
741
+ target: text,
742
+ type: ASTEngine.RelationshipType.Imports,
743
+ confidence: 1,
744
+ line_number: this.nodeLine(this.nodeNamingToken(nameNode2, text) ?? nameNode2),
745
+ metadata: {
746
+ isUsingDirective: true,
747
+ isImport: true,
748
+ relationshipType: "using_import",
749
+ importKind: usingKind,
750
+ ...usingAlias ? { isUsingAlias: true, usingAlias } : {},
751
+ ...citationRoots.length > 0 ? { languageNamespace: citationRoots, languageNamespacePolicy: "strict-absent" } : {}
752
+ }
753
+ });
754
+ }
755
+ }
756
+ if (type === "extern_alias_directive") {
757
+ const aliasNode = node.childForFieldName?.("name") ?? this.findChild(node, "identifier");
758
+ const aliasText = aliasNode ? csharpTypeNameText(String(aliasNode.text ?? "")) : "";
759
+ if (aliasText) {
760
+ imports.push({
761
+ module: aliasText,
762
+ source: aliasText,
763
+ imported: [],
764
+ range: this.nodeToRange(node),
765
+ isTypeOnly: false
766
+ });
767
+ relationships.push({
768
+ source: "root",
769
+ target: aliasText,
770
+ type: ASTEngine.RelationshipType.Imports,
771
+ confidence: 1,
772
+ line_number: this.nodeLine(aliasNode),
773
+ metadata: {
774
+ isImport: true,
775
+ isExternAlias: true,
776
+ relationshipType: "extern_alias_import",
777
+ importKind: "extern_alias"
778
+ }
779
+ });
780
+ }
781
+ }
782
+ if (type === "namespace_declaration") {
783
+ if (fileScopedNamespace) {
784
+ const fi = scopeStack.indexOf(fileScopedNamespace);
785
+ if (fi >= 0) scopeStack.splice(fi, 1);
786
+ fileScopedNamespace = void 0;
787
+ }
788
+ const rawName = this.extractNamespaceName(node);
789
+ const fullName = rawName.indexOf(".") >= 0 ? rawName : this.buildFullName(scopeStack, rawName);
790
+ symbols.push({
791
+ name: rawName,
792
+ kind: ASTEngine.SymbolKind.Namespace,
793
+ range: this.nodeToRange(node),
794
+ visibility: "public",
795
+ metadata: { isCSharpNamespace: true, fullName }
796
+ });
797
+ newContext = {
798
+ node,
799
+ name: rawName,
800
+ rawName,
801
+ kind: ASTEngine.SymbolKind.Namespace,
802
+ fqn: fullName,
803
+ visibility: "public",
804
+ isInterface: false,
805
+ parents: []
806
+ };
807
+ scopeStack.push(newContext);
808
+ pushedScope = true;
809
+ } else if (type === "file_scoped_namespace_declaration") {
810
+ if (fileScopedNamespace) {
811
+ const fi = scopeStack.indexOf(fileScopedNamespace);
812
+ if (fi >= 0) scopeStack.splice(fi, 1);
813
+ fileScopedNamespace = void 0;
814
+ }
815
+ const rawName = this.extractNamespaceName(node);
816
+ const fullName = rawName.indexOf(".") >= 0 ? rawName : this.buildFullName(scopeStack, rawName);
817
+ symbols.push({
818
+ name: rawName,
819
+ kind: ASTEngine.SymbolKind.Namespace,
820
+ range: this.nodeToRange(node),
821
+ visibility: "public",
822
+ metadata: { isCSharpNamespace: true, fullName, isFileScoped: true }
823
+ });
824
+ fileScopedNamespace = {
825
+ node,
826
+ name: rawName,
827
+ rawName,
828
+ kind: ASTEngine.SymbolKind.Namespace,
829
+ fqn: fullName,
830
+ visibility: "public",
831
+ isInterface: false,
832
+ parents: []
833
+ };
834
+ newContext = fileScopedNamespace;
835
+ scopeStack.push(newContext);
836
+ pushedScope = false;
837
+ } else if (type === "class_declaration" || type === "struct_declaration" || type === "interface_declaration" || type === "record_declaration") {
838
+ let rawName = node.childForFieldName("name")?.text || this.childText(node, "identifier") || "anonymous";
839
+ const fullName = this.buildFullName(scopeStack, rawName);
840
+ const isInterface = type === "interface_declaration";
841
+ const kind = csharpTypeDeclarationKind(node) ?? ASTEngine.SymbolKind.Class;
842
+ const visibility = this.extractVisibility(node);
843
+ typeKinds.set(rawName, kind);
844
+ const ownerScope = parentContext?.kind === ASTEngine.SymbolKind.Namespace ? parentContext : fileScopedNamespace && !parentContext ? fileScopedNamespace : void 0;
845
+ const parents = [];
846
+ const baseList = this.findChild(node, "base_list");
847
+ if (baseList) {
848
+ const baseTypes = [];
849
+ const baseNodes = [];
850
+ for (let i = 0; i < baseList.namedChildCount; i++) {
851
+ const baseType = baseList.namedChild(i);
852
+ if (!baseType) continue;
853
+ if (baseType.type === "primary_constructor_base_type") {
854
+ const tn = this.findChild(baseType, (n) => n.type === "identifier" || n.type === "generic_name");
855
+ if (tn) {
856
+ baseTypes.push(this.cleanTypeName(tn.text));
857
+ baseNodes.push(tn);
858
+ }
859
+ continue;
860
+ }
861
+ if (baseType.type === "argument_list") continue;
862
+ baseTypes.push(this.cleanTypeName(csharpTypeNameText(baseType.text)));
863
+ baseNodes.push(baseType);
864
+ }
865
+ if (isInterface) {
866
+ for (let i = 0; i < baseTypes.length; i++) {
867
+ const b = baseTypes[i];
868
+ parents.push(b);
869
+ relationships.push({
870
+ source: this.declarationPath(scopeStack, rawName),
871
+ target: b,
872
+ type: ASTEngine.RelationshipType.Extends,
873
+ confidence: 1,
874
+ line_number: this.nodeLine(this.nodeNamingToken(baseNodes[i], b) ?? baseNodes[i]),
875
+ metadata: { isInterfaceBase: true }
876
+ });
877
+ }
878
+ } else {
879
+ const crossFileKinds = context?.typeKinds;
880
+ for (let i = 0; i < baseTypes.length; i++) {
881
+ const b = baseTypes[i];
882
+ parents.push(b);
883
+ const dotIdx = b.lastIndexOf(".");
884
+ const leaf = dotIdx > 0 ? b.slice(dotIdx + 1) : b;
885
+ const declaredKind = typeKinds.get(b) || crossFileKinds?.get(b) || typeKinds.get(leaf) || crossFileKinds?.get(leaf);
886
+ const isStruct = kind === ASTEngine.SymbolKind.Struct;
887
+ const looksLikeInterface = !declaredKind && (isStruct || i === 0 && leaf.charCodeAt(0) === 73 && leaf.charCodeAt(1) >= 65 && leaf.charCodeAt(1) <= 90 && leaf.length > 2);
888
+ const isImplements = declaredKind === ASTEngine.SymbolKind.Interface || looksLikeInterface || i > 0 && !declaredKind;
889
+ relationships.push({
890
+ source: this.declarationPath(scopeStack, rawName),
891
+ target: b,
892
+ type: isImplements ? ASTEngine.RelationshipType.Implements : ASTEngine.RelationshipType.Extends,
893
+ confidence: 1,
894
+ // the leaf's own node: a wrapped qualified base writes its last
895
+ // segment on a different line than the name starts on
896
+ line_number: this.nodeLine(this.nodeNamingToken(baseNodes[i], b) ?? baseNodes[i]),
897
+ metadata: { isImplements }
898
+ });
899
+ }
900
+ }
901
+ }
902
+ classHierarchy.set(fullName, parents);
903
+ if (rawName !== fullName && !classHierarchy.has(rawName)) classHierarchy.set(rawName, parents);
904
+ const typeParamsNode = this.findChild(node, "type_parameter_list");
905
+ const genericTypes = [];
906
+ if (typeParamsNode) {
907
+ for (let i = 0; i < typeParamsNode.namedChildCount; i++) {
908
+ const child = typeParamsNode.namedChild(i);
909
+ if (child) genericTypes.push(child.text);
910
+ }
911
+ }
912
+ const isRecord = stringIncludes(type, "record");
913
+ const paramList = this.findChild(node, "parameter_list");
914
+ if (isRecord && paramList) {
915
+ for (let i = 0; i < paramList.namedChildCount; i++) {
916
+ const p = paramList.namedChild(i);
917
+ if (p && p.type === "parameter") {
918
+ const pName = p.childForFieldName("name")?.text || this.childText(p, "identifier") || "anonymous";
919
+ const pType = this.extractTypeString(p);
920
+ symbols.push({
921
+ name: pName,
922
+ kind: ASTEngine.SymbolKind.Property,
923
+ range: this.nodeToRange(p),
924
+ visibility: "public",
925
+ ownerName: rawName,
926
+ ownerKind: kind,
927
+ metadata: { hasGet: true, hasInit: true, dataType: pType, isRecordProperty: true }
928
+ });
929
+ }
930
+ }
931
+ }
932
+ const sym = {
933
+ name: rawName,
934
+ kind,
935
+ range: this.nodeToRange(node),
936
+ visibility,
937
+ ownerName: ownerScope ? ownerScope.rawName : parentContext?.rawName,
938
+ ownerKind: ownerScope ? ownerScope.kind : parentContext?.kind,
939
+ decorators: this.extractAttributes(node),
940
+ metadata: {
941
+ isCSharpType: true,
942
+ isStruct: kind === ASTEngine.SymbolKind.Struct,
943
+ isValueType: kind === ASTEngine.SymbolKind.Struct,
944
+ isRecord,
945
+ genericTypes: genericTypes.length > 0 ? genericTypes : void 0,
946
+ fullName,
947
+ isInterface
948
+ }
949
+ };
950
+ symbols.push(sym);
951
+ const exportTopLevel = (!parentContext || parentContext.kind === ASTEngine.SymbolKind.Namespace) && !this.hasModifier(node, "file") && visibility === "public";
952
+ if (exportTopLevel) {
953
+ this.pushExportInfo(exports, fullName, genericTypes.length, this.nodeLine(node.childForFieldName("name") ?? this.declarationNameNode(node)), kind, visibility);
954
+ }
955
+ newContext = {
956
+ node,
957
+ name: fullName,
958
+ rawName,
959
+ kind,
960
+ fqn: fullName,
961
+ visibility,
962
+ symbolRef: sym,
963
+ isInterface,
964
+ parents
965
+ };
966
+ scopeStack.push(newContext);
967
+ pushedScope = true;
968
+ } else if (type === "enum_declaration") {
969
+ const rawName = node.childForFieldName("name")?.text || this.childText(node, "identifier") || "anonymous";
970
+ const fullName = this.buildFullName(scopeStack, rawName);
971
+ const visibility = this.extractVisibility(node);
972
+ typeKinds.set(rawName, ASTEngine.SymbolKind.Enum);
973
+ const ownerScope = parentContext?.kind === ASTEngine.SymbolKind.Namespace ? parentContext : fileScopedNamespace && !parentContext ? fileScopedNamespace : void 0;
974
+ let baseType;
975
+ const baseList = this.findChild(node, "base_list");
976
+ if (baseList) baseType = baseList.namedChild(0)?.text;
977
+ symbols.push({
978
+ name: rawName,
979
+ kind: ASTEngine.SymbolKind.Enum,
980
+ range: this.nodeToRange(node),
981
+ visibility,
982
+ ownerName: ownerScope ? ownerScope.rawName : parentContext?.rawName,
983
+ ownerKind: ownerScope ? ownerScope.kind : parentContext?.kind,
984
+ decorators: this.extractAttributes(node),
985
+ metadata: { isEnum: true, baseType, fullName }
986
+ });
987
+ if ((!parentContext || parentContext.kind === ASTEngine.SymbolKind.Namespace) && visibility === "public") {
988
+ this.pushExportInfo(exports, fullName, 0, this.nodeLine(node.childForFieldName("name") ?? this.declarationNameNode(node)), ASTEngine.SymbolKind.Enum, visibility);
989
+ }
990
+ newContext = {
991
+ node,
992
+ name: rawName,
993
+ rawName,
994
+ kind: ASTEngine.SymbolKind.Enum,
995
+ fqn: fullName,
996
+ visibility,
997
+ isInterface: false,
998
+ parents: []
999
+ };
1000
+ scopeStack.push(newContext);
1001
+ pushedScope = true;
1002
+ } else if (type === "enum_member_declaration") {
1003
+ const name = node.childForFieldName("name")?.text || this.childText(node, "identifier") || "anonymous";
1004
+ symbols.push({
1005
+ name,
1006
+ kind: ASTEngine.SymbolKind.EnumMember,
1007
+ range: this.nodeToRange(node),
1008
+ visibility: "public",
1009
+ ownerName: parentContext?.rawName,
1010
+ ownerKind: parentContext?.kind,
1011
+ metadata: {}
1012
+ });
1013
+ } else if (type === "delegate_declaration") {
1014
+ const name = node.childForFieldName("name")?.text || this.childText(node, "identifier") || "anonymous";
1015
+ const returnType = node.childForFieldName("type")?.text || "void";
1016
+ const parameters = [];
1017
+ const paramList = this.findChild(node, "parameter_list");
1018
+ if (paramList) {
1019
+ for (let i = 0; i < paramList.namedChildCount; i++) {
1020
+ const parameter = paramList.namedChild(i);
1021
+ if (parameter?.type !== "parameter") continue;
1022
+ const parameterName = parameter.childForFieldName("name")?.text || "anonymous";
1023
+ parameters.push({ name: parameterName, type: parameter.childForFieldName("type")?.text });
1024
+ }
1025
+ }
1026
+ const visibility = this.extractVisibility(node);
1027
+ const ownerScope = parentContext?.kind === ASTEngine.SymbolKind.Namespace ? parentContext : fileScopedNamespace && !parentContext ? fileScopedNamespace : void 0;
1028
+ const delegateFullName = this.buildFullName(scopeStack, name);
1029
+ const delegateTypeParams = this.findChild(node, "type_parameter_list");
1030
+ const delegateArity = delegateTypeParams ? delegateTypeParams.namedChildCount : 0;
1031
+ symbols.push({
1032
+ name,
1033
+ kind: ASTEngine.SymbolKind.Delegate,
1034
+ range: this.nodeToRange(node),
1035
+ visibility,
1036
+ ownerName: ownerScope ? ownerScope.rawName : parentContext?.rawName,
1037
+ ownerKind: ownerScope ? ownerScope.kind : parentContext?.kind,
1038
+ parameters,
1039
+ returnType,
1040
+ decorators: this.extractAttributes(node),
1041
+ metadata: { isDelegate: true, returnType, fullName: delegateFullName, genericTypes: delegateArity > 0 ? delegateArity : void 0 }
1042
+ });
1043
+ if ((!parentContext || parentContext.kind === ASTEngine.SymbolKind.Namespace) && !this.hasModifier(node, "file") && visibility === "public") {
1044
+ this.pushExportInfo(exports, delegateFullName, delegateArity, this.nodeLine(node.childForFieldName("name") ?? this.declarationNameNode(node)), ASTEngine.SymbolKind.Delegate, visibility);
1045
+ }
1046
+ } else if (type === "event_field_declaration") {
1047
+ const varDecl = this.findChild(node, "variable_declaration");
1048
+ const visibility = this.extractVisibility(node);
1049
+ if (varDecl) {
1050
+ for (let i = 0; i < varDecl.namedChildCount; i++) {
1051
+ const child = varDecl.namedChild(i);
1052
+ if (child && child.type === "variable_declarator") {
1053
+ const name = this.childText(child, "identifier") || "anonymous";
1054
+ this.collectMemberContract(
1055
+ node,
1056
+ name,
1057
+ parentContext,
1058
+ parentContext ? parentContext.fqn : "",
1059
+ parentContext ? `${parentContext.rawName}.${name}` : name,
1060
+ interfaceTasks,
1061
+ interfaceMembers,
1062
+ classMembers,
1063
+ this.findChild(child, (n) => n.type === "identifier") ?? void 0
1064
+ );
1065
+ symbols.push({
1066
+ name,
1067
+ kind: ASTEngine.SymbolKind.Event,
1068
+ range: this.nodeToRange(node),
1069
+ visibility,
1070
+ ownerName: parentContext?.rawName,
1071
+ ownerKind: parentContext?.kind,
1072
+ decorators: this.extractAttributes(node),
1073
+ metadata: { isEvent: true }
1074
+ });
1075
+ if (this.hasModifier(node, "override")) {
1076
+ overrideTasks.push({
1077
+ fqn: parentContext ? `${parentContext.rawName}.${name}` : name,
1078
+ methodName: name,
1079
+ signature: "",
1080
+ memberKind: "event",
1081
+ ownerFqn: parentContext ? parentContext.fqn : "",
1082
+ line: this.nodeLine(this.findChild(child, (n) => n.type === "identifier") ?? child)
1083
+ });
1084
+ }
1085
+ }
1086
+ }
1087
+ }
1088
+ } else if (type === "operator_declaration" || type === "conversion_operator_declaration") {
1089
+ const opField = node.childForFieldName("operator");
1090
+ const convTargetNode = type === "conversion_operator_declaration" ? node.childForFieldName("type") : null;
1091
+ const modifierKeyword = this.anonymousChildNode(node, "implicit") ?? this.anonymousChildNode(node, "explicit");
1092
+ const checkedKeyword = this.anonymousChildNode(node, "checked");
1093
+ const opName = modifierKeyword ? `${modifierKeyword.type}${convTargetNode ? ` ${csharpTypeNameText(csharpTypeSpelling(convTargetNode.text))}` : ""}` : opField ? `operator ${checkedKeyword ? "checked " : ""}${opField.text}` : "operator";
1094
+ const visibility = this.extractVisibility(node);
1095
+ symbols.push({
1096
+ name: opName,
1097
+ kind: ASTEngine.SymbolKind.Method,
1098
+ range: this.nodeToRange(node),
1099
+ visibility,
1100
+ ownerName: parentContext?.rawName,
1101
+ ownerKind: parentContext?.kind,
1102
+ complexity: this.calculateCyclomaticComplexity(node),
1103
+ metadata: { isOperatorOverload: true, isConversionOperator: type === "conversion_operator_declaration" }
1104
+ });
1105
+ } else if (type === "event_declaration") {
1106
+ const nameNode = node.childForFieldName("name");
1107
+ const name = nameNode?.text || this.childText(node, "identifier") || "anonymous";
1108
+ const typeNode = this.findChild(
1109
+ node,
1110
+ (n) => n.type === "qualified_name" || (n.type === "identifier" || n.type === "generic_name") && n.id !== nameNode?.id
1111
+ );
1112
+ this.collectMemberContract(
1113
+ node,
1114
+ name,
1115
+ parentContext,
1116
+ parentContext ? parentContext.fqn : "",
1117
+ parentContext ? `${parentContext.rawName}.${name}` : name,
1118
+ interfaceTasks,
1119
+ interfaceMembers,
1120
+ classMembers
1121
+ );
1122
+ symbols.push({
1123
+ name,
1124
+ kind: ASTEngine.SymbolKind.Event,
1125
+ range: this.nodeToRange(node),
1126
+ visibility: this.extractVisibility(node),
1127
+ ownerName: parentContext?.rawName,
1128
+ ownerKind: parentContext?.kind,
1129
+ decorators: this.extractAttributes(node),
1130
+ metadata: { isEvent: true, isAccessorForm: true, dataType: typeNode?.text }
1131
+ });
1132
+ if (this.hasModifier(node, "override")) {
1133
+ overrideTasks.push({
1134
+ fqn: parentContext ? `${parentContext.rawName}.${name}` : name,
1135
+ methodName: name,
1136
+ signature: "",
1137
+ memberKind: "event",
1138
+ ownerFqn: parentContext ? parentContext.fqn : "",
1139
+ line: this.nodeLine(nameNode ?? this.declarationNameNode(node))
1140
+ });
1141
+ }
1142
+ } else if (type === "constructor_initializer") {
1143
+ const target = this.matchesBaseInitializer(node.text) ? "base" : "this";
1144
+ if (parentContext?.name) {
1145
+ relationships.push({
1146
+ source: parentContext.name === "constructor" ? parentContext.rawName || "constructor" : parentContext.name,
1147
+ target,
1148
+ type: ASTEngine.RelationshipType.Calls,
1149
+ confidence: 0.95,
1150
+ // M59.A7 (#825): the `base`/`this` KEYWORD, not the initializer: the
1151
+ // node starts at the `:` and a wrapped initializer writes the
1152
+ // keyword on the next line. Both tokens are anonymous children.
1153
+ line_number: this.nodeLine(this.initializerKeywordNode(node)),
1154
+ metadata: { isConstructorInitializer: true }
1155
+ });
1156
+ }
1157
+ } else if (type === "method_declaration" || type === "constructor_declaration" || type === "destructor_declaration") {
1158
+ let name = node.childForFieldName("name")?.text || this.childText(node, "identifier") || (type === "constructor_declaration" ? parentContext?.rawName : "anonymous") || "anonymous";
1159
+ if (type === "constructor_declaration") name = "constructor";
1160
+ if (type === "destructor_declaration") name = "Finalize";
1161
+ const visibility = this.extractVisibility(node);
1162
+ const returnType = type === "constructor_declaration" || type === "destructor_declaration" ? "void" : node.childForFieldName("type")?.text || this.extractTypeString(node) || "void";
1163
+ const parameters = [];
1164
+ let isExtensionMethod = false;
1165
+ let sigParams = "";
1166
+ const paramList = this.findChild(node, "parameter_list");
1167
+ if (paramList) {
1168
+ let inParamsForm = false;
1169
+ let paramsTypeNode = null;
1170
+ for (let i = 0; i < paramList.childCount; i++) {
1171
+ const child = paramList.child(i);
1172
+ if (!child) continue;
1173
+ const childType = child.type;
1174
+ if (childType === "params") {
1175
+ inParamsForm = true;
1176
+ paramsTypeNode = null;
1177
+ continue;
1178
+ }
1179
+ if (childType === "parameter") {
1180
+ inParamsForm = false;
1181
+ paramsTypeNode = null;
1182
+ const pName = child.childForFieldName("name")?.text || this.childText(child, "identifier") || "anonymous";
1183
+ const pTypeField = child.childForFieldName("type")?.text;
1184
+ let pType = pTypeField || this.extractTypeString(child) || void 0;
1185
+ if (!pTypeField && pType && pType === pName) pType = void 0;
1186
+ if (child.text.startsWith("this ")) isExtensionMethod = true;
1187
+ parameters.push(pType ? { name: pName, type: pType } : { name: pName });
1188
+ if (sigParams.length > 0) sigParams += ",";
1189
+ sigParams += pType ?? csharpTypeNameText(child.text);
1190
+ continue;
1191
+ }
1192
+ if (!inParamsForm) continue;
1193
+ if (!paramsTypeNode && CSHARP_DECLARED_TYPE_NODES.has(childType)) {
1194
+ paramsTypeNode = child;
1195
+ continue;
1196
+ }
1197
+ if (childType === "identifier" || childType === "generic_name" || childType === "qualified_name") {
1198
+ const pName = csharpTypeNameText(child.text);
1199
+ if (pName.length > 0) {
1200
+ const pType = paramsTypeNode ? csharpTypeNameText(paramsTypeNode.text) : void 0;
1201
+ parameters.push(pType ? { name: pName, type: pType } : { name: pName });
1202
+ if (sigParams.length > 0) sigParams += ",";
1203
+ sigParams += pType ?? pName;
1204
+ }
1205
+ inParamsForm = false;
1206
+ paramsTypeNode = null;
1207
+ }
1208
+ }
1209
+ }
1210
+ const signature = `(${sigParams})`;
1211
+ const ownerFqn = parentContext ? parentContext.fqn : "";
1212
+ const fqn = parentContext ? `${ownerFqn}.${name}${signature}` : `${name}${signature}`;
1213
+ const localOwnerPrefix = parentContext ? `${parentContext.rawName}.${name}${signature}` : `${name}${signature}`;
1214
+ const sym = {
1215
+ name,
1216
+ kind: type === "constructor_declaration" ? ASTEngine.SymbolKind.Constructor : ASTEngine.SymbolKind.Method,
1217
+ range: this.nodeToRange(node),
1218
+ visibility,
1219
+ ownerName: parentContext?.rawName,
1220
+ ownerKind: parentContext?.kind,
1221
+ parameters,
1222
+ returnType,
1223
+ decorators: this.extractAttributes(node),
1224
+ // Per-symbol cyclomatic complexity (family contract — JVM/rust/go/c
1225
+ // all emit symbol.complexity; csharp only had file-level complexity, so
1226
+ // the completeness section-C payload pin was impossible. Added csharp
1227
+ // #264 wave, same counter as the file-level one).
1228
+ complexity: this.calculateCyclomaticComplexity(node),
1229
+ metadata: {
1230
+ returnType,
1231
+ isExtensionMethod,
1232
+ isVirtual: this.hasModifier(node, "virtual"),
1233
+ isOverride: this.hasModifier(node, "override"),
1234
+ isAbstract: this.hasModifier(node, "abstract"),
1235
+ isStatic: this.hasModifier(node, "static")
1236
+ }
1237
+ };
1238
+ symbols.push(sym);
1239
+ symbolMap.set(fqn, sym);
1240
+ symbolMap.set(localOwnerPrefix, sym);
1241
+ this.collectMemberContract(node, name, parentContext, ownerFqn, localOwnerPrefix, interfaceTasks, interfaceMembers, classMembers);
1242
+ if (this.hasModifier(node, "override")) {
1243
+ overrideTasks.push({
1244
+ fqn: localOwnerPrefix,
1245
+ methodName: name,
1246
+ signature,
1247
+ memberKind: "method",
1248
+ ownerFqn,
1249
+ // M59.A7 (#825): the NAME node, not the declaration's start — an
1250
+ // attribute above the override would otherwise be the claimed site
1251
+ // of a name written on the next line.
1252
+ line: this.nodeLine(this.declarationNameNode(node))
1253
+ });
1254
+ }
1255
+ newContext = {
1256
+ node,
1257
+ name,
1258
+ rawName: name,
1259
+ kind: type === "constructor_declaration" ? ASTEngine.SymbolKind.Constructor : ASTEngine.SymbolKind.Method,
1260
+ fqn: ownerFqn,
1261
+ visibility,
1262
+ symbolRef: sym,
1263
+ isInterface: parentContext?.isInterface ?? false,
1264
+ parents: []
1265
+ };
1266
+ scopeStack.push(newContext);
1267
+ pushedScope = true;
1268
+ } else if (type === "invocation_expression") {
1269
+ let inPattern = false;
1270
+ {
1271
+ let q = node.parent;
1272
+ while (q) {
1273
+ const t = q.type;
1274
+ if (t === "constant_pattern" || t === "is_pattern_expression") {
1275
+ inPattern = true;
1276
+ break;
1277
+ }
1278
+ if (t === "invocation_expression" || t.includes("statement") || t.includes("declaration") || t.includes("block") || t.includes("function") || t === "lambda_expression" || t === "local_function_statement" || t === "query_expression" || t === "method_declaration" || t === "constructor_declaration") break;
1279
+ q = q.parent;
1280
+ }
1281
+ }
1282
+ if (inPattern) {
1283
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1284
+ const child = node.namedChild(i);
1285
+ if (child) stack.push({ node: child, parentContext: newContext });
1286
+ }
1287
+ continue;
1288
+ }
1289
+ const callExpr = this.buildCSharpCallExpression(node);
1290
+ const calleeNode = this.csharpCallCalleeNode(node);
1291
+ const enclosingKind = parentContext?.kind;
1292
+ const isCallSite = enclosingKind === ASTEngine.SymbolKind.Method || enclosingKind === ASTEngine.SymbolKind.Constructor || enclosingKind === ASTEngine.SymbolKind.Property || // Class-body expression contexts (field/type-member initializers and
1293
+ // attribute arguments) — csharp #264 Station-6: calls like
1294
+ // `Thread.AllocateDataSlot()`, `PSTraceSource.GetTracer(...)`,
1295
+ // `DependencyProperty.Register(...)` in static field initializers
1296
+ // live at class scope, so the enclosing context is the Class/Struct/
1297
+ // Interface, not a method. Previously dropped, the differential
1298
+ // oracle surfaced them ALL as MISSING (it derives every
1299
+ // invocation_expression leaf from `(expr)`).
1300
+ enclosingKind === ASTEngine.SymbolKind.Class || enclosingKind === ASTEngine.SymbolKind.Struct || enclosingKind === ASTEngine.SymbolKind.Interface;
1301
+ const callSource = parentContext?.rawName || "global";
1302
+ if (callExpr && callSource && (isCallSite || !parentContext)) {
1303
+ const target = String(callExpr.split(".").pop() || callExpr).split("<")[0];
1304
+ const isCSharpKeyword = CSHARP_KEYWORDS.has(target);
1305
+ if (!isCSharpKeyword && this.isPlainIdentifier(target) && !this.isCSharpBuiltin(callExpr) && this.isCSharpCalleeNameNode(calleeNode)) {
1306
+ relationships.push({
1307
+ source: callSource,
1308
+ target,
1309
+ type: ASTEngine.RelationshipType.Calls,
1310
+ confidence: 0.9,
1311
+ // M59.A7 (#825): the CALLEE LEAF, never the call node — an
1312
+ // invocation starts at its receiver, so `helper\n .Strip()`
1313
+ // would otherwise be stamped on the receiver's line.
1314
+ line_number: this.nodeLine(this.csharpCallCalleeNode(node)),
1315
+ metadata: { csharpCallExpression: callExpr }
1316
+ });
1317
+ }
1318
+ }
1319
+ {
1320
+ const fn = node.childForFieldName("function");
1321
+ const nameNode = fn && fn.type === "member_access_expression" ? fn.childForFieldName("name") : fn;
1322
+ if (nameNode && (nameNode.type === "generic_name" || nameNode.type === "identifier")) {
1323
+ const idNode = nameNode.type === "generic_name" ? nameNode.childForFieldName("name") ?? nameNode.namedChild(0) : nameNode;
1324
+ const host = (idNode?.text ?? "").split("<")[0];
1325
+ if (CSHARP_RENDER_HOSTS.has(host)) {
1326
+ const renderSource = parentContext?.rawName || "global";
1327
+ const tal = nameNode.type === "generic_name" ? nameNode.namedChildren.find((c) => c && c.type === "type_argument_list") : void 0;
1328
+ const typeArg = tal?.namedChild(0);
1329
+ if (typeArg) {
1330
+ relationships.push({
1331
+ source: renderSource,
1332
+ target: this.cleanTypeName(csharpTypeNameText(typeArg.text)),
1333
+ type: ASTEngine.RelationshipType.Renders,
1334
+ confidence: 0.9,
1335
+ line_number: this.nodeLine(typeArg),
1336
+ metadata: { isRenderHost: true, renderHost: host }
1337
+ });
1338
+ }
1339
+ const args = node.childForFieldName("arguments");
1340
+ const findTypeof = (n, depth) => {
1341
+ if (depth > 3) return null;
1342
+ for (let i = 0; i < n.namedChildCount; i++) {
1343
+ const c = n.namedChild(i);
1344
+ if (!c) continue;
1345
+ if (c.type === "typeof_expression") return c;
1346
+ const deeper = findTypeof(c, depth + 1);
1347
+ if (deeper) return deeper;
1348
+ }
1349
+ return null;
1350
+ };
1351
+ for (const a of args?.namedChildren ?? []) {
1352
+ if (!a) continue;
1353
+ const to = findTypeof(a, 0);
1354
+ if (!to) continue;
1355
+ const tn = this.findChild(to, (n) => n.type === "identifier" || n.type === "qualified_name" || n.type === "generic_name");
1356
+ if (!tn) continue;
1357
+ relationships.push({
1358
+ source: renderSource,
1359
+ target: this.cleanTypeName(csharpTypeNameText(tn.text)),
1360
+ type: ASTEngine.RelationshipType.Renders,
1361
+ confidence: 0.9,
1362
+ line_number: this.nodeLine(tn),
1363
+ metadata: { isRenderHost: true, renderHost: host }
1364
+ });
1365
+ }
1366
+ }
1367
+ }
1368
+ }
1369
+ } else if (type === "object_creation_expression") {
1370
+ const typeNode = this.findChild(
1371
+ node,
1372
+ (n) => n.type === "identifier" || n.type === "generic_name" || n.type === "qualified_name" || n.type === "predefined_type" || // C2a: `new global::Root()` — single-segment alias shape. Without this the edge was
1373
+ // not merely mis-spelled, it was ABSENT (measured: `new Root()` published
1374
+ // `instantiates -> Root` while `new global::Root()` published nothing).
1375
+ n.type === "alias_qualified_name"
1376
+ );
1377
+ if (typeNode) {
1378
+ const source = parentContext?.rawName || "global";
1379
+ relationships.push({
1380
+ source,
1381
+ target: this.cleanTypeName(typeNode.text),
1382
+ type: ASTEngine.RelationshipType.Instantiates,
1383
+ confidence: 0.95,
1384
+ line_number: this.nodeLine(typeNode),
1385
+ metadata: { isNew: true }
1386
+ });
1387
+ }
1388
+ } else if (type === "implicit_object_creation_expression") {
1389
+ const declaredType = this.resolveImplicitNewType(node, memberTypes);
1390
+ if (declaredType) {
1391
+ const source = parentContext?.rawName || "global";
1392
+ relationships.push({
1393
+ source,
1394
+ target: declaredType,
1395
+ type: ASTEngine.RelationshipType.Instantiates,
1396
+ confidence: 0.95,
1397
+ line_number: this.nodeLine(
1398
+ this.targetTypedNewTypeNode(node, memberTypes, memberTypeNodes, declaredType)
1399
+ ),
1400
+ metadata: { isNew: true, isImplicit: true }
1401
+ });
1402
+ }
1403
+ } else if (type === "property_declaration" || type === "indexer_declaration") {
1404
+ const name = type === "indexer_declaration" ? "this" : node.childForFieldName("name")?.text || this.childText(node, "identifier") || "anonymous";
1405
+ const dataType = this.extractTypeString(node);
1406
+ const visibility = this.extractVisibility(node);
1407
+ let hasGet = false;
1408
+ let hasSet = false;
1409
+ let hasInit = false;
1410
+ let isAutoProperty = false;
1411
+ const accessorList = this.findChild(node, "accessor_list");
1412
+ if (accessorList) {
1413
+ isAutoProperty = true;
1414
+ for (let i = 0; i < accessorList.namedChildCount; i++) {
1415
+ const acc = accessorList.namedChild(i);
1416
+ if (acc && acc.type === "accessor_declaration") {
1417
+ const accText = acc.text;
1418
+ if (stringIncludes(accText, "get")) hasGet = true;
1419
+ if (stringIncludes(accText, "set")) hasSet = true;
1420
+ if (stringIncludes(accText, "init")) hasInit = true;
1421
+ if (this.findChild(acc, "block") || this.findChild(acc, "arrow_expression_clause")) {
1422
+ isAutoProperty = false;
1423
+ }
1424
+ }
1425
+ }
1426
+ } else if (this.findChild(node, "arrow_expression_clause")) {
1427
+ hasGet = true;
1428
+ }
1429
+ symbols.push({
1430
+ name,
1431
+ kind: ASTEngine.SymbolKind.Property,
1432
+ range: this.nodeToRange(node),
1433
+ visibility,
1434
+ ownerName: parentContext?.rawName,
1435
+ ownerKind: parentContext?.kind,
1436
+ decorators: this.extractAttributes(node),
1437
+ complexity: this.calculateCyclomaticComplexity(node),
1438
+ metadata: { hasGet, hasSet, hasInit, isAutoProperty, dataType }
1439
+ });
1440
+ this.collectMemberContract(
1441
+ node,
1442
+ name,
1443
+ parentContext,
1444
+ parentContext ? parentContext.fqn : "",
1445
+ parentContext ? `${parentContext.rawName}.${name}` : name,
1446
+ interfaceTasks,
1447
+ interfaceMembers,
1448
+ classMembers
1449
+ );
1450
+ if (this.hasModifier(node, "override")) {
1451
+ overrideTasks.push({
1452
+ fqn: parentContext ? `${parentContext.rawName}.${name}` : name,
1453
+ methodName: name,
1454
+ signature: "",
1455
+ memberKind: type === "indexer_declaration" ? "indexer" : "property",
1456
+ ownerFqn: parentContext ? parentContext.fqn : "",
1457
+ line: this.nodeLine(this.declarationNameNode(node))
1458
+ });
1459
+ }
1460
+ newContext = {
1461
+ node,
1462
+ name,
1463
+ rawName: name,
1464
+ kind: ASTEngine.SymbolKind.Property,
1465
+ fqn: parentContext ? `${parentContext.fqn}.${name}` : name,
1466
+ visibility,
1467
+ symbolRef: symbols[symbols.length - 1],
1468
+ isInterface: parentContext?.isInterface ?? false,
1469
+ parents: []
1470
+ };
1471
+ scopeStack.push(newContext);
1472
+ pushedScope = true;
1473
+ } else if (type === "field_declaration") {
1474
+ const dataType = this.extractTypeString(node);
1475
+ const varDecl = this.findChild(node, "variable_declaration");
1476
+ const visibility = this.extractVisibility(node);
1477
+ if (varDecl) {
1478
+ for (let i = 0; i < varDecl.namedChildCount; i++) {
1479
+ const child = varDecl.namedChild(i);
1480
+ if (child && child.type === "variable_declarator") {
1481
+ const name = this.childText(child, "identifier") || "anonymous";
1482
+ symbols.push({
1483
+ name,
1484
+ kind: ASTEngine.SymbolKind.Property,
1485
+ range: this.nodeToRange(node),
1486
+ visibility,
1487
+ ownerName: parentContext?.rawName,
1488
+ ownerKind: parentContext?.kind,
1489
+ decorators: this.extractAttributes(node),
1490
+ metadata: { dataType, isField: true }
1491
+ });
1492
+ if (this.hasModifier(node, "override")) {
1493
+ const declNameNode = this.findChild(child, (n) => n.type === "identifier") ?? child;
1494
+ overrideTasks.push({
1495
+ fqn: parentContext ? `${parentContext.rawName}.${name}` : name,
1496
+ methodName: name,
1497
+ signature: "",
1498
+ memberKind: "field",
1499
+ ownerFqn: parentContext ? parentContext.fqn : "",
1500
+ line: this.nodeLine(declNameNode)
1501
+ });
1502
+ }
1503
+ }
1504
+ }
1505
+ }
1506
+ }
1507
+ if (pushedScope) {
1508
+ stack.push({ node, parentContext: newContext, isExit: true });
1509
+ }
1510
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1511
+ const child = node.namedChild(i);
1512
+ if (child) {
1513
+ stack.push({ node: child, parentContext: newContext });
1514
+ }
1515
+ }
1516
+ }
1517
+ const membersByOwner = /* @__PURE__ */ new Map();
1518
+ for (const sym of symbols) {
1519
+ if (!sym.ownerName || !sym.name) continue;
1520
+ let set = membersByOwner.get(sym.ownerName);
1521
+ if (!set) {
1522
+ set = /* @__PURE__ */ new Set();
1523
+ membersByOwner.set(sym.ownerName, set);
1524
+ }
1525
+ set.add(sym.name);
1526
+ }
1527
+ this.resolveOverrides(overrideTasks, classHierarchy, symbolMap, relationships, membersByOwner, context?.overrideCompanion);
1528
+ this.resolveInterfaceImplementations(interfaceTasks, classHierarchy, interfaceMembers, classMembers, relationships);
1529
+ const primaryType = symbols.find((s) => {
1530
+ if (s.kind === ASTEngine.SymbolKind.Namespace) return false;
1531
+ if (s.ownerKind && s.ownerKind !== ASTEngine.SymbolKind.Namespace) return false;
1532
+ return s.kind === ASTEngine.SymbolKind.Class || s.kind === ASTEngine.SymbolKind.Interface || s.kind === ASTEngine.SymbolKind.Enum || s.kind === ASTEngine.SymbolKind.Struct || s.kind === ASTEngine.SymbolKind.Delegate;
1533
+ });
1534
+ if (primaryType) {
1535
+ for (const rel of relationships) {
1536
+ if (rel.type === ASTEngine.RelationshipType.References && rel.source === "root") {
1537
+ rel.source = primaryType.name;
1538
+ }
1539
+ }
1540
+ }
1541
+ const containmentSites = this.collectContainmentSites(rootNode);
1542
+ for (const s of symbols) {
1543
+ const _owner = s.ownerName || s.scope;
1544
+ if (_owner) {
1545
+ relationships.push({
1546
+ source: _owner,
1547
+ target: s.name,
1548
+ type: ASTEngine.RelationshipType.Contains,
1549
+ confidence: 1,
1550
+ // M59.A7 (#825): the member's own declaration — but the line its NAME
1551
+ // is written on, which is NOT always the declaration's start line: an
1552
+ // attribute (`[Parameter]`) or a wrapped signature puts the name a
1553
+ // line or more later. Measured on a 200-file draw: the range-start
1554
+ // stamp claimed a line the target is not written on for 653 of 23,924
1555
+ // relationships, every one of them this shape.
1556
+ line_number: this.containmentLine(s, containmentSites),
1557
+ metadata: {}
1558
+ });
1559
+ }
1560
+ }
1561
+ for (const e of exports) {
1562
+ if (typeof e.name !== "string" || typeof e.arity !== "number") continue;
1563
+ relationships.push({
1564
+ source: "root",
1565
+ target: e.name,
1566
+ type: ASTEngine.RelationshipType.Exports,
1567
+ confidence: 1,
1568
+ line_number: typeof e.line === "number" ? e.line : void 0,
1569
+ metadata: {
1570
+ relationshipType: "assembly_public_surface",
1571
+ evidenceClass: "structural",
1572
+ exportForm: "public_top_level_type",
1573
+ visibility: "public",
1574
+ arity: e.arity
1575
+ }
1576
+ });
1577
+ }
1578
+ this.analyzeFieldAccessUses(rootNode, relationships, symbols);
1579
+ this.analyzeCSharpBareIdentifierUses(rootNode, relationships, symbols, classHierarchy);
1580
+ for (const ref of csharpDeclaredTypeRefs(rootNode)) {
1581
+ relationships.push({
1582
+ source: ref.source,
1583
+ target: ref.target,
1584
+ type: ASTEngine.RelationshipType.References,
1585
+ confidence: 0.9,
1586
+ ...ref.line ? { line_number: ref.line } : {},
1587
+ metadata: { relationshipType: ref.relationshipType, declaredOn: ref.declaredOn }
1588
+ });
1589
+ }
1590
+ this.classifyEvidenceTier(relationships);
1591
+ const { detectedFrameworks, frameworkPatterns } = this.detectCSharpFrameworks(rootNode);
1592
+ return {
1593
+ symbols,
1594
+ relationships,
1595
+ imports,
1596
+ exports,
1597
+ errors,
1598
+ metadata: {
1599
+ cyclomaticComplexity,
1600
+ complexity: cyclomaticComplexity,
1601
+ linesOfCode: content.split("\n").length,
1602
+ hasTypeInference: true,
1603
+ framework: detectedFrameworks.length > 0 ? detectedFrameworks[0] : void 0,
1604
+ detectedFrameworks,
1605
+ frameworkPatterns,
1606
+ hasFrameworkIntelligence: true,
1607
+ analysisVersion: "4.1.0-pure-ast-m12"
1608
+ }
1609
+ };
1610
+ }
1611
+ /**
1612
+ * Evidence-tier classification (family contract — mirrors JVM/rust/zig; M14
1613
+ * section D requires >=2 distinct evidenceClass values). Same rules as the
1614
+ * JVM family: structural (grammar clauses, conf 1.0) | usage_contextual
1615
+ * (calls, field access) | import_based (using-directive dependencies) |
1616
+ * reference_qualified (type references) | inferred (confidence < 1 edges).
1617
+ */
1618
+ classifyEvidenceTier(relationships) {
1619
+ for (const r of relationships) {
1620
+ const type = r.type ?? r.relationshipType ?? "";
1621
+ const md = r.metadata ?? {};
1622
+ if (type === "contains") {
1623
+ md.evidenceClass = "structural";
1624
+ continue;
1625
+ }
1626
+ if (type === "references") {
1627
+ md.evidenceClass = md.isUsingDirective || md.isImport ? "import_based" : "reference_qualified";
1628
+ continue;
1629
+ }
1630
+ if (type === "imports") {
1631
+ md.evidenceClass = "import_based";
1632
+ continue;
1633
+ }
1634
+ if (type === "calls" || type === "uses") {
1635
+ md.evidenceClass = (r.confidence ?? 0) >= 0.85 ? "usage_contextual" : "inferred";
1636
+ continue;
1637
+ }
1638
+ if (type === "instantiates" || type === "extends" || type === "implements") {
1639
+ md.evidenceClass = (r.confidence ?? 0) >= 0.9 ? "structural" : "inferred";
1640
+ continue;
1641
+ }
1642
+ if (type === "overrides") {
1643
+ md.evidenceClass = "structural";
1644
+ continue;
1645
+ }
1646
+ if (type === "exports") {
1647
+ md.evidenceClass = "structural";
1648
+ continue;
1649
+ }
1650
+ md.evidenceClass = "usage_contextual";
1651
+ }
1652
+ }
1653
+ /**
1654
+ * CONV-CS-2 (#751): framework detection — the family contract (java
1655
+ * sibling): metadata carries `framework` (deterministic primary pick),
1656
+ * `detectedFrameworks` (always an array, [] when none) and
1657
+ * `frameworkPatterns`. Markers are grammar-level: using-directive roots
1658
+ * (incl. static / alias / global forms), base-list type names and
1659
+ * attribute names. The emitted order is the fixed CS_FRAMEWORK_ORDER
1660
+ * (application frameworks most-specific first, test frameworks last), so
1661
+ * source/import order can never change the payload. String ops only (R2
1662
+ * shrink-only: no new regex literals); edges are untouched — fixtures +
1663
+ * mutants gate this surface.
1664
+ */
1665
+ detectCSharpFrameworks(rootNode) {
1666
+ const usings = /* @__PURE__ */ new Set();
1667
+ const bases = /* @__PURE__ */ new Set();
1668
+ const attributes = /* @__PURE__ */ new Set();
1669
+ const stack = [rootNode];
1670
+ while (stack.length > 0) {
1671
+ const n = stack.pop();
1672
+ const t = n.type;
1673
+ if (t === "using_directive") {
1674
+ const path = csharpUsingDirectivePath(n.text);
1675
+ if (path) usings.add(path);
1676
+ continue;
1677
+ }
1678
+ if (t === "base_list") {
1679
+ for (let i = 0; i < n.namedChildCount; i++) {
1680
+ const leaf = csharpTypeLeafName(n.namedChild(i));
1681
+ if (leaf) bases.add(leaf);
1682
+ }
1683
+ }
1684
+ if (t === "attribute") {
1685
+ const first = n.namedChild(0);
1686
+ const leaf = first ? csharpTypeLeafName(first) : void 0;
1687
+ if (leaf) attributes.add(leaf);
1688
+ }
1689
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1690
+ const c = n.namedChild(i);
1691
+ if (c) stack.push(c);
1692
+ }
1693
+ }
1694
+ const detected = [];
1695
+ for (let i = 0; i < CS_FRAMEWORK_ORDER.length; i++) {
1696
+ const fw = CS_FRAMEWORK_ORDER[i];
1697
+ if (CS_FRAMEWORK_MARKERS[fw](usings, bases, attributes)) detected.push(fw);
1698
+ }
1699
+ return {
1700
+ detectedFrameworks: detected,
1701
+ frameworkPatterns: detected.map((fw) => ({ framework: fw, patterns: CS_FRAMEWORK_PATTERNS[fw] }))
1702
+ };
1703
+ }
1704
+ /**
1705
+ * Per-symbol cyclomatic complexity (family contract — csharp #264 wave).
1706
+ * Same node set as the file-level counter above so per-symbol and
1707
+ * file-level agree; base complexity 1.
1708
+ */
1709
+ calculateCyclomaticComplexity(node) {
1710
+ let complexity = 1;
1711
+ const complexityNodes = /* @__PURE__ */ new Set([
1712
+ "if_statement",
1713
+ "for_statement",
1714
+ "foreach_statement",
1715
+ "while_statement",
1716
+ // CS-B3: `catch_clause` (not `catch_declaration`) — both catch forms
1717
+ // parse as catch_clause containing an optional declaration.
1718
+ "case_switch_label",
1719
+ "catch_clause",
1720
+ "conditional_expression",
1721
+ "logical_and_expression",
1722
+ "logical_or_expression",
1723
+ // CSD2: keep per-symbol in sync with the file-level counter above.
1724
+ "switch_expression_arm"
1725
+ ]);
1726
+ const stack = [node];
1727
+ while (stack.length > 0) {
1728
+ const n = stack.pop();
1729
+ if (complexityNodes.has(n.type)) complexity++;
1730
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1731
+ const c = n.namedChild(i);
1732
+ if (c) stack.push(c);
1733
+ }
1734
+ }
1735
+ return complexity;
1736
+ }
1737
+ /** Pre-pass: record every type declaration's kind for in-file base-list resolution. */
1738
+ // CSD11: declarator name -> declared type for fields and properties.
1739
+ // Feeds assignment-form target-typed `new()` resolution (see
1740
+ // resolveImplicitNewType). Locals are NOT collected — a local resolved
1741
+ // through an assignment LHS would need a locals map with block scoping;
1742
+ // out of scope here, honestly unresolved instead.
1743
+ collectMemberTypes(rootNode, memberTypes, memberTypeNodes) {
1744
+ const stack = [rootNode];
1745
+ while (stack.length > 0) {
1746
+ const n = stack.pop();
1747
+ const t = n.type;
1748
+ if (t === "field_declaration" || t === "property_declaration") {
1749
+ const isField = t === "field_declaration";
1750
+ const declaredType = csharpMemberDeclaredTypeText(n) ?? void 0;
1751
+ const names = [];
1752
+ if (isField) {
1753
+ const varDecl = this.findChild(n, "variable_declaration");
1754
+ if (varDecl) {
1755
+ for (let i = 0; i < varDecl.namedChildCount; i++) {
1756
+ const d = varDecl.namedChild(i);
1757
+ if (d?.type === "variable_declarator") {
1758
+ const nm = this.childText(d, "identifier");
1759
+ if (nm) names.push(nm);
1760
+ }
1761
+ }
1762
+ }
1763
+ } else {
1764
+ const nm = n.childForFieldName("name")?.text || this.childText(n, "identifier");
1765
+ if (nm) names.push(nm);
1766
+ }
1767
+ const declaredTypeNode = this.memberDeclaredTypeNode(n);
1768
+ if (declaredType) {
1769
+ for (const nm of names) if (!memberTypes.has(nm)) memberTypes.set(nm, declaredType);
1770
+ }
1771
+ if (declaredTypeNode) {
1772
+ for (const nm of names) if (!memberTypeNodes.has(nm)) memberTypeNodes.set(nm, declaredTypeNode);
1773
+ }
1774
+ }
1775
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1776
+ const child = n.namedChild(i);
1777
+ if (child) stack.push(child);
1778
+ }
1779
+ }
1780
+ }
1781
+ /**
1782
+ * M59.A7 (#825): where each SYMBOL's name is written.
1783
+ *
1784
+ * The containment edge's contract is "the line of the node that NAMES the
1785
+ * target", and for a member that node is the declaration's NAME — which the
1786
+ * symbol's `range` cannot stand in for, because the range starts at the
1787
+ * declaration node and a C# declaration can begin a line or more before its
1788
+ * name (attributes such as `[Parameter]`, modifiers on their own line, a
1789
+ * wrapped signature). One walk over the declarations this analyzer turns into
1790
+ * symbols, keyed by the declaration's start index AND its name, because the
1791
+ * start index alone is ambiguous: a multi-declarator field (`int a, b;`)
1792
+ * produces two symbols that share the field_declaration's range. Keying by
1793
+ * name is also what makes the mapping self-protecting — a symbol whose name the
1794
+ * declaration does NOT write (a constructor is named `constructor`, an
1795
+ * operator `operator +`) finds no entry here and so can never claim a line the
1796
+ * target is not written on.
1797
+ */
1798
+ collectContainmentSites(rootNode) {
1799
+ const named = /* @__PURE__ */ new Map();
1800
+ const synthesized = /* @__PURE__ */ new Set();
1801
+ const stack = [rootNode];
1802
+ while (stack.length > 0) {
1803
+ const n = stack.pop();
1804
+ const t = n.type;
1805
+ if (t === "field_declaration" || t === "event_field_declaration") {
1806
+ const varDecl = this.findChild(n, "variable_declaration");
1807
+ if (varDecl) {
1808
+ for (let i = 0; i < varDecl.namedChildCount; i++) {
1809
+ const d = varDecl.namedChild(i);
1810
+ if (!d || d.type !== "variable_declarator") continue;
1811
+ const id = this.findChild(d, "identifier");
1812
+ if (id) named.set(`${n.startIndex}\0${id.text}`, id.startPosition.row + 1);
1813
+ }
1814
+ }
1815
+ } else if (t === "destructor_declaration" || t === "constructor_declaration") {
1816
+ synthesized.add(n.startIndex);
1817
+ } else if (CSHARP_SYMBOL_DECLARATIONS.has(t)) {
1818
+ const nameNode = this.declarationNameNode(n);
1819
+ if (nameNode) named.set(`${n.startIndex}\0${nameNode.text}`, nameNode.startPosition.row + 1);
1820
+ }
1821
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1822
+ const child = n.namedChild(i);
1823
+ if (child) stack.push(child);
1824
+ }
1825
+ }
1826
+ return { named, synthesized };
1827
+ }
1828
+ /**
1829
+ * The containment edge's line: the NAME node where the declaration writes the
1830
+ * symbol's name, the declaration's own start line otherwise (a synthesised or
1831
+ * rewritten name still has a navigable declaration, and the oracle classifies
1832
+ * an uncheckable target as `notCheckable` rather than as a failed claim), and
1833
+ * NO line for a declaration whose symbol name is written nowhere in the file.
1834
+ */
1835
+ containmentLine(s, sites) {
1836
+ const start = s.range?.startIndex;
1837
+ if (typeof start !== "number") return void 0;
1838
+ if (sites.synthesized.has(start)) return void 0;
1839
+ return sites.named.get(`${start}\0${s.name}`) ?? s.range?.startLine;
1840
+ }
1841
+ /**
1842
+ * The node that WRITES a declaration's name — the symbol pass's own rule
1843
+ * (`childForFieldName("name")`, then the first identifier), plus the one shape
1844
+ * where the name is not a field: an indexer's symbol is named `this`, which the
1845
+ * grammar writes as an anonymous keyword child.
1846
+ */
1847
+ declarationNameNode(node) {
1848
+ const field = node.childForFieldName("name");
1849
+ if (field) return field;
1850
+ if (node.type === "indexer_declaration") {
1851
+ for (let i = 0; i < node.childCount; i++) {
1852
+ const child = node.child(i);
1853
+ if (child && child.type === "this") return child;
1854
+ }
1855
+ return null;
1856
+ }
1857
+ return this.findChild(node, "identifier");
1858
+ }
1859
+ collectDeclaredTypeKinds(rootNode, typeKinds) {
1860
+ const stack = [rootNode];
1861
+ while (stack.length > 0) {
1862
+ const n = stack.pop();
1863
+ const t = n.type;
1864
+ if (t === "class_declaration" || t === "struct_declaration" || t === "interface_declaration" || t === "record_declaration" || t === "enum_declaration") {
1865
+ const name = n.childForFieldName("name")?.text || this.childText(n, "identifier");
1866
+ if (name) {
1867
+ const kind = t === "interface_declaration" ? ASTEngine.SymbolKind.Interface : t === "enum_declaration" ? ASTEngine.SymbolKind.Enum : csharpTypeDeclarationKind(n) ?? ASTEngine.SymbolKind.Class;
1868
+ typeKinds.set(name, kind);
1869
+ }
1870
+ }
1871
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1872
+ const child = n.namedChild(i);
1873
+ if (child) stack.push(child);
1874
+ }
1875
+ }
1876
+ }
1877
+ /**
1878
+ * C923 (#923): record one member declaration for the interface-implementation contract — or,
1879
+ * when the declaration IS the interface's, record the CONTRACT it declares.
1880
+ *
1881
+ * The contract side is indexed under BOTH the interface's FQN and its local name, because a
1882
+ * base-list entry is written either way (`class C : IFoo` / `class C : Ns.IFoo`), and the
1883
+ * resolution below looks the ancestor up by the name the base list actually wrote.
1884
+ */
1885
+ collectMemberContract(node, name, parentContext, ownerFqn, localLabel, tasks, members, classMembers, lineNode) {
1886
+ if (!parentContext) return;
1887
+ const kind = parentContext.kind;
1888
+ if (kind !== ASTEngine.SymbolKind.Class && kind !== ASTEngine.SymbolKind.Struct && kind !== ASTEngine.SymbolKind.Interface) {
1889
+ return;
1890
+ }
1891
+ if (parentContext.isInterface) {
1892
+ for (const key of [parentContext.fqn, parentContext.rawName]) {
1893
+ if (!key) continue;
1894
+ let set = members.get(key);
1895
+ if (!set) {
1896
+ set = /* @__PURE__ */ new Set();
1897
+ members.set(key, set);
1898
+ }
1899
+ set.add(name);
1900
+ }
1901
+ return;
1902
+ }
1903
+ for (const key of [parentContext.fqn, parentContext.rawName]) {
1904
+ if (!key) continue;
1905
+ let set = classMembers.get(key);
1906
+ if (!set) {
1907
+ set = /* @__PURE__ */ new Set();
1908
+ classMembers.set(key, set);
1909
+ }
1910
+ set.add(name);
1911
+ }
1912
+ tasks.push({
1913
+ fqn: localLabel,
1914
+ ownerFqn,
1915
+ memberName: name,
1916
+ explicitIface: this.explicitInterfaceName(node),
1917
+ // M59.A7: the NAME node's line. A field-like event writes its name on a
1918
+ // `variable_declarator`, not on the declaration's `name` field, so the caller passes that
1919
+ // node — otherwise the edge is stamped with an honest-but-avoidable no-line.
1920
+ line: this.nodeLine(lineNode ?? this.declarationNameNode(node))
1921
+ });
1922
+ }
1923
+ /**
1924
+ * The interface an explicit interface member writes (`void IFoo.M()` → `IFoo`). The trailing
1925
+ * `.` is punctuation, not part of the name, so it is cut by a linear scan (no regex).
1926
+ */
1927
+ explicitInterfaceName(node) {
1928
+ const spec = this.findChild(node, (n) => n.type === "explicit_interface_specifier");
1929
+ if (!spec) return null;
1930
+ const cleaned = this.cleanTypeName(spec.text);
1931
+ let end = cleaned.length;
1932
+ while (end > 0) {
1933
+ const c = cleaned.charCodeAt(end - 1);
1934
+ if (c === 46 || c === 32 || c === 9 || c === 10 || c === 13) end--;
1935
+ else break;
1936
+ }
1937
+ const name = cleaned.slice(0, end);
1938
+ return name.length > 0 ? name : null;
1939
+ }
1940
+ /**
1941
+ * C923 (#923): the member-level implements contract, mirroring the family's five-lane
1942
+ * precedent (`overrides M -> I.m`, measured in java, kotlin, typescript, dart and python).
1943
+ *
1944
+ * explicit (`void IFoo.M()`): ALWAYS. The interface is written in the declaration, so the
1945
+ * edge is derivable from the tree alone at any scope — measured on csharp's two pinned
1946
+ * corpora, 215 of 352 explicit members name an interface the corpus text never declares,
1947
+ * so requiring resolution would drop 61% of a class that needs none.
1948
+ * implicit (a member that satisfies a base-list interface): only where the member set of
1949
+ * that interface is KNOWN, which is the case exactly when the interface is declared in
1950
+ * this file. An interface the analyzer cannot see stays an honest no-edge (measured in the
1951
+ * full extent: 273 member declarations whose contract lives in another file, and 2,107
1952
+ * types whose bases are not in the corpus text at all — both disclosed, neither guessed).
1953
+ *
1954
+ * No caller context is consulted, deliberately: a rule that changes with an optional companion
1955
+ * would be a rule a fixture cannot pin (fixtures pass no context), and the family's own doctrine
1956
+ * is that nothing ships unverified. The cross-file extension is measured and registered as an
1957
+ * open scope limit instead (issue #923).
1958
+ *
1959
+ * First ancestor in declaration order that both IS an interface and declares the member wins —
1960
+ * the family's rule for a name-keyed target (cf. findDeclaringParent).
1961
+ */
1962
+ resolveInterfaceImplementations(tasks, classHierarchy, interfaceMembers, classMembers, relationships) {
1963
+ if (tasks.length === 0) return;
1964
+ const declaresMember = (iface, member) => interfaceMembers.get(iface)?.has(member) === true;
1965
+ const emitted = /* @__PURE__ */ new Set();
1966
+ for (const task of tasks) {
1967
+ let target = null;
1968
+ if (task.explicitIface) {
1969
+ target = `${task.explicitIface}.${task.memberName}`;
1970
+ } else if (task.ownerFqn) {
1971
+ const queue = [...classHierarchy.get(task.ownerFqn) ?? []];
1972
+ const seen = /* @__PURE__ */ new Set();
1973
+ while (queue.length > 0) {
1974
+ const parent = queue.shift();
1975
+ if (seen.has(parent)) continue;
1976
+ seen.add(parent);
1977
+ if (declaresMember(parent, task.memberName)) {
1978
+ target = `${parent}.${task.memberName}`;
1979
+ break;
1980
+ }
1981
+ if (classMembers.get(parent)?.has(task.memberName)) continue;
1982
+ for (const next of classHierarchy.get(parent) ?? []) {
1983
+ if (!seen.has(next)) queue.push(next);
1984
+ }
1985
+ }
1986
+ }
1987
+ if (!target) continue;
1988
+ const source = localEdgeLabel(task.fqn);
1989
+ const label = localEdgeName(target);
1990
+ if (!source || !label) continue;
1991
+ const key = `${source}|${label}`;
1992
+ if (emitted.has(key)) continue;
1993
+ emitted.add(key);
1994
+ relationships.push({
1995
+ source,
1996
+ target: label,
1997
+ type: ASTEngine.RelationshipType.Overrides,
1998
+ confidence: 1,
1999
+ line_number: task.line,
2000
+ metadata: {
2001
+ relationshipType: "interface_member_implementation",
2002
+ isCSharpInterfaceImpl: true,
2003
+ explicitInterfaceMember: task.explicitIface != null
2004
+ }
2005
+ });
2006
+ }
2007
+ }
2008
+ resolveOverrides(tasks, classHierarchy, symbolMap, relationships, membersByOwner, companion) {
2009
+ for (const task of tasks) {
2010
+ let targetFqn = null;
2011
+ const memberKind = task.memberKind ?? "method";
2012
+ const isMethod = memberKind === "method";
2013
+ const queue = [];
2014
+ const ownerH = classHierarchy.get(task.ownerFqn);
2015
+ if (ownerH) {
2016
+ for (let i = 0; i < ownerH.length; i++) queue.push(ownerH[i]);
2017
+ }
2018
+ const seen = /* @__PURE__ */ new Set();
2019
+ while (queue.length > 0) {
2020
+ const parent = queue.shift();
2021
+ if (seen.has(parent)) continue;
2022
+ seen.add(parent);
2023
+ if (isMethod) {
2024
+ const potentialTargetFqn = `${parent}.${task.methodName}${task.signature}`;
2025
+ if (symbolMap.has(potentialTargetFqn)) {
2026
+ targetFqn = potentialTargetFqn;
2027
+ break;
2028
+ }
2029
+ } else if (membersByOwner.get(parent)?.has(task.methodName)) {
2030
+ targetFqn = `${parent}.${task.methodName}`;
2031
+ break;
2032
+ }
2033
+ const pH = classHierarchy.get(parent);
2034
+ if (pH) {
2035
+ for (let i = 0; i < pH.length; i++) queue.push(pH[i]);
2036
+ }
2037
+ }
2038
+ if (!targetFqn && isMethod && companion && ownerH && ownerH.length > 0) {
2039
+ const declaring = findDeclaringParent(
2040
+ task.methodName,
2041
+ ownerH,
2042
+ companion,
2043
+ (t) => classHierarchy.get(t) ?? []
2044
+ );
2045
+ if (declaring) targetFqn = `${declaring}.${task.methodName}${task.signature}`;
2046
+ }
2047
+ if (!targetFqn && ownerH && ownerH.length > 0) {
2048
+ targetFqn = `${ownerH[0]}.${task.methodName}${isMethod ? task.signature : ""}`;
2049
+ }
2050
+ if (targetFqn) {
2051
+ const localSource = localEdgeLabel(task.fqn);
2052
+ const localTarget = localEdgeName(targetFqn);
2053
+ relationships.push({
2054
+ source: localSource,
2055
+ target: localTarget,
2056
+ type: ASTEngine.RelationshipType.Overrides,
2057
+ confidence: 1,
2058
+ line_number: task.line,
2059
+ metadata: {
2060
+ relationshipType: isMethod ? "method_override" : `${memberKind}_override`,
2061
+ isCSharpOverride: true,
2062
+ overriddenMemberKind: memberKind
2063
+ }
2064
+ });
2065
+ }
2066
+ }
2067
+ }
2068
+ /**
2069
+ * Field-access Uses pass (csharp #264 wave, Station 3). Emits `uses
2070
+ * containingFn -> field` for member_access_expression on a field (e.g.
2071
+ * `this.Name`, `obj.Radius`) that is NOT the callee of a call. Mirror of the
2072
+ * go/rust selector-uses family contract. Call-callee member accesses are
2073
+ * skipped (calls analysis emits the leaf-target calls edge instead).
2074
+ */
2075
+ analyzeFieldAccessUses(rootNode, relationships, symbols) {
2076
+ const stack = [rootNode];
2077
+ const seen = /* @__PURE__ */ new Set();
2078
+ while (stack.length > 0) {
2079
+ const node = stack.pop();
2080
+ if (node.type === "member_access_expression" || node.type === "member_binding_expression") {
2081
+ let isCallee = false;
2082
+ const parent = node.parent;
2083
+ if (parent && parent.type === "invocation_expression") {
2084
+ const fn = parent.childForFieldName("function");
2085
+ if (fn && fn.id === node.id) isCallee = true;
2086
+ } else if (parent && parent.type === "conditional_access_expression") {
2087
+ const gp = parent.parent;
2088
+ if (gp && gp.type === "invocation_expression" && gp.childForFieldName("function")?.id === parent.id) isCallee = true;
2089
+ }
2090
+ let isLhsWrite = false;
2091
+ {
2092
+ let a = node.parent;
2093
+ while (a && (a.type === "member_access_expression" || a.type === "member_binding_expression")) a = a.parent;
2094
+ if (a && a.type === "assignment_expression") {
2095
+ const lhs = a.childForFieldName("left");
2096
+ if (lhs && lhs.startIndex <= node.startIndex && lhs.endIndex >= node.endIndex) isLhsWrite = true;
2097
+ }
2098
+ }
2099
+ if (!isCallee && !isLhsWrite) {
2100
+ const field = node.childForFieldName("name");
2101
+ const expr = node.childForFieldName("expression");
2102
+ if (field && (expr || node.type === "member_binding_expression")) {
2103
+ const containing = this.findContainingCSharpFunction(node);
2104
+ const src = containing || "global";
2105
+ const tgt = field.text;
2106
+ const key = `${src}.${tgt}`;
2107
+ if (!seen.has(key)) {
2108
+ seen.add(key);
2109
+ relationships.push({
2110
+ source: src,
2111
+ target: tgt,
2112
+ type: ASTEngine.RelationshipType.Uses,
2113
+ confidence: 0.7,
2114
+ // M59.A7 (#825): the member-access NAME field (`obj\n .Radius`
2115
+ // writes Radius on line 2, the access node starts on line 1).
2116
+ line_number: this.nodeLine(field),
2117
+ metadata: { relationshipType: "csharp_field_access", fieldAccess: key }
2118
+ });
2119
+ }
2120
+ }
2121
+ }
2122
+ }
2123
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2124
+ const child = node.namedChild(i);
2125
+ if (child) stack.push(child);
2126
+ }
2127
+ }
2128
+ }
2129
+ /**
2130
+ * CS-R1: bare-identifier value reads (see the call site for the contract).
2131
+ * Inventory = Property-kind member names keyed by owner (full name and
2132
+ * leaf); resolution walks the lexical class chain innermost-first, then
2133
+ * base classes transitively (capped), then lexically enclosing classes.
2134
+ * Methods, enum members, events and delegates never resolve bare
2135
+ * (method groups, qualified-only members, ruled boundaries).
2136
+ */
2137
+ analyzeCSharpBareIdentifierUses(rootNode, relationships, symbols, classHierarchy) {
2138
+ const importSpans = [];
2139
+ {
2140
+ const importStack = [rootNode];
2141
+ while (importStack.length > 0) {
2142
+ const n = importStack.pop();
2143
+ if (n.type === "using_directive" || n.type === "extern_alias_directive") {
2144
+ importSpans.push([n.startIndex, n.endIndex]);
2145
+ continue;
2146
+ }
2147
+ for (let k = 0; k < n.childCount; k++) {
2148
+ const kid = n.child(k);
2149
+ if (kid) importStack.push(kid);
2150
+ }
2151
+ }
2152
+ }
2153
+ const leafOf = (s) => {
2154
+ const segs = [];
2155
+ for (const a of s.split("::")) {
2156
+ for (const b of a.split(".")) {
2157
+ if (b) segs.push(b);
2158
+ }
2159
+ }
2160
+ return segs.length > 0 ? segs[segs.length - 1] : s;
2161
+ };
2162
+ const membersByOwner = /* @__PURE__ */ new Map();
2163
+ const addMember = (owner, name) => {
2164
+ if (!owner || !name || name === "_") return;
2165
+ for (const key of [owner, leafOf(owner)]) {
2166
+ let s = membersByOwner.get(key);
2167
+ if (!s) {
2168
+ s = /* @__PURE__ */ new Set();
2169
+ membersByOwner.set(key, s);
2170
+ }
2171
+ s.add(name);
2172
+ }
2173
+ };
2174
+ for (const s of symbols) {
2175
+ if (s.kind === ASTEngine.SymbolKind.Property && s.ownerName) addMember(s.ownerName, s.name);
2176
+ }
2177
+ const emitted = /* @__PURE__ */ new Set();
2178
+ const scopeStack = [];
2179
+ scopeStack.push({ names: /* @__PURE__ */ new Set(), cls: null });
2180
+ const isShadowed = (name) => {
2181
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
2182
+ if (scopeStack[i].names.has(name)) return true;
2183
+ }
2184
+ return false;
2185
+ };
2186
+ const isResolvableRead = (name) => {
2187
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
2188
+ const fr = scopeStack[i];
2189
+ if (!fr.cls) continue;
2190
+ const seen = /* @__PURE__ */ new Set();
2191
+ const queue = [fr.cls];
2192
+ let depth = 0;
2193
+ while (queue.length > 0 && depth < 10) {
2194
+ depth++;
2195
+ const cur = queue.shift();
2196
+ if (seen.has(cur)) continue;
2197
+ seen.add(cur);
2198
+ const mm = membersByOwner.get(cur) ?? membersByOwner.get(leafOf(cur));
2199
+ if (mm && mm.has(name)) return true;
2200
+ for (const b of classHierarchy.get(cur) ?? classHierarchy.get(leafOf(cur)) ?? []) {
2201
+ if (!seen.has(b)) queue.push(b);
2202
+ }
2203
+ }
2204
+ }
2205
+ return false;
2206
+ };
2207
+ const firstIdent = (n) => {
2208
+ if (!n) return null;
2209
+ for (let i = 0; i < n.namedChildCount; i++) {
2210
+ const c = n.namedChild(i);
2211
+ if (c && c.type === "identifier") return c;
2212
+ }
2213
+ return null;
2214
+ };
2215
+ const declaratorName = (declNode) => {
2216
+ let cur = declNode;
2217
+ while (cur) {
2218
+ if (cur.type === "identifier") return cur;
2219
+ let next = null;
2220
+ for (let i = 0; i < cur.namedChildCount; i++) {
2221
+ const c = cur.namedChild(i);
2222
+ if (c && (c.type === "identifier" || c.type.endsWith("declarator"))) {
2223
+ next = c;
2224
+ break;
2225
+ }
2226
+ }
2227
+ if (!next || next === cur) return null;
2228
+ cur = next;
2229
+ }
2230
+ return null;
2231
+ };
2232
+ const declaratorRole = (declNode) => {
2233
+ let cur = declNode.parent;
2234
+ while (cur) {
2235
+ const t = cur.type;
2236
+ if (t === "method_declaration" || t === "constructor_declaration" || t === "destructor_declaration" || t === "operator_declaration" || t === "conversion_operator_declaration" || t === "local_function_statement" || t === "lambda_expression" || t === "block" || t === "accessor_declaration") return "local";
2237
+ if (t === "class_declaration" || t === "struct_declaration" || t === "interface_declaration" || t === "record_declaration" || t === "enum_declaration") return "member";
2238
+ cur = cur.parent;
2239
+ }
2240
+ return "local";
2241
+ };
2242
+ const hasEqualsAfter = (parent, node) => {
2243
+ let sawSelf = false;
2244
+ for (let i = 0; i < parent.childCount; i++) {
2245
+ const c = parent.child(i);
2246
+ if (!c) continue;
2247
+ if (c.startIndex === node.startIndex && c.endIndex === node.endIndex) {
2248
+ sawSelf = true;
2249
+ continue;
2250
+ }
2251
+ if (!c.isNamed && sawSelf && (c.type === "=" || c.type === ":")) return true;
2252
+ }
2253
+ return false;
2254
+ };
2255
+ const stack = [{ node: rootNode, exit: false, pushed: false }];
2256
+ while (stack.length > 0) {
2257
+ const { node, exit, pushed } = stack.pop();
2258
+ if (exit) {
2259
+ if (pushed) scopeStack.pop();
2260
+ continue;
2261
+ }
2262
+ const t = node.type;
2263
+ let pushedScope = false;
2264
+ const top = () => scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
2265
+ if (t === "method_declaration" || t === "constructor_declaration" || t === "destructor_declaration" || t === "operator_declaration" || t === "conversion_operator_declaration" || t === "local_function_statement") {
2266
+ const frame = { names: /* @__PURE__ */ new Set(), cls: null };
2267
+ const plist = this.findChild(node, (n) => n.type === "parameter_list");
2268
+ if (plist) {
2269
+ for (let i = 0; i < plist.namedChildCount; i++) {
2270
+ const p = plist.namedChild(i);
2271
+ if (!p || p.type !== "parameter") continue;
2272
+ const nm = p.childForFieldName("name") ?? firstIdent(p);
2273
+ if (nm && nm.text !== "_") frame.names.add(nm.text);
2274
+ }
2275
+ }
2276
+ if (t === "local_function_statement") {
2277
+ const nm = node.childForFieldName("name") ?? firstIdent(node);
2278
+ const outer = top();
2279
+ if (outer && nm && nm.text !== "_") outer.names.add(nm.text);
2280
+ }
2281
+ scopeStack.push(frame);
2282
+ pushedScope = true;
2283
+ } else if (t === "block" || t === "lambda_expression" || t === "switch_expression_arm" || t === "query_expression" || t === "foreach_statement" || t === "for_statement" || t === "using_statement" || t === "catch_clause") {
2284
+ if (t === "lambda_expression") {
2285
+ const frame = { names: /* @__PURE__ */ new Set(), cls: null };
2286
+ const walk = [node];
2287
+ while (walk.length > 0) {
2288
+ const m = walk.pop();
2289
+ if (m !== node && (m.type === "block" || m.type === "lambda_expression")) continue;
2290
+ if (m.type === "parameter") {
2291
+ const pn = m.childForFieldName("name") ?? firstIdent(m);
2292
+ if (pn && pn.text !== "_") frame.names.add(pn.text);
2293
+ } else if (m.type === "implicit_parameter") {
2294
+ for (let i = 0; i < m.namedChildCount; i++) {
2295
+ const c = m.namedChild(i);
2296
+ if (c && c.type === "identifier" && c.text !== "_") frame.names.add(c.text);
2297
+ }
2298
+ }
2299
+ for (let i = m.namedChildCount - 1; i >= 0; i--) {
2300
+ const c = m.namedChild(i);
2301
+ if (c) walk.push(c);
2302
+ }
2303
+ }
2304
+ scopeStack.push(frame);
2305
+ pushedScope = true;
2306
+ } else if (t === "foreach_statement") {
2307
+ const frame = { names: /* @__PURE__ */ new Set(), cls: null };
2308
+ const isTypeish = (c) => c.type === "implicit_type" || c.type === "predefined_type" || c.type === "generic_name" || c.type === "qualified_name" || c.type === "nullable_type" || c.type === "array_type" || c.type === "pointer_type" || c.type === "tuple_type" || c.type === "ref_type";
2309
+ const kids = [];
2310
+ for (let i = 0; i < node.namedChildCount; i++) {
2311
+ const c = node.namedChild(i);
2312
+ if (!c || c.type === "block") break;
2313
+ kids.push(c);
2314
+ }
2315
+ const hasType = kids.some((c) => isTypeish(c));
2316
+ if (hasType) {
2317
+ let bound = false;
2318
+ let seen = false;
2319
+ for (const c of kids) {
2320
+ if (isTypeish(c)) {
2321
+ seen = true;
2322
+ continue;
2323
+ }
2324
+ if (!bound && seen && c.type === "identifier" && c.text !== "_") {
2325
+ frame.names.add(c.text);
2326
+ bound = true;
2327
+ }
2328
+ }
2329
+ } else {
2330
+ const ids = kids.filter((c) => c.type === "identifier" && c.text !== "_");
2331
+ for (let i = 1; i + 1 < ids.length; i++) frame.names.add(ids[i].text);
2332
+ }
2333
+ scopeStack.push(frame);
2334
+ pushedScope = true;
2335
+ } else {
2336
+ scopeStack.push({ names: /* @__PURE__ */ new Set(), cls: null });
2337
+ pushedScope = true;
2338
+ }
2339
+ } else if (t === "class_declaration" || t === "struct_declaration" || t === "interface_declaration" || t === "record_declaration") {
2340
+ const frame = { names: /* @__PURE__ */ new Set(), cls: null };
2341
+ const nm = node.childForFieldName("name")?.text ?? firstIdent(node)?.text ?? null;
2342
+ if (nm) frame.cls = nm;
2343
+ if (t !== "record_declaration") {
2344
+ for (let i = 0; i < node.namedChildCount; i++) {
2345
+ const c = node.namedChild(i);
2346
+ if (c && c.type === "parameter_list") {
2347
+ for (let k = 0; k < c.namedChildCount; k++) {
2348
+ const p = c.namedChild(k);
2349
+ if (!p || p.type !== "parameter") continue;
2350
+ const pn = p.childForFieldName("name") ?? firstIdent(p);
2351
+ if (pn && pn.text !== "_") frame.names.add(pn.text);
2352
+ }
2353
+ }
2354
+ }
2355
+ }
2356
+ scopeStack.push(frame);
2357
+ pushedScope = true;
2358
+ } else if (t === "variable_declarator") {
2359
+ if (declaratorRole(node) === "local") {
2360
+ const f = top();
2361
+ const nm = declaratorName(node);
2362
+ if (f && nm && nm.text !== "_") f.names.add(nm.text);
2363
+ }
2364
+ } else if (t === "declaration_pattern") {
2365
+ const f = top();
2366
+ if (f) {
2367
+ for (let i = 1; i < node.namedChildCount; i++) {
2368
+ const c = node.namedChild(i);
2369
+ if (c && c.type === "identifier" && c.text !== "_") f.names.add(c.text);
2370
+ }
2371
+ }
2372
+ } else if (t === "declaration_expression") {
2373
+ const f = top();
2374
+ if (f) {
2375
+ let last = null;
2376
+ for (let i = 0; i < node.namedChildCount; i++) {
2377
+ const c = node.namedChild(i);
2378
+ if (c && c.type === "identifier") last = c;
2379
+ }
2380
+ if (last && last.text !== "_") f.names.add(last.text);
2381
+ }
2382
+ } else if (t === "from_clause" || t === "join_clause" || t === "let_clause") {
2383
+ const f = top();
2384
+ if (f) {
2385
+ const id = firstIdent(node);
2386
+ if (id && id.text !== "_") f.names.add(id.text);
2387
+ }
2388
+ } else if (t === "catch_declaration") {
2389
+ const f = top();
2390
+ if (f) {
2391
+ for (let i = 0; i < node.namedChildCount; i++) {
2392
+ const c = node.namedChild(i);
2393
+ if (!c || c.type !== "identifier" || c.text === "_") continue;
2394
+ let earlier = false;
2395
+ for (let k = 0; k < i; k++) {
2396
+ if (node.namedChild(k)) {
2397
+ earlier = true;
2398
+ break;
2399
+ }
2400
+ }
2401
+ if (earlier) f.names.add(c.text);
2402
+ }
2403
+ }
2404
+ } else if (t === "tuple_expression") {
2405
+ const p = node.parent;
2406
+ if (p && p.type === "assignment_expression" && p.namedChild(0) && node.startIndex >= p.namedChild(0).startIndex && node.endIndex <= (p.namedChild(0).endIndex ?? 0)) {
2407
+ const f = top();
2408
+ if (f) {
2409
+ const isTypeish = (c) => c.type === "implicit_type" || c.type === "predefined_type" || c.type === "generic_name" || c.type === "qualified_name" || c.type === "nullable_type" || c.type === "array_type" || c.type === "pointer_type" || c.type === "tuple_type" || c.type === "ref_type";
2410
+ for (let i = 0; i < node.namedChildCount; i++) {
2411
+ const arg = node.namedChild(i);
2412
+ if (!arg || arg.type !== "argument") continue;
2413
+ const ids = [];
2414
+ let typed = false;
2415
+ for (let k = 0; k < arg.namedChildCount; k++) {
2416
+ const c = arg.namedChild(k);
2417
+ if (!c) continue;
2418
+ if (isTypeish(c)) typed = true;
2419
+ else if (c.type === "identifier" && c.text !== "_") ids.push(c);
2420
+ }
2421
+ const bind = typed ? ids : ids.slice(1);
2422
+ for (const b of bind) f.names.add(b.text);
2423
+ }
2424
+ }
2425
+ }
2426
+ } else if (t === "identifier") {
2427
+ const name = node.text;
2428
+ const p = node.parent;
2429
+ const isAttrName = !!p && p.type === "attribute" && (() => {
2430
+ for (let i = 0; i < p.namedChildCount; i++) {
2431
+ const c = p.namedChild(i);
2432
+ if (c && (c.type === "identifier" || c.type === "generic_name" || c.type === "qualified_name")) {
2433
+ return c.startIndex === node.startIndex && c.endIndex === node.endIndex;
2434
+ }
2435
+ }
2436
+ return false;
2437
+ })();
2438
+ const isNamedArgDesignator = !!p && p.type === "attribute_argument" && (() => {
2439
+ const first = firstIdent(p);
2440
+ return !!first && first.startIndex === node.startIndex && first.endIndex === node.endIndex && hasEqualsAfter(p, node);
2441
+ })();
2442
+ const isAnonDesignator = !!p && (() => {
2443
+ let q = p;
2444
+ while (q && q.type !== "anonymous_object_creation_expression" && q.type !== "block" && q.type !== "method_declaration" && q.type !== "constructor_declaration" && q.type !== "local_function_statement" && q.type !== "lambda_expression") {
2445
+ q = q.parent;
2446
+ }
2447
+ if (!q || q.type !== "anonymous_object_creation_expression") return false;
2448
+ let fresh = true;
2449
+ let foundFirst = false;
2450
+ for (let i = 0; i < q.childCount; i++) {
2451
+ const c = q.child(i);
2452
+ if (!c) continue;
2453
+ if (!c.isNamed) {
2454
+ if (c.type === "," || c.type === ";" || c.type === "{" || c.type === "}") {
2455
+ fresh = true;
2456
+ foundFirst = false;
2457
+ } else if (c.type === "=" || c.type === ":") fresh = false;
2458
+ continue;
2459
+ }
2460
+ if (c.type === "identifier") {
2461
+ if (!foundFirst && fresh) {
2462
+ if (c.startIndex === node.startIndex && c.endIndex === node.endIndex) {
2463
+ return hasEqualsAfter(q, c);
2464
+ }
2465
+ foundFirst = true;
2466
+ } else {
2467
+ if (c.startIndex === node.startIndex && c.endIndex === node.endIndex) return false;
2468
+ }
2469
+ }
2470
+ }
2471
+ return false;
2472
+ })();
2473
+ const isMemberDesignator = !!p && (p.type === "with_initializer" || p.type === "subpattern") && (() => {
2474
+ const first = firstIdent(p);
2475
+ return !!first && first.startIndex === node.startIndex && first.endIndex === node.endIndex;
2476
+ })();
2477
+ const isOutWrite = !!p && p.type === "argument" && (() => {
2478
+ let sawOut = false;
2479
+ for (let i = 0; i < p.childCount; i++) {
2480
+ const c = p.child(i);
2481
+ if (!c) continue;
2482
+ if (!c.isNamed && c.type === "out") {
2483
+ sawOut = true;
2484
+ continue;
2485
+ }
2486
+ if (c.isNamed) {
2487
+ if (c.type === "declaration_expression") return false;
2488
+ if (c.type === "identifier" && c.startIndex === node.startIndex && c.endIndex === node.endIndex) return sawOut;
2489
+ return false;
2490
+ }
2491
+ }
2492
+ return false;
2493
+ })();
2494
+ const isDeconWrite = (() => {
2495
+ let cur = node;
2496
+ let q = p;
2497
+ while (q && (q.type === "tuple_expression" || q.type === "argument" || q.type === "parenthesized_expression")) {
2498
+ cur = q;
2499
+ q = q.parent;
2500
+ }
2501
+ if (!q || q.type !== "assignment_expression") return false;
2502
+ const lhs = q.namedChild(0);
2503
+ return !!lhs && cur.startIndex >= lhs.startIndex && cur.endIndex <= lhs.endIndex;
2504
+ })();
2505
+ const isMemberDeclName = (() => {
2506
+ if (!p) return false;
2507
+ if (p.type === "variable_declarator") {
2508
+ const nm = declaratorName(p);
2509
+ return !!nm && nm.startIndex === node.startIndex && nm.endIndex === node.endIndex && declaratorRole(p) === "member";
2510
+ }
2511
+ if (p.type === "field_declaration") {
2512
+ const first = firstIdent(p);
2513
+ return !!first && first.startIndex === node.startIndex && first.endIndex === node.endIndex;
2514
+ }
2515
+ return false;
2516
+ })();
2517
+ const isTypeContextName = (() => {
2518
+ if (!p) return false;
2519
+ if (p.type === "type_parameter_list") return true;
2520
+ let q = p;
2521
+ while (q) {
2522
+ const t2 = q.type;
2523
+ if (t2 === "type_parameter_constraints_clause" || t2 === "base_list") return true;
2524
+ if (t2 === "tuple_type") return true;
2525
+ if (t2.includes("statement") || t2.includes("declaration") || t2.includes("block") || t2.includes("function") || t2.includes("body") || t2.includes("clause") && t2 !== "type_parameter_constraints_clause") return false;
2526
+ q = q.parent;
2527
+ }
2528
+ return false;
2529
+ })();
2530
+ const isForeachWrite = !!p && p.type === "foreach_statement" && (() => {
2531
+ let last = null;
2532
+ for (let i = p.namedChildCount - 1; i >= 0; i--) {
2533
+ const c = p.namedChild(i);
2534
+ if (c && c.type !== "block") {
2535
+ last = c;
2536
+ break;
2537
+ }
2538
+ }
2539
+ if (!last || last.type === "block") return false;
2540
+ for (let i = 0; i < p.namedChildCount; i++) {
2541
+ const c = p.namedChild(i);
2542
+ if (!c || c === last || c.type === "block") continue;
2543
+ if (c.type === "identifier" && c.startIndex === node.startIndex && c.endIndex === node.endIndex) return true;
2544
+ }
2545
+ return false;
2546
+ })();
2547
+ const isDeconArgName = !!p && p.type === "argument" && (() => {
2548
+ let q = p.parent;
2549
+ while (q && q.type === "parenthesized_expression") q = q.parent;
2550
+ if (!q || q.type !== "tuple_expression") return false;
2551
+ const a = q.parent;
2552
+ if (!a || a.type !== "assignment_expression") return false;
2553
+ const lhs = a.namedChild(0);
2554
+ if (!lhs || q.startIndex < lhs.startIndex || q.endIndex > (lhs.endIndex ?? 0)) return false;
2555
+ return node.type === "identifier";
2556
+ })();
2557
+ const isImportName = (() => {
2558
+ if (!p) return false;
2559
+ for (let i = 0; i < importSpans.length; i++) {
2560
+ const sp = importSpans[i];
2561
+ if (p.startIndex >= sp[0] && p.endIndex <= sp[1]) return true;
2562
+ }
2563
+ return false;
2564
+ })();
2565
+ if (name && name !== "_" && !isAttrName && !isNamedArgDesignator && !isAnonDesignator && !isMemberDesignator && !isOutWrite && !isDeconWrite && !isDeconArgName && !isMemberDeclName && !isForeachWrite && !isImportName && !isTypeContextName && !this.isInValueSetter(node) && !this.isNameofOperand(node) && !this.isCSharpCallCalleeShaped(node) && !this.isCSharpMemberLeaf(node) && !this.isCSharpQualifiedNamePart(node) && !this.isCSharpNamePosition(node) && !this.isCSharpPreprocText(node) && !this.isCSharpLabelOrDiscard(node) && !this.isCSharpEntityName(node) && !this.isCSharpAssignLhs(node) && !isShadowed(name) && isResolvableRead(name)) {
2566
+ let clsScope = null;
2567
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
2568
+ if (scopeStack[i].cls) {
2569
+ clsScope = scopeStack[i].cls;
2570
+ break;
2571
+ }
2572
+ }
2573
+ const src = this.findContainingCSharpFunction(node) || clsScope || "global";
2574
+ const key = `${src}::uses::${name}`;
2575
+ if (!emitted.has(key)) {
2576
+ emitted.add(key);
2577
+ relationships.push({
2578
+ source: src,
2579
+ target: name,
2580
+ type: ASTEngine.RelationshipType.Uses,
2581
+ confidence: 1,
2582
+ // M59.A7 (#825): the identifier node IS the node that names the
2583
+ // target (this pass visits the read itself).
2584
+ line_number: this.nodeLine(node),
2585
+ metadata: { relationshipType: "identifier_usage", nodeType: node.type }
2586
+ });
2587
+ }
2588
+ }
2589
+ }
2590
+ stack.push({ node, exit: true, pushed: pushedScope });
2591
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2592
+ const child = node.namedChild(i);
2593
+ if (child) stack.push({ node: child, exit: false, pushed: false });
2594
+ }
2595
+ }
2596
+ }
2597
+ /**
2598
+ * CS-R1 gate helpers (see analyzeCSharpBareIdentifierUses for the contract).
2599
+ * All climb-based, span-compared (never object identity — web-tree-sitter
2600
+ * wraps per retrieval), mirroring the family gates where they exist.
2601
+ */
2602
+ /** True when `node` is the implicit `value` parameter of a set/init/add/remove accessor. */
2603
+ isInValueSetter(node) {
2604
+ if (node.text !== "value") return false;
2605
+ let cur = node.parent;
2606
+ while (cur) {
2607
+ const t = cur.type;
2608
+ if (t === "accessor_declaration") {
2609
+ for (let i = 0; i < cur.childCount; i++) {
2610
+ const c = cur.child(i);
2611
+ if (c && !c.isNamed && (c.type === "set" || c.type === "init" || c.type === "add" || c.type === "remove")) {
2612
+ return true;
2613
+ }
2614
+ }
2615
+ return false;
2616
+ }
2617
+ if (t === "method_declaration" || t === "constructor_declaration" || t === "local_function_statement" || t === "lambda_expression" || t === "class_declaration" || t === "struct_declaration" || t === "interface_declaration" || t === "record_declaration" || t === "enum_declaration") return false;
2618
+ cur = cur.parent;
2619
+ }
2620
+ return false;
2621
+ }
2622
+ /** True when `node` is (part of) the callee the calls branch owns. */
2623
+ isCSharpCallCalleeShaped(node) {
2624
+ let top = node;
2625
+ let p = node.parent;
2626
+ while (p && (p.type === "generic_name" || p.type === "parenthesized_expression")) {
2627
+ top = p;
2628
+ p = p.parent;
2629
+ }
2630
+ if (p && p.type === "member_access_expression") {
2631
+ const expr = p.childForFieldName("expression");
2632
+ if (expr && node.startIndex >= expr.startIndex && node.endIndex <= expr.endIndex) return false;
2633
+ top = p;
2634
+ p = p.parent;
2635
+ }
2636
+ if (p && p.type === "member_binding_expression") {
2637
+ top = p;
2638
+ p = p.parent;
2639
+ if (p && p.type === "conditional_access_expression") {
2640
+ top = p;
2641
+ p = p.parent;
2642
+ }
2643
+ }
2644
+ if (!p || p.type !== "invocation_expression") return false;
2645
+ const fn = p.childForFieldName("function");
2646
+ return !!fn && top.startIndex >= fn.startIndex && top.endIndex <= fn.endIndex;
2647
+ }
2648
+ /** True when `node` is the member LEAF the field pass owns. */
2649
+ isCSharpMemberLeaf(node) {
2650
+ const p = node.parent;
2651
+ if (!p || p.type !== "member_access_expression") return false;
2652
+ const field = p.childForFieldName("name");
2653
+ return !!field && field.startIndex === node.startIndex && field.endIndex === node.endIndex;
2654
+ }
2655
+ /** True when `node` sits under a qualified_name (types/namespaces — never value reads). */
2656
+ isCSharpQualifiedNamePart(node) {
2657
+ let cur = node.parent;
2658
+ while (cur) {
2659
+ if (cur.type === "qualified_name") return true;
2660
+ cur = cur.parent;
2661
+ }
2662
+ return false;
2663
+ }
2664
+ /** True for name/type positions that never read values. */
2665
+ isCSharpNamePosition(node) {
2666
+ let cur = node.parent;
2667
+ while (cur) {
2668
+ const t = cur.type;
2669
+ if (t === "typeof_expression" || t === "default_expression" || t === "sizeof_expression") return true;
2670
+ if (t === "is_expression" || t === "as_expression") {
2671
+ const first = cur.namedChild(0);
2672
+ return !first || node.startIndex < first.startIndex || node.endIndex > first.endIndex;
2673
+ }
2674
+ if (t.includes("statement") || t.includes("declaration") || t.includes("expression") || t.includes("clause") || t.includes("function") || t.includes("body") || t.includes("pattern") || t.includes("argument")) return false;
2675
+ cur = cur.parent;
2676
+ }
2677
+ return false;
2678
+ }
2679
+ /** True when `node` is the operand of a `nameof(...)` (names, never reads). */
2680
+ isNameofOperand(node) {
2681
+ const calleeIsNameof = (inv) => {
2682
+ const fn = inv.childForFieldName("function");
2683
+ return !!fn && fn.type === "identifier" && fn.text === "nameof";
2684
+ };
2685
+ const p0 = node.parent;
2686
+ if (p0 && p0.type === "invocation_expression") return calleeIsNameof(p0);
2687
+ let cur = p0;
2688
+ while (cur && (cur.type === "argument_list" || cur.type === "argument" || cur.type === "parenthesized_expression")) {
2689
+ cur = cur.parent;
2690
+ if (cur && cur.type === "invocation_expression") return calleeIsNameof(cur);
2691
+ }
2692
+ return false;
2693
+ }
2694
+ /** True for preprocessor-directive text with no code container between (CGD11 contract). */
2695
+ isCSharpPreprocText(node) {
2696
+ let cur = node.parent;
2697
+ while (cur) {
2698
+ const t = cur.type;
2699
+ if (t.includes("statement") || t.includes("declaration") || t.includes("declarator") || t.includes("specifier") || t.includes("enumerator") || t.includes("compound") || t.includes("argument_list") || t.includes("init") || t.includes("expression") || t.includes("function") || t.includes("class_body") || t.includes("field_declaration_list") || t.includes("block")) return false;
2700
+ if (t.startsWith("preproc_")) return true;
2701
+ cur = cur.parent;
2702
+ }
2703
+ return false;
2704
+ }
2705
+ /** True for goto/break/continue/label identifiers (never values). */
2706
+ isCSharpLabelOrDiscard(node) {
2707
+ const p = node.parent;
2708
+ return !!p && (p.type === "goto_statement" || p.type === "break_statement" || p.type === "continue_statement" || p.type === "labeled_statement");
2709
+ }
2710
+ /** True when `node` is the defining NAME of its entity parent, or a TYPE it declares. */
2711
+ /**
2712
+ * CS-D8 helper: is this identifier inside a declared TYPE, judged by which declaration owns a
2713
+ * `type` field that CONTAINS it? See the CS-D8 note in `isCSharpEntityName` for why the walk
2714
+ * ascends through name-shaped wrappers and why it is bounded.
2715
+ */
2716
+ isDeclaredTypeSite(node) {
2717
+ const DECL = "declaration";
2718
+ let cur = node.parent;
2719
+ for (let hops = 0; cur && hops < 12; hops++) {
2720
+ const t = cur.type;
2721
+ if (t === "variable_declaration" || t === "parameter" || t === "property_declaration" || t === "indexer_declaration" || t === "event_declaration" || t === "event_field_declaration" || t === "variable_declarator" || t === "base_list" || t === "type_parameter_list" || t === "type_parameter_constraints_clause" || t === "delegate_declaration") {
2722
+ const tf = cur.childForFieldName("type");
2723
+ if (tf && node.startIndex >= tf.startIndex && node.endIndex <= tf.endIndex) return true;
2724
+ if (t === "variable_declarator") return false;
2725
+ }
2726
+ if (t.includes(DECL) || t === "class_body" || t === "block" || t.includes("statement")) return false;
2727
+ cur = cur.parent;
2728
+ }
2729
+ return false;
2730
+ }
2731
+ isCSharpEntityName(node) {
2732
+ const p = node.parent;
2733
+ if (!p) return false;
2734
+ if (this.isDeclaredTypeSite(node)) return true;
2735
+ {
2736
+ const nf0 = p?.childForFieldName?.("name");
2737
+ if (nf0 && nf0.startIndex === node.startIndex && nf0.endIndex === node.endIndex) return true;
2738
+ }
2739
+ if (p.type === "parameter") {
2740
+ const t = p.childForFieldName("type");
2741
+ if (t && node.startIndex >= t.startIndex && node.endIndex <= t.endIndex) return true;
2742
+ }
2743
+ {
2744
+ const nf = p.childForFieldName("name");
2745
+ if (nf && nf.startIndex === node.startIndex && nf.endIndex === node.endIndex) return true;
2746
+ }
2747
+ switch (p.type) {
2748
+ case "class_declaration":
2749
+ case "struct_declaration":
2750
+ case "interface_declaration":
2751
+ case "record_declaration":
2752
+ case "enum_declaration":
2753
+ case "delegate_declaration":
2754
+ case "method_declaration":
2755
+ case "constructor_declaration":
2756
+ case "destructor_declaration":
2757
+ case "operator_declaration":
2758
+ case "conversion_operator_declaration":
2759
+ case "property_declaration":
2760
+ case "indexer_declaration":
2761
+ case "event_declaration":
2762
+ case "event_field_declaration":
2763
+ case "enum_member_declaration":
2764
+ case "namespace_declaration":
2765
+ case "file_scoped_namespace_declaration":
2766
+ break;
2767
+ default:
2768
+ return false;
2769
+ }
2770
+ for (let i = 0; i < p.namedChildCount; i++) {
2771
+ const c = p.namedChild(i);
2772
+ if (c && c.type === "identifier") {
2773
+ return c.startIndex === node.startIndex && c.endIndex === node.endIndex;
2774
+ }
2775
+ }
2776
+ return false;
2777
+ }
2778
+ /** True when `node` is an assignment-LHS write (GO9-class climb). */
2779
+ isCSharpAssignLhs(node) {
2780
+ let cur = node;
2781
+ let p = node.parent;
2782
+ while (p && p.type === "parenthesized_expression") {
2783
+ cur = p;
2784
+ p = p.parent;
2785
+ }
2786
+ if (!p || p.type !== "assignment_expression") return false;
2787
+ const lhs = p.namedChild(0);
2788
+ return !!lhs && cur.startIndex >= lhs.startIndex && cur.endIndex <= lhs.endIndex;
2789
+ }
2790
+ /** Find the nearest enclosing method/constructor/property symbol name. */
2791
+ findContainingCSharpFunction(node) {
2792
+ let cur = node.parent;
2793
+ while (cur) {
2794
+ if (cur.type === "method_declaration" || cur.type === "constructor_declaration" || cur.type === "destructor_declaration") {
2795
+ const name = cur.childForFieldName("name")?.text || this.childText(cur, "identifier") || (cur.type === "constructor_declaration" ? "constructor" : "anonymous");
2796
+ if (cur.type === "constructor_declaration") return "constructor";
2797
+ if (cur.type === "destructor_declaration") return "Finalize";
2798
+ return name;
2799
+ }
2800
+ if (cur.type === "property_declaration" || cur.type === "indexer_declaration") {
2801
+ return cur.type === "indexer_declaration" ? "this" : cur.childForFieldName("name")?.text || this.childText(cur, "identifier") || "anonymous";
2802
+ }
2803
+ cur = cur.parent;
2804
+ }
2805
+ return null;
2806
+ }
2807
+ buildCSharpCallExpression(node) {
2808
+ const func = node.childForFieldName("function") || this.findChild(node, (n) => n.type === "identifier" || n.type === "generic_name" || n.type === "member_access_expression");
2809
+ if (!func) return null;
2810
+ if (func.type === "member_access_expression") {
2811
+ const nameNode = func.childForFieldName("name");
2812
+ const exprNode = func.childForFieldName("expression");
2813
+ if (!nameNode) return null;
2814
+ const leaf = nameNode.type === "generic_name" ? nameNode.childForFieldName("name")?.text || nameNode.text.split("<")[0] : nameNode.text;
2815
+ if (exprNode) {
2816
+ const expr = this.cleanTypeName(exprNode.text);
2817
+ return `${expr}.${leaf}`;
2818
+ }
2819
+ return leaf;
2820
+ }
2821
+ if (func.type === "generic_name") {
2822
+ return func.childForFieldName("name")?.text || func.text.split("<")[0];
2823
+ }
2824
+ return func.text;
2825
+ }
2826
+ resolveImplicitNewType(node, memberTypes) {
2827
+ return csharpResolveTargetTypedNew(node, memberTypes);
2828
+ }
2829
+ // ≡ /^[A-Za-z_][A-Za-z0-9_]*$/.test(s) — zero-regex helper (M49 closure
2830
+ // wave). \w ≡ [A-Za-z0-9_] in non-unicode mode.
2831
+ isPlainIdentifier(s) {
2832
+ if (s.length === 0) return false;
2833
+ const c0 = s.charCodeAt(0);
2834
+ const firstOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95;
2835
+ if (!firstOk) return false;
2836
+ for (let i = 1; i < s.length; i++) {
2837
+ const c = s.charCodeAt(i);
2838
+ const ok = c >= 65 && c <= 90 || c >= 97 && c <= 122 || c >= 48 && c <= 57 || c === 95;
2839
+ if (!ok) return false;
2840
+ }
2841
+ return true;
2842
+ }
2843
+ // ≡ /:\s*base\s*\(/ (zero-regex helper, M49 closure wave): colon, any
2844
+ // whitespace run, "base", optional whitespace, open paren.
2845
+ matchesBaseInitializer(text) {
2846
+ let i = text.indexOf(":");
2847
+ if (i === -1) return false;
2848
+ i++;
2849
+ while (i < text.length && (text[i] === " " || text[i] === " " || text[i] === "\n" || text[i] === "\r")) i++;
2850
+ if (!text.startsWith("base", i)) return false;
2851
+ i += 4;
2852
+ while (i < text.length && (text[i] === " " || text[i] === " " || text[i] === "\n" || text[i] === "\r")) i++;
2853
+ return i < text.length && text[i] === "(";
2854
+ }
2855
+ isCSharpBuiltin(call) {
2856
+ if (CSHARP_BUILTINS.has(call)) return true;
2857
+ const leaf = call.split(".").pop() || call;
2858
+ if (leaf === "ToString" || leaf === "GetHashCode" || leaf === "Equals" || leaf === "GetType" || leaf === "ReferenceEquals") return true;
2859
+ return false;
2860
+ }
2861
+ extractVisibility(node) {
2862
+ for (let i = 0; i < node.namedChildCount; i++) {
2863
+ const child = node.namedChild(i);
2864
+ if (child && child.type === "modifier") {
2865
+ const text = child.text;
2866
+ if (text === "public") return "public";
2867
+ if (text === "private") return "private";
2868
+ if (text === "protected") return "protected";
2869
+ if (text === "internal") return "internal";
2870
+ if (text === "file") return "private";
2871
+ }
2872
+ }
2873
+ return void 0;
2874
+ }
2875
+ hasModifier(node, modifier) {
2876
+ for (let i = 0; i < node.namedChildCount; i++) {
2877
+ const child = node.namedChild(i);
2878
+ if (child && child.type === "modifier" && child.text === modifier) return true;
2879
+ }
2880
+ return false;
2881
+ }
2882
+ extractNamespaceName(node) {
2883
+ const nameNode = this.findChild(node, (n) => n.type === "qualified_name" || n.type === "identifier");
2884
+ return nameNode ? nameNode.text : "anonymous";
2885
+ }
2886
+ cleanTypeName(text) {
2887
+ const spelled = csharpTypeSpelling(text);
2888
+ const lt = spelled.indexOf("<");
2889
+ const base = lt > 0 ? spelled.slice(0, lt) : spelled;
2890
+ const q = base.indexOf("?");
2891
+ return (q > 0 ? base.slice(0, q) : base).trim();
2892
+ }
2893
+ /**
2894
+ * A type's DECLARATION path: itself, qualified by enclosing TYPE declarations only.
2895
+ *
2896
+ * `buildFullName` qualifies with every enclosing scope including NAMESPACES, which is
2897
+ * right for an FQN and wrong for a relationship source. This lane's hand-audited truth
2898
+ * labels an extends/implements edge at the declared name — `BaseService`, `UserService`,
2899
+ * `Shape`, `IRepository` — and for a NESTED type it keeps the enclosing type but still
2900
+ * drops the namespace: `UserService.User -> BaseService.Entity`, not
2901
+ * `Example.Service.UserService.User`. That is why the nested row matched before this fix
2902
+ * and the seven top-level ones did not: `UserService.User` happens to equal the declared
2903
+ * path while `Example.Base.BaseService` does not.
2904
+ *
2905
+ * So seven false negatives were a label, not a missing edge.
2906
+ */
2907
+ declarationPath(scopeStack, name) {
2908
+ const segs = [];
2909
+ for (let i = 0; i < scopeStack.length; i++) {
2910
+ if (scopeStack[i].kind === ASTEngine.SymbolKind.Namespace) continue;
2911
+ segs.push(scopeStack[i].rawName);
2912
+ }
2913
+ segs.push(name);
2914
+ return segs.join(".");
2915
+ }
2916
+ /**
2917
+ * One assembly-export row per exported TYPE: the fully-qualified name, the declaration's
2918
+ * ARITY (generic arity is identity — `Reporter` and `Reporter<T>` are two types), the NAME's
2919
+ * own line, and the symbol kind. Deduped on (name, arity): `partial` declarations of one type
2920
+ * are ONE exported unit (on the FIRST declaration's line), while a partial split that crosses
2921
+ * arity stays two units. The M49 duplicate-provider invariant is why the dedupe is here.
2922
+ */
2923
+ pushExportInfo(exports, name, arity, line, kind, visibility) {
2924
+ if (!name || visibility !== "public") return;
2925
+ for (const e of exports) if (e.name === name && e.arity === arity) return;
2926
+ exports.push({ name, kind, arity, line, visibility });
2927
+ }
2928
+ buildFullName(scopeStack, name) {
2929
+ if (scopeStack.length === 0) return name;
2930
+ let res = "";
2931
+ for (let i = 0; i < scopeStack.length; i++) {
2932
+ const raw = scopeStack[i].rawName;
2933
+ if (raw.indexOf(".") >= 0) res = raw + ".";
2934
+ else res += raw + ".";
2935
+ }
2936
+ return res + name;
2937
+ }
2938
+ extractTypeString(node) {
2939
+ const typeNodes = [
2940
+ "predefined_type",
2941
+ "type_identifier",
2942
+ "identifier",
2943
+ "generic_name",
2944
+ "array_type",
2945
+ "nullable_type",
2946
+ "tuple_type",
2947
+ "implicit_type"
2948
+ ];
2949
+ for (let idx = 0; idx < typeNodes.length; idx++) {
2950
+ const t = typeNodes[idx];
2951
+ const found = this.findChild(node, (n) => n.type === t);
2952
+ if (found) return found.text;
2953
+ }
2954
+ return void 0;
2955
+ }
2956
+ extractAttributes(node) {
2957
+ const attrs = [];
2958
+ const attrLists = this.findAllChildren(node, "attribute_list");
2959
+ for (let idx = 0; idx < attrLists.length; idx++) {
2960
+ const list = attrLists[idx];
2961
+ for (let i = 0; i < list.namedChildCount; i++) {
2962
+ const attr = list.namedChild(i);
2963
+ if (attr && attr.type === "attribute") {
2964
+ const nameNode = this.findChild(attr, (n) => n.type === "identifier" || n.type === "generic_name" || n.type === "qualified_name" || n.type === "alias_qualified_name");
2965
+ if (nameNode) {
2966
+ const name = csharpCleanTypeLeaf(csharpTypeNameText(csharpTypeSpelling(nameNode.text)));
2967
+ if (name) attrs.push(name);
2968
+ }
2969
+ }
2970
+ }
2971
+ }
2972
+ return attrs;
2973
+ }
2974
+ /**
2975
+ * M59.A7 (#825): the 1-based line of the node that NAMES an edge's target.
2976
+ *
2977
+ * The contract is the family's, not this file's: a relationship's
2978
+ * `line_number` is the line where the TARGET is written — the callee for a
2979
+ * call, the read for a member use, the constructed type for an instantiation,
2980
+ * the symbol's own declaration for contains/overrides. It is checked
2981
+ * independently by script/m59/oracle-callsite.ts, which re-derives every edge
2982
+ * from the tree and requires the target token to appear on the claimed line.
2983
+ *
2984
+ * Three shapes are traps and all three were measured on this lane (probe:
2985
+ * script/m14/tmp/cs-line-shapes.ts) rather than assumed:
2986
+ * * an invocation node starts at its RECEIVER, so `helper\n .Strip()` needs
2987
+ * the callee leaf, not the call node;
2988
+ * * a `constructor_initializer` starts at its `:` and `base`/`this` are
2989
+ * anonymous children, so a wrapped initializer needs the keyword token or
2990
+ * it lands one line early;
2991
+ * * a target-typed `new()` names NO type at the call site at all — the
2992
+ * target is written in the DECLARATION (see targetTypedNewTypeNode).
2993
+ *
2994
+ * `undefined` is a first-class answer. A node that does not exist contributes
2995
+ * NO line rather than a fabricated 0, which is the rule `0 means unknown and
2996
+ * unknown must be absent` (#820/#821) applied to this field.
2997
+ */
2998
+ nodeLine(node) {
2999
+ if (!node) return void 0;
3000
+ return node.startPosition.row + 1;
3001
+ }
3002
+ /**
3003
+ * The `base` / `this` keyword of a constructor_initializer.
3004
+ *
3005
+ * Both are ANONYMOUS tokens in tree-sitter-c-sharp, so findChild (named
3006
+ * children only) cannot see them, and the initializer node itself starts at
3007
+ * the `:`. Measured: `public C(int x)\n :\n base(x)` puts the colon on 3
3008
+ * and the keyword on 4 — the keyword is the node that names the target.
3009
+ */
3010
+ initializerKeywordNode(node) {
3011
+ for (let i = 0; i < node.childCount; i++) {
3012
+ const child = node.child(i);
3013
+ if (child && (child.type === "base" || child.type === "this")) return child;
3014
+ }
3015
+ return null;
3016
+ }
3017
+ /**
3018
+ * The FIRST anonymous child whose text is `text` — an operator or punctuation
3019
+ * token, which `findChild` (named children only) cannot see.
3020
+ *
3021
+ * Added for the M60.R1 paydown: a using directive's alias form is the only
3022
+ * shape that contains an `=`, and position (not text) is what tells the ALIAS
3023
+ * from the TARGET — see the using_directive branch. Returns the NODE, so the
3024
+ * caller can then ask for the child after it as well as its presence.
3025
+ */
3026
+ anonymousChildNode(node, text) {
3027
+ for (let i = 0; i < node.childCount; i++) {
3028
+ const child = node.child(i);
3029
+ if (child && child.type === text) return child;
3030
+ }
3031
+ return null;
3032
+ }
3033
+ /** The first NAMED child that starts after `after` ends — the target of an
3034
+ * alias using, which the grammar writes after the `=`. */
3035
+ firstNamedChildAfter(node, after) {
3036
+ for (let i = 0; i < node.namedChildCount; i++) {
3037
+ const child = node.namedChild(i);
3038
+ if (child && child.startIndex >= after.endIndex) return child;
3039
+ }
3040
+ return null;
3041
+ }
3042
+ /**
3043
+ * The node that CARRIES a declaration's declared type.
3044
+ *
3045
+ * Mirrors csharpMemberDeclaredTypeText's holder resolution exactly (the same
3046
+ * three shapes: field_declaration > variable_declaration, a variable_declarator
3047
+ * whose type lives on the enclosing variable_declaration, and property/
3048
+ * indexer/other declarations that hold the type themselves), because the two
3049
+ * must never disagree about WHICH declaration answered — one writes the text,
3050
+ * the other is used for the line stamp.
3051
+ */
3052
+ memberDeclaredTypeNode(memberLike) {
3053
+ if (!memberLike) return null;
3054
+ let holder = memberLike;
3055
+ if (memberLike.type === "field_declaration") {
3056
+ holder = this.findChild(memberLike, "variable_declaration");
3057
+ } else if (memberLike.type === "variable_declarator" && memberLike.parent?.type === "variable_declaration") {
3058
+ holder = memberLike.parent;
3059
+ }
3060
+ if (!holder) return null;
3061
+ const typeField = holder.childForFieldName("type");
3062
+ if (typeField) return typeField;
3063
+ const nameChild = holder.childForFieldName("name");
3064
+ for (let i = 0; i < holder.namedChildCount; i++) {
3065
+ const child = holder.namedChild(i);
3066
+ if (!child || !CSHARP_DECLARED_TYPE_NODES.has(child.type)) continue;
3067
+ if (nameChild && child.startIndex === nameChild.startIndex && child.endIndex === nameChild.endIndex) continue;
3068
+ return child;
3069
+ }
3070
+ return null;
3071
+ }
3072
+ /**
3073
+ * The narrowest node inside a type annotation whose text IS `target`.
3074
+ *
3075
+ * For `List<EnumSettingEntry> xs = new();` the target is the ELEMENT type, so
3076
+ * the node that names it is the type argument, not the annotation. Matching is
3077
+ * by exact text (then by csharpCleanTypeLeaf, which is the same unwrapping the
3078
+ * target text went through), and the narrowest match wins. No match means the
3079
+ * target was resolved from something other than a written name — an honest
3080
+ * no-line, never a guess at a nearby line.
3081
+ */
3082
+ nodeNamingToken(typeNode, target) {
3083
+ if (!typeNode) return null;
3084
+ const parts = target.split(".");
3085
+ const leaf = parts[parts.length - 1] || target;
3086
+ let best = null;
3087
+ const stack = [typeNode];
3088
+ while (stack.length > 0) {
3089
+ const n = stack.pop();
3090
+ const text = n.text;
3091
+ if (text === leaf || csharpCleanTypeLeaf(text) === leaf) {
3092
+ if (!best || n.endIndex - n.startIndex <= best.endIndex - best.startIndex) best = n;
3093
+ }
3094
+ for (let i = 0; i < n.namedChildCount; i++) {
3095
+ const child = n.namedChild(i);
3096
+ if (child) stack.push(child);
3097
+ }
3098
+ }
3099
+ return best;
3100
+ }
3101
+ /**
3102
+ * M59.A7 (#825), the target-typed-`new()` site.
3103
+ *
3104
+ * `List<T> xs = new();` writes its construction target in the DECLARATION, and
3105
+ * the assignment form (`xs = new();`) writes it on the MEMBER's declaration,
3106
+ * not on the assignment line. Both are reached through the shared walk
3107
+ * (csharpTargetTypedNewSite) so the stamp and the resolved target can never
3108
+ * describe different declarations; the member table carries the node for the
3109
+ * assignment form, because the declaration is in another subtree.
3110
+ */
3111
+ targetTypedNewTypeNode(node, memberTypes, memberTypeNodes, target) {
3112
+ const site = csharpTargetTypedNewSite(node);
3113
+ if (!site) return null;
3114
+ const holder = site.kind === "declaration" ? site.decl : memberTypeNodes.get(site.memberName) ?? null;
3115
+ return this.nodeNamingToken(this.memberDeclaredTypeNode(holder), target);
3116
+ }
3117
+ /**
3118
+ * Is a call's callee a node that NAMES something?
3119
+ *
3120
+ * Found by a depth draw rather than by reading the code: on powershell's
3121
+ * `RunspaceConnectionInfo.cs` the grammar's error recovery (one ERROR node
3122
+ * spanning `false; return StartSSHProcessImpl(...)`) produced an
3123
+ * invocation_expression whose `function` field IS a `boolean_literal`, and the
3124
+ * analyzer emitted `calls StartSSHProcess -> false` — a fabricated call to a
3125
+ * literal, the only unexplained edge on a 900-file draw (line 2331, measured
3126
+ * with script/m14/tmp/cs-u2331-probe.ts). The old hygiene checked the target
3127
+ * STRING (keyword set + identifier shape + builtin set), and `false` is a
3128
+ * well-formed identifier as far as a string check can see. The rule is
3129
+ * structural instead: a callee names its target only if the node that carries
3130
+ * it is a NAME node (an identifier or a generic_name) — which is what the
3131
+ * existing keyword-list rejection encodes for the legal `if (...)` case, done
3132
+ * once for every junk-callee shape.
3133
+ */
3134
+ isCSharpCalleeNameNode(node) {
3135
+ if (!node) return false;
3136
+ return node.type === "identifier" || node.type === "generic_name";
3137
+ }
3138
+ /**
3139
+ * The node that names a call's target: the callee leaf.
3140
+ *
3141
+ * Mirrors buildCSharpCallExpression's leaf selection (the member-access NAME
3142
+ * field, a generic_name's name field, else the callee node itself) — that
3143
+ * function returns the text, this returns the node the text is written on.
3144
+ */
3145
+ csharpCallCalleeNode(node) {
3146
+ const func = node.childForFieldName("function") || this.findChild(node, (n) => n.type === "identifier" || n.type === "generic_name" || n.type === "member_access_expression");
3147
+ if (!func) return null;
3148
+ if (func.type === "member_access_expression") {
3149
+ const nameNode = func.childForFieldName("name");
3150
+ if (!nameNode) return null;
3151
+ return nameNode.type === "generic_name" ? nameNode.childForFieldName("name") ?? nameNode : nameNode;
3152
+ }
3153
+ if (func.type === "generic_name") return func.childForFieldName("name") ?? func;
3154
+ if (func.type === "conditional_access_expression" || func.type === "member_binding_expression") {
3155
+ const binding = func.type === "member_binding_expression" ? func : this.findChild(func, (n) => n.type === "member_binding_expression");
3156
+ const leaf = binding ? this.csharpBindingLeaf(binding) : null;
3157
+ return leaf ?? func;
3158
+ }
3159
+ return func;
3160
+ }
3161
+ /**
3162
+ * The identifier a `member_binding_expression` binds: the member name after
3163
+ * the dot (`.Invoke` -> `Invoke`). Walks the binding's children backwards
3164
+ * because the dot is an anonymous token and the name is the last name node.
3165
+ */
3166
+ csharpBindingLeaf(binding) {
3167
+ for (let i = binding.childCount - 1; i >= 0; i--) {
3168
+ const child = binding.child(i);
3169
+ if (!child) continue;
3170
+ if (child.type === "identifier") return child;
3171
+ if (child.type === "generic_name") return child.childForFieldName("name") ?? child;
3172
+ }
3173
+ return null;
3174
+ }
3175
+ nodeToRange(node) {
3176
+ return {
3177
+ startLine: node.startPosition.row + 1,
3178
+ startColumn: node.startPosition.column + 1,
3179
+ endLine: node.endPosition.row + 1,
3180
+ endColumn: node.endPosition.column + 1,
3181
+ startIndex: node.startIndex,
3182
+ endIndex: node.endIndex
3183
+ };
3184
+ }
3185
+ findChild(node, type) {
3186
+ for (let i = 0; i < node.namedChildCount; i++) {
3187
+ const child = node.namedChild(i);
3188
+ if (!child) continue;
3189
+ if (typeof type === "string" ? child.type === type : type(child)) return child;
3190
+ }
3191
+ return null;
3192
+ }
3193
+ findAllChildren(node, type) {
3194
+ const res = [];
3195
+ for (let i = 0; i < node.namedChildCount; i++) {
3196
+ const child = node.namedChild(i);
3197
+ if (child && child.type === type) res.push(child);
3198
+ }
3199
+ return res;
3200
+ }
3201
+ childText(node, type) {
3202
+ const child = this.findChild(node, type);
3203
+ return child ? child.text : null;
3204
+ }
3205
+ };
3206
+ function stringIncludes(str, val) {
3207
+ return str.indexOf(val) !== -1;
3208
+ }
3209
+ var CS_FRAMEWORK_ORDER = [
3210
+ "ASP.NET Core",
3211
+ "Entity Framework Core",
3212
+ "Unity",
3213
+ "WPF",
3214
+ "Windows Forms",
3215
+ "xUnit",
3216
+ "NUnit",
3217
+ "MSTest"
3218
+ ];
3219
+ var CS_FRAMEWORK_PATTERNS = {
3220
+ "ASP.NET Core": ["mvc_pattern", "api_endpoints"],
3221
+ "Entity Framework Core": ["orm_mapping", "repository_pattern"],
3222
+ Unity: ["game_engine"],
3223
+ WPF: ["ui_framework"],
3224
+ "Windows Forms": ["ui_framework"],
3225
+ xUnit: ["test_framework"],
3226
+ NUnit: ["test_framework"],
3227
+ MSTest: ["test_framework"]
3228
+ };
3229
+ function csharpSetHasAny(s, vs) {
3230
+ for (let i = 0; i < vs.length; i++) if (s.has(vs[i])) return true;
3231
+ return false;
3232
+ }
3233
+ function csharpUsingPrefix(usings, prefix) {
3234
+ for (const u of usings) {
3235
+ if (u === prefix || u.startsWith(prefix + ".")) return true;
3236
+ }
3237
+ return false;
3238
+ }
3239
+ var CS_FRAMEWORK_MARKERS = {
3240
+ "ASP.NET Core": (u, b, a) => csharpUsingPrefix(u, "Microsoft.AspNetCore") || csharpSetHasAny(b, ["Controller", "ControllerBase", "PageModel", "Hub"]) || csharpSetHasAny(a, ["ApiController", "HttpGet", "HttpPost", "HttpPut", "HttpDelete", "HttpPatch"]),
3241
+ "Entity Framework Core": (u, b) => csharpUsingPrefix(u, "Microsoft.EntityFrameworkCore") || b.has("DbContext"),
3242
+ Unity: (u, b) => csharpUsingPrefix(u, "UnityEngine") || csharpSetHasAny(b, ["MonoBehaviour", "ScriptableObject"]),
3243
+ WPF: (u, b) => {
3244
+ for (const x of u) {
3245
+ if ((x === "System.Windows" || x.startsWith("System.Windows.")) && !(x === "System.Windows.Forms" || x.startsWith("System.Windows.Forms."))) {
3246
+ return true;
3247
+ }
3248
+ }
3249
+ return csharpSetHasAny(b, ["Window", "UserControl"]);
3250
+ },
3251
+ "Windows Forms": (u, b) => csharpUsingPrefix(u, "System.Windows.Forms") || b.has("Form"),
3252
+ xUnit: (u, _b, a) => csharpUsingPrefix(u, "Xunit") || csharpSetHasAny(a, ["Fact", "Theory"]),
3253
+ NUnit: (u, _b, a) => csharpUsingPrefix(u, "NUnit") || a.has("TestFixture"),
3254
+ MSTest: (u, _b, a) => csharpUsingPrefix(u, "Microsoft.VisualStudio.TestTools") || csharpSetHasAny(a, ["TestClass", "TestMethod"])
3255
+ };
3256
+ function csharpUsingDirectivePath(text) {
3257
+ let t = text.trim();
3258
+ const semi = t.indexOf(";");
3259
+ if (semi >= 0) t = t.slice(0, semi);
3260
+ t = t.trim();
3261
+ for (; ; ) {
3262
+ if (t.startsWith("global ")) {
3263
+ t = t.slice(7).trim();
3264
+ continue;
3265
+ }
3266
+ if (t.startsWith("using ")) {
3267
+ t = t.slice(6).trim();
3268
+ continue;
3269
+ }
3270
+ if (t.startsWith("static ")) {
3271
+ t = t.slice(7).trim();
3272
+ continue;
3273
+ }
3274
+ break;
3275
+ }
3276
+ const eq = t.indexOf("=");
3277
+ if (eq >= 0) t = t.slice(eq + 1).trim();
3278
+ const space = t.indexOf(" ");
3279
+ if (space >= 0) t = t.slice(0, space);
3280
+ return t.length > 0 ? t : void 0;
3281
+ }
3282
+ function csharpTypeLeafName(n) {
3283
+ const leaf = csharpTypeLeafNode(n);
3284
+ return leaf ? leaf.text : void 0;
3285
+ }
3286
+ export {
3287
+ RealCSharpAnalyzer,
3288
+ csharpCleanTypeLeaf,
3289
+ csharpDeclaredTypeRefs,
3290
+ csharpMemberDeclaredTypeText,
3291
+ csharpResolveTargetTypedNew,
3292
+ csharpTargetFromDeclaredType,
3293
+ csharpTargetTypedNewSite,
3294
+ csharpTypeNameText,
3295
+ csharpTypeSpelling,
3296
+ csharpUsingDirectiveKind,
3297
+ csharpUsingDirectiveTarget
3298
+ };