@backbencher/brain 0.0.0-stage → 0.1.1

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-Q5APTJQL.js +17 -0
  8. package/dist/brain-relationship-enrichment-MYR2AM4F.js +558 -0
  9. package/dist/brain.sql-EIM4WS4D.js +29 -0
  10. package/dist/chunk-22V37YTK.js +1758 -0
  11. package/dist/chunk-2BSKD7O3.js +40 -0
  12. package/dist/chunk-2DE27DVC.js +1314 -0
  13. package/dist/chunk-2RRBMNBQ.js +322 -0
  14. package/dist/chunk-2WXYNLBA.js +29 -0
  15. package/dist/chunk-3CTFIJJB.js +17 -0
  16. package/dist/chunk-3ZTOHHSW.js +2104 -0
  17. package/dist/chunk-4H22TLOT.js +543 -0
  18. package/dist/chunk-5BVAH26D.js +340 -0
  19. package/dist/chunk-62DHLYW6.js +3427 -0
  20. package/dist/chunk-7AN7U5IZ.js +371 -0
  21. package/dist/chunk-7DRPNVIN.js +782 -0
  22. package/dist/chunk-7MBYT777.js +174 -0
  23. package/dist/chunk-AHDWGM7Q.js +236 -0
  24. package/dist/chunk-B5GEAAYF.js +818 -0
  25. package/dist/chunk-BEIZZ73B.js +1479 -0
  26. package/dist/chunk-BQ3OVQ3P.js +125 -0
  27. package/dist/chunk-D2Q4Y47A.js +53 -0
  28. package/dist/chunk-DIYAGQJL.js +34 -0
  29. package/dist/chunk-DWKXZ6IF.js +336 -0
  30. package/dist/chunk-DYM4FQEE.js +90 -0
  31. package/dist/chunk-ENW4BTBA.js +930 -0
  32. package/dist/chunk-EWMWK7WN.js +75 -0
  33. package/dist/chunk-EY5ZZUUA.js +626 -0
  34. package/dist/chunk-GBI7V7KY.js +69 -0
  35. package/dist/chunk-GEFFO6O2.js +152 -0
  36. package/dist/chunk-HJEWO5EV.js +247 -0
  37. package/dist/chunk-HQSPJDHI.js +613 -0
  38. package/dist/chunk-KAET47ZL.js +125 -0
  39. package/dist/chunk-KCDECRJY.js +440 -0
  40. package/dist/chunk-L5TDYKYK.js +76 -0
  41. package/dist/chunk-MLKGABMK.js +9 -0
  42. package/dist/chunk-NO3U3FJQ.js +201 -0
  43. package/dist/chunk-OWISBAOF.js +61 -0
  44. package/dist/chunk-QKTRECYS.js +1119 -0
  45. package/dist/chunk-QLK6ED4Q.js +235 -0
  46. package/dist/chunk-R2GW4F6R.js +19 -0
  47. package/dist/chunk-RCMTFSEF.js +87 -0
  48. package/dist/chunk-RM3PY6TG.js +376 -0
  49. package/dist/chunk-ROMM6KMC.js +433 -0
  50. package/dist/chunk-SGGCSHAX.js +12050 -0
  51. package/dist/chunk-SK6YVHFZ.js +211 -0
  52. package/dist/chunk-SM7RFQRO.js +214 -0
  53. package/dist/chunk-UGR4QIGS.js +67 -0
  54. package/dist/chunk-UQNQZXHY.js +711 -0
  55. package/dist/chunk-UUNHHX4M.js +13 -0
  56. package/dist/chunk-VL52PL2T.js +71 -0
  57. package/dist/chunk-WIG36E67.js +196 -0
  58. package/dist/chunk-XHK3WWGB.js +7436 -0
  59. package/dist/chunk-XTQM2IP3.js +2863 -0
  60. package/dist/chunk-ZE2LG76D.js +1296 -0
  61. package/dist/chunk-ZETTGPAW.js +6950 -0
  62. package/dist/cli/index.js +37 -0
  63. package/dist/config-HZAAYDP3.js +10 -0
  64. package/dist/content-search-7XIP555Q.js +593 -0
  65. package/dist/database-76RP44JG.js +9 -0
  66. package/dist/doctor-ANGETYMN.js +395 -0
  67. package/dist/edit-engine-CG72LDZD.js +51 -0
  68. package/dist/engine-BKEOGN7N.js +11 -0
  69. package/dist/engine-VIW6NSKO.js +18 -0
  70. package/dist/fingerprint-OBLIMZLP.js +33 -0
  71. package/dist/framework-intelligence-3LORTPOX.js +860 -0
  72. package/dist/freshness-3K6VU5OT.js +174 -0
  73. package/dist/graph-engine-HBSQNPTB.js +21 -0
  74. package/dist/graph_request-Q6NKB6N2.js +350 -0
  75. package/dist/impact_request-LYP672WE.js +68 -0
  76. package/dist/index-space-IUUN5WYV.js +15 -0
  77. package/dist/index-status-7OVGYSGW.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-FK2XKZXY.js +88 -0
  86. package/dist/pool-worker.js +1153 -0
  87. package/dist/project-health-6XPENVAA.js +94 -0
  88. package/dist/project-index-5SDPHITE.js +57 -0
  89. package/dist/project-registry-ZJ3DVUGO.js +355 -0
  90. package/dist/real-bash-analyzer-EJAU5LW5.js +2201 -0
  91. package/dist/real-c-analyzer-HBD3FNNH.js +5942 -0
  92. package/dist/real-clean-analyzer-4EEZLPV5.js +3470 -0
  93. package/dist/real-clojure-analyzer-Q55EBOO2.js +2818 -0
  94. package/dist/real-cpp-analyzer-IVVOD25R.js +4101 -0
  95. package/dist/real-csharp-analyzer-ZBNLNJZJ.js +3298 -0
  96. package/dist/real-css-analyzer-6XRQLUN7.js +15 -0
  97. package/dist/real-dart-analyzer-OLR72EFW.js +3944 -0
  98. package/dist/real-elixir-analyzer-MQWGAH2I.js +2192 -0
  99. package/dist/real-erlang-analyzer-7BVPQEHO.js +1731 -0
  100. package/dist/real-fsharp-analyzer-C2UPFNOA.js +2390 -0
  101. package/dist/real-go-analyzer-UKGI43YS.js +4126 -0
  102. package/dist/real-graphql-analyzer-VE2EEFII.js +1442 -0
  103. package/dist/real-groovy-analyzer-W26VACFW.js +2285 -0
  104. package/dist/real-haskell-analyzer-5CVVAJRX.js +2533 -0
  105. package/dist/real-hcl-analyzer-5ZT4U43N.js +725 -0
  106. package/dist/real-html-analyzer-JWNX3C6I.js +1759 -0
  107. package/dist/real-java-analyzer-GU42VBGQ.js +4677 -0
  108. package/dist/real-javascript-analyzer-QA4QOJ6W.js +14 -0
  109. package/dist/real-json-analyzer-MPA6PRXL.js +1640 -0
  110. package/dist/real-julia-analyzer-22CWYQMN.js +2085 -0
  111. package/dist/real-kotlin-analyzer-QDZJLXXU.js +3956 -0
  112. package/dist/real-lua-analyzer-G7NHLYKS.js +1957 -0
  113. package/dist/real-makefile-analyzer-OCY3GT5N.js +920 -0
  114. package/dist/real-markdown-analyzer-TEJK2JXJ.js +1215 -0
  115. package/dist/real-matlab-analyzer-Q5SWLN7Z.js +480 -0
  116. package/dist/real-nim-analyzer-YLXSK563.js +3603 -0
  117. package/dist/real-objective-c-analyzer-D23ACC2R.js +1518 -0
  118. package/dist/real-perl-analyzer-WWTRHYDT.js +1865 -0
  119. package/dist/real-php-analyzer-JNKJHTCL.js +9368 -0
  120. package/dist/real-powershell-analyzer-XRSNQERV.js +2915 -0
  121. package/dist/real-protobuf-analyzer-3OKUCZ7T.js +867 -0
  122. package/dist/real-python-analyzer-VXAFWI72.js +4880 -0
  123. package/dist/real-r-analyzer-ZGAIDVI4.js +2596 -0
  124. package/dist/real-ruby-analyzer-X2KTLVBH.js +2429 -0
  125. package/dist/real-rust-analyzer-OFFHPL2A.js +3359 -0
  126. package/dist/real-scala-analyzer-TSTW27J6.js +3293 -0
  127. package/dist/real-scss-analyzer-AVWYPSOQ.js +1515 -0
  128. package/dist/real-solidity-analyzer-UCI2KWUB.js +2608 -0
  129. package/dist/real-sql-analyzer-F77ZMQXR.js +3840 -0
  130. package/dist/real-svelte-analyzer-SF7NRUO5.js +2532 -0
  131. package/dist/real-swift-analyzer-MN5QT3QN.js +2311 -0
  132. package/dist/real-toml-analyzer-66L7BDCQ.js +929 -0
  133. package/dist/real-typescript-analyzer-6KEMVDWQ.js +14 -0
  134. package/dist/real-vb-analyzer-VICVPOP7.js +3145 -0
  135. package/dist/real-vba-analyzer-HXLTTHKM.js +466 -0
  136. package/dist/real-vue-analyzer-QXR56CFV.js +2680 -0
  137. package/dist/real-xml-analyzer-YL465ZJW.js +2405 -0
  138. package/dist/real-yaml-analyzer-SUBCBNSI.js +3528 -0
  139. package/dist/real-zig-analyzer-HIQLZMGY.js +2430 -0
  140. package/dist/regex-search-NJKHMZNO.js +239 -0
  141. package/dist/rules-ACHPB7QU.js +152 -0
  142. package/dist/scoped-path-MJYWJZQX.js +11 -0
  143. package/dist/setup-show-NT5ZHYNE.js +15 -0
  144. package/dist/setup-wizard-G5YYR5T6.js +24 -0
  145. package/dist/symbol-search-GZJIM2J2.js +16 -0
  146. package/dist/taint-KXUHHPIE.js +202 -0
  147. package/dist/taint-analyzer-N7YLZU3N.js +163 -0
  148. package/dist/tool-handlers-OJDC35DI.js +72 -0
  149. package/dist/tool-registry-BPEJNSZG.js +17 -0
  150. package/dist/tool-validation-Q57YMMBX.js +32 -0
  151. package/dist/type-inference-QMT2RMLV.js +13 -0
  152. package/dist/vector-binary-LMY4QGAN.js +19 -0
  153. package/dist/version-ABP2TUL2.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,4101 @@
1
+ import {
2
+ buildResolutionTables
3
+ } from "./chunk-2DE27DVC.js";
4
+ import {
5
+ ASTEngine
6
+ } from "./chunk-3ZTOHHSW.js";
7
+ import "./chunk-BQ3OVQ3P.js";
8
+ import "./chunk-SK6YVHFZ.js";
9
+ import "./chunk-2BSKD7O3.js";
10
+ import "./chunk-KAET47ZL.js";
11
+ import "./chunk-KCDECRJY.js";
12
+ import "./chunk-MLKGABMK.js";
13
+
14
+ // src/ast/real-cpp-analyzer.ts
15
+ var CPP_CITATION_STDLIB_ROOTS = /* @__PURE__ */ new Set([
16
+ "move",
17
+ "string",
18
+ "max",
19
+ "infinity",
20
+ "min",
21
+ "quiet_NaN",
22
+ "make_pair",
23
+ "isnan",
24
+ "signaling_NaN",
25
+ "swap",
26
+ "make_tuple",
27
+ "sort",
28
+ "to_string",
29
+ "forward",
30
+ "make_shared",
31
+ "make_unique",
32
+ "size_t",
33
+ "vector",
34
+ "map",
35
+ "unordered_map",
36
+ "set",
37
+ "pair",
38
+ "tuple",
39
+ "optional",
40
+ "variant",
41
+ "function",
42
+ "shared_ptr",
43
+ "unique_ptr",
44
+ "string_view",
45
+ "numeric_limits",
46
+ "find",
47
+ "begin",
48
+ "end",
49
+ "size",
50
+ "copy",
51
+ "fill",
52
+ "count",
53
+ "abs",
54
+ "fabs",
55
+ "sqrt",
56
+ "pow",
57
+ "floor",
58
+ "ceil",
59
+ "round",
60
+ "log",
61
+ "exp"
62
+ ]);
63
+ function cppCitationFacts(qualified, leaf) {
64
+ if (process.env.BB_CPP_CITATION !== "1") return {};
65
+ if (leaf === "" || !CPP_CITATION_STDLIB_ROOTS.has(leaf)) return {};
66
+ let t = String(qualified ?? "").trim();
67
+ if (t.startsWith("::")) t = t.slice(2);
68
+ const lt = t.indexOf("<");
69
+ if (lt > 0) t = t.slice(0, lt);
70
+ if (t.split("::")[0]?.trim() !== "std") return {};
71
+ return { languageNamespace: [leaf], languageNamespacePolicy: "strict-absent" };
72
+ }
73
+ function qualifiedOwnerSegment(qualified, leaf) {
74
+ if (qualified === "" || leaf === "") return null;
75
+ let depth = 0;
76
+ let flat = "";
77
+ for (let i = 0; i < qualified.length; i++) {
78
+ const ch = qualified[i];
79
+ if (ch === "<") depth++;
80
+ else if (ch === ">") depth = Math.max(0, depth - 1);
81
+ else if (depth === 0) flat += ch;
82
+ }
83
+ const t = flat.trim();
84
+ const cut = t.lastIndexOf("::");
85
+ if (cut <= 0) return null;
86
+ const segs = t.split("::").map((x) => x.trim());
87
+ for (const seg of segs) if (!isIdentifierShapeWithDollar(seg)) return null;
88
+ if (segs[segs.length - 1] !== leaf) return null;
89
+ return segs.length >= 2 ? segs[segs.length - 2] : null;
90
+ }
91
+ function isIdentifierShapeWithDollar(s) {
92
+ if (s.length === 0) return false;
93
+ const c0 = s.charCodeAt(0);
94
+ const headOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95 || c0 === 36;
95
+ if (!headOk) return false;
96
+ for (let i = 1; i < s.length; i++) {
97
+ const c = s.charCodeAt(i);
98
+ const ok = c >= 65 && c <= 90 || c >= 97 && c <= 122 || c >= 48 && c <= 57 || c === 95 || c === 36;
99
+ if (!ok) return false;
100
+ }
101
+ return true;
102
+ }
103
+ function collapseTypeNoise(t) {
104
+ let out = "";
105
+ let pending = false;
106
+ for (let i = 0; i < t.length; i++) {
107
+ const c = t[i];
108
+ const isNoise = c === "*" || c === "&" || c === " " || c === " " || c === "\n" || c === "\r" || c === "\f" || c === "\v";
109
+ if (isNoise) {
110
+ if (out.length > 0) pending = true;
111
+ continue;
112
+ }
113
+ if (pending) {
114
+ out += " ";
115
+ pending = false;
116
+ }
117
+ out += c;
118
+ }
119
+ return out.trim();
120
+ }
121
+ function stringIncludes(str, val) {
122
+ return str.indexOf(val) !== -1;
123
+ }
124
+ function stripIncludeChars(text) {
125
+ let out = "";
126
+ for (let i = 0; i < text.length; i++) {
127
+ const c = text[i];
128
+ if (c !== "<" && c !== ">" && c !== '"' && c !== "'") out += c;
129
+ }
130
+ return out;
131
+ }
132
+ function swapChar(text, from, to) {
133
+ let out = "";
134
+ for (let i = 0; i < text.length; i++) out += text[i] === from ? to : text[i];
135
+ return out;
136
+ }
137
+ function cppPackageScopeFacts(leaf, qualified, includeRoots, declaredPackages) {
138
+ if (process.env.BB_CPP_PACKAGE_SCOPE !== "1") return {};
139
+ if (leaf === "" || qualified === "" || includeRoots.size === 0 || declaredPackages.length === 0) return {};
140
+ const cut = qualified.lastIndexOf("::");
141
+ if (cut <= 0) return {};
142
+ const ns = qualified.slice(0, cut).trim().toLowerCase();
143
+ if (ns.length === 0) return {};
144
+ const sep = ns.indexOf("::");
145
+ const root = (sep >= 0 ? ns.slice(0, sep) : ns).trim();
146
+ if (root.length === 0) return {};
147
+ if (!includeRoots.has(root)) return {};
148
+ const matched = [];
149
+ for (const raw of declaredPackages) {
150
+ const pkg = String(raw ?? "").trim();
151
+ if (pkg.length === 0) continue;
152
+ const lower = pkg.toLowerCase();
153
+ if (root === lower || root === swapChar(lower, "_", "-") || root === swapChar(lower, "-", "_")) {
154
+ matched.push(pkg);
155
+ continue;
156
+ }
157
+ if (root.length >= 3 && lower.startsWith(root)) {
158
+ const next = lower.charAt(root.length);
159
+ if (next === "_" || next === "-" || next === "." || next === "/") matched.push(pkg);
160
+ }
161
+ }
162
+ if (matched.length !== 1) return {};
163
+ return { packageScope: { package: matched[0], name: leaf } };
164
+ }
165
+ function cppExternalIncludeRoots(root) {
166
+ const roots = /* @__PURE__ */ new Set();
167
+ const stack = [root];
168
+ while (stack.length > 0) {
169
+ const n = stack.pop();
170
+ if (!n) continue;
171
+ if (n.type === "preproc_include") {
172
+ const pathNode = n.childForFieldName("path");
173
+ const raw = (pathNode?.text ?? "").trim();
174
+ if (raw.startsWith("<")) {
175
+ const p = stripIncludeChars(raw).trim();
176
+ const slash = p.indexOf("/");
177
+ if (slash > 0) {
178
+ const seg = p.slice(0, slash).toLowerCase();
179
+ if (seg.length > 0) roots.add(seg);
180
+ }
181
+ }
182
+ }
183
+ for (let i = 0; i < n.childCount; i++) {
184
+ const c = n.child(i);
185
+ if (c) stack.push(c);
186
+ }
187
+ }
188
+ return roots;
189
+ }
190
+ function cppPartTargetPath(filePath, specifier) {
191
+ const dir = filePath.includes("/") ? filePath.slice(0, filePath.lastIndexOf("/")) : "";
192
+ const joined = dir === "" ? specifier : `${dir}/${specifier}`;
193
+ const absolute = joined.startsWith("/");
194
+ const out = [];
195
+ for (const seg of joined.split("/")) {
196
+ if (seg === "" || seg === ".") continue;
197
+ if (seg === "..") {
198
+ if (out.length > 0 && out[out.length - 1] !== "..") out.pop();
199
+ else out.push("..");
200
+ continue;
201
+ }
202
+ out.push(seg);
203
+ }
204
+ return `${absolute ? "/" : ""}${out.join("/")}`;
205
+ }
206
+ function cppPartSymbol(specifier) {
207
+ const slash = specifier.lastIndexOf("/");
208
+ const base = slash >= 0 ? specifier.slice(slash + 1) : specifier;
209
+ const dot = base.lastIndexOf(".");
210
+ const stem = dot > 0 ? base.slice(0, dot) : base;
211
+ return stem.trim();
212
+ }
213
+ function stripAccessSpecifier(text) {
214
+ const lower = text.toLowerCase();
215
+ if (lower.startsWith("public")) return text.slice("public".length).trim();
216
+ if (lower.startsWith("protected")) return text.slice("protected".length).trim();
217
+ if (lower.startsWith("private")) return text.slice("private".length).trim();
218
+ return text.trim();
219
+ }
220
+ function lastScopeSegment(text) {
221
+ let start = 0;
222
+ let out = "";
223
+ for (let i = 0; i <= text.length; i++) {
224
+ const atEnd = i === text.length;
225
+ const c = atEnd ? ":" : text[i];
226
+ const isSep = c === ":" || c === " " || c === " " || c === "\n" || c === "\r";
227
+ if (isSep) {
228
+ if (i > start) out = text.slice(start, i);
229
+ start = i + 1;
230
+ }
231
+ }
232
+ return out;
233
+ }
234
+ function collapseSpaces(text) {
235
+ let out = "";
236
+ let pendingSpace = false;
237
+ for (let i = 0; i < text.length; i++) {
238
+ const c = text[i];
239
+ const isWs = c === " " || c === " " || c === "\n" || c === "\r" || c === "\f" || c === "\v";
240
+ if (isWs) {
241
+ if (out) pendingSpace = true;
242
+ continue;
243
+ }
244
+ if (pendingSpace) {
245
+ out += " ";
246
+ pendingSpace = false;
247
+ }
248
+ out += c;
249
+ }
250
+ return out;
251
+ }
252
+ function sameExtent(a, b) {
253
+ if (!a || !b) return false;
254
+ return a.startIndex === b.startIndex && a.endIndex === b.endIndex;
255
+ }
256
+ function isMacroDecoratedClassFunction(node) {
257
+ for (let i = 0; i < node.namedChildCount; i++) {
258
+ const c = node.namedChild(i);
259
+ if (c && macroDecoratedClassDecl(c)) return true;
260
+ }
261
+ return false;
262
+ }
263
+ function isMacroSpelling(s) {
264
+ if (s.length < 1) return false;
265
+ const first = s.charCodeAt(0);
266
+ if (first < 65 || first > 90) return false;
267
+ for (let i = 1; i < s.length; i++) {
268
+ const c = s.charCodeAt(i);
269
+ const upper = c >= 65 && c <= 90;
270
+ const digit = c >= 48 && c <= 57;
271
+ if (!upper && !digit && c !== 95) return false;
272
+ }
273
+ return true;
274
+ }
275
+ var CPP_ANONYMOUS = "anonymous";
276
+ function macroDecoratedClassDecl(spec) {
277
+ if (spec.type !== "class_specifier" && spec.type !== "struct_specifier" && spec.type !== "union_specifier") return null;
278
+ for (let i = 0; i < spec.namedChildCount; i++) {
279
+ const c = spec.namedChild(i);
280
+ if (c && c.type === "field_declaration_list") return null;
281
+ }
282
+ const nameField = spec.childForFieldName?.("name")?.text?.trim();
283
+ if (!nameField || !isMacroSpelling(nameField)) return null;
284
+ const parent = spec.parent;
285
+ if (!parent || parent.type !== "function_definition") return null;
286
+ let body = null;
287
+ for (let i = 0; i < parent.namedChildCount; i++) {
288
+ const c = parent.namedChild(i);
289
+ if (c && c.type === "compound_statement") {
290
+ body = c;
291
+ break;
292
+ }
293
+ }
294
+ if (!body) return null;
295
+ const siblings = [];
296
+ let prevWasMacro = false;
297
+ for (let i = 0; i < parent.namedChildCount; i++) {
298
+ const c = parent.namedChild(i);
299
+ if (!c) continue;
300
+ if (sameExtent(c, spec) || body && sameExtent(c, body)) continue;
301
+ if (c.endIndex > body.startIndex) continue;
302
+ if (c.type === "ERROR") {
303
+ let firstNamed = null;
304
+ let named = 0;
305
+ for (let k = 0; k < c.namedChildCount; k++) {
306
+ const kc = c.namedChild(k);
307
+ if (!kc || !kc.isNamed) continue;
308
+ named++;
309
+ if (firstNamed === null) firstNamed = kc;
310
+ }
311
+ let hasColon = false;
312
+ let colonAt = -1;
313
+ for (let k = 0; k < c.childCount; k++) {
314
+ const kc = c.child(k);
315
+ if (kc && kc.type === ":") {
316
+ hasColon = true;
317
+ colonAt = kc.startIndex;
318
+ break;
319
+ }
320
+ }
321
+ const colonFirst = hasColon && firstNamed !== null && colonAt >= 0 && colonAt < firstNamed.startIndex;
322
+ siblings.push({
323
+ node: c,
324
+ error: true,
325
+ errorName: firstNamed && firstNamed.type === "identifier" ? firstNamed : null,
326
+ hasColon,
327
+ colonFirst,
328
+ prevWasMacro,
329
+ namedCount: named
330
+ });
331
+ prevWasMacro = false;
332
+ continue;
333
+ }
334
+ siblings.push({ node: c, error: false, errorName: null, hasColon: false, colonFirst: false, prevWasMacro, namedCount: 0 });
335
+ prevWasMacro = c.type === "identifier" && isMacroSpelling(c.text.trim());
336
+ }
337
+ let nameNode = null;
338
+ const bases = [];
339
+ const colonArm = siblings.find((s) => s.error && s.errorName && s.hasColon && !s.colonFirst);
340
+ if (colonArm) {
341
+ nameNode = colonArm.errorName;
342
+ const at = siblings.indexOf(colonArm);
343
+ for (let i = at + 1; i < siblings.length; i++) {
344
+ const c = siblings[i].node;
345
+ if (c.type === "identifier" || c.type === "qualified_identifier" || c.type === "template_type") bases.push(c);
346
+ }
347
+ } else {
348
+ const attrArm = siblings.find((s) => s.error && s.errorName && s.prevWasMacro);
349
+ if (attrArm) {
350
+ nameNode = attrArm.errorName;
351
+ } else {
352
+ const names = siblings.filter((s) => !s.error && (s.node.type === "identifier" || s.node.type === "template_type"));
353
+ const nonMacro = names.find((s) => !isMacroSpelling(s.node.text.trim()));
354
+ nameNode = (nonMacro ?? names[0])?.node ?? null;
355
+ }
356
+ }
357
+ if (!colonArm) for (const s of siblings) {
358
+ if (!s.error || !s.colonFirst) continue;
359
+ for (let k = 0; k < s.node.namedChildCount; k++) {
360
+ const kc = s.node.namedChild(k);
361
+ if (kc && (kc.type === "identifier" || kc.type === "qualified_identifier" || kc.type === "template_type")) bases.push(kc);
362
+ }
363
+ }
364
+ if (!nameNode) return null;
365
+ const name = nameNode.text.trim();
366
+ if (!isCppSpelledName(name)) return null;
367
+ return { name, nameNode, body, owner: parent, bases };
368
+ }
369
+ function enclosingFriendDeclaration(node) {
370
+ let cur = node.parent;
371
+ let guard = 0;
372
+ while (cur && guard++ < 64) {
373
+ if (cur.type === "friend_declaration") return cur;
374
+ cur = cur.parent;
375
+ }
376
+ return null;
377
+ }
378
+ function friendBodyOwner(scopeStack, fallback) {
379
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
380
+ const scope = scopeStack[i];
381
+ if (scope.kind === ASTEngine.SymbolKind.Class || scope.kind === ASTEngine.SymbolKind.Struct || scope.kind === ASTEngine.SymbolKind.Union) {
382
+ continue;
383
+ }
384
+ return scope;
385
+ }
386
+ return { node: fallback, name: "global", kind: ASTEngine.SymbolKind.Function };
387
+ }
388
+ function templateParameterNames(list) {
389
+ const names = /* @__PURE__ */ new Set();
390
+ for (let j = 0; j < list.namedChildCount; j++) {
391
+ const param = list.namedChild(j);
392
+ if (!param) continue;
393
+ let declared = null;
394
+ for (let k = 0; k < param.namedChildCount; k++) {
395
+ const c = param.namedChild(k);
396
+ if (c && (c.type === "identifier" || c.type === "type_identifier")) declared = c;
397
+ }
398
+ if (!declared) {
399
+ const stack = [param];
400
+ while (stack.length > 0) {
401
+ const n = stack.pop();
402
+ if (n.type === "identifier" || n.type === "type_identifier") declared = n;
403
+ for (let k = 0; k < n.namedChildCount; k++) {
404
+ const c = n.namedChild(k);
405
+ if (c) stack.push(c);
406
+ }
407
+ }
408
+ }
409
+ if (declared?.text) names.add(declared.text);
410
+ }
411
+ return names;
412
+ }
413
+ function isTemplateParameterListFrame(node) {
414
+ if (node.childCount < 3) return false;
415
+ if (node.child(0)?.type !== "<" || node.child(node.childCount - 1)?.type !== ">") return false;
416
+ for (let i = 1; i < node.childCount - 1; i++) {
417
+ const t = node.child(i)?.type;
418
+ if (t === "typename" || t === "class") return true;
419
+ }
420
+ return false;
421
+ }
422
+ function extendsTargetName(baseText, className) {
423
+ const leafOf = (raw) => {
424
+ let t = stripAccessSpecifier(raw);
425
+ const lt = t.indexOf("<");
426
+ if (lt !== -1) t = t.slice(0, lt).trim();
427
+ return lastScopeSegment(t);
428
+ };
429
+ const leaf = leafOf(baseText);
430
+ if (!leaf) return null;
431
+ if (leaf === leafOf(className)) return null;
432
+ return leaf;
433
+ }
434
+ var CPP_ORACLE_CONTRACT = [
435
+ "macroDeclaredBody",
436
+ // #919: a macro-declared BODY is a function body
437
+ "isCppSpelledName",
438
+ // D1: one set, three gates, one impossibility
439
+ "extendsTargetName",
440
+ // D2: a class definition is never a base
441
+ "qualifiedDeclaratorLeaf",
442
+ // the qualified declarator's LEAF is the name
443
+ "templateWrappedDeclaratorName",
444
+ // CPPD15/16: a wrapped declarator declares
445
+ "recoveredDeclaredName",
446
+ // D4: the name beside an error-recovered declarator
447
+ "specifierDeclaredName",
448
+ // D7: a specifier's name is its leaf
449
+ "attributeDisplacedEnumName"
450
+ // D7: an enum name the attribute displaced
451
+ ];
452
+ function macroDeclaredBody(body) {
453
+ if (!body || body.type !== "compound_statement") return null;
454
+ let heading = body.previousSibling;
455
+ for (let i = 0; heading && i < 2 && (heading.isMissing || heading.type === ";"); i++) {
456
+ heading = heading.previousSibling;
457
+ }
458
+ if (!heading || heading.type !== "expression_statement") return null;
459
+ let missing = false;
460
+ for (let i = 0; i < heading.childCount; i++) {
461
+ const c = heading.child(i);
462
+ if (c && c.isMissing) {
463
+ missing = true;
464
+ break;
465
+ }
466
+ }
467
+ if (!missing) return null;
468
+ const call = heading.namedChild(0);
469
+ if (!call || call.type !== "call_expression") return null;
470
+ const macro = call.childForFieldName("function");
471
+ if (!macro || macro.type !== "identifier") return null;
472
+ const macroName = macro.text.trim();
473
+ if (!macroName) return null;
474
+ return { heading, macroName, nameNode: macro };
475
+ }
476
+ function isIdentifierChar(code) {
477
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95;
478
+ }
479
+ function joinHeadingLines(text) {
480
+ let out = "";
481
+ let i = 0;
482
+ while (i < text.length) {
483
+ const c = text[i];
484
+ if (c === "\n") {
485
+ while (out.length > 0 && (out[out.length - 1] === " " || out[out.length - 1] === " " || out[out.length - 1] === "\r")) out = out.slice(0, -1);
486
+ out += " ";
487
+ i++;
488
+ while (i < text.length && (text[i] === " " || text[i] === " " || text[i] === "\r")) i++;
489
+ continue;
490
+ }
491
+ out += c;
492
+ i++;
493
+ }
494
+ return out.trim();
495
+ }
496
+ function phantomQualifierType(nameField) {
497
+ if (!nameField || nameField.type !== "qualified_identifier") return void 0;
498
+ const leaf = qualifiedDeclaratorLeaf(nameField);
499
+ if (!leaf || leaf.scopeQid !== null) return void 0;
500
+ const type = collapseSpaces(nameField.text.slice(0, leaf.nameNode.startIndex - nameField.startIndex));
501
+ return type || void 0;
502
+ }
503
+ function specifierTypeText(specifier) {
504
+ const parts = [];
505
+ for (let i = 0; i < specifier.namedChildCount; i++) {
506
+ const c = specifier.namedChild(i);
507
+ if (c && c.type !== "macro_specifier") parts.push(c.text);
508
+ }
509
+ return collapseSpaces(parts.join(" ")) || void 0;
510
+ }
511
+ var CPP_BUILTIN_TYPE_KEYWORDS = /* @__PURE__ */ new Set([
512
+ "void",
513
+ "bool",
514
+ "char",
515
+ "char8_t",
516
+ "char16_t",
517
+ "char32_t",
518
+ "wchar_t",
519
+ "short",
520
+ "int",
521
+ "long",
522
+ "float",
523
+ "double",
524
+ "signed",
525
+ "unsigned",
526
+ "auto"
527
+ ]);
528
+ var CPP_NON_CLASS_STANDARD_TYPES = /* @__PURE__ */ new Set([
529
+ // <cstdint> exact-width
530
+ "int8_t",
531
+ "int16_t",
532
+ "int32_t",
533
+ "int64_t",
534
+ "uint8_t",
535
+ "uint16_t",
536
+ "uint32_t",
537
+ "uint64_t",
538
+ // <cstdint> least/fast variants
539
+ "int_least8_t",
540
+ "int_least16_t",
541
+ "int_least32_t",
542
+ "int_least64_t",
543
+ "uint_least8_t",
544
+ "uint_least16_t",
545
+ "uint_least32_t",
546
+ "uint_least64_t",
547
+ "int_fast8_t",
548
+ "int_fast16_t",
549
+ "int_fast32_t",
550
+ "int_fast64_t",
551
+ "uint_fast8_t",
552
+ "uint_fast16_t",
553
+ "uint_fast32_t",
554
+ "uint_fast64_t",
555
+ // <cstdint> pointer-width and widest
556
+ "intptr_t",
557
+ "uintptr_t",
558
+ "intmax_t",
559
+ "uintmax_t",
560
+ // <cstddef>
561
+ "size_t",
562
+ "ptrdiff_t",
563
+ "nullptr_t"
564
+ ]);
565
+ var CPP_KEYWORDS = /* @__PURE__ */ new Set([
566
+ // declarations, types, specifiers
567
+ "alignas",
568
+ "auto",
569
+ "bool",
570
+ "char",
571
+ "char8_t",
572
+ "char16_t",
573
+ "char32_t",
574
+ "class",
575
+ "const",
576
+ "consteval",
577
+ "constexpr",
578
+ "constinit",
579
+ "decltype",
580
+ "double",
581
+ "enum",
582
+ "explicit",
583
+ "export",
584
+ "extern",
585
+ "float",
586
+ "friend",
587
+ "inline",
588
+ "int",
589
+ "long",
590
+ "mutable",
591
+ "namespace",
592
+ "register",
593
+ "short",
594
+ "signed",
595
+ "static",
596
+ "struct",
597
+ "template",
598
+ "thread_local",
599
+ "typedef",
600
+ "typeid",
601
+ "typename",
602
+ "union",
603
+ "unsigned",
604
+ "using",
605
+ "virtual",
606
+ "void",
607
+ "volatile",
608
+ "wchar_t",
609
+ // control flow
610
+ "break",
611
+ "case",
612
+ "catch",
613
+ "co_await",
614
+ "co_return",
615
+ "co_yield",
616
+ "continue",
617
+ "default",
618
+ "do",
619
+ "else",
620
+ "for",
621
+ "goto",
622
+ "if",
623
+ "return",
624
+ "switch",
625
+ "throw",
626
+ "try",
627
+ "while",
628
+ // expressions — the CAST family is what #924's type-only set missed
629
+ "const_cast",
630
+ "delete",
631
+ "dynamic_cast",
632
+ "new",
633
+ "noexcept",
634
+ "nullptr",
635
+ "reinterpret_cast",
636
+ "sizeof",
637
+ "static_assert",
638
+ "static_cast",
639
+ "this",
640
+ "true",
641
+ "false",
642
+ "operator",
643
+ "requires",
644
+ "concept",
645
+ // access
646
+ "private",
647
+ "protected",
648
+ "public",
649
+ // alternative tokens (ISO 14882 [lex.digraph], [lex.alternative])
650
+ "and",
651
+ "and_eq",
652
+ "bitand",
653
+ "bitor",
654
+ "compl",
655
+ "not",
656
+ "not_eq",
657
+ "or",
658
+ "or_eq",
659
+ "xor",
660
+ "xor_eq",
661
+ // implementation-reserved spellings and the standard preprocessor operators.
662
+ // None of these is a user-spellable identifier either, and each was measured
663
+ // producing an edge on the corpora (`defined` 34, `__has_include` 42,
664
+ // `__has_cpp_attribute` 6).
665
+ "defined",
666
+ "__has_include",
667
+ "__has_cpp_attribute",
668
+ "asm",
669
+ "__asm",
670
+ "__asm__",
671
+ "__declspec",
672
+ "__attribute__",
673
+ "__attribute",
674
+ "__inline",
675
+ "__inline__",
676
+ "__forceinline",
677
+ "__restrict",
678
+ "__restrict__",
679
+ "__extension__",
680
+ "__typeof__",
681
+ "__typeof",
682
+ "__cdecl",
683
+ "__stdcall",
684
+ "__thiscall",
685
+ "__vectorcall",
686
+ "__int8",
687
+ "__int16",
688
+ "__int32",
689
+ "__int64",
690
+ "__forceinline__",
691
+ "__declspec__",
692
+ "__builtin_offsetof",
693
+ "__builtin_va_arg",
694
+ "__builtin_types_compatible_p",
695
+ "__func__",
696
+ "__FUNCTION__",
697
+ "__PRETTY_FUNCTION__"
698
+ ]);
699
+ function isCppSpelledName(text) {
700
+ if (!text) return false;
701
+ return !CPP_KEYWORDS.has(text);
702
+ }
703
+ function isPublishableFunctionName(name) {
704
+ if (!name) return false;
705
+ if (name.startsWith("operator")) return true;
706
+ const isStart = (c) => c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95 || c === 126;
707
+ const isContinue = (c) => isStart(c) || c >= 48 && c <= 57;
708
+ if (!isStart(name.charCodeAt(0))) return false;
709
+ for (let i = 1; i < name.length; i++) if (!isContinue(name.charCodeAt(i))) return false;
710
+ return true;
711
+ }
712
+ function sameTsNode(a, b) {
713
+ if (!a || !b) return false;
714
+ return a.type === b.type && a.startIndex === b.startIndex && a.endIndex === b.endIndex;
715
+ }
716
+ function cppPureVirtualDeclaration(node) {
717
+ if (!node) return false;
718
+ if (node.type !== "declaration" && node.type !== "field_declaration" && node.type !== "function_definition") return false;
719
+ const direct = node.childForFieldName?.("declarator");
720
+ if (direct?.type === "function_declarator" && hasZeroLiteralChild(node)) return true;
721
+ for (let i = 0; i < node.namedChildCount; i++) {
722
+ const c = node.namedChild(i);
723
+ if (!c || c.type !== "init_declarator") continue;
724
+ const value = c.childForFieldName?.("value");
725
+ const inner = c.childForFieldName?.("declarator");
726
+ if (value?.type === "number_literal" && value.text.trim() === "0" && inner?.type === "function_declarator") return true;
727
+ }
728
+ return false;
729
+ }
730
+ function hasZeroLiteralChild(node) {
731
+ for (let i = 0; i < node.childCount; i++) {
732
+ const child = node.child(i);
733
+ if (child && child.type === "number_literal" && child.text.trim() === "0") return true;
734
+ }
735
+ return false;
736
+ }
737
+ var CPP_EXPORT_MARKER_COMPONENTS = /* @__PURE__ */ new Set([
738
+ "EXPORT",
739
+ "EXPORTS",
740
+ "EXPORTABLE",
741
+ "DLLEXPORT",
742
+ "API",
743
+ "VISIBILITY",
744
+ "PUBLIC_API"
745
+ ]);
746
+ function identifierComponents(text) {
747
+ const out = [];
748
+ let cur = "";
749
+ for (let i = 0; i <= text.length; i++) {
750
+ const c = i < text.length ? text.charCodeAt(i) : 95;
751
+ if (c === 95) {
752
+ if (cur) out.push(cur);
753
+ cur = "";
754
+ continue;
755
+ }
756
+ cur += text[i];
757
+ }
758
+ return out;
759
+ }
760
+ function cppExportMarker(macro) {
761
+ if (!macro) return false;
762
+ const comps = identifierComponents(macro.trim());
763
+ if (comps.length === 0) return false;
764
+ for (const c of comps) if (CPP_EXPORT_MARKER_COMPONENTS.has(c)) return true;
765
+ return false;
766
+ }
767
+ function recoveredDeclaredName(declNode) {
768
+ if (!declNode.hasError) return null;
769
+ const declared = declNode.childForFieldName?.("declarator") ?? null;
770
+ if (!declared) return null;
771
+ let next = declared.nextSibling;
772
+ while (next && (next.isMissing || !next.isNamed)) next = next.nextSibling;
773
+ if (!next || next.type !== "ERROR" || next.namedChildCount !== 1) return null;
774
+ const inner = next.namedChild(0);
775
+ if (!inner || inner.type !== "identifier") return null;
776
+ if (inner.startIndex <= declared.startIndex) return null;
777
+ if (!isCppSpelledName(inner.text)) return null;
778
+ return inner;
779
+ }
780
+ function specifierDeclaredName(spec) {
781
+ const leafOf = (n, depth = 0) => {
782
+ if (!n || depth > 8) return null;
783
+ if (n.type === "type_identifier" || n.type === "identifier") {
784
+ return isCppSpelledName(n.text) ? n.text : null;
785
+ }
786
+ if (n.type === "template_type") {
787
+ const tn = n.childForFieldName?.("name") ?? null;
788
+ if (tn) return leafOf(tn, depth + 1);
789
+ const lt = n.text.indexOf("<");
790
+ return lt > 0 ? n.text.slice(0, lt).trim() : null;
791
+ }
792
+ if (n.type === "qualified_identifier") {
793
+ return leafOf(n.namedChild(n.namedChildCount - 1), depth + 1);
794
+ }
795
+ return null;
796
+ };
797
+ const nameField = spec.childForFieldName?.("name") ?? null;
798
+ if (nameField) {
799
+ if (nameField.type === "type_identifier" || nameField.type === "identifier") {
800
+ return isCppSpelledName(nameField.text) ? nameField.text : null;
801
+ }
802
+ if (nameField.type === "qualified_identifier" || nameField.type === "template_type") {
803
+ return leafOf(nameField);
804
+ }
805
+ }
806
+ return null;
807
+ }
808
+ function attributeDisplacedEnumName(enumSpec) {
809
+ const decl = enumSpec.parent ?? null;
810
+ if (!decl || decl.type !== "declaration" && decl.type !== "field_declaration") return null;
811
+ const outer = decl.childForFieldName?.("declarator") ?? null;
812
+ if (!outer || outer.type !== "init_declarator") return null;
813
+ const id = outer.childForFieldName?.("declarator") ?? null;
814
+ if (!id || id.type !== "identifier") return null;
815
+ if (id.startIndex <= enumSpec.endIndex) return null;
816
+ return isCppSpelledName(id.text) ? id.text : null;
817
+ }
818
+ function qualifiedDeclaratorLeaf(qid) {
819
+ let leaf = qid;
820
+ while (true) {
821
+ const last = leaf.namedChild(leaf.namedChildCount - 1);
822
+ if (last && last.type === "qualified_identifier") leaf = last;
823
+ else break;
824
+ }
825
+ const nameNode = leaf.namedChild(leaf.namedChildCount - 1);
826
+ if (!nameNode) return null;
827
+ let realJoin = false;
828
+ for (let i = 0; i < leaf.childCount; i++) {
829
+ const c = leaf.child(i);
830
+ if (c && !c.isNamed && c.type === "::") {
831
+ realJoin = c.text === "::";
832
+ break;
833
+ }
834
+ }
835
+ return { nameNode, scopeQid: realJoin ? leaf : null };
836
+ }
837
+ function templateWrappedDeclaratorName(nameNode) {
838
+ const p = nameNode.parent;
839
+ if (!p) return false;
840
+ if (p.type !== "template_function" && p.type !== "template_method" && p.type !== "dependent_name") return false;
841
+ const gp = p.parent;
842
+ if (!gp || gp.type !== "function_declarator" && gp.type !== "abstract_function_declarator") return false;
843
+ const decl = gp.childForFieldName?.("declarator");
844
+ return !!decl && decl.startIndex === p.startIndex && decl.endIndex === p.endIndex;
845
+ }
846
+ function macroInvocationText(content, nameStart) {
847
+ const CAP = 4e3;
848
+ let i = nameStart;
849
+ while (i < content.length && isIdentifierChar(content.charCodeAt(i))) i++;
850
+ const end = Math.min(content.length, i + CAP);
851
+ let open = -1;
852
+ while (i < end) {
853
+ const c = content[i];
854
+ if (c === "(") {
855
+ open = i;
856
+ break;
857
+ }
858
+ if (c === "/" && content[i + 1] === "/") {
859
+ const nl = content.indexOf("\n", i);
860
+ if (nl < 0) return null;
861
+ i = nl + 1;
862
+ continue;
863
+ }
864
+ if (c === "/" && content[i + 1] === "*") {
865
+ const cl = content.indexOf("*/", i);
866
+ if (cl < 0) return null;
867
+ i = cl + 2;
868
+ continue;
869
+ }
870
+ if (c === "{" || c === "}" || c === ";") return null;
871
+ i++;
872
+ }
873
+ if (open < 0) return null;
874
+ let depth = 0;
875
+ for (let k = open; k < end; k++) {
876
+ const c = content[k];
877
+ if (c === '"' || c === "'") {
878
+ k++;
879
+ while (k < end) {
880
+ if (content[k] === "\\") {
881
+ k += 2;
882
+ continue;
883
+ }
884
+ if (content[k] === c) break;
885
+ k++;
886
+ }
887
+ continue;
888
+ }
889
+ if (c === "/" && content[k + 1] === "/") {
890
+ const nl = content.indexOf("\n", k);
891
+ if (nl < 0) return null;
892
+ k = nl;
893
+ continue;
894
+ }
895
+ if (c === "/" && content[k + 1] === "*") {
896
+ const cl = content.indexOf("*/", k);
897
+ if (cl < 0) return null;
898
+ k = cl + 1;
899
+ continue;
900
+ }
901
+ if (c === "(") depth++;
902
+ else if (c === ")") {
903
+ depth--;
904
+ if (depth === 0) {
905
+ const text = joinHeadingLines(content.slice(nameStart, k + 1));
906
+ return text || null;
907
+ }
908
+ }
909
+ }
910
+ return null;
911
+ }
912
+ var RealCppAnalyzer = class {
913
+ analyze(rootNode, content, filePath, context) {
914
+ const symbols = [];
915
+ const relationships = [];
916
+ const imports = [];
917
+ const exports = [];
918
+ const errors = [];
919
+ const patterns = {};
920
+ const frameworks = {};
921
+ let memorySafetyScore = 100;
922
+ const usesSeen = /* @__PURE__ */ new Set();
923
+ const referencesSeen = /* @__PURE__ */ new Set();
924
+ const exportsSeen = /* @__PURE__ */ new Set();
925
+ const macroNames = /* @__PURE__ */ new Set();
926
+ let fileDecisions = 0;
927
+ const classVirtuals = /* @__PURE__ */ new Map();
928
+ const pendingOverrides = [];
929
+ const classBases = /* @__PURE__ */ new Map();
930
+ const classPureVirtuals = /* @__PURE__ */ new Map();
931
+ const pendingImplements = [];
932
+ const pendingExports = [];
933
+ const PACKAGE_SCOPE = process.env.BB_CPP_PACKAGE_SCOPE === "1";
934
+ const packageScopePackages = PACKAGE_SCOPE && Array.isArray(context?.cppPackageScopePackages) ? context.cppPackageScopePackages.map((x) => String(x ?? "").trim()).filter((x) => x.length > 0) : [];
935
+ const packageScopeRoots = PACKAGE_SCOPE && packageScopePackages.length > 0 ? cppExternalIncludeRoots(rootNode) : /* @__PURE__ */ new Set();
936
+ const INDEX_CONSUME = process.env.BB_CPP_INDEX_CONSUME === "1";
937
+ const indexCandidate = INDEX_CONSUME ? context?.projectIndex : void 0;
938
+ const indexUsable = !!indexCandidate && indexCandidate.complete === true;
939
+ const indexSymbols = indexUsable && indexCandidate.symbolNames instanceof Set ? indexCandidate.symbolNames : /* @__PURE__ */ new Set();
940
+ const indexCounts = indexUsable && indexCandidate.symbolCounts instanceof Map ? indexCandidate.symbolCounts : /* @__PURE__ */ new Map();
941
+ const indexTypeKinds = indexUsable && indexCandidate.typeKinds instanceof Map ? indexCandidate.typeKinds : /* @__PURE__ */ new Map();
942
+ const indexTypeBases = indexUsable && indexCandidate.typeBases instanceof Map ? indexCandidate.typeBases : /* @__PURE__ */ new Map();
943
+ let indexResolution = null;
944
+ if (indexUsable) {
945
+ try {
946
+ indexResolution = buildResolutionTables(indexCandidate);
947
+ } catch {
948
+ indexResolution = null;
949
+ }
950
+ }
951
+ const indexCallFacts = (targetName) => {
952
+ if (!indexUsable) return {};
953
+ const out = {};
954
+ if (indexSymbols.has(targetName)) out.declaredInProject = true;
955
+ const count = indexCounts.get(targetName);
956
+ if (count !== void 0) out.indexDeclarationCount = count;
957
+ const owners = indexResolution?.memberOwners.get(targetName);
958
+ if (owners && owners.size === 1) out.memberOfProjectType = [...owners][0];
959
+ return out;
960
+ };
961
+ const indexBaseFacts = (targetName) => {
962
+ if (!indexUsable) return {};
963
+ const kind = indexTypeKinds.get(targetName);
964
+ return kind === void 0 ? {} : { indexBaseKind: String(kind) };
965
+ };
966
+ const indexOwnerFacts = (qualified, leaf) => {
967
+ if (!indexUsable) return {};
968
+ const owner = qualifiedOwnerSegment(qualified, leaf);
969
+ if (owner === null) return {};
970
+ const kind = indexTypeKinds.get(owner);
971
+ if (kind !== "class" && kind !== "struct" && kind !== "union") return {};
972
+ const ownMembers = indexCandidate.typeMembers instanceof Map ? indexCandidate.typeMembers.get(owner) : void 0;
973
+ if (!(ownMembers instanceof Set) || !ownMembers.has(leaf)) return {};
974
+ return { owner };
975
+ };
976
+ const indexOverridesFacts = (base, method) => {
977
+ if (!indexUsable || indexResolution === null) return {};
978
+ const declares = indexResolution.memberOwners.get(method)?.has(base) === true;
979
+ return declares ? { indexDeclaresMethod: true } : {};
980
+ };
981
+ void indexTypeBases;
982
+ const fileScopeValues = /* @__PURE__ */ new Set();
983
+ const namespaceValues = /* @__PURE__ */ new Map();
984
+ const classMembers = /* @__PURE__ */ new Map();
985
+ const usedNamespaces = /* @__PURE__ */ new Set();
986
+ const pendingQualified = [];
987
+ {
988
+ const pre = [
989
+ { n: rootNode, ns: [], inFn: false, inClass: null }
990
+ ];
991
+ const addValue = (name, ns, cls) => {
992
+ if (!isCppSpelledName(name)) return;
993
+ if (!name) return;
994
+ if (cls) {
995
+ let s = classMembers.get(cls);
996
+ if (!s) {
997
+ s = /* @__PURE__ */ new Set();
998
+ classMembers.set(cls, s);
999
+ }
1000
+ s.add(name);
1001
+ return;
1002
+ }
1003
+ if (ns.length > 0) {
1004
+ const top = ns[ns.length - 1];
1005
+ let s = namespaceValues.get(top);
1006
+ if (!s) {
1007
+ s = /* @__PURE__ */ new Set();
1008
+ namespaceValues.set(top, s);
1009
+ }
1010
+ s.add(name);
1011
+ return;
1012
+ }
1013
+ fileScopeValues.add(name);
1014
+ };
1015
+ const leftmostId = (n) => {
1016
+ let cur = n;
1017
+ while (cur) {
1018
+ if (cur.type === "identifier" || cur.type === "field_identifier") {
1019
+ return isCppSpelledName(cur.text) ? cur.text : null;
1020
+ }
1021
+ cur = cur.childForFieldName("declarator") || cur.namedChild(0);
1022
+ }
1023
+ return null;
1024
+ };
1025
+ while (pre.length > 0) {
1026
+ const { n, ns, inFn, inClass } = pre.pop();
1027
+ const t = n.type;
1028
+ if (t === "namespace_definition") {
1029
+ const nm = this.childText(n, "namespace_identifier");
1030
+ if (nm && nm !== CPP_ANONYMOUS) {
1031
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1032
+ const c = n.namedChild(i);
1033
+ if (c) pre.push({ n: c, ns: [...ns, nm], inFn, inClass });
1034
+ }
1035
+ continue;
1036
+ }
1037
+ } else if (t === "class_specifier" || t === "struct_specifier" || t === "union_specifier") {
1038
+ const nm = this.childText(n, "type_identifier") || (() => {
1039
+ const tt = this.findChild(n, "template_type");
1040
+ if (!tt) return null;
1041
+ const tn = tt.childForFieldName?.("name") || this.findChild(tt, "type_identifier") || this.findChild(tt, "qualified_identifier");
1042
+ if (tn?.text) return tn.text;
1043
+ const lt = tt.text.indexOf("<");
1044
+ return lt > 0 ? tt.text.slice(0, lt).trim() : null;
1045
+ })();
1046
+ const body = this.findChild(n, "field_declaration_list");
1047
+ if (nm && body) {
1048
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1049
+ const c = n.namedChild(i);
1050
+ if (c) pre.push({ n: c, ns, inFn, inClass: nm });
1051
+ }
1052
+ continue;
1053
+ }
1054
+ } else if (t === "function_definition") {
1055
+ const det = this.getFunctionDetails(n);
1056
+ if (det && !det.isDestructor && !det.name.startsWith("operator") && !this.isMacroFunctionShape(n, det.name)) {
1057
+ const isCtor = inClass !== null && det.name === inClass || det.scope !== void 0 && det.name === det.scope;
1058
+ if (!isCtor) {
1059
+ if (det.scope) pendingQualified.push({ name: det.name, scope: det.scope });
1060
+ else if (!inFn) addValue(det.name, ns, inClass);
1061
+ }
1062
+ }
1063
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1064
+ const c = n.namedChild(i);
1065
+ if (c) pre.push({ n: c, ns, inFn: true, inClass });
1066
+ }
1067
+ continue;
1068
+ } else if (t === "compound_statement" && macroDeclaredBody(n)) {
1069
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1070
+ const c = n.namedChild(i);
1071
+ if (c) pre.push({ n: c, ns, inFn: true, inClass });
1072
+ }
1073
+ continue;
1074
+ } else if (!inFn && (t === "declaration" || t === "field_declaration")) {
1075
+ for (let i = 0; i < n.namedChildCount; i++) {
1076
+ const c = n.namedChild(i);
1077
+ if (!c) continue;
1078
+ if (c.type === "init_declarator" && c.namedChild(0)?.type === "structured_binding_declarator") {
1079
+ const sb = c.namedChild(0);
1080
+ for (let k = 0; k < sb.namedChildCount; k++) {
1081
+ const b = sb.namedChild(k);
1082
+ if (b && (b.type === "identifier" || b.type === "field_identifier")) addValue(b.text, ns, inClass);
1083
+ }
1084
+ } else if (c.type === "init_declarator" || c.type === "identifier" || c.type === "field_identifier" || c.type === "pointer_declarator" || c.type === "reference_declarator" || c.type === "array_declarator") {
1085
+ const nm = leftmostId(c);
1086
+ if (nm) addValue(nm, ns, inClass);
1087
+ } else if (c.type === "function_declarator") {
1088
+ const nm = leftmostId(c);
1089
+ if (nm) addValue(nm, ns, inClass);
1090
+ }
1091
+ }
1092
+ } else if (!inFn && t === "enumerator") {
1093
+ const nm = this.childText(n, "identifier");
1094
+ if (nm) addValue(nm, [], null);
1095
+ } else if (t === "using_declaration" && !inFn && !inClass) {
1096
+ const txt = n.text;
1097
+ if (txt.indexOf("using namespace") !== -1) {
1098
+ const tgt = this.findChild(n, "qualified_identifier") || this.findChild(n, "identifier");
1099
+ if (tgt) usedNamespaces.add(tgt.text.split("::").filter(Boolean).join("::"));
1100
+ } else {
1101
+ const leaf = this.findChild(n, "qualified_identifier") || this.findChild(n, "identifier");
1102
+ if (leaf) {
1103
+ const segs = leaf.text.split("::").filter(Boolean);
1104
+ if (segs.length > 0) addValue(segs[segs.length - 1], [], null);
1105
+ }
1106
+ }
1107
+ }
1108
+ for (let i = n.namedChildCount - 1; i >= 0; i--) {
1109
+ const c = n.namedChild(i);
1110
+ if (c) pre.push({ n: c, ns, inFn, inClass });
1111
+ }
1112
+ }
1113
+ for (const q of pendingQualified) {
1114
+ if (classMembers.has(q.scope)) addValue(q.name, [], q.scope);
1115
+ else if (namespaceValues.has(q.scope)) addValue(q.name, [q.scope], null);
1116
+ else addValue(q.name, [], null);
1117
+ }
1118
+ }
1119
+ const scopeStack = [];
1120
+ const stack = [{ node: rootNode }];
1121
+ const DECL_PARENT_TYPES = /* @__PURE__ */ new Set([
1122
+ "declaration",
1123
+ "field_declaration",
1124
+ "parameter_declaration",
1125
+ "init_declarator",
1126
+ "function_declarator",
1127
+ "pointer_declarator",
1128
+ "reference_declarator",
1129
+ "array_declarator",
1130
+ "abstract_pointer_declarator",
1131
+ "abstract_array_declarator",
1132
+ "abstract_function_declarator",
1133
+ "enumerator",
1134
+ "using_declaration",
1135
+ "alias_declaration",
1136
+ "optional_parameter_declaration",
1137
+ "type_parameter_declaration",
1138
+ // CP6 (second review): `auto [x, y]` bindings declare (see the
1139
+ // carve-out in isDeclarationPosition — all names, not first-only).
1140
+ "structured_binding_declarator",
1141
+ // A DESTRUCTOR's name is declared, never read: `~json_sax()` puts the
1142
+ // class name inside a `destructor_name` node, and without this entry the
1143
+ // guard below returned false and the class name read as a value use. The
1144
+ // analyzer's behaviour was already correct — the destructor branch reads
1145
+ // the name to BUILD the symbol and never emitted a `uses` for it — so
1146
+ // this entry changes no output here; it is here so the SET matches the
1147
+ // F5 oracle's, because the oracle was the side that got it wrong and the
1148
+ // whole point of a shared set is that neither side can drift alone.
1149
+ // Measured on the oracle: 27 `uses` truth rows for names that are all
1150
+ // constructor/destructor declarations in nlohmann's ABI test header
1151
+ // (`json_sax`, `lexer`, `binary_reader`, `iter_impl`, `nonesuch`,
1152
+ // `file_input_adapter`, `input_stream_adapter`, `json_sax_dom_parser`) —
1153
+ // the analyzer published ZERO `uses` for every one of them.
1154
+ "destructor_name"
1155
+ // F6 audit: `template_type_parameter` / `template_value_parameter` are
1156
+ // NOT types in the pinned tree-sitter-cpp grammar — template parameters
1157
+ // parse as `type_parameter_declaration` (`typename T` / `class T`) and
1158
+ // `parameter_declaration` / `optional_parameter_declaration`
1159
+ // (`int N`, `int N = M`), all live in this set above. Removed.
1160
+ ]);
1161
+ const isDeclaringChainLeftmost = (node) => {
1162
+ const p = node.parent;
1163
+ if (!p || !p.type.endsWith("declarator")) return false;
1164
+ let cur = p;
1165
+ while (cur) {
1166
+ if (cur.type === "identifier" || cur.type === "field_identifier") {
1167
+ return cur.startIndex === node.startIndex;
1168
+ }
1169
+ let next = null;
1170
+ for (let k = 0; k < cur.namedChildCount; k++) {
1171
+ const c = cur.namedChild(k);
1172
+ if (c && (c.type.endsWith("declarator") || c.type === "identifier" || c.type === "field_identifier")) {
1173
+ next = c;
1174
+ break;
1175
+ }
1176
+ }
1177
+ cur = next;
1178
+ }
1179
+ return false;
1180
+ };
1181
+ const isDeclarationPosition = (node) => {
1182
+ const p = node.parent;
1183
+ if (!p) return false;
1184
+ if (templateWrappedDeclaratorName(node)) return true;
1185
+ if (p.type === "optional_parameter_declaration" || p.type === "type_parameter_declaration") {
1186
+ for (let k = 0; k < p.namedChildCount; k++) {
1187
+ const c = p.namedChild(k);
1188
+ if (c && (c.type === "identifier" || c.type === "field_identifier")) {
1189
+ return c.startIndex === node.startIndex;
1190
+ }
1191
+ }
1192
+ return false;
1193
+ }
1194
+ if (p.type === "field_declaration" || p.type === "enumerator") {
1195
+ let fresh = true;
1196
+ let foundFirst = false;
1197
+ for (let k = 0; k < p.childCount; k++) {
1198
+ const c = p.child(k);
1199
+ if (!c) continue;
1200
+ if (!c.isNamed) {
1201
+ if (c.type === "," || c.type === ";") {
1202
+ fresh = true;
1203
+ foundFirst = false;
1204
+ } else if (c.type === "=" || c.type === ":" || c.type === "{") fresh = false;
1205
+ continue;
1206
+ }
1207
+ if (c.type === "identifier" || c.type === "field_identifier") {
1208
+ if (!foundFirst && fresh) {
1209
+ if (c.startIndex === node.startIndex && c.endIndex === node.endIndex) return true;
1210
+ foundFirst = true;
1211
+ } else {
1212
+ if (c.startIndex === node.startIndex && c.endIndex === node.endIndex) return false;
1213
+ }
1214
+ }
1215
+ }
1216
+ return false;
1217
+ }
1218
+ if (!DECL_PARENT_TYPES.has(p.type)) return false;
1219
+ if (p.type === "structured_binding_declarator") return true;
1220
+ if (p.type.endsWith("declarator") || p.type === "init_declarator") {
1221
+ return isDeclaringChainLeftmost(node);
1222
+ }
1223
+ return true;
1224
+ };
1225
+ const isPreprocText = (node) => {
1226
+ let cur = node.parent;
1227
+ while (cur) {
1228
+ const t = cur.type;
1229
+ 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_definition") || t.includes("field_declaration_list")) return false;
1230
+ if (t.startsWith("preproc_")) return true;
1231
+ cur = cur.parent;
1232
+ }
1233
+ return false;
1234
+ };
1235
+ const hasQualifiedAncestor = (node) => {
1236
+ let cur = node.parent;
1237
+ while (cur) {
1238
+ const t = cur.type;
1239
+ if (t === "qualified_identifier") return true;
1240
+ if (t.includes("statement") || t.includes("declaration") || t.includes("declarator") || t.includes("expression") || t.includes("function_definition") || t.includes("field_declaration_list") || t.includes("argument_list")) return false;
1241
+ cur = cur.parent;
1242
+ }
1243
+ return false;
1244
+ };
1245
+ const hasAttributeAncestor = (node) => {
1246
+ let cur = node.parent;
1247
+ while (cur) {
1248
+ const t = cur.type;
1249
+ if (t === "attribute" || t === "attribute_declaration" || t === "attribute_specifier") return true;
1250
+ if (t.includes("statement") || t.includes("declaration") || t.includes("function_definition") || t.includes("expression") || t.includes("field_declaration_list")) return false;
1251
+ cur = cur.parent;
1252
+ }
1253
+ return false;
1254
+ };
1255
+ const memberLeafTop = (node) => {
1256
+ let top = node;
1257
+ let p = node.parent;
1258
+ while (p && (p.type === "template_function" || p.type === "template_method" || p.type === "dependent_name")) {
1259
+ top = p;
1260
+ p = p.parent;
1261
+ }
1262
+ return top;
1263
+ };
1264
+ const isMemberLeaf = (node) => {
1265
+ const top = memberLeafTop(node);
1266
+ const p = top.parent;
1267
+ if (!p || p.type !== "field_expression") return false;
1268
+ const field = p.childForFieldName("field");
1269
+ return !!field && field.startIndex === top.startIndex;
1270
+ };
1271
+ const isCallCallee = (node) => {
1272
+ let top = node;
1273
+ let p = node.parent;
1274
+ while (p && (p.type === "template_function" || p.type === "template_method" || p.type === "dependent_name" || p.type === "parenthesized_expression")) {
1275
+ top = p;
1276
+ p = p.parent;
1277
+ }
1278
+ if (!p || p.type !== "call_expression") return false;
1279
+ const fnField = p.childForFieldName("function");
1280
+ if (fnField) return fnField.startIndex === top.startIndex && fnField.endIndex >= top.endIndex;
1281
+ const first = p.namedChild(0);
1282
+ return !!first && first.startIndex === top.startIndex && first.endIndex >= top.endIndex;
1283
+ };
1284
+ const isFunctionOwnName = (node) => {
1285
+ let up = node.parent;
1286
+ while (up) {
1287
+ if (up.type === "parameter_list" || up.type === "parameter_declaration") return false;
1288
+ if (up.type === "function_declarator" && up.parent && up.parent.type === "function_definition") return true;
1289
+ up = up.parent;
1290
+ }
1291
+ return false;
1292
+ };
1293
+ const enclosingFunctionScope = () => {
1294
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
1295
+ const s = scopeStack[i];
1296
+ if (s.kind === ASTEngine.SymbolKind.Function || s.kind === ASTEngine.SymbolKind.Method || s.kind === ASTEngine.SymbolKind.Constructor) return s;
1297
+ }
1298
+ return null;
1299
+ };
1300
+ const ownerIsFunctionScope = (ctx) => !!ctx && (ctx.kind === ASTEngine.SymbolKind.Function || ctx.kind === ASTEngine.SymbolKind.Method || ctx.kind === ASTEngine.SymbolKind.Constructor);
1301
+ const isResolvableRead = (name) => {
1302
+ if (fileScopeValues.has(name)) return true;
1303
+ const enclosingNs = [];
1304
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
1305
+ const s = scopeStack[i];
1306
+ if (s.kind === ASTEngine.SymbolKind.Class || s.kind === ASTEngine.SymbolKind.Struct) {
1307
+ const mm = classMembers.get(s.name);
1308
+ if (mm && mm.has(name)) return true;
1309
+ }
1310
+ if ((s.kind === ASTEngine.SymbolKind.Function || s.kind === ASTEngine.SymbolKind.Method || s.kind === ASTEngine.SymbolKind.Constructor) && s.classScope) {
1311
+ const mm = classMembers.get(s.classScope);
1312
+ if (mm && mm.has(name)) return true;
1313
+ }
1314
+ if (s.kind === ASTEngine.SymbolKind.Namespace && s.name !== CPP_ANONYMOUS) enclosingNs.push(s.name);
1315
+ }
1316
+ for (const ns of enclosingNs) {
1317
+ const nm = namespaceValues.get(ns);
1318
+ if (nm && nm.has(name)) return true;
1319
+ }
1320
+ for (const used of usedNamespaces) {
1321
+ const nm = namespaceValues.get(used);
1322
+ if (nm && nm.has(name)) return true;
1323
+ }
1324
+ return false;
1325
+ };
1326
+ const declaredNameNode = (node) => {
1327
+ let cur = node;
1328
+ while (cur) {
1329
+ if (cur.type === "identifier" || cur.type === "field_identifier") {
1330
+ if (!isCppSpelledName(cur.text)) return null;
1331
+ return cur;
1332
+ }
1333
+ if (cur.type === "function_declarator" || cur.type === "abstract_function_declarator") {
1334
+ const inner = cur.childForFieldName?.("declarator") ?? null;
1335
+ if (!inner || inner.type === "identifier" || inner.type === "field_identifier" || inner.type === "qualified_identifier" || inner.type === "operator_name" || inner.type === "destructor_name" || inner.type === "type_identifier") {
1336
+ return null;
1337
+ }
1338
+ }
1339
+ const viaField = cur.childForFieldName?.("declarator") ?? null;
1340
+ let next = viaField;
1341
+ if (!next) {
1342
+ for (let k = 0; k < cur.namedChildCount; k++) {
1343
+ const c = cur.namedChild(k);
1344
+ if (c && (c.type.endsWith("declarator") || c.type === "identifier" || c.type === "field_identifier")) {
1345
+ next = c;
1346
+ break;
1347
+ }
1348
+ }
1349
+ }
1350
+ cur = next;
1351
+ }
1352
+ return null;
1353
+ };
1354
+ const declaredValueName = (node) => {
1355
+ const decl = node?.childForFieldName?.("declarator") ?? null;
1356
+ if (!decl) return null;
1357
+ if (decl.type === "function_declarator" || decl.type === "abstract_function_declarator") {
1358
+ const inner = decl.childForFieldName?.("declarator") ?? null;
1359
+ if (!inner || inner.type === "identifier" || inner.type === "field_identifier" || inner.type === "qualified_identifier" || inner.type === "operator_name" || inner.type === "destructor_name") {
1360
+ return null;
1361
+ }
1362
+ }
1363
+ return declaredNameNode(decl);
1364
+ };
1365
+ const declaratorParamNames = (decl) => {
1366
+ const out = [];
1367
+ if (!decl) return out;
1368
+ const walk = [decl];
1369
+ while (walk.length > 0) {
1370
+ const m = walk.pop();
1371
+ if (m.type === "parameter_declaration") {
1372
+ const nm = declaredNameNode(m);
1373
+ if (nm) out.push(nm.text);
1374
+ continue;
1375
+ }
1376
+ for (let k = 0; k < m.namedChildCount; k++) {
1377
+ const c = m.namedChild(k);
1378
+ if (c) walk.push(c);
1379
+ }
1380
+ }
1381
+ return out;
1382
+ };
1383
+ const declaratorParameters = (decl) => {
1384
+ const out = [];
1385
+ if (!decl) return out;
1386
+ const paramsNode = decl.childForFieldName?.("parameters") ?? this.findChild(decl, "parameter_list") ?? null;
1387
+ if (!paramsNode) return out;
1388
+ for (let i = 0; i < paramsNode.namedChildCount; i++) {
1389
+ const p = paramsNode.namedChild(i);
1390
+ if (!p) continue;
1391
+ if (p.type === "comment") continue;
1392
+ if (p.type === "variadic_parameter_declaration") continue;
1393
+ if (p.type !== "parameter_declaration" && p.type !== "optional_parameter_declaration") continue;
1394
+ const nameNode = declaredNameNode(p);
1395
+ if (!nameNode) continue;
1396
+ const cut = nameNode.startIndex - p.startIndex;
1397
+ const type = cut > 0 ? p.text.slice(0, cut).trim() : "";
1398
+ const param = { name: nameNode.text };
1399
+ if (type) param.type = type;
1400
+ const defaultNode = p.childForFieldName?.("default_value") ?? null;
1401
+ if (defaultNode || p.type === "optional_parameter_declaration") {
1402
+ if (defaultNode) param.defaultValue = defaultNode.text;
1403
+ param.isOptional = true;
1404
+ }
1405
+ out.push(param);
1406
+ }
1407
+ return out;
1408
+ };
1409
+ const buildParamSig = (parametersNode) => {
1410
+ if (!parametersNode) return "";
1411
+ const parts = [];
1412
+ for (let i = 0; i < parametersNode.namedChildCount; i++) {
1413
+ const pc = parametersNode.namedChild(i);
1414
+ if (!pc) continue;
1415
+ if (pc.type === "comment") continue;
1416
+ if (pc.type === "variadic_parameter_declaration") {
1417
+ parts.push("...");
1418
+ continue;
1419
+ }
1420
+ if (pc.type !== "parameter_declaration" && pc.type !== "optional_parameter_declaration") {
1421
+ continue;
1422
+ }
1423
+ const eqAt = pc.text.indexOf("=");
1424
+ const nameNode = declaredNameNode(pc);
1425
+ let t = pc.text;
1426
+ if (nameNode) {
1427
+ const cut = nameNode.startIndex - pc.startIndex;
1428
+ if (cut > 0) t = t.slice(0, cut);
1429
+ } else if (eqAt !== -1) {
1430
+ t = t.slice(0, eqAt);
1431
+ }
1432
+ t = t.trim();
1433
+ if (t) parts.push(t);
1434
+ }
1435
+ return parts.join(",");
1436
+ };
1437
+ const declaredReturnType = (node, declarator) => {
1438
+ if (declarator) {
1439
+ const tail = this.findChild(declarator, "trailing_return_type") ?? null;
1440
+ const td = tail ? this.findChild(tail, "type_descriptor") ?? tail.namedChild(0) : null;
1441
+ const t = td?.text?.trim();
1442
+ if (t) return t;
1443
+ }
1444
+ const typeField = node?.childForFieldName?.("type") ?? null;
1445
+ if (!typeField) return void 0;
1446
+ if (typeField.type === "macro_prefixed_type_specifier") return specifierTypeText(typeField);
1447
+ const stated = collapseSpaces(typeField.text);
1448
+ if (!stated) return void 0;
1449
+ if (!isMacroSpelling(stated)) return stated;
1450
+ const rejoined = phantomQualifierType(declarator?.childForFieldName?.("declarator") ?? null);
1451
+ if (rejoined) return rejoined;
1452
+ if (!node) return stated;
1453
+ const displaced = this.displacedReturnType(node, declarator);
1454
+ if (displaced) return displaced;
1455
+ return this.recoveredDecoratorHead(node, declarator) ? void 0 : stated;
1456
+ };
1457
+ const buildFunctionSymbol = (node, declarator, parts) => {
1458
+ const parameters = declaratorParameters(declarator);
1459
+ const returnType = declaredReturnType(node, declarator);
1460
+ const ownerName = parts.ownerName === "global" ? void 0 : parts.ownerName;
1461
+ const decorators = parts.decorators ?? [];
1462
+ return {
1463
+ name: parts.name,
1464
+ kind: parts.kind,
1465
+ range: this.nodeToRange(node),
1466
+ complexity: this.methodComplexityCpp(node),
1467
+ visibility: parts.visibility || "public",
1468
+ // Absent for a construct with no linkage of its own (a friend definition),
1469
+ // present-and-false for every member declaration: the store reads the KEY.
1470
+ ...parts.isStatic === void 0 ? {} : { isStatic: parts.isStatic },
1471
+ ownerName,
1472
+ ownerKind: ownerName === void 0 ? void 0 : parts.ownerKind,
1473
+ ...parameters.length > 0 ? { parameters } : {},
1474
+ ...returnType ? { returnType } : {},
1475
+ ...decorators.length > 0 ? { decorators } : {},
1476
+ metadata: { isCppFunction: true, ...parts.metadata }
1477
+ };
1478
+ };
1479
+ const INDEX_CLASS_KINDS = /* @__PURE__ */ new Set(["class", "struct", "union"]);
1480
+ const enclosingClassForOwner = () => {
1481
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
1482
+ const sc = scopeStack[i];
1483
+ if (sc.kind === ASTEngine.SymbolKind.Class || sc.kind === ASTEngine.SymbolKind.Struct || sc.kind === ASTEngine.SymbolKind.Union) return sc.name;
1484
+ if ((sc.kind === ASTEngine.SymbolKind.Function || sc.kind === ASTEngine.SymbolKind.Method || sc.kind === ASTEngine.SymbolKind.Constructor) && sc.classScope) return sc.classScope;
1485
+ }
1486
+ return "";
1487
+ };
1488
+ const indexDeclaresMemberForOwner = (owner, leaf) => {
1489
+ if (!indexUsable || indexResolution === null) return false;
1490
+ const kind = indexTypeKinds.get(owner);
1491
+ if (typeof kind !== "string" || !INDEX_CLASS_KINDS.has(kind)) return false;
1492
+ return indexResolution.allMembers.get(owner)?.has(leaf) === true;
1493
+ };
1494
+ const writtenTypeCache = /* @__PURE__ */ new Map();
1495
+ const simpleDeclName = (decl, depth = 0) => {
1496
+ if (!decl || depth > 6) return "";
1497
+ const t = String(decl.type);
1498
+ if (t === "identifier" || t === "field_identifier") return decl.text.trim();
1499
+ if (t === "init_declarator" || t === "pointer_declarator" || t === "reference_declarator" || t === "array_declarator" || t === "parenthesized_declarator" || t === "attributed_declarator") {
1500
+ const inner = decl.childForFieldName?.("declarator") ?? decl.namedChild(Math.max(0, decl.namedChildCount - 1));
1501
+ return simpleDeclName(inner, depth + 1);
1502
+ }
1503
+ return "";
1504
+ };
1505
+ const writtenTypesOf = (fnNode) => {
1506
+ const cached = writtenTypeCache.get(fnNode.id);
1507
+ if (cached !== void 0) return cached;
1508
+ const table = /* @__PURE__ */ new Map();
1509
+ const add = (typeNode, declNode) => {
1510
+ if (!typeNode) return;
1511
+ const nm = simpleDeclName(declNode);
1512
+ if (nm === "" || !isIdentifierShapeWithDollar(nm)) return;
1513
+ if (!table.has(nm)) table.set(nm, String(typeNode.text ?? ""));
1514
+ };
1515
+ const scan = (n, depth = 0) => {
1516
+ if (!n || depth > 30) return;
1517
+ const t = String(n.type);
1518
+ if (t === "parameter" || t === "parameter_declaration" || t === "optional_parameter_declaration") {
1519
+ add(n.childForFieldName?.("type"), n.childForFieldName?.("declarator"));
1520
+ return;
1521
+ }
1522
+ if (t === "declaration") {
1523
+ const typeNode = n.childForFieldName?.("type");
1524
+ const firstDecl = n.childForFieldName?.("declarator");
1525
+ add(typeNode, firstDecl);
1526
+ for (let i = 0; i < n.namedChildCount; i++) {
1527
+ const c = n.namedChild(i);
1528
+ if (sameTsNode(c, typeNode) || sameTsNode(c, firstDecl)) continue;
1529
+ add(typeNode, c);
1530
+ }
1531
+ return;
1532
+ }
1533
+ if (t === "for_range_loop") {
1534
+ const typeField = n.childForFieldName?.("type");
1535
+ const declField = n.childForFieldName?.("declarator");
1536
+ let written = null;
1537
+ let declared = null;
1538
+ for (let i = 0; i < n.namedChildCount; i++) {
1539
+ const c = n.namedChild(i);
1540
+ if (sameTsNode(c, typeField) || sameTsNode(c, declField)) continue;
1541
+ if (!written) {
1542
+ written = c;
1543
+ continue;
1544
+ }
1545
+ if (!declared) {
1546
+ declared = c;
1547
+ break;
1548
+ }
1549
+ }
1550
+ add(written, declared);
1551
+ }
1552
+ for (let i = 0; i < n.namedChildCount; i++) scan(n.namedChild(i), depth + 1);
1553
+ };
1554
+ const decl = fnNode.childForFieldName?.("declarator");
1555
+ if (decl) scan(decl);
1556
+ const body = fnNode.childForFieldName?.("body") ?? fnNode.namedChild(fnNode.namedChildCount - 1);
1557
+ if (body) scan(body);
1558
+ writtenTypeCache.set(fnNode.id, table);
1559
+ return table;
1560
+ };
1561
+ const writtenTypeOfReceiver = (name) => {
1562
+ const fnScope = enclosingFunctionScope();
1563
+ const fnNode = fnScope?.node;
1564
+ if (!fnNode) return "";
1565
+ return writtenTypesOf(fnNode).get(name) ?? "";
1566
+ };
1567
+ const typeLeafOf = (typeText) => {
1568
+ let t = String(typeText ?? "");
1569
+ const lt = t.indexOf("<");
1570
+ if (lt > 0) t = t.slice(0, lt);
1571
+ for (const kw of ["const", "volatile", "static", "typename", "struct", "class", "union", "enum"]) t = t.split(kw).join(" ");
1572
+ t = collapseTypeNoise(t);
1573
+ const cut = Math.max(t.lastIndexOf("::"), t.lastIndexOf(" "));
1574
+ const leaf = (cut >= 0 ? t.slice(cut + 1) : t).trim();
1575
+ return isIdentifierShapeWithDollar(leaf) ? leaf : "";
1576
+ };
1577
+ const templatePointeeOf = (typeText) => {
1578
+ const lt = typeText.indexOf("<");
1579
+ const gt = typeText.lastIndexOf(">");
1580
+ if (lt < 0 || gt <= lt) return "";
1581
+ return typeLeafOf(typeText.slice(lt + 1, gt).split(",")[0] ?? "");
1582
+ };
1583
+ const OWNER_WRAPPER_TYPES = /* @__PURE__ */ new Set(["unique_ptr", "shared_ptr", "weak_ptr", "auto_ptr", "optional", "reference_wrapper", "atomic"]);
1584
+ const ownerCallLeafName = (n, depth = 0) => {
1585
+ if (!n || depth > 6) return "";
1586
+ const t = String(n.type);
1587
+ if (t === "identifier" || t === "field_identifier" || t === "type_identifier") return n.text.trim();
1588
+ if (t === "qualified_identifier") {
1589
+ const parts = String(n.text).split("::");
1590
+ return parts[parts.length - 1].trim();
1591
+ }
1592
+ if (t === "template_function" || t === "template_method") return ownerCallLeafName(n.namedChild(0), depth + 1);
1593
+ if (t === "field_expression") return ownerCallLeafName(n.childForFieldName?.("field"), depth + 1);
1594
+ return "";
1595
+ };
1596
+ const indexReceiverOwnerFacts = (callee, leaf) => {
1597
+ if (!indexUsable || leaf === "" || !callee) return {};
1598
+ if (callee.type === "field_expression") {
1599
+ const obj = callee.childForFieldName?.("argument") ?? callee.namedChild(0);
1600
+ if (!obj) return {};
1601
+ if (obj.type === "call_expression") {
1602
+ const innerCallee = obj.childForFieldName?.("function") ?? obj.namedChild(0);
1603
+ const owner = ownerCallLeafName(innerCallee);
1604
+ return owner !== "" && indexDeclaresMemberForOwner(owner, leaf) ? { owner } : {};
1605
+ }
1606
+ if (obj.type === "new_expression") {
1607
+ const typeNode = obj.childForFieldName?.("type") ?? null;
1608
+ const owner = typeNode ? typeLeafOf(String(typeNode.text ?? "")) : "";
1609
+ return owner !== "" && indexDeclaresMemberForOwner(owner, leaf) ? { owner } : {};
1610
+ }
1611
+ if (obj.type === "identifier") {
1612
+ const written = writtenTypeOfReceiver(obj.text.trim());
1613
+ if (written === "") return {};
1614
+ const holder = typeLeafOf(written);
1615
+ if (OWNER_WRAPPER_TYPES.has(holder)) {
1616
+ const pointee = templatePointeeOf(written);
1617
+ return pointee !== "" && indexDeclaresMemberForOwner(pointee, leaf) ? { owner: pointee } : {};
1618
+ }
1619
+ return holder !== "" && indexDeclaresMemberForOwner(holder, leaf) ? { owner: holder } : {};
1620
+ }
1621
+ return {};
1622
+ }
1623
+ if (callee.type === "identifier") {
1624
+ if (enclosingFunctionScope() === null) return {};
1625
+ const enclosing = enclosingClassForOwner();
1626
+ return enclosing !== "" && indexDeclaresMemberForOwner(enclosing, leaf) ? { owner: enclosing } : {};
1627
+ }
1628
+ return {};
1629
+ };
1630
+ while (stack.length > 0) {
1631
+ const item = stack.pop();
1632
+ const { node, parentContext, isExit } = item;
1633
+ if (isExit) {
1634
+ if (parentContext?.symbolRef && parentContext.isAbstract) {
1635
+ parentContext.symbolRef.isAbstract = true;
1636
+ if (parentContext.symbolRef.metadata) {
1637
+ parentContext.symbolRef.metadata.isAbstract = true;
1638
+ }
1639
+ }
1640
+ if (parentContext && scopeStack.length > 0 && scopeStack[scopeStack.length - 1] === parentContext) {
1641
+ scopeStack.pop();
1642
+ }
1643
+ continue;
1644
+ }
1645
+ if (node.isMissing || node.hasError) {
1646
+ if (node.type === "ERROR" || node.type === "MISSING") {
1647
+ if (errors.length < 3) errors.push({
1648
+ message: `Syntax ${node.type} detected`,
1649
+ range: this.nodeToRange(node),
1650
+ severity: "warning"
1651
+ });
1652
+ }
1653
+ }
1654
+ let newContext = parentContext;
1655
+ const type = node.type;
1656
+ let pushedScope = false;
1657
+ if (type === "identifier" || type === "qualified_identifier" || type === "type_identifier") {
1658
+ const text = node.text;
1659
+ if (text === "std::make_unique" || text === "std::make_shared") {
1660
+ memorySafetyScore = Math.min(100, memorySafetyScore + 5);
1661
+ }
1662
+ }
1663
+ if (type === "new_expression" || type === "delete_expression") {
1664
+ memorySafetyScore = Math.max(0, memorySafetyScore - 5);
1665
+ }
1666
+ if (type === "if_statement" || type === "for_statement" || type === "while_statement" || type === "do_statement" || type === "case_statement" || type === "catch_clause" || type === "conditional_expression") {
1667
+ fileDecisions++;
1668
+ } else if (type === "binary_expression") {
1669
+ const op = node.childForFieldName("operator")?.text;
1670
+ if (op === "&&" || op === "||") fileDecisions++;
1671
+ }
1672
+ if (type === "using_declaration") {
1673
+ const inClass = parentContext && (parentContext.kind === ASTEngine.SymbolKind.Class || parentContext.kind === ASTEngine.SymbolKind.Struct || parentContext.kind === ASTEngine.SymbolKind.Method || parentContext.kind === ASTEngine.SymbolKind.Function || parentContext.kind === ASTEngine.SymbolKind.Constructor);
1674
+ if (!inClass) {
1675
+ const targetNode = this.findChild(node, "qualified_identifier") || this.findChild(node, "identifier");
1676
+ const raw = targetNode?.text ?? "";
1677
+ const isNamespaceForm = node.text.indexOf("using namespace") !== -1;
1678
+ if (raw && isCppSpelledName(raw)) {
1679
+ const segs = raw.split("::").filter(Boolean);
1680
+ imports.push({
1681
+ module: raw,
1682
+ items: isNamespaceForm ? ["*"] : segs.length > 1 ? [segs[segs.length - 1]] : [raw],
1683
+ range: this.nodeToRange(node),
1684
+ metadata: { isImport: true, isUsingDeclaration: true, isNamespaceImport: isNamespaceForm }
1685
+ });
1686
+ if (!referencesSeen.has(raw)) {
1687
+ referencesSeen.add(raw);
1688
+ relationships.push({
1689
+ // File-level dependency statement → source "global" (same
1690
+ // convention as the #include references edge above).
1691
+ source: "global",
1692
+ target: raw,
1693
+ type: ASTEngine.RelationshipType.References,
1694
+ confidence: 0.9,
1695
+ // the written path names the edge, not the `using`
1696
+ // keyword — `using namespace\n std;` would otherwise name the line
1697
+ // above the module.
1698
+ line_number: this.nodeLine(targetNode ?? node),
1699
+ // M14-HONESTY-CONTRACT : an edge below 1.0 carries a
1700
+ // machine-readable reason code, and `classifyEvidenceTier` defaults
1701
+ // a MISSING confidence to 1 — so a 0.9 with no code is a number a
1702
+ // consumer can bucket but not explain. Measured over 929 corpus
1703
+ // files before this field existed: 625 `references` rows at 0.9 and
1704
+ // 0 of them with a code.
1705
+ //
1706
+ // What the 0.9 means here, stated so it is checkable: the edge
1707
+ // binds the NAME the source spells, and nothing inside the named
1708
+ // module. `using std::vector;` proves a dependency on `std`; it
1709
+ // does not prove which declaration of `vector` is meant, and this
1710
+ // analyzer does no header-level resolution to find out.
1711
+ metadata: {
1712
+ isUsingDeclaration: true,
1713
+ isImport: true,
1714
+ relationshipType: "using_dependency",
1715
+ reasonCode: "using-dependency-name-only"
1716
+ }
1717
+ });
1718
+ }
1719
+ }
1720
+ }
1721
+ } else if (type === "alias_declaration") {
1722
+ if (ownerIsFunctionScope(parentContext)) {
1723
+ newContext = parentContext;
1724
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1725
+ const child = node.namedChild(i);
1726
+ if (child) stack.push({ node: child, parentContext: newContext });
1727
+ }
1728
+ continue;
1729
+ }
1730
+ const nameNode = node.childForFieldName("name") || this.findChild(node, "type_identifier");
1731
+ const name = nameNode?.text;
1732
+ if (name && isCppSpelledName(name)) {
1733
+ symbols.push({
1734
+ name,
1735
+ kind: ASTEngine.SymbolKind.Type,
1736
+ range: this.nodeToRange(node),
1737
+ visibility: parentContext?.visibility || "public",
1738
+ ownerName: parentContext?.name,
1739
+ ownerKind: parentContext?.kind,
1740
+ // #921: the type NAME's own line (a wrapped alias writes it below).
1741
+ metadata: { isTypeAlias: true, isUsingDeclaration: true, nameLine: this.nodeLine(nameNode) }
1742
+ });
1743
+ }
1744
+ } else if (type === "type_definition" || node.text.startsWith("typedef")) {
1745
+ if (ownerIsFunctionScope(parentContext)) {
1746
+ newContext = parentContext;
1747
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1748
+ const child = node.namedChild(i);
1749
+ if (child) stack.push({ node: child, parentContext: newContext });
1750
+ }
1751
+ continue;
1752
+ }
1753
+ const typeId = this.findChild(node, "type_identifier");
1754
+ if (typeId && isCppSpelledName(typeId.text)) {
1755
+ symbols.push({
1756
+ name: typeId.text,
1757
+ kind: ASTEngine.SymbolKind.Type,
1758
+ range: this.nodeToRange(node),
1759
+ visibility: parentContext?.visibility || "public",
1760
+ ownerName: parentContext?.name,
1761
+ ownerKind: parentContext?.kind,
1762
+ metadata: { isTypeAlias: true, nameLine: this.nodeLine(typeId) }
1763
+ });
1764
+ }
1765
+ } else if (type === "preproc_def" || type === "preproc_function_def") {
1766
+ const nameNode = node.childForFieldName("name");
1767
+ const macroName = nameNode?.text?.trim();
1768
+ if (macroName && isCppSpelledName(macroName) && !symbols.some((s) => s.name === macroName)) {
1769
+ const isFunctionLikeMacro = type === "preproc_function_def";
1770
+ const parameters = [];
1771
+ if (isFunctionLikeMacro) {
1772
+ const paramsNode = node.childForFieldName("parameters") ?? this.findChild(node, "preproc_params");
1773
+ if (paramsNode) {
1774
+ for (let i = 0; i < paramsNode.childCount; i++) {
1775
+ const param = paramsNode.child(i);
1776
+ if (param && param.isNamed) parameters.push({ name: param.text, type: "any" });
1777
+ else if (param && (param.type === "..." || param.text === "...")) {
1778
+ parameters.push({ name: "...", type: "variadic", modifiers: [] });
1779
+ }
1780
+ }
1781
+ }
1782
+ }
1783
+ symbols.push({
1784
+ name: macroName,
1785
+ kind: isFunctionLikeMacro ? ASTEngine.SymbolKind.Macro : ASTEngine.SymbolKind.Constant,
1786
+ range: this.nodeToRange(node),
1787
+ scope: "global",
1788
+ visibility: "public",
1789
+ parameters: isFunctionLikeMacro ? parameters : void 0,
1790
+ metadata: { isMacro: true, isFunctionLikeMacro, nameLine: this.nodeLine(nameNode) }
1791
+ });
1792
+ }
1793
+ } else if (type === "preproc_include") {
1794
+ const text = node.text;
1795
+ let pathNode = node.childForFieldName("path");
1796
+ if (pathNode && pathNode.type !== "string_literal" && pathNode.type !== "system_lib_string") pathNode = null;
1797
+ if (!pathNode) {
1798
+ pathNode = this.findChild(node, "string_literal") ?? this.findChild(node, "system_lib_string");
1799
+ }
1800
+ const rawPath = (pathNode?.text ?? "").trim();
1801
+ const includePath = pathNode ? stripIncludeChars(rawPath).trim() : "";
1802
+ const isSystem = rawPath.startsWith("<");
1803
+ if (includePath) {
1804
+ imports.push({
1805
+ module: includePath,
1806
+ items: ["*"],
1807
+ range: this.nodeToRange(node),
1808
+ metadata: { isSystemInclude: isSystem, isImport: true, isIncludeDependency: true }
1809
+ });
1810
+ }
1811
+ if (includePath) {
1812
+ if (!referencesSeen.has(includePath)) {
1813
+ referencesSeen.add(includePath);
1814
+ const isQuotedPart = !isSystem;
1815
+ relationships.push({
1816
+ source: "global",
1817
+ // ★ THE TARGET IS A SYMBOL, NOT A PATH (per the measured ruling). MEASURED before this
1818
+ // change: emitting the PATH gave 0 resolved of 4,612 `part_of` edges — 100 % unresolved —
1819
+ // because the arbiter resolves TARGET STRINGS AGAINST SYMBOL NAMES and has no space for a
1820
+ // path. The contract permits either ("the part's file or its module symbol"); the symbol is
1821
+ // the only one that can bind.
1822
+ target: isQuotedPart ? cppPartSymbol(includePath) : includePath,
1823
+ type: isQuotedPart ? ASTEngine.RelationshipType.PartOf : ASTEngine.RelationshipType.Imports,
1824
+ confidence: 1,
1825
+ // , the C lane's rule: the include directive is the
1826
+ // source construct and its WRITTEN NAME is the path token — take
1827
+ // that node's line, not the directive's (a multi-line include puts
1828
+ // the path last).
1829
+ line_number: this.nodeLine(pathNode ?? node),
1830
+ metadata: {
1831
+ relationshipType: isQuotedPart ? "part_of_directive" : "include_dependency",
1832
+ isSystem,
1833
+ isSystemInclude: isSystem,
1834
+ // A part is NOT an import: the contract keeps `imports` and `part_of` DISTINCT, and
1835
+ // a quoted include that also claimed `isImport` would be the second fact that can
1836
+ // differ from the first.
1837
+ isImport: !isQuotedPart,
1838
+ isIncludeDependency: true,
1839
+ // THE MANDATORY PART ROLE (src/ast/types.ts:148-160). "part" is the directive that
1840
+ // NAMES a part (`part 'x.dart'` / `#include "x.h"`); "library" is the directive that
1841
+ // names the library a part belongs to (`part of 'y.dart'`). C++ has only the first
1842
+ // written form: the including unit names its fragments, never the reverse.
1843
+ ...isQuotedPart ? {
1844
+ partRole: "part",
1845
+ partFile: true,
1846
+ isQuotedInclude: true,
1847
+ // THE PATH IS EVIDENCE, THE STEM IS THE TARGET. Keeping both is what makes the
1848
+ // difference between them checkable rather than a reader's inference.
1849
+ partPath: cppPartTargetPath(filePath, includePath),
1850
+ partSymbol: cppPartSymbol(includePath)
1851
+ } : {},
1852
+ // THE SPECIFIER IS KEPT BESIDE THE PATH: the path is what might resolve, the
1853
+ // specifier is what was WRITTEN, and only one of them is evidence.
1854
+ specifier: includePath,
1855
+ module: includePath,
1856
+ fileLevel: true
1857
+ }
1858
+ });
1859
+ }
1860
+ }
1861
+ const lowerText = text.toLowerCase();
1862
+ if (stringIncludes(lowerText, "memory") || stringIncludes(lowerText, "unique_ptr") || stringIncludes(lowerText, "shared_ptr")) {
1863
+ patterns["RAII"] = true;
1864
+ patterns["Smart Pointers"] = true;
1865
+ }
1866
+ if (stringIncludes(lowerText, "qt") || stringIncludes(lowerText, "qobject") || stringIncludes(lowerText, "qstring") || stringIncludes(lowerText, "qwidget"))
1867
+ frameworks["Qt"] = true;
1868
+ if (stringIncludes(lowerText, "iostream") || stringIncludes(lowerText, "vector") || stringIncludes(lowerText, "algorithm"))
1869
+ frameworks["stl"] = true;
1870
+ if (stringIncludes(lowerText, "windows.h")) frameworks["win32"] = true;
1871
+ }
1872
+ if (type === "auto") patterns["auto"] = true;
1873
+ if (type === "lambda_expression") patterns["lambda"] = true;
1874
+ if (this.hasDirectModifier(node, "constexpr")) patterns["constexpr"] = true;
1875
+ if (type === "access_specifier") {
1876
+ if (parentContext) {
1877
+ const t = node.text.replace(":", "").trim();
1878
+ if (t === "public" || t === "private" || t === "protected") {
1879
+ parentContext.visibility = t;
1880
+ }
1881
+ }
1882
+ }
1883
+ if (type === "namespace_definition") {
1884
+ const name = this.childText(node, "namespace_identifier") || CPP_ANONYMOUS;
1885
+ if (name === CPP_ANONYMOUS || !isCppSpelledName(name)) {
1886
+ newContext = parentContext;
1887
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1888
+ const child = node.namedChild(i);
1889
+ if (child) stack.push({ node: child, parentContext: newContext });
1890
+ }
1891
+ continue;
1892
+ }
1893
+ symbols.push({
1894
+ name,
1895
+ kind: ASTEngine.SymbolKind.Namespace,
1896
+ range: this.nodeToRange(node),
1897
+ visibility: "public",
1898
+ metadata: { isCppNamespace: true, fullName: this.buildFullName(scopeStack, name) }
1899
+ });
1900
+ newContext = {
1901
+ node,
1902
+ name,
1903
+ kind: ASTEngine.SymbolKind.Namespace,
1904
+ visibility: "public",
1905
+ isTemplate: false,
1906
+ isAbstract: false,
1907
+ friends: []
1908
+ };
1909
+ scopeStack.push(newContext);
1910
+ pushedScope = true;
1911
+ } else if (type === "class_specifier" || type === "struct_specifier" || type === "union_specifier") {
1912
+ let bodyNode = this.findChild(node, "field_declaration_list");
1913
+ if (!bodyNode) {
1914
+ const decorated = macroDecoratedClassDecl(node);
1915
+ if (decorated) {
1916
+ const ownerName = parentContext?.name;
1917
+ const decorBases = [];
1918
+ for (const b of decorated.bases) {
1919
+ const target = extendsTargetName(b.text, decorated.name);
1920
+ if (!target) continue;
1921
+ decorBases.push(target);
1922
+ relationships.push({
1923
+ source: decorated.name,
1924
+ target,
1925
+ type: ASTEngine.RelationshipType.Extends,
1926
+ confidence: 1,
1927
+ line_number: this.nameLine(b),
1928
+ metadata: { nodeType: b.type, macroDecoratedHead: true, ...indexBaseFacts(target) }
1929
+ });
1930
+ }
1931
+ classBases.set(decorated.name, decorBases);
1932
+ const decorMacro = node.childForFieldName?.("name")?.text?.trim() ?? "";
1933
+ if (decorMacro && cppExportMarker(decorMacro)) {
1934
+ const ek = `exports::${decorated.name}::${decorMacro}`;
1935
+ if (!exportsSeen.has(ek)) {
1936
+ exportsSeen.add(ek);
1937
+ relationships.push({
1938
+ source: decorated.name,
1939
+ target: decorMacro,
1940
+ type: ASTEngine.RelationshipType.Exports,
1941
+ confidence: 1,
1942
+ line_number: this.nodeLine(node),
1943
+ metadata: { relationshipType: "module_export", exportMacro: decorMacro, reasonCode: "export-marker-in-specifier" }
1944
+ });
1945
+ }
1946
+ }
1947
+ const decoratedSym = {
1948
+ name: decorated.name,
1949
+ kind: ASTEngine.SymbolKind.Class,
1950
+ range: {
1951
+ startLine: node.startPosition.row + 1,
1952
+ startColumn: node.startPosition.column + 1,
1953
+ endLine: decorated.body.endPosition.row + 1,
1954
+ endColumn: decorated.body.endPosition.column + 1,
1955
+ startIndex: node.startIndex,
1956
+ endIndex: decorated.body.endIndex
1957
+ },
1958
+ ...ownerName ? { ownerName, ownerKind: parentContext?.kind } : { scope: "global" },
1959
+ visibility: parentContext?.visibility || "public",
1960
+ metadata: {
1961
+ isCppClass: true,
1962
+ isTemplate: false,
1963
+ nameLine: this.nodeLine(decorated.nameNode),
1964
+ macroDecoratedHead: node.childForFieldName?.("name")?.text?.trim() ?? "",
1965
+ baseClasses: decorated.bases.map((b) => extendsTargetName(b.text, decorated.name)).filter((x) => !!x)
1966
+ }
1967
+ };
1968
+ symbols.push(decoratedSym);
1969
+ newContext = {
1970
+ node: decorated.owner,
1971
+ name: decorated.name,
1972
+ kind: ASTEngine.SymbolKind.Class,
1973
+ visibility: "public",
1974
+ isTemplate: false,
1975
+ isAbstract: false,
1976
+ friends: [],
1977
+ symbolRef: decoratedSym,
1978
+ locals: /* @__PURE__ */ new Set()
1979
+ };
1980
+ pushedScope = true;
1981
+ stack.push({ node: decorated.owner, parentContext: newContext, isExit: true });
1982
+ stack.push({ node: decorated.body, parentContext: newContext });
1983
+ continue;
1984
+ }
1985
+ newContext = parentContext;
1986
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
1987
+ const child = node.child(i);
1988
+ if (child) stack.push({ node: child, parentContext: newContext });
1989
+ }
1990
+ continue;
1991
+ }
1992
+ const name = this.childText(node, "type_identifier") || // D7 arm A: a `class`/`struct` may have a QUALIFIED name (an explicit
1993
+ // specialization, `template <> struct fmt::formatter<T> : formatter<U>
1994
+ // { … }`), which the direct-child `type_identifier` scan cannot see, so
1995
+ // the class published as `anonymous` — the no-name sentinel. The rule
1996
+ // is CPPD1's leaf, read off the grammar's `name` field.
1997
+ specifierDeclaredName(node) || (() => {
1998
+ const tt = this.findChild(node, "template_type");
1999
+ if (tt) {
2000
+ const tn = tt.childForFieldName?.("name") || this.findChild(tt, "type_identifier") || this.findChild(tt, "qualified_identifier");
2001
+ if (tn?.text) return tn.text;
2002
+ const lt = tt.text.indexOf("<");
2003
+ return lt > 0 ? tt.text.slice(0, lt).trim() : null;
2004
+ }
2005
+ return null;
2006
+ })() || CPP_ANONYMOUS;
2007
+ const kind = ASTEngine.SymbolKind.Class;
2008
+ const defaultVis = type === "class_specifier" ? "private" : "public";
2009
+ if (name === CPP_ANONYMOUS) {
2010
+ newContext = parentContext;
2011
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2012
+ const child = node.namedChild(i);
2013
+ if (child) stack.push({ node: child, parentContext: newContext });
2014
+ }
2015
+ continue;
2016
+ }
2017
+ if (!isCppSpelledName(name)) {
2018
+ newContext = parentContext;
2019
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2020
+ const child = node.namedChild(i);
2021
+ if (child) stack.push({ node: child, parentContext: newContext });
2022
+ }
2023
+ continue;
2024
+ }
2025
+ const isTemplate = node.parent?.type === "template_declaration";
2026
+ newContext = { node, name, kind, visibility: defaultVis, isTemplate, isAbstract: false, friends: [] };
2027
+ scopeStack.push(newContext);
2028
+ pushedScope = true;
2029
+ const baseClasses = [];
2030
+ const baseClause = this.findChild(node, "base_class_clause");
2031
+ if (baseClause) {
2032
+ for (let i = 0; i < baseClause.namedChildCount; i++) {
2033
+ const bc = baseClause.namedChild(i);
2034
+ if (!bc || bc.type === "access_specifier") continue;
2035
+ const typeNode = this.findChild(bc, "type_identifier") || this.findChild(bc, "qualified_identifier") || this.findChild(bc, "template_type") || bc;
2036
+ const target = extendsTargetName(typeNode.text, name);
2037
+ if (target) {
2038
+ baseClasses.push(target);
2039
+ relationships.push({
2040
+ source: name,
2041
+ target,
2042
+ type: ASTEngine.RelationshipType.Extends,
2043
+ confidence: 1,
2044
+ // a type expression's start is not always the
2045
+ // line of the names inside it (a specifier starts at its
2046
+ // KEYWORD) — `nameLine` prefers the grammar's `name` field.
2047
+ line_number: this.nameLine(typeNode),
2048
+ metadata: { nodeType: typeNode.type, ...indexBaseFacts(target) }
2049
+ });
2050
+ pendingImplements.push({ derived: name, base: target, line: this.nameLine(typeNode) ?? 1 });
2051
+ }
2052
+ }
2053
+ classBases.set(name, [...baseClasses]);
2054
+ }
2055
+ const sym = {
2056
+ name,
2057
+ kind: ASTEngine.SymbolKind.Class,
2058
+ range: this.nodeToRange(node),
2059
+ visibility: parentContext?.visibility || "public",
2060
+ ownerName: parentContext?.name,
2061
+ ownerKind: parentContext?.kind,
2062
+ metadata: {
2063
+ isCppClass: true,
2064
+ isTemplate,
2065
+ baseClasses,
2066
+ // #921: the class NAME's own line (`template <…>` puts it below).
2067
+ nameLine: this.nameLine(node)
2068
+ }
2069
+ };
2070
+ symbols.push(sym);
2071
+ newContext.symbolRef = sym;
2072
+ {
2073
+ const spelling = this.exportAttributeSpelling(node);
2074
+ if (spelling) {
2075
+ pendingExports.push({
2076
+ name,
2077
+ owner: parentContext?.name ?? null,
2078
+ line: this.nameLine(node) ?? 1,
2079
+ spelling
2080
+ });
2081
+ }
2082
+ }
2083
+ } else if (type === "compound_statement" && enclosingFunctionScope() === null && macroDeclaredBody(node) && // D8: a trailing ANNOTATION's body reaches this branch looking exactly like
2084
+ // a macro-declared heading's body, and publishing it here is what produced
2085
+ // `function GTEST_LOCK_EXCLUDED_(mutex_)` with `expandedFrom:
2086
+ // "macro-heading"` — a symbol for a macro, carrying the REAL function's
2087
+ // statements. The `function_definition` branch refuses the annotation
2088
+ // itself; this is the second half of the same suppression, because the body
2089
+ // is a SEPARATE node and arrives here on its own.
2090
+ //
2091
+ // The body's statements are still walked (the branch is only skipped, not
2092
+ // the subtree), so its reads keep a real owner instead of a macro's.
2093
+ !this.isTrailingAnnotationMacro(node.parent, content)) {
2094
+ const rec = macroDeclaredBody(node);
2095
+ const headingText = macroInvocationText(content, rec.nameNode.startIndex);
2096
+ if (headingText) {
2097
+ const headingRange = this.nodeToRange(rec.heading);
2098
+ const sym = {
2099
+ name: headingText,
2100
+ kind: ASTEngine.SymbolKind.Function,
2101
+ range: {
2102
+ ...headingRange,
2103
+ endLine: node.endPosition.row + 1,
2104
+ endColumn: node.endPosition.column + 1,
2105
+ endIndex: node.endIndex
2106
+ },
2107
+ visibility: "public",
2108
+ metadata: {
2109
+ isCppFunction: false,
2110
+ expandedFrom: "macro-heading",
2111
+ macroName: rec.macroName,
2112
+ headingText
2113
+ }
2114
+ };
2115
+ symbols.push(sym);
2116
+ newContext = {
2117
+ node,
2118
+ name: headingText,
2119
+ kind: ASTEngine.SymbolKind.Function,
2120
+ visibility: "public",
2121
+ isTemplate: false,
2122
+ isAbstract: false,
2123
+ friends: [],
2124
+ symbolRef: sym,
2125
+ locals: /* @__PURE__ */ new Set()
2126
+ };
2127
+ scopeStack.push(newContext);
2128
+ pushedScope = true;
2129
+ }
2130
+ } else if (type === "enum_specifier") {
2131
+ const enumNameNode = node.childForFieldName("name") || this.findChild(node, "type_identifier");
2132
+ const displaced = attributeDisplacedEnumName(node);
2133
+ const name = displaced || this.childText(node, "type_identifier") || specifierDeclaredName(node) || CPP_ANONYMOUS;
2134
+ if (name === CPP_ANONYMOUS || !isCppSpelledName(name)) {
2135
+ newContext = parentContext;
2136
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2137
+ const child = node.namedChild(i);
2138
+ if (child) stack.push({ node: child, parentContext: newContext });
2139
+ }
2140
+ continue;
2141
+ }
2142
+ let isEnumClass = false;
2143
+ for (let i = 0; i < node.childCount; i++) {
2144
+ const child = node.child(i);
2145
+ if (child && (child.text === "class" || child.text === "struct")) {
2146
+ isEnumClass = true;
2147
+ break;
2148
+ }
2149
+ }
2150
+ symbols.push({
2151
+ name,
2152
+ kind: ASTEngine.SymbolKind.Enum,
2153
+ range: this.nodeToRange(node),
2154
+ visibility: parentContext?.visibility || "public",
2155
+ ownerName: parentContext?.name,
2156
+ ownerKind: parentContext?.kind,
2157
+ metadata: { isCppEnum: true, isEnumClass, isScopedEnum: isEnumClass, nameLine: this.nodeLine(enumNameNode) }
2158
+ });
2159
+ newContext = {
2160
+ node,
2161
+ name,
2162
+ kind: ASTEngine.SymbolKind.Enum,
2163
+ visibility: "public",
2164
+ isTemplate: false,
2165
+ isAbstract: false,
2166
+ friends: []
2167
+ };
2168
+ scopeStack.push(newContext);
2169
+ pushedScope = true;
2170
+ } else if (type === "function_definition" || type === "field_declaration" || type === "declaration") {
2171
+ const friendDecl = enclosingFriendDeclaration(node);
2172
+ if (friendDecl) {
2173
+ const friendDefines = type === "function_definition";
2174
+ const friendDetails = friendDefines ? this.getFunctionDetails(node) : null;
2175
+ if (friendDetails && !friendDetails.isDestructor && !this.isMacroFunctionShape(node, friendDetails.name)) {
2176
+ const owner = friendBodyOwner(scopeStack, friendDecl);
2177
+ const fnDeclarator2 = friendDetails.declarator;
2178
+ const sym = buildFunctionSymbol(node, fnDeclarator2, {
2179
+ name: friendDetails.name,
2180
+ kind: ASTEngine.SymbolKind.Function,
2181
+ visibility: parentContext?.visibility,
2182
+ // `global` (nothing published encloses the class) is the sentinel the
2183
+ // builder turns into "no owner": the friend belongs to the FILE then.
2184
+ ownerName: owner.name,
2185
+ ownerKind: owner.kind,
2186
+ metadata: {
2187
+ isCppFriendDefinition: true,
2188
+ isDestructor: false,
2189
+ isOperatorOverload: friendDetails.isOperator,
2190
+ // The friend's OWN template parameter list hangs one level higher
2191
+ // than a member's: `template_declaration > friend_declaration >
2192
+ // function_definition`, not `template_declaration >
2193
+ // function_definition`. The outer class's template is the CLASS
2194
+ // symbol's `isTemplate`, not this function's.
2195
+ isTemplate: node.parent?.type === "template_declaration" || friendDecl.parent?.type === "template_declaration",
2196
+ nameLine: this.nodeLine(friendDetails.nameNode)
2197
+ }
2198
+ });
2199
+ symbols.push(sym);
2200
+ newContext = {
2201
+ node,
2202
+ name: friendDetails.name,
2203
+ kind: ASTEngine.SymbolKind.Function,
2204
+ visibility: "public",
2205
+ isTemplate: false,
2206
+ isAbstract: false,
2207
+ friends: [],
2208
+ symbolRef: sym,
2209
+ locals: new Set(declaratorParamNames(fnDeclarator2))
2210
+ };
2211
+ scopeStack.push(newContext);
2212
+ pushedScope = true;
2213
+ stack.push({ node, parentContext: newContext, isExit: true });
2214
+ } else {
2215
+ newContext = parentContext;
2216
+ if (friendDefines) {
2217
+ const outer = friendBodyOwner(scopeStack, friendDecl);
2218
+ newContext = { ...parentContext, node: outer.node, name: outer.name, kind: outer.kind };
2219
+ }
2220
+ }
2221
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2222
+ const child = node.namedChild(i);
2223
+ if (child) stack.push({ node: child, parentContext: newContext });
2224
+ }
2225
+ continue;
2226
+ }
2227
+ const funcDetails = this.getFunctionDetails(node);
2228
+ const fnDeclarator = funcDetails?.declarator ?? null;
2229
+ const cppDecorators = this.declarationDecorators(node, fnDeclarator);
2230
+ let isStatic = cppDecorators.includes("static");
2231
+ let isConstexpr = cppDecorators.includes("constexpr");
2232
+ let isConst = cppDecorators.includes("const");
2233
+ let isVirtual = cppDecorators.includes("virtual") || cppDecorators.includes("override");
2234
+ if (type === "function_definition" && this.isTrailingAnnotationMacro(node, content)) {
2235
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2236
+ const child = node.namedChild(i);
2237
+ if (child) stack.push({ node: child, parentContext });
2238
+ }
2239
+ continue;
2240
+ }
2241
+ if (type === "function_definition" && isMacroDecoratedClassFunction(node)) {
2242
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2243
+ const child = node.namedChild(i);
2244
+ if (!child || child.type === "compound_statement") continue;
2245
+ stack.push({ node: child, parentContext });
2246
+ }
2247
+ continue;
2248
+ }
2249
+ if (type === "function_definition" && this.returnTypeIsClassDefinition(node)) {
2250
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2251
+ const child = node.namedChild(i);
2252
+ if (child) stack.push({ node: child, parentContext });
2253
+ }
2254
+ continue;
2255
+ }
2256
+ if (funcDetails) {
2257
+ const { name: funcName, scope: explicitScope, isDestructor, isOperator, nameNode: funcNameNode } = funcDetails;
2258
+ const ownerIsFunction = ownerIsFunctionScope(parentContext);
2259
+ if (funcDetails) {
2260
+ const marker = this.specifierExportMacro(node.childForFieldName?.("type") ?? null);
2261
+ if (marker && cppExportMarker(marker) && isCppSpelledName(funcName)) {
2262
+ const ek = `exports::${funcName}::${marker}`;
2263
+ if (!exportsSeen.has(ek)) {
2264
+ exportsSeen.add(ek);
2265
+ relationships.push({
2266
+ source: funcName,
2267
+ target: marker,
2268
+ type: ASTEngine.RelationshipType.Exports,
2269
+ confidence: 1,
2270
+ line_number: this.nodeLine(funcNameNode ?? node),
2271
+ metadata: {
2272
+ relationshipType: "module_export",
2273
+ exportMacro: marker,
2274
+ reasonCode: "export-marker-in-specifier"
2275
+ }
2276
+ });
2277
+ }
2278
+ }
2279
+ }
2280
+ if (ownerIsFunction && !explicitScope) {
2281
+ const fnScope = enclosingFunctionScope();
2282
+ if (fnScope && isCppSpelledName(funcName)) {
2283
+ if (!fnScope.locals) fnScope.locals = /* @__PURE__ */ new Set();
2284
+ fnScope.locals.add(funcName);
2285
+ }
2286
+ newContext = parentContext;
2287
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2288
+ const child = node.namedChild(i);
2289
+ if (child) stack.push({ node: child, parentContext: newContext });
2290
+ }
2291
+ continue;
2292
+ }
2293
+ if (!isDestructor && this.isMacroFunctionShape(node, funcName)) {
2294
+ const annotation = this.isTrailingAnnotationMacro(node, content);
2295
+ const macroHeading = annotation ? null : this.macroHeadingText(node, content, funcName);
2296
+ let sym2 = null;
2297
+ if (macroHeading) {
2298
+ sym2 = {
2299
+ name: macroHeading,
2300
+ kind: ASTEngine.SymbolKind.Function,
2301
+ range: this.nodeToRange(node),
2302
+ visibility: "public",
2303
+ metadata: {
2304
+ isCppFunction: false,
2305
+ expandedFrom: "macro-heading",
2306
+ macroName: funcName,
2307
+ headingText: macroHeading
2308
+ }
2309
+ };
2310
+ symbols.push(sym2);
2311
+ }
2312
+ newContext = {
2313
+ node,
2314
+ name: macroHeading ?? "",
2315
+ kind: ASTEngine.SymbolKind.Function,
2316
+ visibility: "public",
2317
+ isTemplate: false,
2318
+ isAbstract: false,
2319
+ friends: [],
2320
+ ...sym2 ? { symbolRef: sym2 } : {},
2321
+ locals: /* @__PURE__ */ new Set()
2322
+ };
2323
+ scopeStack.push(newContext);
2324
+ pushedScope = true;
2325
+ stack.push({ node, parentContext: newContext, isExit: true });
2326
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2327
+ const child = node.namedChild(i);
2328
+ if (child) stack.push({ node: child, parentContext: newContext });
2329
+ }
2330
+ continue;
2331
+ }
2332
+ const actualOwnerName = explicitScope || parentContext?.name;
2333
+ const actualOwnerKind = explicitScope ? ASTEngine.SymbolKind.Class : parentContext?.kind;
2334
+ const isConstructor = actualOwnerName === funcName && actualOwnerKind === ASTEngine.SymbolKind.Class;
2335
+ const isPureVirtual = cppPureVirtualDeclaration(node);
2336
+ if (isPureVirtual && parentContext && parentContext.name === actualOwnerName) {
2337
+ parentContext.isAbstract = true;
2338
+ }
2339
+ const isTemplate = node.parent?.type === "template_declaration";
2340
+ const kind = isConstructor ? ASTEngine.SymbolKind.Constructor : actualOwnerKind === ASTEngine.SymbolKind.Class ? ASTEngine.SymbolKind.Method : ASTEngine.SymbolKind.Function;
2341
+ const sym = buildFunctionSymbol(node, fnDeclarator, {
2342
+ name: isConstructor ? "constructor" : funcName,
2343
+ kind,
2344
+ // CP3 (cpp review, HC1 parity): file-scope `static` (internal linkage) is
2345
+ // private. Class-member `static` is NOT internal linkage — members keep
2346
+ // their access-specifier visibility.
2347
+ visibility: isStatic && actualOwnerKind !== ASTEngine.SymbolKind.Class ? "private" : parentContext?.visibility,
2348
+ isStatic,
2349
+ ownerName: actualOwnerName,
2350
+ ownerKind: actualOwnerKind,
2351
+ decorators: cppDecorators,
2352
+ metadata: {
2353
+ isTemplate,
2354
+ isVirtual,
2355
+ isPureVirtual,
2356
+ isConst,
2357
+ isStatic,
2358
+ isConstexpr,
2359
+ isConstructor,
2360
+ isDestructor,
2361
+ isOperatorOverload: isOperator,
2362
+ // #612 store-phase: DECLARATION vs DEFINITION. This branch is reached for
2363
+ // all three node types that can name a function, and the type itself is
2364
+ // the whole discriminator — the grammar parses a body as
2365
+ // `function_definition` and a prototype (file-scope `int f(void);`, an
2366
+ // in-class `int f();`, a field declaration) as
2367
+ // `declaration`/`field_declaration`. Without this key the only signal the
2368
+ // store had was the symbol NAME, so a cpp header prototype competed on
2369
+ // equal footing with the .cpp definition in another file and name
2370
+ // resolution could pick the prototype.
2371
+ ...type === "function_definition" ? {} : { isDeclaration: true },
2372
+ // #921 (M60): the line the declared NAME is written on. A wrapped return
2373
+ // type puts it below the declaration's start (`void NORETURN` then
2374
+ // `CheckFailed(const char *file, …)`), and the containment edge this
2375
+ // symbol may own has to name THAT line — the rule every other
2376
+ // relationship type already follows. Absent when the tree gives no name
2377
+ // node (the containment edge then falls back to the symbol range, which
2378
+ // is the pre-#921 behaviour).
2379
+ nameLine: this.nodeLine(funcNameNode)
2380
+ }
2381
+ });
2382
+ if (!isConstructor && kind === ASTEngine.SymbolKind.Method && parentContext?.kind === ASTEngine.SymbolKind.Class && funcName !== parentContext.name) {
2383
+ const decl2 = this.functionDeclaratorOf(node);
2384
+ const paramsNode = decl2?.childForFieldName("parameters") ?? null;
2385
+ const normParams = buildParamSig(paramsNode);
2386
+ const sigs = classVirtuals.get(parentContext.name) ?? /* @__PURE__ */ new Map();
2387
+ const prev = sigs.get(funcName) ?? [];
2388
+ if (!prev.includes(normParams)) sigs.set(funcName, [...prev, normParams]);
2389
+ else sigs.set(funcName, prev);
2390
+ classVirtuals.set(parentContext.name, sigs);
2391
+ if (this.isPureVirtualDeclaration(node)) {
2392
+ const pure = classPureVirtuals.get(parentContext.name) ?? /* @__PURE__ */ new Set();
2393
+ pure.add(funcName);
2394
+ classPureVirtuals.set(parentContext.name, pure);
2395
+ }
2396
+ const overrideKeyword = this.functionOverrideSpecifier(node);
2397
+ if ((classBases.get(parentContext.name)?.length ?? 0) > 0) {
2398
+ pendingOverrides.push({
2399
+ cls: parentContext.name,
2400
+ method: funcName,
2401
+ params: normParams,
2402
+ line: this.nodeLine(node),
2403
+ ...overrideKeyword ? { keyword: overrideKeyword } : {}
2404
+ });
2405
+ }
2406
+ }
2407
+ {
2408
+ const spelling = this.exportAttributeSpelling(node);
2409
+ if (spelling) {
2410
+ const owner = parentContext && parentContext.kind !== ASTEngine.SymbolKind.Function ? parentContext.name : null;
2411
+ pendingExports.push({
2412
+ name: funcName,
2413
+ owner,
2414
+ line: this.nodeLine(funcNameNode ?? node) ?? 1,
2415
+ spelling
2416
+ });
2417
+ }
2418
+ }
2419
+ symbols.push(sym);
2420
+ if (type === "function_definition") {
2421
+ newContext = {
2422
+ node,
2423
+ // CPPD9 (deep review 2026-09-05): the scope NAME must match the
2424
+ // emitted symbol name. Constructors were pushed as the raw
2425
+ // class name (`Engine`) while their symbol was normalized to
2426
+ // "constructor" — so ctor-body calls emitted source=Engine (the
2427
+ // Class symbol) instead of the Constructor symbol, and the
2428
+ // qualified_calls payload never reached the constructor. The
2429
+ // family contract (groovy/java/csharp) scopes ctors under the
2430
+ // normalized "constructor" name, which is why the scope takes the
2431
+ // name off the SYMBOL rather than keeping a second copy of it.
2432
+ name: sym.name,
2433
+ kind,
2434
+ visibility: "public",
2435
+ isTemplate: false,
2436
+ isAbstract: false,
2437
+ friends: [],
2438
+ symbolRef: sym,
2439
+ // CP5: out-of-line class scope for member resolution.
2440
+ classScope: explicitScope,
2441
+ // CP1: parameters bind at function entry (flow-sensitive
2442
+ // shadowing like the C family — reads before any local
2443
+ // binding still resolve outward).
2444
+ locals: new Set(declaratorParamNames(this.findChild(node, "function_declarator")))
2445
+ };
2446
+ scopeStack.push(newContext);
2447
+ pushedScope = true;
2448
+ }
2449
+ } else if (type === "field_declaration" || type === "declaration") {
2450
+ const decls = this.findAllChildren(node, "init_declarator");
2451
+ if (decls.length === 0) {
2452
+ if (declaredValueName(node)) decls.push(node);
2453
+ }
2454
+ for (let idx = 0; idx < decls.length; idx++) {
2455
+ const d = decls[idx];
2456
+ const idNode = recoveredDeclaredName(d) ?? (d.type === "init_declarator" ? declaredNameNode(d) : declaredValueName(d));
2457
+ const name = idNode ? idNode.text : "";
2458
+ const isDisplacedEnumName = (() => {
2459
+ const holder = d.type === "init_declarator" ? d.parent ?? null : d;
2460
+ const tf = holder?.childForFieldName?.("type") ?? null;
2461
+ if (!tf || tf.type !== "enum_specifier") return false;
2462
+ return attributeDisplacedEnumName(tf) === name;
2463
+ })();
2464
+ const insideFunction = parentContext && (parentContext.kind === ASTEngine.SymbolKind.Function || parentContext.kind === ASTEngine.SymbolKind.Method || parentContext.kind === ASTEngine.SymbolKind.Constructor);
2465
+ if (name && insideFunction) {
2466
+ const fnScope = enclosingFunctionScope();
2467
+ if (fnScope) {
2468
+ if (!fnScope.locals) fnScope.locals = /* @__PURE__ */ new Set();
2469
+ fnScope.locals.add(name);
2470
+ }
2471
+ }
2472
+ if (name && !isDisplacedEnumName && !stringIncludes(name, "(") && !insideFunction && !this.isBareMacroDeclaration(node, name)) {
2473
+ const visStatic = isStatic && parentContext?.kind !== ASTEngine.SymbolKind.Class ? "private" : void 0;
2474
+ const declDecorators = this.declarationDecorators(node, this.findChild(node, "function_declarator"));
2475
+ symbols.push({
2476
+ name,
2477
+ kind: isConstexpr ? ASTEngine.SymbolKind.Constant : parentContext?.kind === ASTEngine.SymbolKind.Class ? ASTEngine.SymbolKind.Property : ASTEngine.SymbolKind.Variable,
2478
+ range: this.nodeToRange(d),
2479
+ visibility: visStatic || parentContext?.visibility || "public",
2480
+ isStatic,
2481
+ ownerName: parentContext?.name,
2482
+ ownerKind: parentContext?.kind,
2483
+ ...declDecorators.length > 0 ? { decorators: declDecorators } : {},
2484
+ metadata: {
2485
+ isConstexpr,
2486
+ isStatic,
2487
+ isConst,
2488
+ // #921: the declared NAME's own line — `struct { … } options;`
2489
+ // and a wrapped type both write it below the declaration start.
2490
+ nameLine: this.nodeLine(idNode)
2491
+ }
2492
+ });
2493
+ }
2494
+ }
2495
+ }
2496
+ } else if (type === "enumerator") {
2497
+ const enumeratorNameNode = node.childForFieldName("name") || this.findChild(node, "identifier");
2498
+ const name = this.childText(node, "identifier");
2499
+ if (name && isCppSpelledName(name)) {
2500
+ const fnScope = enclosingFunctionScope();
2501
+ if (fnScope && scopeStack.length > 0) {
2502
+ if (this.insideFunctionBody(node.parent)) {
2503
+ if (!fnScope.locals) fnScope.locals = /* @__PURE__ */ new Set();
2504
+ fnScope.locals.add(name);
2505
+ }
2506
+ }
2507
+ symbols.push({
2508
+ name,
2509
+ kind: ASTEngine.SymbolKind.EnumMember,
2510
+ range: this.nodeToRange(node),
2511
+ visibility: "public",
2512
+ ownerName: parentContext?.name,
2513
+ ownerKind: parentContext?.kind,
2514
+ metadata: { isCppEnumMember: true, nameLine: this.nodeLine(enumeratorNameNode) }
2515
+ });
2516
+ }
2517
+ } else if (type === "field_expression") {
2518
+ const field = node.childForFieldName("field");
2519
+ const obj = node.childForFieldName("argument") || node.namedChild(0);
2520
+ const pType = node.parent?.type;
2521
+ const lhsAssign = pType === "assignment_expression" && node.parent?.namedChild(0) && node.parent.namedChild(0).startIndex === node.startIndex;
2522
+ if (field && field.text.trim() && isCppSpelledName(field.text) && pType !== "call_expression" && !lhsAssign) {
2523
+ const source = parentContext?.name || "global";
2524
+ const relKey = `${source}::uses::${field.text}`;
2525
+ if (!usesSeen.has(relKey)) {
2526
+ usesSeen.add(relKey);
2527
+ relationships.push({
2528
+ source,
2529
+ target: field.text,
2530
+ type: ASTEngine.RelationshipType.Uses,
2531
+ confidence: 0.9,
2532
+ // / #870: the FIELD LEAF names this edge. This row
2533
+ // carried no line at all, which is the #870 measurement (a member
2534
+ // read reported at line 0 in the fmt lane).
2535
+ line_number: this.nodeLine(field),
2536
+ // M14-HONESTY-CONTRACT , and the code says what the 0.9 means:
2537
+ // the edge states that THIS SCOPE READS a member with this name, and
2538
+ // the RECEIVER'S TYPE is not resolved — nothing here carries C++ type
2539
+ // inference, so which class declares the member is unknown and a
2540
+ // same-named member on an unrelated class is indistinguishable from
2541
+ // the intended one. Measured before this field existed: 3,012 `uses`
2542
+ // rows at 0.9, none carrying a code.
2543
+ metadata: {
2544
+ relationshipType: "field_access",
2545
+ accessedFrom: obj?.text,
2546
+ reasonCode: "member-read-receiver-type-unresolved"
2547
+ }
2548
+ });
2549
+ }
2550
+ }
2551
+ } else if (type === "call_expression") {
2552
+ const funcNode = node.childForFieldName("function") || node.namedChild(0);
2553
+ if (funcNode) {
2554
+ let targetName = funcNode.text;
2555
+ let qualifiedName = targetName;
2556
+ const NAME_BEARING = (t) => t === "identifier" || t === "field_identifier" || t === "type_identifier" || t === "operator_name" || t === "destructor_name" || t === "namespace_identifier";
2557
+ const calleeLeafNode = (n) => {
2558
+ let cur = n;
2559
+ let guard = 0;
2560
+ while (cur && guard++ < 8) {
2561
+ const t = cur.type;
2562
+ if (t === "field_expression") {
2563
+ const f = cur.childForFieldName("field") ?? cur.namedChild(cur.namedChildCount - 1);
2564
+ if (!f) return null;
2565
+ cur = f;
2566
+ continue;
2567
+ }
2568
+ if (t === "template_function" || t === "template_method") {
2569
+ const base = cur.namedChild(0);
2570
+ if (!base) return null;
2571
+ cur = base;
2572
+ continue;
2573
+ }
2574
+ if (t === "dependent_name" && cur.namedChildCount >= 1) {
2575
+ const inner = cur.namedChild(0);
2576
+ if (inner && (inner.type === "template_method" || inner.type === "template_function" || inner.type === "identifier" || inner.type === "field_identifier")) {
2577
+ cur = inner;
2578
+ continue;
2579
+ }
2580
+ return null;
2581
+ }
2582
+ if (t === "qualified_identifier" && cur.namedChildCount >= 1) {
2583
+ cur = cur.namedChild(cur.namedChildCount - 1);
2584
+ continue;
2585
+ }
2586
+ if (t === "parenthesized_expression" && cur.namedChildCount >= 1) {
2587
+ cur = cur.namedChild(0);
2588
+ continue;
2589
+ }
2590
+ if (!NAME_BEARING(t)) return null;
2591
+ if (t === "identifier" && !isCppSpelledName(cur.text)) return null;
2592
+ return cur;
2593
+ }
2594
+ return null;
2595
+ };
2596
+ const calleeLeaf = (n) => calleeLeafNode(n)?.text ?? "";
2597
+ let calleeSite = calleeLeafNode(funcNode);
2598
+ if (funcNode.type === "field_expression") {
2599
+ const field = funcNode.childForFieldName("field");
2600
+ const obj = funcNode.childForFieldName("argument") || funcNode.namedChild(0);
2601
+ if (field) {
2602
+ targetName = calleeLeaf(field);
2603
+ qualifiedName = obj ? `${obj.text}.${field.text}` : field.text;
2604
+ calleeSite = calleeLeafNode(field);
2605
+ }
2606
+ } else {
2607
+ targetName = calleeLeaf(funcNode);
2608
+ qualifiedName = funcNode.text;
2609
+ }
2610
+ const source = parentContext?.name || "global";
2611
+ const calleeIsTempCall = funcNode.type === "call_expression";
2612
+ const calleeIsUnnamed = calleeSite === null;
2613
+ const calleeIsError = !!funcNode.hasError;
2614
+ const ownerIsTypeScope = parentContext?.kind === ASTEngine.SymbolKind.Class || parentContext?.kind === ASTEngine.SymbolKind.Struct;
2615
+ const classCallingItself = ownerIsTypeScope && parentContext?.name === targetName;
2616
+ if (!targetName.startsWith("operator") && !calleeIsTempCall && !calleeIsUnnamed && !calleeIsError && !classCallingItself) {
2617
+ relationships.push({
2618
+ source,
2619
+ target: targetName,
2620
+ fromSymbol: source,
2621
+ toSymbol: qualifiedName,
2622
+ type: ASTEngine.RelationshipType.Calls,
2623
+ // M14 ONTOLOGY (this round), question 6 ("is `confidence` right?").
2624
+ // This row carried NO `confidence` at all, and it is the largest edge
2625
+ // family in the lane: measured 101,340 `calls` rows over 929 corpus
2626
+ // files, every one of them `undefined`, against a documentation
2627
+ // table that claimed 1.0. A consumer reading `rel.confidence` got
2628
+ // `undefined` on three quarters of the lane's output, and
2629
+ // `classifyEvidenceTier` papered over it by defaulting a missing
2630
+ // value to 1 — so the missing field was invisible from inside the
2631
+ // analyzer and from the evidence tier at the same time.
2632
+ //
2633
+ // 1.0 is the honest value, and it is not a claim that the CALLEE is
2634
+ // the function the author meant: it is a claim about what the edge
2635
+ // IS. A `call_expression` whose callee leaf is a name is a
2636
+ // deterministic AST fact, which is why `uses`/`extends`/
2637
+ // `instantiates`/`references` all publish a number for the same kind
2638
+ // of edge. Which overload a bare name selects is recorded separately
2639
+ // and honestly, in `metadata.qualified` (the full callee path) — it
2640
+ // is not a confidence question.
2641
+ confidence: 1,
2642
+ // / M60.P1 (#873): ONE line, ONE base, ONE node. The
2643
+ // row's `line_number` is the callee leaf's line (the node that
2644
+ // names the edge) and the metadata mirror repeats THAT value
2645
+ // instead of the call node's — a mirror that named a different
2646
+ // node would make "the row's line" ambiguous again, which is what
2647
+ // #873 was about. Base stays 1-based (R6).
2648
+ line_number: this.nodeLine(calleeSite),
2649
+ // task-22 (flag-gated): the project index's declaration facts for this callee. Empty
2650
+ // object = flag off / incomplete index, so the row is byte-identical to the verdict.
2651
+ metadata: {
2652
+ line: this.nodeLine(calleeSite),
2653
+ qualified: qualifiedName,
2654
+ ...indexCallFacts(targetName),
2655
+ // task-22: a QUALIFIED callee names its owner syntactically; the owner channel can
2656
+ // resolve the row through it. Emitted only under the flag + a complete index + the
2657
+ // index agreeing the class-like owner DECLARES the member.
2658
+ ...indexOwnerFacts(qualifiedName, targetName),
2659
+ // task-22 milestone 5: the three declaration-bearing RECEIVER classes (constructor-temp,
2660
+ // typed-local, implicit-this). Empty for opaque receivers — the owner is never guessed.
2661
+ ...indexReceiverOwnerFacts(funcNode, targetName),
2662
+ // ISO C++ citation claim (Lead vocabulary `iso-cpp-stdlib`, flag-gated): ONLY a listed
2663
+ // symbol whose own spelling root is std; verified by the arbiter as extOK, never resolved.
2664
+ ...cppCitationFacts(qualifiedName, targetName),
2665
+ // The package-scope claim (flag-gated): the callee is a member of a dependency the
2666
+ // GOVERNING MANIFEST declares, on the evidence of the translation unit's external
2667
+ // include roots. The package name carried is the MANIFEST'S OWN SPELLING, so the
2668
+ // arbiter's exact-match verification holds and the claim cannot refute itself.
2669
+ ...cppPackageScopeFacts(targetName, qualifiedName, packageScopeRoots, packageScopePackages)
2670
+ }
2671
+ });
2672
+ const caller = parentContext?.symbolRef;
2673
+ if (caller && (caller.kind === ASTEngine.SymbolKind.Method || caller.kind === ASTEngine.SymbolKind.Function || caller.kind === ASTEngine.SymbolKind.Constructor)) {
2674
+ if (!caller.qualified_calls) caller.qualified_calls = [];
2675
+ caller.qualified_calls.push(qualifiedName);
2676
+ }
2677
+ }
2678
+ }
2679
+ } else if (type === "new_expression") {
2680
+ const typeNode = node.namedChild(0);
2681
+ if (typeNode) {
2682
+ let typeName = typeNode.text;
2683
+ let cur = typeNode;
2684
+ while (cur && cur.type === "qualified_identifier" && cur.namedChildCount >= 1) {
2685
+ const inner = cur.namedChild(cur.namedChildCount - 1);
2686
+ if (!inner) break;
2687
+ cur = inner;
2688
+ }
2689
+ if (cur && cur !== typeNode) typeName = cur.text;
2690
+ const lt3 = typeName.indexOf("<");
2691
+ if (lt3 !== -1) typeName = typeName.slice(0, lt3);
2692
+ if (this.isPlainIdentifier(typeName) && isCppSpelledName(typeName) && !CPP_NON_CLASS_STANDARD_TYPES.has(typeName) && !this.isTemplateParameterName(node, typeName)) {
2693
+ const source = parentContext?.name || "global";
2694
+ relationships.push({
2695
+ source,
2696
+ target: typeName,
2697
+ fromSymbol: source,
2698
+ toSymbol: typeNode.text,
2699
+ type: ASTEngine.RelationshipType.Instantiates,
2700
+ confidence: typeNode.hasError ? 0.6 : 1,
2701
+ // the constructed type's own node names this edge —
2702
+ // `new` and its type can sit on different lines. Same value in the
2703
+ // #873 mirror, 1-based.
2704
+ line_number: this.nodeLine(typeNode),
2705
+ metadata: { line: this.nodeLine(typeNode), isNew: true }
2706
+ });
2707
+ }
2708
+ }
2709
+ } else if (type === "identifier") {
2710
+ const p = node.parent;
2711
+ if (p && p.type === "lambda_capture_initializer" && p.namedChild(0)?.startIndex === node.startIndex) {
2712
+ const fnScope = enclosingFunctionScope();
2713
+ if (fnScope) {
2714
+ if (!fnScope.locals) fnScope.locals = /* @__PURE__ */ new Set();
2715
+ fnScope.locals.add(node.text);
2716
+ }
2717
+ } else if (isDeclarationPosition(node) && !isFunctionOwnName(node)) {
2718
+ const fnScope = enclosingFunctionScope();
2719
+ if (fnScope) {
2720
+ if (this.insideFunctionBody(p)) {
2721
+ if (!fnScope.locals) fnScope.locals = /* @__PURE__ */ new Set();
2722
+ fnScope.locals.add(node.text);
2723
+ }
2724
+ }
2725
+ } else if (node.text && // D1, EDGE GATE. The roster gate above is the structural fix; this is
2726
+ // the edge-level guarantee, so the impossibility holds on the row
2727
+ // itself even if a future path adds a name to a roster directly. A
2728
+ // keyword names no value, so it is never a read.
2729
+ isCppSpelledName(node.text) && !isDeclarationPosition(node) && !isPreprocText(node) && // Assignment LHS is a WRITE, never a read (C CGD1 / family
2730
+ // write-is-not-a-use contract — plain and compound assignments
2731
+ // both carry the LHS as first named child).
2732
+ !(p && p.type === "assignment_expression" && p.namedChild(0)?.startIndex === node.startIndex && (p.namedChild(0)?.endIndex ?? 0) >= node.endIndex) && // Call callee (span-matched like C CGD17, climbing through
2733
+ // template/dependent/parenthesized wrappers like the calls
2734
+ // branch's calleeLeaf) — the calls branch owns it.
2735
+ !isCallCallee(node) && // Member leaves — the field path owns them (both read and call
2736
+ // positions). The OBJECT of a field access is a genuine read and
2737
+ // stays (CGD31 contract): only the field-role leaf is skipped.
2738
+ // CPPD14: seen through template wrappers (`key.get_ref<string_t&>()`).
2739
+ !isMemberLeaf(node) && // Qualified reads (`ns::x`) — limitation, stays silent.
2740
+ !hasQualifiedAncestor(node) && // Labels and attributes never name values.
2741
+ !(p && (p.type === "goto_statement" || p.type === "labeled_statement")) && !hasAttributeAncestor(node)) {
2742
+ const fnScope = enclosingFunctionScope();
2743
+ const shadowed = !!fnScope?.locals?.has(node.text);
2744
+ if (!shadowed && isResolvableRead(node.text)) {
2745
+ const source = parentContext?.name || "global";
2746
+ const relKey = `${source}::uses::${node.text}`;
2747
+ if (!usesSeen.has(relKey)) {
2748
+ usesSeen.add(relKey);
2749
+ relationships.push({
2750
+ source,
2751
+ target: node.text,
2752
+ type: ASTEngine.RelationshipType.Uses,
2753
+ confidence: 1,
2754
+ line_number: this.nodeLine(node),
2755
+ metadata: { relationshipType: "identifier_usage", nodeType: node.type }
2756
+ });
2757
+ }
2758
+ }
2759
+ }
2760
+ }
2761
+ if (pushedScope) {
2762
+ stack.push({ node, parentContext: newContext, isExit: true });
2763
+ }
2764
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
2765
+ const child = node.namedChild(i);
2766
+ if (child) {
2767
+ stack.push({ node: child, parentContext: newContext });
2768
+ }
2769
+ }
2770
+ }
2771
+ const seenExportNames = /* @__PURE__ */ new Set();
2772
+ for (const sym of symbols) {
2773
+ if (!sym.ownerName && !sym.ownerKind) {
2774
+ const isPrivate = sym.visibility === "private" || sym.isStatic;
2775
+ const isMacroExpansion = sym.metadata?.expandedFrom === "macro-heading";
2776
+ if (!isPrivate && !isMacroExpansion && sym.name !== CPP_ANONYMOUS && !seenExportNames.has(sym.name)) {
2777
+ seenExportNames.add(sym.name);
2778
+ exports.push({
2779
+ name: sym.name,
2780
+ kind: sym.kind,
2781
+ range: sym.range,
2782
+ visibility: sym.visibility || "public"
2783
+ });
2784
+ }
2785
+ }
2786
+ }
2787
+ const companion = context?.overrideCompanion instanceof Map ? context.overrideCompanion : void 0;
2788
+ {
2789
+ const resolves = (startCls, method, params, keyword) => {
2790
+ const found = [];
2791
+ const seen = /* @__PURE__ */ new Set();
2792
+ const queue = [startCls];
2793
+ let depth = 0;
2794
+ while (queue.length && depth < 10) {
2795
+ depth++;
2796
+ const cls = queue.shift();
2797
+ if (seen.has(cls)) continue;
2798
+ seen.add(cls);
2799
+ for (const base of classBases.get(cls) ?? []) {
2800
+ if (base === startCls) continue;
2801
+ const baseSigs = classVirtuals.get(base);
2802
+ const sigMatch = !!baseSigs && (baseSigs.get(method) ?? []).includes(params);
2803
+ if (sigMatch) {
2804
+ found.push({
2805
+ base,
2806
+ confidence: keyword ? 1 : 0.9,
2807
+ reasonCode: keyword ? "override-keyword+signature-match" : "signature-match"
2808
+ });
2809
+ } else if (keyword && companion) {
2810
+ const declared = companion.get(base);
2811
+ if (declared && declared.has(method)) {
2812
+ found.push({ base, confidence: 0.95, reasonCode: "override-keyword+companion-declares-method" });
2813
+ }
2814
+ }
2815
+ queue.push(base);
2816
+ }
2817
+ }
2818
+ return found;
2819
+ };
2820
+ const seenOv = /* @__PURE__ */ new Set();
2821
+ for (const pend of pendingOverrides) {
2822
+ for (const hit of resolves(pend.cls, pend.method, pend.params, !!pend.keyword)) {
2823
+ const k = `${pend.cls}.${pend.method}|${hit.base}.${pend.method}`;
2824
+ if (seenOv.has(k)) continue;
2825
+ seenOv.add(k);
2826
+ relationships.push({
2827
+ source: `${pend.cls}.${pend.method}`,
2828
+ // THE TARGET IS THE DECLARED MEMBER, NOT `Base.method`. The resolver matches an
2829
+ // edge target against a SYMBOL NAME (or a qualified-name alias), and a cpp member
2830
+ // symbol publishes only its leaf — `pool-worker.ts` normalises `qualifiedName` to
2831
+ // `name` for a symbol with no `scope`/`fqn`, so `Base.method` is a spelling no
2832
+ // declaration answers to. Measured before this spelling was restored: 1,875 of
2833
+ // 1,875 `overrides` edges unresolved on the whole cpp population (CPP-RESIDUAL ).
2834
+ // This is commit a29357562's landed fix ("the leaf spelling … WITH the owner carried
2835
+ // in metadata", measured there as 86 edges: 86 unresolved -> 0), which the
2836
+ // `0b597d2e4` take-main merge dropped and this iteration restores.
2837
+ target: pend.method,
2838
+ type: ASTEngine.RelationshipType.Overrides,
2839
+ confidence: hit.confidence,
2840
+ // the overriding method's own declaration site (the
2841
+ // pending record carries the line captured where the method was
2842
+ // walked — a post-loop resolution has no node to ask).
2843
+ line_number: pend.line,
2844
+ metadata: {
2845
+ isVirtualOverride: true,
2846
+ reasonCode: hit.reasonCode,
2847
+ // THE OWNER CARRIES THE DISTINCTION THE TARGET NO LONGER CAN. Two methods named
2848
+ // `run` in two classes are two declarations; the leaf names both, so the base
2849
+ // that was actually matched by the signature/keyword evidence rides HERE rather
2850
+ // than disappearing. This is the field the lane's own fixtures pin
2851
+ // (`meta.overriddenOwner`), and it is the machine-readable answer to "which
2852
+ // declaration did the resolver intend" when the leaf alone is ambiguous.
2853
+ overriddenOwner: hit.base,
2854
+ // task-22 (flag-gated): does the INDEX's inheritance-closed member view confirm this
2855
+ // base declares the method? Absent when there is no complete index.
2856
+ ...indexOverridesFacts(hit.base, pend.method),
2857
+ // M14-HONESTY-CONTRACT : any edge under 1.0 carries a
2858
+ // machine-readable reason code, and `override`/`final` is
2859
+ // recorded so a reader can tell an asserted override from an
2860
+ // inferred one without re-parsing the source.
2861
+ ...pend.keyword ? { overrideSpecifier: pend.keyword } : {}
2862
+ }
2863
+ });
2864
+ }
2865
+ }
2866
+ }
2867
+ {
2868
+ const seenImpl = /* @__PURE__ */ new Set();
2869
+ for (const pend of pendingImplements) {
2870
+ const k = `${pend.derived} ${pend.base}`;
2871
+ if (seenImpl.has(k)) continue;
2872
+ const pure = classPureVirtuals.get(pend.base);
2873
+ if (!pure || pure.size === 0) continue;
2874
+ seenImpl.add(k);
2875
+ relationships.push({
2876
+ source: pend.derived,
2877
+ target: pend.base,
2878
+ type: ASTEngine.RelationshipType.Implements,
2879
+ confidence: 1,
2880
+ line_number: pend.line,
2881
+ metadata: {
2882
+ // WHY this base is a contract, stated in machine-readable form so a
2883
+ // consumer can re-derive it: the pure virtual members it declares.
2884
+ reasonCode: "pure-virtual-base",
2885
+ pureVirtuals: [...pure],
2886
+ pureVirtualCount: pure.size,
2887
+ ...indexBaseFacts(pend.base)
2888
+ }
2889
+ });
2890
+ }
2891
+ }
2892
+ {
2893
+ for (const pend of pendingExports) {
2894
+ const target = pend.owner ? `${pend.owner}.${pend.name}` : pend.name;
2895
+ if (exportsSeen.has(target)) continue;
2896
+ exportsSeen.add(target);
2897
+ relationships.push({
2898
+ source: "global",
2899
+ target,
2900
+ type: ASTEngine.RelationshipType.Exports,
2901
+ confidence: 1,
2902
+ // the exported NAME's line, which is the declaration's
2903
+ // `nameLine`, not the attribute's — `__declspec` precedes the type.
2904
+ line_number: pend.line,
2905
+ metadata: {
2906
+ // WHICH spelling declared the export. Recorded because the two
2907
+ // mechanisms have different reach — `dllexport` is MSVC and
2908
+ // `visibility("default")` is GCC/Clang ELF — and a reader triaging
2909
+ // a symbol's visibility needs to know which one the author used.
2910
+ exportSpelling: pend.spelling,
2911
+ relationshipType: "export_attribute"
2912
+ }
2913
+ });
2914
+ }
2915
+ }
2916
+ const containsSeen = /* @__PURE__ */ new Set();
2917
+ for (const s of symbols) {
2918
+ const _owner = s.ownerName || s.scope;
2919
+ if (!_owner) continue;
2920
+ const relKey = `${_owner}\0${s.name}`;
2921
+ if (containsSeen.has(relKey)) continue;
2922
+ containsSeen.add(relKey);
2923
+ relationships.push({
2924
+ source: _owner,
2925
+ target: s.name,
2926
+ type: ASTEngine.RelationshipType.Contains,
2927
+ confidence: 1,
2928
+ // + #921 (M60): a contains edge takes the CHILD's line,
2929
+ // and "the child's line" means the line that NAMES it — the rule every
2930
+ // other relationship type already follows (`nameLine`) and the rule the
2931
+ // Tier A oracle checks. The symbol's RANGE still starts at its whole
2932
+ // declaration node (search, edit anchors and the M73 line base read
2933
+ // that), so the two are no longer forced to agree: a wrapped return
2934
+ // type used to put the edge on the declaration's first line, where the
2935
+ // name is not written (`void NORETURN` then `CheckFailed(…)`).
2936
+ line_number: s.metadata?.nameLine ?? s.range?.startLine,
2937
+ metadata: {}
2938
+ });
2939
+ }
2940
+ for (const sym of symbols) {
2941
+ if (Array.isArray(sym.qualified_calls) && sym.qualified_calls.length > 1) {
2942
+ sym.qualified_calls = [...new Set(sym.qualified_calls)];
2943
+ }
2944
+ }
2945
+ this.classifyEvidenceTier(relationships);
2946
+ for (const sym of symbols) {
2947
+ const owner = String(sym?.ownerName ?? "").trim();
2948
+ if (owner === "" || owner === "global") continue;
2949
+ const name = String(sym?.name ?? "").trim();
2950
+ if (name === "") continue;
2951
+ const existing = sym?.qualifiedName;
2952
+ if (typeof existing === "string" && existing !== "") continue;
2953
+ sym.qualifiedName = `${owner}::${name}`;
2954
+ }
2955
+ return {
2956
+ symbols,
2957
+ relationships,
2958
+ imports,
2959
+ exports,
2960
+ errors,
2961
+ metadata: {
2962
+ linesOfCode: content.split("\n").length,
2963
+ cyclomaticComplexity: 1 + fileDecisions,
2964
+ complexity: 1 + fileDecisions,
2965
+ patterns: (() => {
2966
+ const arr = [];
2967
+ for (const p in patterns) arr.push(p);
2968
+ return arr;
2969
+ })(),
2970
+ detectedFrameworks: (() => {
2971
+ const arr = [];
2972
+ for (const f in frameworks) arr.push(f);
2973
+ return arr;
2974
+ })(),
2975
+ memorySafetyScore
2976
+ }
2977
+ };
2978
+ }
2979
+ // CP2 (cpp review): test/macro function shapes — `TEST(suite, name)
2980
+ // {...}`, `BOOST_AUTO_TEST_CASE(x) {...}` parse as function_definitions
2981
+ // whose declarator params are BARE identifiers (macro paste-tokens, no
2982
+ // types). Minting a `TEST` Function symbol per site (11 in one file) and
2983
+ // resolving reads against it fabricates API + edges for a preprocessor
2984
+ // fiction (C-D2: no macro expansion). Detection: ALL-CAPS declarator
2985
+ // name + a non-empty parameter list in which NO parameter carries a type
2986
+ // node. Real functions always type their params (`void f()`/`f(void)`
2987
+ // have empty/void lists and are kept); ALL-CAPS real functions with
2988
+ // typed params (`WINAPI Foo(int)`) are kept.
2989
+ // #919: the heading TEXT of a `function_definition`-spelled macro body — from
2990
+ // the node's start to the end of its parameter list, i.e. exactly the text the
2991
+ // source writes before the block (`TEST(my_case, keeps_its_locals)`). Returns
2992
+ // null when the shape has no body (a decorator fragment such as gmock's
2993
+ // `GTEST_LOCK_EXCLUDED_(g_gmock_mutex) = 0;`), because then there is no
2994
+ // heading/body pair at all.
2995
+ macroHeadingText(node, content, funcName) {
2996
+ if (!node.childForFieldName("body")) return null;
2997
+ const decl = this.findChild(node, "function_declarator");
2998
+ if (!decl) return null;
2999
+ let nameNode = null;
3000
+ {
3001
+ let cur = decl;
3002
+ while (cur) {
3003
+ if ((cur.type === "identifier" || cur.type === "field_identifier") && cur.text === funcName) {
3004
+ nameNode = cur;
3005
+ break;
3006
+ }
3007
+ let next = null;
3008
+ for (let k = 0; k < cur.namedChildCount; k++) {
3009
+ const c = cur.namedChild(k);
3010
+ if (c && (c.type.endsWith("declarator") || c.type === "identifier" || c.type === "field_identifier")) {
3011
+ next = c;
3012
+ break;
3013
+ }
3014
+ }
3015
+ cur = next;
3016
+ }
3017
+ }
3018
+ if (!nameNode) return null;
3019
+ return macroInvocationText(content, nameNode.startIndex);
3020
+ }
3021
+ // #919: is this node inside a function BODY? Two shapes qualify — a
3022
+ // `function_definition`, and the body of a macro-declared heading (which has
3023
+ // no `function_definition` at all: see `macroDeclaredBody`). A class/struct/
3024
+ // union boundary ends the search, exactly as the inline walk did before this
3025
+ // was factored out: a declaration inside a nested class belongs to that class,
3026
+ // not to the enclosing function whose locals we are collecting.
3027
+ insideFunctionBody(node) {
3028
+ let cur = node;
3029
+ while (cur) {
3030
+ if (cur.type === "function_definition") return true;
3031
+ if (cur.type === "class_specifier" || cur.type === "struct_specifier" || cur.type === "union_specifier") return false;
3032
+ if (macroDeclaredBody(cur)) return true;
3033
+ cur = cur.parent;
3034
+ }
3035
+ return false;
3036
+ }
3037
+ /**
3038
+ * Is this `function_definition` actually a MACRO INVOCATION?
3039
+ *
3040
+ * Two independent signals, and the second is the one that catches the annotation
3041
+ * class. The first is the historical one: an ALL-CAPS name whose parameters are
3042
+ * typeless (`TEST(a, b) { … }`).
3043
+ *
3044
+ * D8: a THREAD-SAFETY ANNOTATION is recovered as a whole extra function
3045
+ * definition. Given
3046
+ *
3047
+ * virtual void SetReaction(int obj, long r) GTEST_LOCK_EXCLUDED_(mu) {}
3048
+ *
3049
+ * the grammar emits the real definition AND a second, phantom one whose entire
3050
+ * text is `GTEST_LOCK_EXCLUDED_(mu) {}` — the annotation, parsed as a function
3051
+ * named after the macro. The analyzer published that phantom as a real method,
3052
+ * so `GTEST_LOCK_EXCLUDED_` and `GTEST_EXCLUSIVE_LOCK_REQUIRED_(m)` became
3053
+ * members of the class. (In the second one the published name even carried the
3054
+ * argument list, because the declarator is an identifier followed by a
3055
+ * parenthesised argument the grammar reads as a function-pointer declarator.)
3056
+ *
3057
+ * Why the existing parameter test could not see it: the argument of an
3058
+ * annotation is an EXPRESSION — a mutex variable, a member name — and
3059
+ * `internal::g_mutex` is spelled exactly like a parameter that has a type, so
3060
+ * `paramHasType` said yes and the function-shape test bailed. Testing the
3061
+ * parameter was always a proxy for "is this a macro invocation", and the
3062
+ * RETURN TYPE is the real thing: **C++ has no function definition without one.**
3063
+ * A constructor or destructor has no return type either, but its declarator
3064
+ * names the class, and a class name spelled in all caps is not a shape this
3065
+ * codebase has to survive. Measured on this lane's corpora: the annotation
3066
+ * phantoms are uniformly `type=(NONE)` while every real definition carries
3067
+ * `primitive_type`, `sized_type_specifier`, `qualified_identifier` or a
3068
+ * `macro_prefixed_type_specifier`.
3069
+ */
3070
+ isMacroFunctionShape(node, funcName) {
3071
+ const decl = this.findChild(node, "function_declarator");
3072
+ if (!decl) return false;
3073
+ const bare = this.bareDeclaratorName(decl) ?? funcName;
3074
+ if (!this.isAllCapsName(bare)) return false;
3075
+ if (!node.childForFieldName?.("type")) {
3076
+ const body = this.findChild(node, "compound_statement");
3077
+ if (this.findChild(decl, "parameters") && body && body.namedChildCount === 0) return true;
3078
+ }
3079
+ const params = decl.childForFieldName("parameters");
3080
+ if (!params || params.namedChildCount === 0) return false;
3081
+ for (let i = 0; i < params.namedChildCount; i++) {
3082
+ const p = params.namedChild(i);
3083
+ if (!p) continue;
3084
+ if (p.type === "comment") continue;
3085
+ if (this.paramHasType(p)) return false;
3086
+ }
3087
+ return true;
3088
+ }
3089
+ /**
3090
+ * The BARE name a declarator chain declares: the first `identifier` /
3091
+ * `field_identifier` down the chain, with no argument list and no qualifier.
3092
+ * For `GTEST_LOCK_EXCLUDED_(mu)` that is `GTEST_LOCK_EXCLUDED_`; for
3093
+ * `namespace::detail::Widget` it is `Widget`. Returns null when the chain has
3094
+ * no spelled name, so a caller can fall back to the name it already has.
3095
+ */
3096
+ /**
3097
+ * D8: is this no-return-type `function_definition` a TRAILING ANNOTATION — one
3098
+ * that decorates the declaration immediately before it and declares nothing?
3099
+ *
3100
+ * The shape is fixed by the grammar. Given
3101
+ *
3102
+ * void SetReaction(int obj, long r) GTEST_LOCK_EXCLUDED_(mu) { …body… }
3103
+ *
3104
+ * the grammar ends the `declaration` at the `)` and starts a SECOND
3105
+ * `function_definition` whose declarator is the annotation and whose BODY is the
3106
+ * real function's body. So the node is not a phantom with an empty body — it
3107
+ * carries the statements — and publishing it as a method both invents a symbol
3108
+ * and misattributes every read in that body to the macro.
3109
+ *
3110
+ * The discriminator is structural and it is the only one that held up against
3111
+ * the corpus. Everything else tried was confounded by real data:
3112
+ *
3113
+ * * the annotation's ARGUMENT looks like a parameter type
3114
+ * (`internal::g_gmock_mutex`), so the historical "params are typeless" test
3115
+ * cannot see it
3116
+ * * the body's being empty does not hold — this node HAS the body
3117
+ * * the character before the macro in the SOURCE does not hold: it is `)` for
3118
+ * some sites and `t` (of a trailing `const`) for others, and a `TEST` macro
3119
+ * preceded by a comment ending in `)` reads as `)` too
3120
+ * * `prevNamedSibling` is `null` throughout this grammar
3121
+ *
3122
+ * What does hold: the annotation's immediately preceding NAMED SIBLING is the
3123
+ * `declaration`/`field_declaration` of the function it decorates, and that
3124
+ * declaration carries a `function_declarator` — the grammar cut it at the `)`.
3125
+ * A `TEST(Suite, Name) { …body… }` heading has no such predecessor: it is the
3126
+ * first thing in its statement, so its previous named sibling is a comment, a
3127
+ * brace, or another `function_definition`. The `function_declarator` requirement
3128
+ * is what keeps `int x;` immediately before a `TEST` from being read as a
3129
+ * continuation.
3130
+ *
3131
+ * Node-only on purpose: it must be decidable WITHOUT `getFunctionDetails`, which
3132
+ * is null for exactly the nodes this rule is about.
3133
+ */
3134
+ /**
3135
+ * Is this `function_definition`'s return type a class DEFINITION?
3136
+ *
3137
+ * C++ has no such thing: a function cannot return a class *definition*, only a
3138
+ * class type (by name, or an elaborated `class X` with no body). So a
3139
+ * `function_definition` whose `type` field resolves to a `class_specifier` /
3140
+ * `struct_specifier` / `union_specifier` that CARRIES A BODY is the recovery's
3141
+ * invention.
3142
+ *
3143
+ * The unwrap matters: fork patch 2's `macro_prefixed_type_specifier` puts the
3144
+ * class one level down, so the `type` field is that node and the specifier is its
3145
+ * child. Requiring a body is what separates this from the legal
3146
+ * `class X f() { ... }` (an elaborated return type), which has no body and must
3147
+ * keep publishing its function.
3148
+ */
3149
+ returnTypeIsClassDefinition(node) {
3150
+ const t = node.childForFieldName?.("type");
3151
+ if (!t) return false;
3152
+ const spec = t.type === "macro_prefixed_type_specifier" ? (t.namedChildren ?? []).find(
3153
+ (c) => c.type === "class_specifier" || c.type === "struct_specifier" || c.type === "union_specifier"
3154
+ ) : t;
3155
+ if (!spec) return false;
3156
+ if (spec.type !== "class_specifier" && spec.type !== "struct_specifier" && spec.type !== "union_specifier") {
3157
+ return false;
3158
+ }
3159
+ return (spec.namedChildren ?? []).some((c) => c.type === "field_declaration_list");
3160
+ }
3161
+ isTrailingAnnotationMacro(node, content) {
3162
+ if (node.childForFieldName?.("type")) return false;
3163
+ const body = this.findChild(node, "compound_statement");
3164
+ if (!body) return false;
3165
+ const decl = this.findChild(node, "function_declarator");
3166
+ if (!decl || !this.findChild(decl, "parameter_list")) return false;
3167
+ const bare = this.bareDeclaratorName(decl);
3168
+ if (bare === null || !this.isAllCapsName(bare)) return false;
3169
+ return this.continuesADeclaration(node.startIndex, content);
3170
+ }
3171
+ /**
3172
+ * D8's discriminator, and the only formulation that held up against the corpus:
3173
+ * does this macro invocation CONTINUE the declaration in front of it?
3174
+ *
3175
+ * Everything structural was confounded by real data, and each was tried and
3176
+ * measured before being dropped:
3177
+ *
3178
+ * * the annotation's ARGUMENT looks like a parameter type
3179
+ * (`internal::g_gmock_mutex`), so the historical "params are typeless" test
3180
+ * cannot see it
3181
+ * * the body's being empty does not hold — the node CARRIES the real body
3182
+ * * the previous named sibling is unreliable: `prevNamedSibling` is `null`
3183
+ * throughout this grammar, and finding the predecessor by index in the
3184
+ * parent's child list yields `declaration` for a real annotation AND for a
3185
+ * `TEST` that happens to follow a function declaration — that version
3186
+ * deleted every gtest heading, which is the largest single loss available
3187
+ * * `TEST` is itself spelled in all caps, so the macro-name test cannot
3188
+ * separate the two families
3189
+ *
3190
+ * What separates them is where the invocation SITS. An annotation is trailing:
3191
+ * it follows the parameter list (and possibly a trailing `const`/`&`/`noexcept`)
3192
+ * of the declaration it decorates. A heading is a statement in its own right.
3193
+ * So scan back over whitespace and comments; if the previous significant
3194
+ * character could END a statement, this macro OPENS one and is not an
3195
+ * annotation.
3196
+ *
3197
+ * Comments must be skipped, and that is not a refinement — the first attempt
3198
+ * did not skip them and read a `TEST` preceded by a comment ending in `)` as an
3199
+ * annotation, which is how the first version of this rule deleted the whole
3200
+ * gtest suite's worth of headings.
3201
+ */
3202
+ continuesADeclaration(startIndex, content) {
3203
+ let j = startIndex - 1;
3204
+ while (j >= 0) {
3205
+ const c2 = content[j];
3206
+ if (c2 === " " || c2 === " " || c2 === "\r" || c2 === "\n") {
3207
+ j--;
3208
+ continue;
3209
+ }
3210
+ break;
3211
+ }
3212
+ if (j < 0) return false;
3213
+ const tail = content.slice(Math.max(0, j - 40), startIndex);
3214
+ if (tail.indexOf("//") !== -1 || tail.indexOf("/*") !== -1) return false;
3215
+ const c = content[j];
3216
+ if (c === ")" || c === "&" || c === ">" || c === "*") return true;
3217
+ const upTo = content.slice(Math.max(0, j - 12), j + 1).toLowerCase();
3218
+ let letters = "";
3219
+ for (let k = 0; k < upTo.length; k++) {
3220
+ const ch = upTo[k];
3221
+ if (ch >= "a" && ch <= "z") letters += ch;
3222
+ }
3223
+ for (const kw of ["const", "noexcept", "override", "final", "mutable", "volatile"]) {
3224
+ if (letters.endsWith(kw)) return true;
3225
+ }
3226
+ return false;
3227
+ }
3228
+ bareDeclaratorName(decl) {
3229
+ let cur = decl;
3230
+ for (let i = 0; i < 8 && cur; i++) {
3231
+ if (cur.type === "identifier" || cur.type === "field_identifier") return cur.text;
3232
+ const next = cur.childForFieldName?.("declarator") ?? null;
3233
+ if (!next) {
3234
+ for (let k = 0; k < cur.namedChildCount; k++) {
3235
+ const c = cur.namedChild(k);
3236
+ if (c && (c.type === "identifier" || c.type === "field_identifier")) return c.text;
3237
+ }
3238
+ return null;
3239
+ }
3240
+ cur = next;
3241
+ }
3242
+ return null;
3243
+ }
3244
+ // #915: a bare top-level macro must not become a `variable`. Two consecutive
3245
+ // macros at file scope are recovered by the grammar as a `declaration` whose
3246
+ // "type" is itself a macro and whose terminator is MISSING
3247
+ // (`FMT_END_EXPORT` / `FMT_END_NAMESPACE` -> type_identifier + identifier +
3248
+ // MISSING `;`), and the declaration branch then names the symbol after the
3249
+ // second macro. Measured on fmt: 13 such phantoms in a 58-file draw, all bare
3250
+ // ALL-CAPS macro names (`variable FMT_END_NAMESPACE` x8, `GTEST_ATTRIBUTE_UNUSED_`
3251
+ // x2, `RUN_ALL_TESTS`, `GTEST_DEFAULT_DEATH_TEST_STYLE`, `FMT_BEGIN_EXPORT`),
3252
+ // and 0 on nlohmann-json. This is the BARE sibling of the call-shaped class
3253
+ // `isMacroFunctionShape` already suppresses.
3254
+ //
3255
+ // Three conditions, each doing real work — the first two alone would lose a
3256
+ // real symbol:
3257
+ // * the name is ALL-CAPS (`MAX_SIZE` stays a symbol, `MAX_SIZE;`)
3258
+ // * the node is ERROR-RECOVERED (a clean `MyType MAX_SIZE;` is kept,
3259
+ // because its terminator is real; only
3260
+ // already-broken code is affected)
3261
+ // * it carries NO hard type (`int MAX_SIZE` and
3262
+ // `MyType *MAX_SIZE` are kept — a lone
3263
+ // `type_identifier` is the grammar's
3264
+ // classification of macro soup, not a type,
3265
+ // the same reading `paramHasType` uses)
3266
+ isBareMacroDeclaration(node, name) {
3267
+ if (!this.isAllCapsName(name)) return false;
3268
+ let recovered = false;
3269
+ const walkRecovered = [node];
3270
+ while (walkRecovered.length > 0) {
3271
+ const m = walkRecovered.pop();
3272
+ if (m.isMissing || m.isError) {
3273
+ recovered = true;
3274
+ break;
3275
+ }
3276
+ for (let i = 0; i < m.childCount; i++) {
3277
+ const c = m.child(i);
3278
+ if (c) walkRecovered.push(c);
3279
+ }
3280
+ }
3281
+ if (!recovered) return false;
3282
+ const walkType = [node];
3283
+ while (walkType.length > 0) {
3284
+ const m = walkType.pop();
3285
+ if (m.type === "primitive_type" || m.type === "sized_type_specifier" || m.type === "template_type" || m.type === "qualified_identifier" || m.type === "dependent_type" || m.type === "decltype" || m.type === "struct_specifier" || m.type === "union_specifier" || m.type === "enum_specifier" || m.type === "class_specifier" || m.type === "placeholder_type_specifier" || m.type === "macro_prefixed_type_specifier") {
3286
+ return false;
3287
+ }
3288
+ for (let i = 0; i < m.childCount; i++) {
3289
+ const c = m.child(i);
3290
+ if (c) walkType.push(c);
3291
+ }
3292
+ }
3293
+ return true;
3294
+ }
3295
+ isAllCapsName(name) {
3296
+ let hasUpper = false;
3297
+ for (let i = 0; i < name.length; i++) {
3298
+ const c = name[i];
3299
+ if (c >= "a" && c <= "z") return false;
3300
+ if (c >= "A" && c <= "Z") hasUpper = true;
3301
+ }
3302
+ return hasUpper;
3303
+ }
3304
+ paramHasType(param) {
3305
+ let sawHardType = false;
3306
+ let sawTypeIdent = false;
3307
+ let sawNameIdent = false;
3308
+ const stack = [param];
3309
+ while (stack.length > 0) {
3310
+ const m = stack.pop();
3311
+ if (m.type === "primitive_type" || m.type === "sized_type_specifier" || m.type === "template_type" || m.type === "qualified_identifier" || m.type === "dependent_type" || m.type === "decltype" || m.type === "struct_specifier" || m.type === "union_specifier" || m.type === "enum_specifier") {
3312
+ sawHardType = true;
3313
+ break;
3314
+ }
3315
+ if (m.type === "type_identifier") sawTypeIdent = true;
3316
+ if (m.type === "identifier" || m.type === "field_identifier") sawNameIdent = true;
3317
+ for (let i = 0; i < m.namedChildCount; i++) {
3318
+ const c = m.namedChild(i);
3319
+ if (c) stack.push(c);
3320
+ }
3321
+ }
3322
+ return sawHardType || sawTypeIdent && sawNameIdent;
3323
+ }
3324
+ /**
3325
+ * M60.P1 `decorators`: a declaration's modifiers, as the SOURCE SPELLINGS the
3326
+ * node carries, in source order — so a consumer reads `["static", "constexpr"]`
3327
+ * instead of reversing four booleans back into words.
3328
+ *
3329
+ * This is the declared payload field, and the `metadata` flags
3330
+ * (`isVirtual`/`isConst`/`isConstexpr`/`isStatic`) were duplicating its content
3331
+ * without ever filling it: the M60 payload-seam matrix recorded
3332
+ * `UniversalSymbol.decorators` as a DEAD emit cell for cpp while this file's own
3333
+ * documentation claimed the row was supported.
3334
+ *
3335
+ * Shared by the function and the field/variable branch, because
3336
+ * `static constexpr int kMax = 10;` carries exactly as much modifier
3337
+ * information as `virtual int area() const = 0;` and a payload field that only
3338
+ * answered for one of them is a field a consumer cannot rely on.
3339
+ *
3340
+ * A destructor and an operator overload are deliberately ABSENT: `~File` and
3341
+ * `operator==` are part of the NAME, not modifiers applied to it, and listing
3342
+ * them here would put a name in a field whose meaning is "applied to this
3343
+ * declaration".
3344
+ *
3345
+ * The scan keys off the child's TEXT and EXCLUDES the declaration's own
3346
+ * payload fields (`type`, `declarator`, `default_value`, …), not off
3347
+ * `isNamed`. The grammar is inconsistent here and both forms occur in this
3348
+ * lane's own fixtures: `virtual int area() const = 0;` exposes `virtual` as an
3349
+ * UNNAMED token, while `static constexpr int kMax = 10;` exposes `static` and
3350
+ * `constexpr` as NAMED `storage_class_specifier` / `type_qualifier` wrappers.
3351
+ * A rule that only read unnamed tokens would find the modifier on the method
3352
+ * and miss it on the field, which is the worst of both — a payload field that
3353
+ * answers sometimes.
3354
+ */
3355
+ declarationDecorators(node, declarator = null) {
3356
+ const out = [];
3357
+ const MODIFIERS = /* @__PURE__ */ new Set([
3358
+ "static",
3359
+ "constexpr",
3360
+ "const",
3361
+ "inline",
3362
+ "virtual",
3363
+ "explicit",
3364
+ "extern",
3365
+ "friend",
3366
+ "mutable",
3367
+ "thread_local",
3368
+ "volatile",
3369
+ "override",
3370
+ "final"
3371
+ ]);
3372
+ const PAYLOAD_FIELDS = /* @__PURE__ */ new Set([
3373
+ "type",
3374
+ "declarator",
3375
+ "default_value",
3376
+ "value",
3377
+ "initializer",
3378
+ "parameters",
3379
+ "body",
3380
+ "name",
3381
+ "argument",
3382
+ "condition",
3383
+ "left",
3384
+ "right",
3385
+ "operator"
3386
+ ]);
3387
+ const seen = /* @__PURE__ */ new Set();
3388
+ const scan = (n) => {
3389
+ if (!n) return;
3390
+ for (let i = 0; i < n.childCount; i++) {
3391
+ const c = n.child(i);
3392
+ if (!c) continue;
3393
+ const field = n.fieldNameForChild ? n.fieldNameForChild(i) : null;
3394
+ if (field && PAYLOAD_FIELDS.has(field)) continue;
3395
+ if (MODIFIERS.has(c.text) && !seen.has(c.text)) {
3396
+ seen.add(c.text);
3397
+ out.push(c.text);
3398
+ }
3399
+ }
3400
+ };
3401
+ scan(node);
3402
+ scan(declarator);
3403
+ return out;
3404
+ }
3405
+ /**
3406
+ * The `function_declarator` of a declaration, descending one `init_declarator`.
3407
+ *
3408
+ * ONTOLOGY `overrides`, second-order defect. `virtual bool ReportContext(const
3409
+ * Context&) = 0;` — the PURE VIRTUAL, which is how C++ spells the interface a
3410
+ * derived class implements — does not put the declarator where the shallow scan
3411
+ * looks:
3412
+ *
3413
+ * declaration [declarator=init_declarator type=primitive_type]
3414
+ * virtual, primitive_type "bool"
3415
+ * init_declarator [declarator=function_declarator value=number_literal]
3416
+ * function_declarator [declarator=identifier parameters=parameter_list]
3417
+ *
3418
+ * So `findChild(node, "function_declarator")` returned null, the signature
3419
+ * normaliser registered the base method with an EMPTY parameter list, and no
3420
+ * derived signature could ever equal it. `Finalize()` resolved only because it
3421
+ * takes no parameters and `""` matched `""` — which is why the pre-fix count on
3422
+ * `reporter.h` was 2 of 4 and both happened to be the zero-argument ones.
3423
+ *
3424
+ * Scoped to ONE level and ONE wrapper on purpose. A general "descend until you
3425
+ * find a declarator" walk would also reach through `pointer_declarator` and
3426
+ * `reference_declarator`, where the pointer/reference is part of the C++ type
3427
+ * and dropping the wrapper would make `void f(Widget&)` and `void f(Widget)`
3428
+ * hash alike — the exact defect D8 removed from the published `parameters`
3429
+ * field. `init_declarator` carries no type, so descending through it loses
3430
+ * nothing.
3431
+ */
3432
+ functionDeclaratorOf(node) {
3433
+ if (!node) return null;
3434
+ const direct = this.findChild(node, "function_declarator");
3435
+ if (direct) return direct;
3436
+ const init = this.findChild(node, "init_declarator");
3437
+ return init ? this.findChild(init, "function_declarator") : null;
3438
+ }
3439
+ methodComplexityCpp(node) {
3440
+ const decisionTypes = /* @__PURE__ */ new Set([
3441
+ "if_statement",
3442
+ "for_statement",
3443
+ "while_statement",
3444
+ "do_statement",
3445
+ "case_statement",
3446
+ "catch_clause",
3447
+ "conditional_expression"
3448
+ ]);
3449
+ let c = 1;
3450
+ const st = [node];
3451
+ while (st.length) {
3452
+ const n = st.pop();
3453
+ if (decisionTypes.has(n.type)) c++;
3454
+ else if (n.type === "binary_expression") {
3455
+ const op = n.childForFieldName("operator")?.text;
3456
+ if (op === "&&" || op === "||") c++;
3457
+ }
3458
+ for (let i = 0; i < n.namedChildCount; i++) {
3459
+ const ch = n.namedChild(i);
3460
+ if (ch) st.push(ch);
3461
+ }
3462
+ }
3463
+ return c;
3464
+ }
3465
+ /**
3466
+ * #419-D - evidence-tier classification for EVERY emitted relationship
3467
+ * (same rules as the JVM/web family).
3468
+ */
3469
+ classifyEvidenceTier(relationships) {
3470
+ for (const r of relationships) {
3471
+ const md = r.metadata ?? (r.metadata = {});
3472
+ if (md.evidenceClass) continue;
3473
+ const t = String(r.type ?? "");
3474
+ const conf = typeof r.confidence === "number" ? r.confidence : 1;
3475
+ if (t === "contains" || t === "exports") {
3476
+ md.evidenceClass = "structural";
3477
+ continue;
3478
+ }
3479
+ if (t === "imports") {
3480
+ md.evidenceClass = "import_based";
3481
+ continue;
3482
+ }
3483
+ if (t === "references") {
3484
+ md.evidenceClass = md.isImport ? "import_based" : "reference_qualified";
3485
+ continue;
3486
+ }
3487
+ if (t === "imports") {
3488
+ md.evidenceClass = md.isImport ? "import_based" : "usage_contextual";
3489
+ continue;
3490
+ }
3491
+ if (t === "extends" || t === "implements" || t === "overrides") {
3492
+ md.evidenceClass = conf >= 1 ? "structural" : conf >= 0.85 ? "usage_contextual" : "inferred";
3493
+ continue;
3494
+ }
3495
+ if (t === "instantiates") {
3496
+ md.evidenceClass = "structural";
3497
+ continue;
3498
+ }
3499
+ md.evidenceClass = "usage_contextual";
3500
+ }
3501
+ }
3502
+ /**
3503
+ * The EXPORT MARKER macro of a declaration-specifier, or `undefined`.
3504
+ *
3505
+ * The other half of `specifierTypeText`, and the reader for ONTOLOGY `exports`.
3506
+ * Both walk the same node and neither imports the other, because they answer
3507
+ * different questions — one asks what the type IS, the other asks what the
3508
+ * declaration is DECORATED with — and a node can answer both at once only if
3509
+ * both are asked. `cppExportMarker` decides whether the macro is an export
3510
+ * marker; see its comment for the measured population that forced the rule.
3511
+ */
3512
+ specifierExportMacro(t) {
3513
+ if (!t || t.type !== "macro_prefixed_type_specifier") return void 0;
3514
+ for (let i = 0; i < t.namedChildCount; i++) {
3515
+ const c = t.namedChild(i);
3516
+ if (c && c.type === "macro_specifier") return c.text.trim();
3517
+ }
3518
+ return void 0;
3519
+ }
3520
+ /**
3521
+ * the line of the node that NAMES a relationship, 1-based, or
3522
+ * `undefined` when the site is not attributable — never a fabricated 0 and
3523
+ * never an enclosing declaration's line. The C lane carries the identical
3524
+ * helper; the contract is "call-site line or NULL" ().
3525
+ */
3526
+ nodeLine(node) {
3527
+ if (!node || !node.startPosition || typeof node.startPosition.row !== "number") return void 0;
3528
+ return node.startPosition.row + 1;
3529
+ }
3530
+ /**
3531
+ * a type expression's start is not the line of the names inside
3532
+ * it. A specifier starts at its KEYWORD, and a wrapped declaration puts the
3533
+ * name on the following line:
3534
+ *
3535
+ * struct <- the specifier's start
3536
+ * Bigint { <- where the name is written
3537
+ *
3538
+ * The grammar's `name` field is the site when it exists; otherwise the node is.
3539
+ * (Mirror of the C lane's `nameLine`.)
3540
+ */
3541
+ nameLine(node) {
3542
+ if (!node) return void 0;
3543
+ const nameField = typeof node.childForFieldName === "function" ? node.childForFieldName("name") : null;
3544
+ return this.nodeLine(nameField ?? node);
3545
+ }
3546
+ nodeToRange(node) {
3547
+ return {
3548
+ startLine: node.startPosition.row + 1,
3549
+ startColumn: node.startPosition.column + 1,
3550
+ endLine: node.endPosition.row + 1,
3551
+ endColumn: node.endPosition.column + 1,
3552
+ startIndex: node.startIndex,
3553
+ endIndex: node.endIndex
3554
+ };
3555
+ }
3556
+ findChild(node, type, text) {
3557
+ for (let i = 0; i < node.namedChildCount; i++) {
3558
+ const child = node.namedChild(i);
3559
+ if (child && child.type === type) {
3560
+ if (text === void 0 || child.text === text) return child;
3561
+ }
3562
+ }
3563
+ return null;
3564
+ }
3565
+ findAllChildren(node, type) {
3566
+ const res = [];
3567
+ for (let i = 0; i < node.namedChildCount; i++) {
3568
+ const child = node.namedChild(i);
3569
+ if (child && child.type === type) res.push(child);
3570
+ }
3571
+ return res;
3572
+ }
3573
+ childText(node, type) {
3574
+ const child = this.findChild(node, type);
3575
+ return child ? child.text : null;
3576
+ }
3577
+ /**
3578
+ * The `override` / `final` `virtual_specifier` on a function declaration, or
3579
+ * null. Read from the DECLARATOR, because that is where the pinned grammar puts
3580
+ * it: measured on the fork,
3581
+ *
3582
+ * field_declaration[declarator="go() override"]
3583
+ * primitive_type
3584
+ * function_declarator[declarator="go"]
3585
+ * field_identifier
3586
+ * parameter_list
3587
+ * virtual_specifier "override" <- a CHILD of the declarator
3588
+ *
3589
+ * so a declaration-level scan never fires — which is why the `decorators`
3590
+ * payload needed its own second lookup, and why override RESOLUTION ignored the
3591
+ * strongest evidence C++ offers until this round.
3592
+ */
3593
+ functionOverrideSpecifier(declaration) {
3594
+ if (!declaration) return null;
3595
+ const fd = declaration.type === "function_declarator" ? declaration : this.findChild(declaration, "function_declarator");
3596
+ if (!fd) return null;
3597
+ for (let i = 0; i < fd.childCount; i++) {
3598
+ const c = fd.child(i);
3599
+ if (c?.type !== "virtual_specifier") continue;
3600
+ const txt = String(c.text ?? "").trim();
3601
+ if (txt === "override" || txt === "final") return txt;
3602
+ }
3603
+ return null;
3604
+ }
3605
+ /**
3606
+ * The EXPORT attribute a declaration carries, or null. Which spelling exists is
3607
+ * a measurement, not a preference — see `docs/analyzers/cpp.md`
3608
+ * "the exports construct, measured three ways".
3609
+ *
3610
+ * Two are readable on the pinned grammar and one of them is not:
3611
+ *
3612
+ * 1. `__declspec(dllexport)` — MSVC. The grammar keeps the paren group as a
3613
+ * `ms_declspec_modifier` node whose named children are the attribute names
3614
+ * (`ms_declspec_modifier [__declspec ( identifier)]`), so the spelling is a
3615
+ * node, not text.
3616
+ * 2. `__attribute__((visibility("default")))` — GCC/Clang ELF. An
3617
+ * `attribute_specifier` holding an `argument_list` whose
3618
+ * `call_expression` names `visibility` with a `"default"` string argument.
3619
+ * 3. `#define FOO __declspec(dllexport)` + `FOO void f();` — how both of the
3620
+ * above are ACTUALLY used. Measured over the corpus: 11 macro definitions
3621
+ * name `dllexport` and 0 declarations spell it inline except through one.
3622
+ * Reading that needs macro expansion, which is a DECLARED limitation of
3623
+ * this lane (M14-HONESTY-CONTRACT , "macro/template expansion
3624
+ * boundaries (c, cpp, rust, hcl)"), so the macro-mediated population is
3625
+ * reported with its count rather than resolved.
3626
+ *
3627
+ * `dllimport` is the opposite direction (this translation unit imports the
3628
+ * symbol from another module) and `visibility("hidden")` is the opposite of
3629
+ * default visibility, so neither is an export and neither is emitted.
3630
+ */
3631
+ exportAttributeSpelling(node) {
3632
+ for (let i = 0; i < node.namedChildCount; i++) {
3633
+ const c = node.namedChild(i);
3634
+ if (!c) continue;
3635
+ if (c.type === "ms_declspec_modifier") {
3636
+ for (let j = 0; j < c.namedChildCount; j++) {
3637
+ const a = c.namedChild(j);
3638
+ if (a?.type === "identifier" && a.text === "dllexport") return "declspec-dllexport";
3639
+ }
3640
+ continue;
3641
+ }
3642
+ if (c.type === "attribute_specifier") {
3643
+ let hit = false;
3644
+ const visit = (n) => {
3645
+ if (hit) return;
3646
+ if (n.type === "call_expression") {
3647
+ const fn = n.childForFieldName?.("function");
3648
+ if (fn && String(fn.text ?? "").trim() === "visibility") {
3649
+ const args = n.childForFieldName?.("arguments");
3650
+ if (args) {
3651
+ for (let k = 0; k < args.namedChildCount; k++) {
3652
+ const arg = args.namedChild(k);
3653
+ const lit = arg?.type === "string_literal" ? arg : arg ? this.findChild(arg, "string_literal") : null;
3654
+ if (lit && stripIncludeChars(String(lit.text ?? "")).trim() === "default") {
3655
+ hit = true;
3656
+ return;
3657
+ }
3658
+ }
3659
+ }
3660
+ }
3661
+ }
3662
+ for (let k = 0; k < n.namedChildCount; k++) {
3663
+ const g = n.namedChild(k);
3664
+ if (g) visit(g);
3665
+ }
3666
+ };
3667
+ visit(c);
3668
+ if (hit) return "attribute-visibility-default";
3669
+ }
3670
+ if (c.type === "attribute_declaration") {
3671
+ const hit = this.attributeRoleExport(c);
3672
+ if (hit) return hit;
3673
+ }
3674
+ }
3675
+ return null;
3676
+ }
3677
+ /**
3678
+ * Does an `attribute_declaration` (`[[...]]`) export its declaration?
3679
+ *
3680
+ * Returns the spelling, or null. Node walk only: the attribute's last
3681
+ * `identifier` is its name, and the argument is read from the `argument_list`
3682
+ * child rather than sliced out of the attribute's text — so a COMMENT naming
3683
+ * `visibility` and a `visibility` inside a string literal cannot produce an
3684
+ * edge, which is the whole reason this lane holds no regexes.
3685
+ */
3686
+ attributeRoleExport(attrDecl) {
3687
+ for (let i = 0; i < attrDecl.namedChildCount; i++) {
3688
+ const attr = attrDecl.namedChild(i);
3689
+ if (attr?.type !== "attribute") continue;
3690
+ let name = null;
3691
+ for (let j = 0; j < attr.namedChildCount; j++) {
3692
+ const c = attr.namedChild(j);
3693
+ if (c?.type === "identifier") name = String(c.text ?? "");
3694
+ }
3695
+ if (name === "dllexport") return "attribute-dllexport";
3696
+ if (name !== "visibility") continue;
3697
+ const args = this.findChild(attr, "argument_list");
3698
+ if (!args) continue;
3699
+ for (let k = 0; k < args.namedChildCount; k++) {
3700
+ const arg = args.namedChild(k);
3701
+ const lit = arg?.type === "string_literal" ? arg : arg ? this.findChild(arg, "string_literal") : null;
3702
+ if (lit && stripIncludeChars(String(lit.text ?? "")).trim() === "default") return "attribute-visibility-default";
3703
+ }
3704
+ }
3705
+ return null;
3706
+ }
3707
+ /**
3708
+ * Is this class-scope function declaration PURE VIRTUAL — `virtual void f() = 0;`?
3709
+ *
3710
+ * Structural, because the pinned grammar has no reachable node for it. The
3711
+ * fork DOES declare a `pure_virtual_clause` rule, but reaches it only from
3712
+ * `inline_method_definition` / `constructor_or_destructor_definition` and the
3713
+ * corpus produces none of them, so the marker has to be read from the tree.
3714
+ *
3715
+ * TWO SHAPES, because the grammar produces two and they occur inside the same
3716
+ * file (measured on cpp-example: 19 of 34 sites are the first, 15 the second):
3717
+ *
3718
+ * field_declaration [declarator=function_declarator type=primitive_type]
3719
+ * virtual, primitive_type "bool", function_declarator …
3720
+ * "=", number_literal "0" <- `0` a DIRECT child
3721
+ *
3722
+ * declaration [declarator=init_declarator type=primitive_type]
3723
+ * virtual, primitive_type "bool",
3724
+ * init_declarator [declarator=function_declarator value=number_literal]
3725
+ * <- `0` nested under value
3726
+ *
3727
+ * D23: the first cut read the `=`/`0` pair off the declaration's own direct
3728
+ * children only, which is why the second shape — the one `reporter.h` and
3729
+ * `json.hpp` actually use — was never registered as an interface operation.
3730
+ * A member variable initialised to zero (`virtual int x = 0;`) is NOT a pure
3731
+ * virtual, and in both shapes the declarator must be a `function_declarator`;
3732
+ * that pairing is what separates the two. A defaulted argument (`void f(int x =
3733
+ * 0)`) puts its `=` inside the `parameter_list`, which no arm here reads.
3734
+ */
3735
+ isPureVirtualDeclaration(declaration) {
3736
+ if (declaration.type !== "field_declaration" && declaration.type !== "declaration") return false;
3737
+ const direct = declaration.childForFieldName?.("declarator");
3738
+ if (direct?.type === "function_declarator" && hasZeroLiteralChild(declaration)) return true;
3739
+ for (let i = 0; i < declaration.namedChildCount; i++) {
3740
+ const c = declaration.namedChild(i);
3741
+ if (!c || c.type !== "init_declarator") continue;
3742
+ const value = c.childForFieldName?.("value");
3743
+ const inner = c.childForFieldName?.("declarator");
3744
+ if (value?.type === "number_literal" && String(value.text ?? "").trim() === "0" && inner?.type === "function_declarator") return true;
3745
+ }
3746
+ return false;
3747
+ }
3748
+ /**
3749
+ * Truth guard for `instantiates`: is this constructed-type name bound by an
3750
+ * enclosing template's parameter list?
3751
+ *
3752
+ * `new Reporter(n)` inside `template <typename Reporter> Reporter*
3753
+ * reporterCreator(...)` constructs a TYPE PARAMETER, not a class, and the
3754
+ * published row named a target no translation unit can declare — measured on
3755
+ * cpp-example as `instantiates -> Reporter` from doctest's
3756
+ * `reporterCreator<Reporter>`, next to `instantiates -> char` from
3757
+ * `new char[4]` (refused by the keyword funnel beside this call). Both are
3758
+ * fabricated rows in the sense the honesty contract cares about: they are
3759
+ * stored, compared against nothing, and unresolvable in every file.
3760
+ *
3761
+ * TWO ARMS, because the binding survives in two spellings:
3762
+ *
3763
+ * (1) the ORDINARY shape — an ancestor `template_declaration` whose
3764
+ * `template_parameter_list` is a real node. The walk ascends through every
3765
+ * one of them (a nested template's inner list can bind a name an outer list
3766
+ * does not), and the declared names come from `templateParameterNames`.
3767
+ * (2) the RECOVERY shape — the list is displaced out of the ancestor chain
3768
+ * entirely, left as a `< … >` frame among the preceding children of the ERROR
3769
+ * region the grammar produced (`isTemplateParameterListFrame`), introduced by
3770
+ * the `template` token beside it. Measured at `doctest.h:2104`: that whole
3771
+ * file is one ERROR region, no `template_declaration` node exists for
3772
+ * `reporterCreator`, and arm (1) can never see the binding — which is why
3773
+ * `instantiates -> Reporter` survived this guard's first cut. Both arms ask
3774
+ * `templateParameterNames` the same question, so the two spellings cannot
3775
+ * drift apart.
3776
+ *
3777
+ * Arm (2) reads only nodes that START before the construction: a frame written
3778
+ * after it cannot have bound the name.
3779
+ */
3780
+ isTemplateParameterName(node, name) {
3781
+ for (let cur = node.parent, i = 0; cur && i < 64; i++, cur = cur.parent) {
3782
+ if (cur.type === "template_declaration") {
3783
+ const params = this.findChild(cur, "template_parameter_list");
3784
+ if (params && templateParameterNames(params).has(name)) return true;
3785
+ continue;
3786
+ }
3787
+ if (cur.type !== "ERROR") continue;
3788
+ for (let k = 0; k < cur.childCount; k++) {
3789
+ const frame = cur.child(k);
3790
+ if (!frame || frame.startIndex >= node.startIndex) break;
3791
+ if (!isTemplateParameterListFrame(frame)) continue;
3792
+ if (cur.child(k - 1)?.type !== "template") continue;
3793
+ if (frame.startIndex <= node.startIndex && frame.endIndex >= node.endIndex) continue;
3794
+ if (templateParameterNames(frame).has(name)) return true;
3795
+ }
3796
+ }
3797
+ return false;
3798
+ }
3799
+ hasDirectModifier(node, modifier) {
3800
+ for (let i = 0; i < node.childCount; i++) {
3801
+ const child = node.child(i);
3802
+ if (!child) continue;
3803
+ if (child.text === modifier) return true;
3804
+ if ((child.type === "type_qualifier" || child.type === "storage_class_specifier" || child.type === "virtual_specifier") && child.text === modifier) {
3805
+ return true;
3806
+ }
3807
+ }
3808
+ const funcDecl = this.findChild(node, "function_declarator");
3809
+ if (funcDecl) {
3810
+ for (let i = 0; i < funcDecl.childCount; i++) {
3811
+ const child = funcDecl.child(i);
3812
+ if (child?.type === "virtual_specifier" && child.text === modifier) return true;
3813
+ }
3814
+ }
3815
+ return false;
3816
+ }
3817
+ /**
3818
+ * #921 (M60): `nameNode` is the node whose text IS the declared name (the
3819
+ * qualified form returns its LAST named child, the constructor/destructor and
3820
+ * operator spellings included). The containment edge needs the line that
3821
+ * NAMES the child — a wrapped return type puts the name one or more lines
3822
+ * below the declaration's start (`void NORETURN` then `CheckFailed(…)`).
3823
+ */
3824
+ getFunctionDetails(node) {
3825
+ let decl = this.findChild(node, "function_declarator");
3826
+ if (!decl) {
3827
+ const WRAPPERS = ["init_declarator", "pointer_declarator", "reference_declarator", "parenthesized_declarator"];
3828
+ let cur = null;
3829
+ for (const w of WRAPPERS) {
3830
+ cur = this.findChild(node, w);
3831
+ if (cur) break;
3832
+ }
3833
+ const enterRecovery = !!this.findChild(node, "compound_statement") || this.recoveryStatesType(cur);
3834
+ for (let i = 0; cur && i < 8; i++) {
3835
+ const found = this.firstDeclaratorIn(cur, enterRecovery);
3836
+ if (found) {
3837
+ decl = found;
3838
+ break;
3839
+ }
3840
+ let next = null;
3841
+ for (const w of WRAPPERS) {
3842
+ next = this.findChild(cur, w);
3843
+ if (next) break;
3844
+ }
3845
+ cur = next;
3846
+ }
3847
+ }
3848
+ if (!decl) return null;
3849
+ let nameNode = null;
3850
+ {
3851
+ let cur = decl;
3852
+ for (let i = 0; cur && i < 8; i++) {
3853
+ nameNode = this.findChild(cur, "identifier") || this.findChild(cur, "field_identifier") || this.findChild(cur, "destructor_name") || this.findChild(cur, "operator_name") || this.findChild(cur, "qualified_identifier");
3854
+ if (nameNode) break;
3855
+ cur = this.findChild(cur, "parenthesized_declarator");
3856
+ }
3857
+ }
3858
+ if (!nameNode) return null;
3859
+ let namedNode = nameNode;
3860
+ let name = nameNode.text;
3861
+ let scope = void 0;
3862
+ let isDestructor = nameNode.type === "destructor_name" || name.startsWith("~");
3863
+ let isOperator = nameNode.type === "operator_name" || name.startsWith("operator");
3864
+ if (!isCppSpelledName(name)) return null;
3865
+ if (nameNode.type === "qualified_identifier") {
3866
+ const parts = qualifiedDeclaratorLeaf(nameNode);
3867
+ const actualNameNode = parts?.nameNode ?? nameNode.namedChild(nameNode.namedChildCount - 1);
3868
+ const scopeQid = parts?.scopeQid ?? null;
3869
+ let scopeNode = null;
3870
+ for (let i = 0; scopeQid && i < scopeQid.namedChildCount - 1; i++) {
3871
+ const c = scopeQid.namedChild(i);
3872
+ if (c && (c.type === "namespace_identifier" || c.type === "type_identifier" || c.type === "identifier")) {
3873
+ scopeNode = c;
3874
+ break;
3875
+ }
3876
+ if (c && c.type === "template_type") {
3877
+ const tname = c.childForFieldName("name") || this.findChild(c, "type_identifier");
3878
+ if (tname) {
3879
+ scopeNode = tname;
3880
+ break;
3881
+ }
3882
+ }
3883
+ }
3884
+ const firstChild = scopeQid?.namedChild(0);
3885
+ if (!scopeNode && firstChild && firstChild.type === "qualified_identifier") {
3886
+ scopeNode = firstChild;
3887
+ }
3888
+ if (actualNameNode) {
3889
+ name = actualNameNode.text;
3890
+ namedNode = actualNameNode;
3891
+ if (scopeNode) scope = scopeNode.text;
3892
+ if (actualNameNode.type === "destructor_name" || name.startsWith("~")) isDestructor = true;
3893
+ if (actualNameNode.type === "operator_name" || name.startsWith("operator")) isOperator = true;
3894
+ }
3895
+ }
3896
+ if (!isPublishableFunctionName(name)) return null;
3897
+ return { name, scope, isDestructor, isOperator, nameNode: namedNode, declarator: decl };
3898
+ }
3899
+ /**
3900
+ * The FIRST `function_declarator` in DOCUMENT order under a declarator wrapper.
3901
+ * `findChild` scans one level, and inside a recovered head the wrapper's DIRECT
3902
+ * children can hold a DECOY the recovery read out of a mem-initializer, while the
3903
+ * declarator the source wrote sits one level deeper, in the grammar's own ERROR:
3904
+ *
3905
+ * JSON_HEDLEY_NON_NULL(3)
3906
+ * invalid_iterator(int id_, const char* what_arg) : exception(id_, what_arg) {}
3907
+ * function_definition[type: JSON_HEDLEY_NON_NULL]
3908
+ * parenthesized_declarator <- the macro's own parens
3909
+ * ERROR <- the recovery
3910
+ * number_literal(3)
3911
+ * function_declarator(invalid_iterator) <- the DECLARED name
3912
+ * function_declarator(exception) <- the base ctor CALL
3913
+ *
3914
+ * The recovery writes them in source order, so the first is the declared name;
3915
+ * taking the direct child instead published `method invalid_iterator.exception` —
3916
+ * a member named after the class's own BASE, with no parameters and a body it
3917
+ * does not have, while the constructor itself stayed unpublished. Depth is bounded
3918
+ * and the descent stays inside declarator wrappers, so a declarator inside the
3919
+ * function's BODY can never be reached.
3920
+ *
3921
+ * `enterRecovery` gates the descent into an ERROR, and the caller sets it from the
3922
+ * declaration's own evidence: a body, or a TYPE in the recovery. The same recovery
3923
+ * wraps a macro INVOCATION in the macro's parens, and there the ERROR holds an
3924
+ * EXPRESSION, not a declarator — `CHECK(p3.getHairColor() == "blue");` inside a
3925
+ * test macro's body recovers with the CALL's own `function_declarator`, and reading
3926
+ * it published a method nobody declared.
3927
+ */
3928
+ firstDeclaratorIn(container, enterRecovery, depth = 0) {
3929
+ if (depth > 6) return null;
3930
+ for (let i = 0; i < container.namedChildCount; i++) {
3931
+ const c = container.namedChild(i);
3932
+ if (!c) continue;
3933
+ if (c.type === "function_declarator") return c;
3934
+ if (c.type.endsWith("declarator")) {
3935
+ const inner = this.firstDeclaratorIn(c, enterRecovery, depth + 1);
3936
+ if (inner) return inner;
3937
+ } else if (enterRecovery && c.type === "ERROR") {
3938
+ const inner = this.firstDeclaratorIn(c, enterRecovery, depth + 1);
3939
+ if (inner) return inner;
3940
+ }
3941
+ }
3942
+ return null;
3943
+ }
3944
+ /**
3945
+ * The other half of the declaration test for entering a recovery: does the wrapper
3946
+ * the macro left behind STATE A TYPE? That is what separates the declaration the
3947
+ * recovery swallowed from a macro INVOCATION, and the two are one node type apart:
3948
+ *
3949
+ * JSON_HEDLEY_RETURNS_NON_NULL CHECK(p3.getHairColor() == "blue");
3950
+ * char* to_chars(…) // field_declaration
3951
+ * parenthesized_declarator parenthesized_declarator
3952
+ * ERROR ERROR
3953
+ * identifier(JSON_HEDLEY_…) identifier(p3)
3954
+ * primitive_type(char) <- the TYPE function_declarator(getHairColor)
3955
+ * pointer_declarator <- (the call, no parameters)
3956
+ *
3957
+ * `char` is the discriminator: only a declaration of something states a type before
3958
+ * its declarator, and `recoveredTypeSpelling` reads it with the same narrowness the
3959
+ * return-type arm uses.
3960
+ */
3961
+ recoveryStatesType(wrapper) {
3962
+ if (!wrapper) return false;
3963
+ for (let i = 0; i < wrapper.namedChildCount; i++) {
3964
+ const c = wrapper.namedChild(i);
3965
+ if (c && c.type === "ERROR" && this.recoveredTypeSpelling(c)) return true;
3966
+ }
3967
+ return false;
3968
+ }
3969
+ /**
3970
+ * D17's premise test: did the recovery leave material BETWEEN the decorator and
3971
+ * the declarator? A decorated head does — the macro's own parens, or an ERROR
3972
+ * holding the displaced type — while `HANDLE Open();` does not, and only the
3973
+ * first can be a decorator. Stops at the declarator, so an unrelated ERROR inside
3974
+ * the function's BODY cannot make a type look decorated.
3975
+ */
3976
+ recoveredDecoratorHead(node, declarator) {
3977
+ for (let i = 0; i < node.namedChildCount; i++) {
3978
+ const c = node.namedChild(i);
3979
+ if (!c || declarator && c.startIndex > declarator.startIndex) break;
3980
+ if (c.type === "ERROR" || c.type === "parenthesized_declarator") return true;
3981
+ }
3982
+ return false;
3983
+ }
3984
+ /**
3985
+ * D18 arm B: the return type the recovery DISPLACED out of the `type` field,
3986
+ * visible as material between the decorator and the declarator:
3987
+ *
3988
+ * JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_WARN_UNUSED_RESULT
3989
+ * void grisu2(char* buf, …) constexpr bool is_primitive() const
3990
+ * ERROR[number_literal(1), type_qualifier(constexpr)
3991
+ * primitive_type(void)] ERROR[identifier(bool)]
3992
+ *
3993
+ * The type is the LAST type the recovery left before the declarator, read
3994
+ * OUTWARD from the declarator (its own ERROR first, then each enclosing node up
3995
+ * to the declaration) so the nearest evidence wins. Returns undefined when the
3996
+ * recovery left no type at all — a constructor's decorated head, where the ERROR
3997
+ * holds only the macro's argument and the declarator.
3998
+ */
3999
+ displacedReturnType(node, declarator) {
4000
+ if (!declarator) return void 0;
4001
+ let cur = declarator;
4002
+ for (let depth = 0; cur && depth < 8; depth++) {
4003
+ const parent = cur.parent;
4004
+ if (!parent) break;
4005
+ if (parent.startIndex < node.startIndex || parent.endIndex > node.endIndex) break;
4006
+ let found = void 0;
4007
+ for (let i = 0; i < parent.namedChildCount; i++) {
4008
+ const c = parent.namedChild(i);
4009
+ if (!c || c.startIndex >= declarator.startIndex) break;
4010
+ const spelling = this.recoveredTypeSpelling(c);
4011
+ if (spelling) found = spelling;
4012
+ }
4013
+ if (found) return found;
4014
+ cur = parent;
4015
+ }
4016
+ return void 0;
4017
+ }
4018
+ /**
4019
+ * The type ONE recovered node states, or undefined when it states none.
4020
+ *
4021
+ * A bare `identifier` counts only when the ERROR holds exactly one named child,
4022
+ * the same narrowness `recoveredDeclaredName` uses for a displaced NAME: `bool`
4023
+ * and `T` arrive that way (the recovery does not classify them as types), and
4024
+ * anything richer is the recovery's own soup rather than a type. A macro
4025
+ * spelling never counts — the decorator is not the type it decorates, which is
4026
+ * the whole point of the arm.
4027
+ */
4028
+ recoveredTypeSpelling(n, depth = 0) {
4029
+ if (depth > 6 || n.type === "function_declarator") return void 0;
4030
+ if (n.type === "ERROR") {
4031
+ if (n.namedChildCount === 1) {
4032
+ const only = n.namedChild(0);
4033
+ if (only && only.type === "identifier") {
4034
+ const single = collapseSpaces(only.text);
4035
+ return single && !isMacroSpelling(single) ? single : void 0;
4036
+ }
4037
+ }
4038
+ let found = void 0;
4039
+ for (let i = 0; i < n.namedChildCount; i++) {
4040
+ const c = n.namedChild(i);
4041
+ if (!c || c.type === "function_declarator") break;
4042
+ const spelling = this.recoveredTypeSpelling(c, depth + 1);
4043
+ if (spelling) found = spelling;
4044
+ }
4045
+ return found;
4046
+ }
4047
+ if (n.type === "primitive_type" || n.type === "sized_type_specifier" || n.type === "template_type" || n.type === "qualified_identifier" || n.type === "dependent_type" || n.type === "decltype" || n.type === "struct_specifier" || n.type === "union_specifier" || n.type === "enum_specifier" || n.type === "placeholder_type_specifier" || n.type === "macro_prefixed_type_specifier" || n.type === "type_identifier") {
4048
+ const text = n.type === "macro_prefixed_type_specifier" ? specifierTypeText(n) ?? "" : collapseSpaces(n.text);
4049
+ return text && !isMacroSpelling(text) ? text : void 0;
4050
+ }
4051
+ return void 0;
4052
+ }
4053
+ // ≡ /^[A-Za-z_]\w*$/ (zero-regex helper, M49 closure wave) — full-string
4054
+ // identifier shape: letter/underscore head, word-class tail. CGD19 class:
4055
+ // recovery-artifact type names (qualified, templated, mangled) fail this
4056
+ // and emit no edge.
4057
+ isPlainIdentifier(s) {
4058
+ if (s.length === 0) return false;
4059
+ const c0 = s.charCodeAt(0);
4060
+ const firstOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95;
4061
+ if (!firstOk) return false;
4062
+ for (let i = 1; i < s.length; i++) {
4063
+ const c = s.charCodeAt(i);
4064
+ const ok = c >= 65 && c <= 90 || c >= 97 && c <= 122 || c >= 48 && c <= 57 || c === 95;
4065
+ if (!ok) return false;
4066
+ }
4067
+ return true;
4068
+ }
4069
+ buildFullName(scopeStack, name) {
4070
+ const parts = [];
4071
+ for (let i = 0; i < scopeStack.length; i++) {
4072
+ if (scopeStack[i].kind === ASTEngine.SymbolKind.Namespace) {
4073
+ parts.push(scopeStack[i].name);
4074
+ }
4075
+ }
4076
+ parts.push(name);
4077
+ return parts.join("::");
4078
+ }
4079
+ };
4080
+ export {
4081
+ CPP_ANONYMOUS,
4082
+ CPP_BUILTIN_TYPE_KEYWORDS,
4083
+ CPP_EXPORT_MARKER_COMPONENTS,
4084
+ CPP_KEYWORDS,
4085
+ CPP_NON_CLASS_STANDARD_TYPES,
4086
+ CPP_ORACLE_CONTRACT,
4087
+ RealCppAnalyzer,
4088
+ attributeDisplacedEnumName,
4089
+ cppExportMarker,
4090
+ cppPureVirtualDeclaration,
4091
+ extendsTargetName,
4092
+ isCppSpelledName,
4093
+ isPublishableFunctionName,
4094
+ macroDeclaredBody,
4095
+ macroInvocationText,
4096
+ qualifiedDeclaratorLeaf,
4097
+ recoveredDeclaredName,
4098
+ sameTsNode,
4099
+ specifierDeclaredName,
4100
+ templateWrappedDeclaratorName
4101
+ };