@lzehrung/codegraph 2.3.31 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (596) hide show
  1. package/README.md +33 -141
  2. package/codegraph-skill/codegraph/SKILL.md +8 -6
  3. package/dist/agent/artifact.d.ts +2 -0
  4. package/dist/agent/artifact.d.ts.map +1 -1
  5. package/dist/agent/artifact.js.map +1 -1
  6. package/dist/agent/call-hierarchy.js +2 -4
  7. package/dist/agent/call-hierarchy.js.map +1 -1
  8. package/dist/agent/explore.d.ts +1 -1
  9. package/dist/agent/explore.d.ts.map +1 -1
  10. package/dist/agent/explore.js +3 -2
  11. package/dist/agent/explore.js.map +1 -1
  12. package/dist/agent/refactor-plan.js +2 -4
  13. package/dist/agent/refactor-plan.js.map +1 -1
  14. package/dist/agent/rename-preview.d.ts.map +1 -1
  15. package/dist/agent/rename-preview.js +4 -3
  16. package/dist/agent/rename-preview.js.map +1 -1
  17. package/dist/agent/search.d.ts.map +1 -1
  18. package/dist/agent/search.js +5 -3
  19. package/dist/agent/search.js.map +1 -1
  20. package/dist/agent/semantic-symbols.d.ts.map +1 -1
  21. package/dist/agent/semantic-symbols.js +2 -3
  22. package/dist/agent/semantic-symbols.js.map +1 -1
  23. package/dist/agent/session.d.ts +3 -0
  24. package/dist/agent/session.d.ts.map +1 -1
  25. package/dist/agent/session.js +10 -2
  26. package/dist/agent/session.js.map +1 -1
  27. package/dist/agent/type-hierarchy.js +2 -4
  28. package/dist/agent/type-hierarchy.js.map +1 -1
  29. package/dist/agent/workspace-symbols.d.ts.map +1 -1
  30. package/dist/agent/workspace-symbols.js +2 -3
  31. package/dist/agent/workspace-symbols.js.map +1 -1
  32. package/dist/agent-tools.d.ts +0 -4
  33. package/dist/agent-tools.d.ts.map +1 -1
  34. package/dist/agent-tools.js +3 -6
  35. package/dist/agent-tools.js.map +1 -1
  36. package/dist/analysis-summary.d.ts +8 -4
  37. package/dist/analysis-summary.d.ts.map +1 -1
  38. package/dist/analysis-summary.js +15 -66
  39. package/dist/analysis-summary.js.map +1 -1
  40. package/dist/bin/cli.js +51145 -41770
  41. package/dist/bin/query-index-worker.js +122 -82
  42. package/dist/cli/affected.d.ts.map +1 -1
  43. package/dist/cli/affected.js +4 -1
  44. package/dist/cli/affected.js.map +1 -1
  45. package/dist/cli/command-catalog.js +1 -1
  46. package/dist/cli/command-catalog.js.map +1 -1
  47. package/dist/cli/command-table.d.ts.map +1 -1
  48. package/dist/cli/command-table.js +9 -17
  49. package/dist/cli/command-table.js.map +1 -1
  50. package/dist/cli/context.js +10 -10
  51. package/dist/cli/context.js.map +1 -1
  52. package/dist/cli/drift.d.ts +0 -2
  53. package/dist/cli/drift.d.ts.map +1 -1
  54. package/dist/cli/drift.js +0 -1
  55. package/dist/cli/drift.js.map +1 -1
  56. package/dist/cli/graph-delta.d.ts +0 -2
  57. package/dist/cli/graph-delta.d.ts.map +1 -1
  58. package/dist/cli/graph-delta.js +0 -4
  59. package/dist/cli/graph-delta.js.map +1 -1
  60. package/dist/cli/graph-queries.d.ts.map +1 -1
  61. package/dist/cli/graph-queries.js +27 -1
  62. package/dist/cli/graph-queries.js.map +1 -1
  63. package/dist/cli/graph.d.ts +0 -3
  64. package/dist/cli/graph.d.ts.map +1 -1
  65. package/dist/cli/graph.js +4 -14
  66. package/dist/cli/graph.js.map +1 -1
  67. package/dist/cli/help.d.ts +34 -34
  68. package/dist/cli/help.d.ts.map +1 -1
  69. package/dist/cli/help.js +9 -14
  70. package/dist/cli/help.js.map +1 -1
  71. package/dist/cli/impact.d.ts +0 -2
  72. package/dist/cli/impact.d.ts.map +1 -1
  73. package/dist/cli/impact.js +0 -1
  74. package/dist/cli/impact.js.map +1 -1
  75. package/dist/cli/index.d.ts +0 -2
  76. package/dist/cli/index.d.ts.map +1 -1
  77. package/dist/cli/index.js +5 -6
  78. package/dist/cli/index.js.map +1 -1
  79. package/dist/cli/inspect.d.ts +0 -2
  80. package/dist/cli/inspect.d.ts.map +1 -1
  81. package/dist/cli/inspect.js +5 -8
  82. package/dist/cli/inspect.js.map +1 -1
  83. package/dist/cli/invocation-context.d.ts +0 -3
  84. package/dist/cli/invocation-context.d.ts.map +1 -1
  85. package/dist/cli/invocation-context.js +4 -16
  86. package/dist/cli/invocation-context.js.map +1 -1
  87. package/dist/cli/navigation.d.ts +0 -2
  88. package/dist/cli/navigation.d.ts.map +1 -1
  89. package/dist/cli/navigation.js +0 -1
  90. package/dist/cli/navigation.js.map +1 -1
  91. package/dist/cli/options.d.ts.map +1 -1
  92. package/dist/cli/options.js +4 -14
  93. package/dist/cli/options.js.map +1 -1
  94. package/dist/cli/review.d.ts +0 -2
  95. package/dist/cli/review.d.ts.map +1 -1
  96. package/dist/cli/review.js +0 -5
  97. package/dist/cli/review.js.map +1 -1
  98. package/dist/cli/root-policy.d.ts +0 -2
  99. package/dist/cli/root-policy.d.ts.map +1 -1
  100. package/dist/cli/root-policy.js +0 -8
  101. package/dist/cli/root-policy.js.map +1 -1
  102. package/dist/cli/server.d.ts.map +1 -1
  103. package/dist/cli/server.js +0 -2
  104. package/dist/cli/server.js.map +1 -1
  105. package/dist/drift/artifact.d.ts.map +1 -1
  106. package/dist/drift/artifact.js +15 -18
  107. package/dist/drift/artifact.js.map +1 -1
  108. package/dist/drift/compare.js +1 -1
  109. package/dist/drift/compare.js.map +1 -1
  110. package/dist/drift/git.d.ts.map +1 -1
  111. package/dist/drift/git.js +0 -1
  112. package/dist/drift/git.js.map +1 -1
  113. package/dist/drift/snapshot.d.ts.map +1 -1
  114. package/dist/drift/snapshot.js +5 -7
  115. package/dist/drift/snapshot.js.map +1 -1
  116. package/dist/drift/types.d.ts +2 -2
  117. package/dist/drift/types.d.ts.map +1 -1
  118. package/dist/drift/types.js.map +1 -1
  119. package/dist/duplicates/unit-cache.d.ts +0 -1
  120. package/dist/duplicates/unit-cache.d.ts.map +1 -1
  121. package/dist/duplicates/unit-cache.js +3 -11
  122. package/dist/duplicates/unit-cache.js.map +1 -1
  123. package/dist/duplicates/units.d.ts +5 -5
  124. package/dist/duplicates/units.d.ts.map +1 -1
  125. package/dist/duplicates/units.js +25 -88
  126. package/dist/duplicates/units.js.map +1 -1
  127. package/dist/graph-builder.d.ts +0 -6
  128. package/dist/graph-builder.d.ts.map +1 -1
  129. package/dist/graph-builder.js +6 -11
  130. package/dist/graph-builder.js.map +1 -1
  131. package/dist/graph-edge-collector.d.ts +4 -6
  132. package/dist/graph-edge-collector.d.ts.map +1 -1
  133. package/dist/graph-edge-collector.js +31 -26
  134. package/dist/graph-edge-collector.js.map +1 -1
  135. package/dist/graphs/angularjs.d.ts.map +1 -1
  136. package/dist/graphs/angularjs.js +2 -1
  137. package/dist/graphs/angularjs.js.map +1 -1
  138. package/dist/graphs/edge-resolution.d.ts +4 -1
  139. package/dist/graphs/edge-resolution.d.ts.map +1 -1
  140. package/dist/graphs/edge-resolution.js +24 -76
  141. package/dist/graphs/edge-resolution.js.map +1 -1
  142. package/dist/graphs/specifiers.d.ts +4 -13
  143. package/dist/graphs/specifiers.d.ts.map +1 -1
  144. package/dist/graphs/specifiers.js +80 -173
  145. package/dist/graphs/specifiers.js.map +1 -1
  146. package/dist/graphs/symbol-graph-detailed/ast.d.ts +20 -0
  147. package/dist/graphs/symbol-graph-detailed/ast.d.ts.map +1 -1
  148. package/dist/graphs/symbol-graph-detailed/ast.js +154 -15
  149. package/dist/graphs/symbol-graph-detailed/ast.js.map +1 -1
  150. package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts +60 -8
  151. package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts.map +1 -1
  152. package/dist/graphs/symbol-graph-detailed/edge-passes.js +997 -168
  153. package/dist/graphs/symbol-graph-detailed/edge-passes.js.map +1 -1
  154. package/dist/graphs/symbol-graph-detailed/import-aliases.d.ts +2 -1
  155. package/dist/graphs/symbol-graph-detailed/import-aliases.d.ts.map +1 -1
  156. package/dist/graphs/symbol-graph-detailed/import-aliases.js +150 -7
  157. package/dist/graphs/symbol-graph-detailed/import-aliases.js.map +1 -1
  158. package/dist/graphs/symbol-graph-detailed/member-chains.d.ts +1 -0
  159. package/dist/graphs/symbol-graph-detailed/member-chains.d.ts.map +1 -1
  160. package/dist/graphs/symbol-graph-detailed/member-chains.js +3 -1
  161. package/dist/graphs/symbol-graph-detailed/member-chains.js.map +1 -1
  162. package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts +141 -25
  163. package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts.map +1 -1
  164. package/dist/graphs/symbol-graph-detailed/receiver-calls.js +1015 -166
  165. package/dist/graphs/symbol-graph-detailed/receiver-calls.js.map +1 -1
  166. package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
  167. package/dist/graphs/symbol-graph-detailed.js +449 -46
  168. package/dist/graphs/symbol-graph-detailed.js.map +1 -1
  169. package/dist/graphs/symbol-graph.d.ts +2 -0
  170. package/dist/graphs/symbol-graph.d.ts.map +1 -1
  171. package/dist/graphs/symbol-graph.js +34 -16
  172. package/dist/graphs/symbol-graph.js.map +1 -1
  173. package/dist/graphs/types.d.ts +0 -4
  174. package/dist/graphs/types.d.ts.map +1 -1
  175. package/dist/graphs.d.ts +1 -1
  176. package/dist/graphs.d.ts.map +1 -1
  177. package/dist/impact/call-compatibility/providers/index.d.ts +4 -4
  178. package/dist/impact/call-compatibility/providers/index.d.ts.map +1 -1
  179. package/dist/impact/call-compatibility/providers/index.js +6 -6
  180. package/dist/impact/call-compatibility/providers/index.js.map +1 -1
  181. package/dist/impact/call-compatibility/providers/types.d.ts +2 -0
  182. package/dist/impact/call-compatibility/providers/types.d.ts.map +1 -1
  183. package/dist/impact/call-compatibility/types.d.ts +6 -0
  184. package/dist/impact/call-compatibility/types.d.ts.map +1 -1
  185. package/dist/impact/call-compatibility.d.ts.map +1 -1
  186. package/dist/impact/call-compatibility.js +316 -526
  187. package/dist/impact/call-compatibility.js.map +1 -1
  188. package/dist/impact/map.js +1 -0
  189. package/dist/impact/map.js.map +1 -1
  190. package/dist/impact/reference-cache.d.ts.map +1 -1
  191. package/dist/impact/reference-cache.js +2 -2
  192. package/dist/impact/reference-cache.js.map +1 -1
  193. package/dist/index.d.ts +2 -2
  194. package/dist/index.d.ts.map +1 -1
  195. package/dist/index.js +1 -1
  196. package/dist/index.js.map +1 -1
  197. package/dist/indexer/ambiguous-resolution.d.ts +11 -0
  198. package/dist/indexer/ambiguous-resolution.d.ts.map +1 -0
  199. package/dist/indexer/ambiguous-resolution.js +19 -0
  200. package/dist/indexer/ambiguous-resolution.js.map +1 -0
  201. package/dist/indexer/build-cache/module-cache.d.ts +39 -1
  202. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  203. package/dist/indexer/build-cache/module-cache.js +218 -21
  204. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  205. package/dist/indexer/build-cache/options.d.ts +30 -44
  206. package/dist/indexer/build-cache/options.d.ts.map +1 -1
  207. package/dist/indexer/build-cache/options.js +32 -71
  208. package/dist/indexer/build-cache/options.js.map +1 -1
  209. package/dist/indexer/build-cache/project-snapshot.d.ts +3 -3
  210. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  211. package/dist/indexer/build-cache/project-snapshot.js +164 -84
  212. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  213. package/dist/indexer/build-cache/reports.d.ts +0 -2
  214. package/dist/indexer/build-cache/reports.d.ts.map +1 -1
  215. package/dist/indexer/build-cache/reports.js +0 -97
  216. package/dist/indexer/build-cache/reports.js.map +1 -1
  217. package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -1
  218. package/dist/indexer/build-cache/resolver-environment.js +32 -2
  219. package/dist/indexer/build-cache/resolver-environment.js.map +1 -1
  220. package/dist/indexer/build-cache.d.ts +2 -2
  221. package/dist/indexer/build-cache.d.ts.map +1 -1
  222. package/dist/indexer/build-cache.js +2 -2
  223. package/dist/indexer/build-cache.js.map +1 -1
  224. package/dist/indexer/build-index.d.ts.map +1 -1
  225. package/dist/indexer/build-index.js +656 -71
  226. package/dist/indexer/build-index.js.map +1 -1
  227. package/dist/indexer/build-workers.d.ts.map +1 -1
  228. package/dist/indexer/build-workers.js +9 -9
  229. package/dist/indexer/build-workers.js.map +1 -1
  230. package/dist/indexer/call-hierarchy.js +1 -1
  231. package/dist/indexer/call-hierarchy.js.map +1 -1
  232. package/dist/indexer/callable-identity.d.ts +24 -0
  233. package/dist/indexer/callable-identity.d.ts.map +1 -0
  234. package/dist/indexer/callable-identity.js +111 -0
  235. package/dist/indexer/callable-identity.js.map +1 -0
  236. package/dist/indexer/compilation-units.d.ts +103 -0
  237. package/dist/indexer/compilation-units.d.ts.map +1 -0
  238. package/dist/indexer/compilation-units.js +607 -0
  239. package/dist/indexer/compilation-units.js.map +1 -0
  240. package/dist/indexer/cpp-callables.d.ts +25 -0
  241. package/dist/indexer/cpp-callables.d.ts.map +1 -0
  242. package/dist/indexer/cpp-callables.js +562 -0
  243. package/dist/indexer/cpp-callables.js.map +1 -0
  244. package/dist/indexer/declaration-visibility.d.ts +43 -2
  245. package/dist/indexer/declaration-visibility.d.ts.map +1 -1
  246. package/dist/indexer/declaration-visibility.js +158 -2
  247. package/dist/indexer/declaration-visibility.js.map +1 -1
  248. package/dist/indexer/expand-star-imports.d.ts +6 -1
  249. package/dist/indexer/expand-star-imports.d.ts.map +1 -1
  250. package/dist/indexer/expand-star-imports.js +131 -37
  251. package/dist/indexer/expand-star-imports.js.map +1 -1
  252. package/dist/indexer/finalize.d.ts.map +1 -1
  253. package/dist/indexer/finalize.js +0 -1
  254. package/dist/indexer/finalize.js.map +1 -1
  255. package/dist/indexer/import-resolution-tables.d.ts +72 -0
  256. package/dist/indexer/import-resolution-tables.d.ts.map +1 -0
  257. package/dist/indexer/import-resolution-tables.js +137 -0
  258. package/dist/indexer/import-resolution-tables.js.map +1 -0
  259. package/dist/indexer/import-types.d.ts +54 -0
  260. package/dist/indexer/import-types.d.ts.map +1 -1
  261. package/dist/indexer/import-types.js +24 -1
  262. package/dist/indexer/import-types.js.map +1 -1
  263. package/dist/indexer/imports/context.d.ts +16 -1
  264. package/dist/indexer/imports/context.d.ts.map +1 -1
  265. package/dist/indexer/imports/import-binding-tables.d.ts +13 -1
  266. package/dist/indexer/imports/import-binding-tables.d.ts.map +1 -1
  267. package/dist/indexer/imports/import-binding-tables.js +149 -30
  268. package/dist/indexer/imports/import-binding-tables.js.map +1 -1
  269. package/dist/indexer/imports/js-text-imports.js +4 -4
  270. package/dist/indexer/imports/js-text-imports.js.map +1 -1
  271. package/dist/indexer/imports/native-captures.d.ts.map +1 -1
  272. package/dist/indexer/imports/native-captures.js +24 -6
  273. package/dist/indexer/imports/native-captures.js.map +1 -1
  274. package/dist/indexer/imports/python.d.ts +10 -2
  275. package/dist/indexer/imports/python.d.ts.map +1 -1
  276. package/dist/indexer/imports/python.js +128 -112
  277. package/dist/indexer/imports/python.js.map +1 -1
  278. package/dist/indexer/imports/text-import-extractors.d.ts.map +1 -1
  279. package/dist/indexer/imports/text-import-extractors.js +68 -19
  280. package/dist/indexer/imports/text-import-extractors.js.map +1 -1
  281. package/dist/indexer/imports.d.ts +3 -4
  282. package/dist/indexer/imports.d.ts.map +1 -1
  283. package/dist/indexer/imports.js +116 -72
  284. package/dist/indexer/imports.js.map +1 -1
  285. package/dist/indexer/incremental-plan.d.ts +33 -0
  286. package/dist/indexer/incremental-plan.d.ts.map +1 -1
  287. package/dist/indexer/incremental-plan.js +203 -1
  288. package/dist/indexer/incremental-plan.js.map +1 -1
  289. package/dist/indexer/locals-and-exports.d.ts +3 -2
  290. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  291. package/dist/indexer/locals-and-exports.js +659 -78
  292. package/dist/indexer/locals-and-exports.js.map +1 -1
  293. package/dist/indexer/member-selection.d.ts +46 -0
  294. package/dist/indexer/member-selection.d.ts.map +1 -0
  295. package/dist/indexer/member-selection.js +169 -0
  296. package/dist/indexer/member-selection.js.map +1 -0
  297. package/dist/indexer/name-lookup-policies/c-family.d.ts +7 -0
  298. package/dist/indexer/name-lookup-policies/c-family.d.ts.map +1 -0
  299. package/dist/indexer/name-lookup-policies/c-family.js +137 -0
  300. package/dist/indexer/name-lookup-policies/c-family.js.map +1 -0
  301. package/dist/indexer/name-lookup-policies/csharp-using-static.d.ts +11 -0
  302. package/dist/indexer/name-lookup-policies/csharp-using-static.d.ts.map +1 -0
  303. package/dist/indexer/name-lookup-policies/csharp-using-static.js +136 -0
  304. package/dist/indexer/name-lookup-policies/csharp-using-static.js.map +1 -0
  305. package/dist/indexer/name-lookup-policies/implicit-self.d.ts +10 -0
  306. package/dist/indexer/name-lookup-policies/implicit-self.d.ts.map +1 -0
  307. package/dist/indexer/name-lookup-policies/implicit-self.js +119 -0
  308. package/dist/indexer/name-lookup-policies/implicit-self.js.map +1 -0
  309. package/dist/indexer/name-lookup-policies/index.d.ts +3 -0
  310. package/dist/indexer/name-lookup-policies/index.d.ts.map +1 -0
  311. package/dist/indexer/name-lookup-policies/index.js +132 -0
  312. package/dist/indexer/name-lookup-policies/index.js.map +1 -0
  313. package/dist/indexer/name-lookup-policies/php.d.ts +3 -0
  314. package/dist/indexer/name-lookup-policies/php.d.ts.map +1 -0
  315. package/dist/indexer/name-lookup-policies/php.js +82 -0
  316. package/dist/indexer/name-lookup-policies/php.js.map +1 -0
  317. package/dist/indexer/name-resolution-types.d.ts +101 -0
  318. package/dist/indexer/name-resolution-types.d.ts.map +1 -0
  319. package/dist/indexer/name-resolution-types.js +2 -0
  320. package/dist/indexer/name-resolution-types.js.map +1 -0
  321. package/dist/indexer/name-resolution.d.ts +57 -0
  322. package/dist/indexer/name-resolution.d.ts.map +1 -0
  323. package/dist/indexer/name-resolution.js +204 -0
  324. package/dist/indexer/name-resolution.js.map +1 -0
  325. package/dist/indexer/navigation-cpp.d.ts +58 -0
  326. package/dist/indexer/navigation-cpp.d.ts.map +1 -0
  327. package/dist/indexer/navigation-cpp.js +935 -0
  328. package/dist/indexer/navigation-cpp.js.map +1 -0
  329. package/dist/indexer/navigation-goto.d.ts +115 -3
  330. package/dist/indexer/navigation-goto.d.ts.map +1 -1
  331. package/dist/indexer/navigation-goto.js +2469 -190
  332. package/dist/indexer/navigation-goto.js.map +1 -1
  333. package/dist/indexer/navigation-local.d.ts +21 -2
  334. package/dist/indexer/navigation-local.d.ts.map +1 -1
  335. package/dist/indexer/navigation-local.js +520 -63
  336. package/dist/indexer/navigation-local.js.map +1 -1
  337. package/dist/indexer/navigation-php.d.ts +66 -0
  338. package/dist/indexer/navigation-php.d.ts.map +1 -1
  339. package/dist/indexer/navigation-php.js +287 -4
  340. package/dist/indexer/navigation-php.js.map +1 -1
  341. package/dist/indexer/navigation-provenance.d.ts +1 -1
  342. package/dist/indexer/navigation-provenance.d.ts.map +1 -1
  343. package/dist/indexer/navigation-provenance.js +4 -13
  344. package/dist/indexer/navigation-provenance.js.map +1 -1
  345. package/dist/indexer/navigation-references.d.ts +73 -6
  346. package/dist/indexer/navigation-references.d.ts.map +1 -1
  347. package/dist/indexer/navigation-references.js +661 -67
  348. package/dist/indexer/navigation-references.js.map +1 -1
  349. package/dist/indexer/navigation-resolve.d.ts +46 -2
  350. package/dist/indexer/navigation-resolve.d.ts.map +1 -1
  351. package/dist/indexer/navigation-resolve.js +599 -193
  352. package/dist/indexer/navigation-resolve.js.map +1 -1
  353. package/dist/indexer/navigation.d.ts +29 -2
  354. package/dist/indexer/navigation.d.ts.map +1 -1
  355. package/dist/indexer/navigation.js +1092 -153
  356. package/dist/indexer/navigation.js.map +1 -1
  357. package/dist/indexer/parse-context.d.ts +2 -3
  358. package/dist/indexer/parse-context.d.ts.map +1 -1
  359. package/dist/indexer/parse-context.js +8 -21
  360. package/dist/indexer/parse-context.js.map +1 -1
  361. package/dist/indexer/php-namespace-symbols.d.ts +66 -0
  362. package/dist/indexer/php-namespace-symbols.d.ts.map +1 -0
  363. package/dist/indexer/php-namespace-symbols.js +342 -0
  364. package/dist/indexer/php-namespace-symbols.js.map +1 -0
  365. package/dist/indexer/reference-candidates.d.ts.map +1 -1
  366. package/dist/indexer/reference-candidates.js +13 -7
  367. package/dist/indexer/reference-candidates.js.map +1 -1
  368. package/dist/indexer/reference-context.d.ts +2 -0
  369. package/dist/indexer/reference-context.d.ts.map +1 -1
  370. package/dist/indexer/reference-context.js +4 -0
  371. package/dist/indexer/reference-context.js.map +1 -1
  372. package/dist/indexer/scope-nodes.d.ts +92 -13
  373. package/dist/indexer/scope-nodes.d.ts.map +1 -1
  374. package/dist/indexer/scope-nodes.js +212 -20
  375. package/dist/indexer/scope-nodes.js.map +1 -1
  376. package/dist/indexer/scope-types.d.ts +29 -1
  377. package/dist/indexer/scope-types.d.ts.map +1 -1
  378. package/dist/indexer/scope.d.ts +2 -3
  379. package/dist/indexer/scope.d.ts.map +1 -1
  380. package/dist/indexer/scope.js +968 -47
  381. package/dist/indexer/scope.js.map +1 -1
  382. package/dist/indexer/shared-owner-identity.d.ts +53 -0
  383. package/dist/indexer/shared-owner-identity.d.ts.map +1 -0
  384. package/dist/indexer/shared-owner-identity.js +460 -0
  385. package/dist/indexer/shared-owner-identity.js.map +1 -0
  386. package/dist/indexer/shared.d.ts +1 -1
  387. package/dist/indexer/shared.d.ts.map +1 -1
  388. package/dist/indexer/shared.js +1 -1
  389. package/dist/indexer/shared.js.map +1 -1
  390. package/dist/indexer/star-import-precedence.d.ts +113 -0
  391. package/dist/indexer/star-import-precedence.d.ts.map +1 -0
  392. package/dist/indexer/star-import-precedence.js +402 -0
  393. package/dist/indexer/star-import-precedence.js.map +1 -0
  394. package/dist/indexer/symbols.d.ts +3 -1
  395. package/dist/indexer/symbols.d.ts.map +1 -1
  396. package/dist/indexer/symbols.js +58 -18
  397. package/dist/indexer/symbols.js.map +1 -1
  398. package/dist/indexer/ts-callables.d.ts +42 -0
  399. package/dist/indexer/ts-callables.d.ts.map +1 -0
  400. package/dist/indexer/ts-callables.js +233 -0
  401. package/dist/indexer/ts-callables.js.map +1 -0
  402. package/dist/indexer/types.d.ts +41 -26
  403. package/dist/indexer/types.d.ts.map +1 -1
  404. package/dist/indexer/unused-exports.d.ts +13 -0
  405. package/dist/indexer/unused-exports.d.ts.map +1 -0
  406. package/dist/indexer/unused-exports.js +159 -0
  407. package/dist/indexer/unused-exports.js.map +1 -0
  408. package/dist/indexer/workspace-symbols.d.ts.map +1 -1
  409. package/dist/indexer/workspace-symbols.js +3 -2
  410. package/dist/indexer/workspace-symbols.js.map +1 -1
  411. package/dist/indexer.d.ts +3 -8
  412. package/dist/indexer.d.ts.map +1 -1
  413. package/dist/indexer.js +1 -1
  414. package/dist/indexer.js.map +1 -1
  415. package/dist/languages/callable-arity.d.ts +223 -0
  416. package/dist/languages/callable-arity.d.ts.map +1 -0
  417. package/dist/languages/callable-arity.js +1199 -0
  418. package/dist/languages/callable-arity.js.map +1 -0
  419. package/dist/languages/definitions/c-family.d.ts.map +1 -1
  420. package/dist/languages/definitions/c-family.js +30 -1
  421. package/dist/languages/definitions/c-family.js.map +1 -1
  422. package/dist/languages/definitions/c.d.ts +4 -0
  423. package/dist/languages/definitions/c.d.ts.map +1 -1
  424. package/dist/languages/definitions/c.js +19 -0
  425. package/dist/languages/definitions/c.js.map +1 -1
  426. package/dist/languages/definitions/cpp.d.ts.map +1 -1
  427. package/dist/languages/definitions/cpp.js +12 -0
  428. package/dist/languages/definitions/cpp.js.map +1 -1
  429. package/dist/languages/definitions/csharp.d.ts.map +1 -1
  430. package/dist/languages/definitions/csharp.js +2 -8
  431. package/dist/languages/definitions/csharp.js.map +1 -1
  432. package/dist/languages/definitions/go.d.ts.map +1 -1
  433. package/dist/languages/definitions/go.js +3 -0
  434. package/dist/languages/definitions/go.js.map +1 -1
  435. package/dist/languages/definitions/javascript.d.ts.map +1 -1
  436. package/dist/languages/definitions/javascript.js +10 -1
  437. package/dist/languages/definitions/javascript.js.map +1 -1
  438. package/dist/languages/definitions/js-family.d.ts +1 -1
  439. package/dist/languages/definitions/js-family.d.ts.map +1 -1
  440. package/dist/languages/definitions/js-family.js +7 -1
  441. package/dist/languages/definitions/js-family.js.map +1 -1
  442. package/dist/languages/definitions/php.d.ts.map +1 -1
  443. package/dist/languages/definitions/php.js +5 -1
  444. package/dist/languages/definitions/php.js.map +1 -1
  445. package/dist/languages/definitions/typescript.d.ts.map +1 -1
  446. package/dist/languages/definitions/typescript.js +8 -1
  447. package/dist/languages/definitions/typescript.js.map +1 -1
  448. package/dist/languages/definitions/zig.d.ts.map +1 -1
  449. package/dist/languages/definitions/zig.js +8 -0
  450. package/dist/languages/definitions/zig.js.map +1 -1
  451. package/dist/lifecycle/manifest.d.ts.map +1 -1
  452. package/dist/lifecycle/manifest.js +0 -1
  453. package/dist/lifecycle/manifest.js.map +1 -1
  454. package/dist/mcp/handlers.js +14 -7
  455. package/dist/mcp/handlers.js.map +1 -1
  456. package/dist/native/byte-index.d.ts +6 -0
  457. package/dist/native/byte-index.d.ts.map +1 -1
  458. package/dist/native/byte-index.js +11 -6
  459. package/dist/native/byte-index.js.map +1 -1
  460. package/dist/native/contracts.d.ts +2 -3
  461. package/dist/native/contracts.d.ts.map +1 -1
  462. package/dist/native/execution.d.ts +9 -9
  463. package/dist/native/execution.d.ts.map +1 -1
  464. package/dist/native/execution.js +37 -77
  465. package/dist/native/execution.js.map +1 -1
  466. package/dist/native/js-bridge.d.ts +2 -15
  467. package/dist/native/js-bridge.d.ts.map +1 -1
  468. package/dist/native/js-bridge.js +2 -15
  469. package/dist/native/js-bridge.js.map +1 -1
  470. package/dist/native/query-results.js +2 -2
  471. package/dist/native/query-results.js.map +1 -1
  472. package/dist/native/runtime.d.ts +12 -12
  473. package/dist/native/runtime.d.ts.map +1 -1
  474. package/dist/native/runtime.js +24 -69
  475. package/dist/native/runtime.js.map +1 -1
  476. package/dist/native/tree-sitter-native.d.ts +3 -3
  477. package/dist/native/tree-sitter-native.d.ts.map +1 -1
  478. package/dist/native/tree-sitter-native.js +2 -2
  479. package/dist/native/tree-sitter-native.js.map +1 -1
  480. package/dist/presets.d.ts.map +1 -1
  481. package/dist/presets.js +0 -4
  482. package/dist/presets.js.map +1 -1
  483. package/dist/review/candidates.d.ts.map +1 -1
  484. package/dist/review/candidates.js +1 -1
  485. package/dist/review/candidates.js.map +1 -1
  486. package/dist/review/deleted.d.ts +3 -3
  487. package/dist/review/deleted.d.ts.map +1 -1
  488. package/dist/review/deleted.js +82 -32
  489. package/dist/review/deleted.js.map +1 -1
  490. package/dist/review/report.d.ts +1 -0
  491. package/dist/review/report.d.ts.map +1 -1
  492. package/dist/review/report.js +1 -1
  493. package/dist/review/report.js.map +1 -1
  494. package/dist/review.d.ts.map +1 -1
  495. package/dist/review.js +3 -20
  496. package/dist/review.js.map +1 -1
  497. package/dist/session.d.ts.map +1 -1
  498. package/dist/session.js +0 -5
  499. package/dist/session.js.map +1 -1
  500. package/dist/sql/navigation.d.ts.map +1 -1
  501. package/dist/sql/navigation.js +2 -1
  502. package/dist/sql/navigation.js.map +1 -1
  503. package/dist/sql/source-graph.d.ts.map +1 -1
  504. package/dist/sql/source-graph.js +2 -2
  505. package/dist/sql/source-graph.js.map +1 -1
  506. package/dist/sqlite/schema.d.ts +1 -1
  507. package/dist/sqlite/schema.d.ts.map +1 -1
  508. package/dist/sqlite/schema.js +8 -2
  509. package/dist/sqlite/schema.js.map +1 -1
  510. package/dist/sqlite/write.js +2 -2
  511. package/dist/sqlite/write.js.map +1 -1
  512. package/dist/types.d.ts +2 -0
  513. package/dist/types.d.ts.map +1 -1
  514. package/dist/util/bloom-filter.d.ts +8 -1
  515. package/dist/util/bloom-filter.d.ts.map +1 -1
  516. package/dist/util/bloom-filter.js +15 -2
  517. package/dist/util/bloom-filter.js.map +1 -1
  518. package/dist/util/glob.d.ts +32 -0
  519. package/dist/util/glob.d.ts.map +1 -0
  520. package/dist/util/glob.js +137 -0
  521. package/dist/util/glob.js.map +1 -0
  522. package/dist/util/graph-edges.d.ts +19 -1
  523. package/dist/util/graph-edges.d.ts.map +1 -1
  524. package/dist/util/graph-edges.js +30 -4
  525. package/dist/util/graph-edges.js.map +1 -1
  526. package/dist/util/identifiers.d.ts +15 -0
  527. package/dist/util/identifiers.d.ts.map +1 -1
  528. package/dist/util/identifiers.js +35 -0
  529. package/dist/util/identifiers.js.map +1 -1
  530. package/dist/util/member-access-tables.d.ts +61 -4
  531. package/dist/util/member-access-tables.d.ts.map +1 -1
  532. package/dist/util/member-access-tables.js +139 -19
  533. package/dist/util/member-access-tables.js.map +1 -1
  534. package/dist/util/member-access.d.ts +17 -0
  535. package/dist/util/member-access.d.ts.map +1 -1
  536. package/dist/util/member-access.js +98 -3
  537. package/dist/util/member-access.js.map +1 -1
  538. package/dist/util/project-files.d.ts +2 -10
  539. package/dist/util/project-files.d.ts.map +1 -1
  540. package/dist/util/project-files.js +29 -51
  541. package/dist/util/project-files.js.map +1 -1
  542. package/dist/util/python-type-checking.d.ts +18 -0
  543. package/dist/util/python-type-checking.d.ts.map +1 -0
  544. package/dist/util/python-type-checking.js +160 -0
  545. package/dist/util/python-type-checking.js.map +1 -0
  546. package/dist/util/resolution/cargo-targets.d.ts +11 -0
  547. package/dist/util/resolution/cargo-targets.d.ts.map +1 -1
  548. package/dist/util/resolution/cargo-targets.js +174 -13
  549. package/dist/util/resolution/cargo-targets.js.map +1 -1
  550. package/dist/util/resolution/csharp.d.ts +33 -1
  551. package/dist/util/resolution/csharp.d.ts.map +1 -1
  552. package/dist/util/resolution/csharp.js +145 -30
  553. package/dist/util/resolution/csharp.js.map +1 -1
  554. package/dist/util/resolution/jvm.d.ts +7 -3
  555. package/dist/util/resolution/jvm.d.ts.map +1 -1
  556. package/dist/util/resolution/jvm.js +56 -38
  557. package/dist/util/resolution/jvm.js.map +1 -1
  558. package/dist/util/resolution/php.d.ts.map +1 -1
  559. package/dist/util/resolution/php.js +35 -8
  560. package/dist/util/resolution/php.js.map +1 -1
  561. package/dist/util/resolution/python.d.ts +9 -0
  562. package/dist/util/resolution/python.d.ts.map +1 -1
  563. package/dist/util/resolution/python.js +46 -0
  564. package/dist/util/resolution/python.js.map +1 -1
  565. package/dist/util/resolution/rust.d.ts +0 -1
  566. package/dist/util/resolution/rust.d.ts.map +1 -1
  567. package/dist/util/resolution/rust.js +95 -35
  568. package/dist/util/resolution/rust.js.map +1 -1
  569. package/dist/util/resolution/specifier-targets.d.ts +44 -0
  570. package/dist/util/resolution/specifier-targets.d.ts.map +1 -0
  571. package/dist/util/resolution/specifier-targets.js +152 -0
  572. package/dist/util/resolution/specifier-targets.js.map +1 -0
  573. package/dist/util/resolution-candidates.d.ts +5 -0
  574. package/dist/util/resolution-candidates.d.ts.map +1 -1
  575. package/dist/util/resolution-candidates.js +16 -3
  576. package/dist/util/resolution-candidates.js.map +1 -1
  577. package/dist/util/resolution.d.ts +2 -1
  578. package/dist/util/resolution.d.ts.map +1 -1
  579. package/dist/util/resolution.js +101 -15
  580. package/dist/util/resolution.js.map +1 -1
  581. package/dist/util/specifiers.d.ts +29 -1
  582. package/dist/util/specifiers.d.ts.map +1 -1
  583. package/dist/util/specifiers.js +56 -8
  584. package/dist/util/specifiers.js.map +1 -1
  585. package/dist/util/trivia.d.ts.map +1 -1
  586. package/dist/util/trivia.js +49 -30
  587. package/dist/util/trivia.js.map +1 -1
  588. package/dist/util/workspace.d.ts.map +1 -1
  589. package/dist/util/workspace.js +32 -4
  590. package/dist/util/workspace.js.map +1 -1
  591. package/docs/mcp.md +3 -2
  592. package/package.json +5 -7
  593. package/dist/impact/call-compatibility/providers/profiles.d.ts +0 -80
  594. package/dist/impact/call-compatibility/providers/profiles.d.ts.map +0 -1
  595. package/dist/impact/call-compatibility/providers/profiles.js +0 -164
  596. package/dist/impact/call-compatibility/providers/profiles.js.map +0 -1
@@ -1,10 +1,16 @@
1
1
  import { readFileSync } from "node:fs";
2
+ import { findCommentEnd } from "../../impact/call-compatibility/text-scanner.js";
3
+ import { isGoExportedMemberName } from "../../indexer/declaration-visibility.js";
4
+ import { hasSeparateMemberScopes, inheritsMemberOverloads, selectMember, } from "../../indexer/member-selection.js";
2
5
  import { SymbolKind } from "../../indexer/types.js";
6
+ import { supportForFileWithoutHeaderSample } from "../../languages.js";
7
+ import { isJsTsLanguage } from "../../languages/js-family.js";
3
8
  import { sliceText } from "../../util/ast.js";
4
- import { XID_IDENTIFIER_SOURCE } from "../../util/identifiers.js";
5
- import { MEMBER_ACCESS_ROWS } from "../../util/member-access-tables.js";
6
- import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isMemberReferencePropertyIdentifier, isReceiverNameNode, } from "../../util/member-access.js";
7
- const INSTANCE_RECEIVER_KEYWORDS = new Set(["this", "$this"]);
9
+ import { foldPhpIdentifierCase, XID_IDENTIFIER_SOURCE } from "../../util/identifiers.js";
10
+ import { fileIdentityKey } from "../../util/paths.js";
11
+ import { keywordReceiverKind, ownReceiverMemberScope } from "../../util/member-access-tables.js";
12
+ import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isMemberReferencePropertyIdentifier, isReceiverNameNode, receiverKeywordText, } from "../../util/member-access.js";
13
+ import { declarationMemberArity, findFirstNodeByType, isIdentifierType, PARAMETER_LIST_NODE_TYPES } from "./ast.js";
8
14
  /** Languages whose grammar distinguishes static members from instance members. */
9
15
  const STATIC_MEMBER_LANGUAGES = {
10
16
  cpp: true,
@@ -12,15 +18,74 @@ const STATIC_MEMBER_LANGUAGES = {
12
18
  java: true,
13
19
  js: true,
14
20
  php: true,
21
+ ruby: true,
15
22
  swift: true,
16
23
  ts: true,
17
24
  tsx: true,
18
25
  };
26
+ const MEMBER_OVERLOAD_LANGUAGE_IDS = {
27
+ cpp: true,
28
+ csharp: true,
29
+ java: true,
30
+ kotlin: true,
31
+ swift: true,
32
+ ts: true,
33
+ tsx: true,
34
+ };
35
+ /** Bare calls inside members can target a proven member even without an explicit receiver. */
36
+ const IMPLICIT_SELF_MEMBER_CALL_LANGUAGES = {
37
+ csharp: true,
38
+ swift: true,
39
+ };
40
+ /** Whether a bare, receiver-less call inside a member function may target `this`/an inherited member. */
41
+ export function supportsImplicitSelfMemberCalls(languageId) {
42
+ return !!IMPLICIT_SELF_MEMBER_CALL_LANGUAGES[languageId];
43
+ }
44
+ /** Whether member lookup uses call arity to select or reject same-name declarations. */
45
+ export function supportsReceiverMemberOverloads(languageId) {
46
+ return !!MEMBER_OVERLOAD_LANGUAGE_IDS[languageId];
47
+ }
19
48
  /** Every language with a static-member distinction, guarded by the registry-consistency test. */
20
49
  export const staticMemberLanguageIds = Object.keys(STATIC_MEMBER_LANGUAGES);
21
50
  export function hasStaticMemberDistinction(languageId) {
22
51
  return STATIC_MEMBER_LANGUAGES[languageId] !== undefined;
23
52
  }
53
+ /**
54
+ * Languages whose grammar gives members a static-equivalent scope without a `static` keyword:
55
+ * a Kotlin member of a `companion object` or a named `object` declaration is reachable as
56
+ * `Outer.member()`. Member lookup classifies those members "static" and every other member
57
+ * "instance", matching the keyword-`static` languages.
58
+ */
59
+ const STATIC_EQUIVALENT_MEMBER_CONTAINERS = {
60
+ kotlin: { companion_object: true, object_declaration: true },
61
+ };
62
+ /**
63
+ * Whether `node` is lexically declared inside its language's static-equivalent member
64
+ * container. The nearest enclosing member container decides: a nested type's members belong
65
+ * to that type, not to an outer `object`.
66
+ */
67
+ export function declarationIsStaticEquivalent(languageId, node) {
68
+ const containers = STATIC_EQUIVALENT_MEMBER_CONTAINERS[languageId];
69
+ if (!containers)
70
+ return false;
71
+ let current = node.parent;
72
+ while (current) {
73
+ if (containers[current.type] === true)
74
+ return true;
75
+ if (MEMBER_CONTAINER_TYPES[current.type] === true)
76
+ return false;
77
+ current = current.parent;
78
+ }
79
+ return false;
80
+ }
81
+ /**
82
+ * Whether member lookup for `languageId` distinguishes static-equivalent members from
83
+ * instance members. A bare type-name receiver restricts lookup to the static-equivalent
84
+ * scope exactly when this holds; otherwise every member must stay reachable.
85
+ */
86
+ export function supportsStaticMemberScope(languageId) {
87
+ return (STATIC_MEMBER_LANGUAGES[languageId] !== undefined || STATIC_EQUIVALENT_MEMBER_CONTAINERS[languageId] !== undefined);
88
+ }
24
89
  /**
25
90
  * Call nodes that carry the receiver and the member name on the call node itself
26
91
  * instead of exposing a member-access callee.
@@ -51,6 +116,25 @@ const MEMBER_CONTAINER_TYPES = {
51
116
  struct_specifier: true,
52
117
  trait_declaration: true,
53
118
  trait_item: true,
119
+ type_alias_declaration: true,
120
+ // C/C++ unions declare members exactly like structs (tree-sitter-cpp captures
121
+ // union names and classifies them as classes).
122
+ union_specifier: true,
123
+ };
124
+ const CPP_MEMBER_CONTAINER_TYPES = {
125
+ class_specifier: true,
126
+ struct_specifier: true,
127
+ union_specifier: true,
128
+ };
129
+ /**
130
+ * Container nodes whose declared members belong to the *enclosing* member container for
131
+ * direct-member lookup, rather than forming a separate nested type. Kotlin's unnamed
132
+ * `companion object { ... }` block is the language's static-member mechanism: `create()`
133
+ * declared inside one is a member of the enclosing class, reachable as `Outer.create()`,
134
+ * not a member of a distinct "Companion" type the indexer would need to name separately.
135
+ */
136
+ export const TRANSPARENT_MEMBER_CONTAINER_TYPES = {
137
+ companion_object: true,
54
138
  };
55
139
  /** Nodes holding a call's argument list across the supported grammars. */
56
140
  export const CALL_ARGUMENT_NODE_TYPES = {
@@ -66,6 +150,16 @@ const HIERARCHY_LABELS = {
66
150
  mixin: true,
67
151
  trait: true,
68
152
  };
153
+ const UNPROVEN_HERITAGE_EXPRESSION_TYPES = new Set([
154
+ "binary_expression",
155
+ "call_expression",
156
+ "new_expression",
157
+ "subscript_expression",
158
+ "ternary_expression",
159
+ ]);
160
+ export function isUnprovenHeritageExpression(node) {
161
+ return UNPROVEN_HERITAGE_EXPRESSION_TYPES.has(node.type);
162
+ }
69
163
  /**
70
164
  * Nodes that bind a value name across the supported grammars: locals, parameters,
71
165
  * and assignment targets. A receiver naming one of these is a value, not a type.
@@ -75,6 +169,9 @@ const VALUE_BINDING_TYPES = {
75
169
  assignment_expression: true,
76
170
  assignment_statement: true,
77
171
  class_parameter: true,
172
+ // C/C++ local variable statement (`Box b;`, `Box* p = raw;`); the declared type sits
173
+ // beside the declarator, unlike other grammars' dedicated `variable_declaration` node.
174
+ declaration: true,
78
175
  formal_parameter: true,
79
176
  init_declarator: true,
80
177
  let_declaration: true,
@@ -90,21 +187,6 @@ const VALUE_BINDING_TYPES = {
90
187
  variable_declaration: true,
91
188
  variable_declarator: true,
92
189
  };
93
- /**
94
- * Parameter lists whose identifier children are value bindings (Ruby has no wrapping param node).
95
- * Union of the receiver-call and call-compatibility lists so Kotlin `function_value_parameters`
96
- * and Ruby `block_parameters` are both recognized.
97
- */
98
- export const PARAMETER_LIST_NODE_TYPES = {
99
- block_parameters: true,
100
- formal_parameters: true,
101
- function_parameter_clause: true,
102
- function_value_parameters: true,
103
- lambda_parameters: true,
104
- method_parameters: true,
105
- parameter_list: true,
106
- parameters: true,
107
- };
108
190
  /**
109
191
  * Access nodes whose syntax is type-scoped (`::`), not dotted member access.
110
192
  * A dotted identifier is never itself proof of a type.
@@ -180,6 +262,8 @@ const BINDING_DECLARATION_TYPES = new Set([
180
262
  "property_declaration",
181
263
  "local_variable_declaration",
182
264
  "local_declaration_statement",
265
+ // C/C++ local variable statement, e.g. `Box b;`, `Box* p = raw;`, `Box w{5};`.
266
+ "declaration",
183
267
  ]);
184
268
  const RUBY_CONSTANT_SOURCE = String.raw `(?=\p{Lu})${XID_IDENTIFIER_SOURCE}`;
185
269
  /** Proven construction forms that name a receiver's type, keyed by language. */
@@ -193,14 +277,12 @@ const LANGUAGE_CONSTRUCTION_FORMS = {
193
277
  php: { newExpression: true },
194
278
  python: { capitalizedCall: true },
195
279
  ruby: { rubyNew: true },
196
- rust: { capitalizedCall: true, rustUnitStruct: true },
280
+ rust: { capitalizedCall: true, rustUnitStruct: true, compositeLiteral: true },
197
281
  swift: { capitalizedCall: true },
198
282
  ts: { newExpression: true },
199
283
  tsx: { newExpression: true },
200
284
  zig: { compositeLiteral: true },
201
285
  };
202
- /** Guards against a cyclic or pathological declared hierarchy. */
203
- const MAX_SUPERTYPE_DEPTH = 16;
204
286
  /**
205
287
  * Resolves the receiver and member-name nodes of a call, or null when the call has no
206
288
  * receiver or its shape is not a member access. `callee` is the call's resolved callee
@@ -237,12 +319,13 @@ export function receiverCallAccess(sup, callNode, callee) {
237
319
  return { accessNode, receiver, property };
238
320
  }
239
321
  /**
240
- * Identifier a binding node declares: a `name` field, a nested C/C++ declarator,
241
- * an assignment left-hand side, or the last identifier child (C++ parameters hide
242
- * the name after the type).
322
+ * Identifier a binding node declares: a `name` or `pattern` field, a nested C/C++
323
+ * declarator, an assignment left-hand side, or the last identifier child (C++
324
+ * parameters hide the name after the type). Rust spells parameter and `let` names in
325
+ * the `pattern` field, where the last-identifier fallback would pick the declared type.
243
326
  */
244
327
  function bindingIdentifier(node, sup) {
245
- const named = node.childForFieldName("name");
328
+ const named = node.childForFieldName("name") ?? node.childForFieldName("pattern");
246
329
  if (named && (isReceiverNameNode(sup, named.type) || named.type === "field_identifier")) {
247
330
  return named;
248
331
  }
@@ -323,6 +406,17 @@ function containsIndex(node, index) {
323
406
  return node.startIndex <= index && node.endIndex >= index;
324
407
  }
325
408
  function constructorNameNode(node, sup) {
409
+ // A dedicated `type` field (C#'s `object_creation_expression`, C/C++'s `new_expression`) can
410
+ // wrap a qualified (`Outer.Inner`) or generic (`Box<int>`) shape the fallback scan below never
411
+ // matches; a language without that field (TS/PHP's `constructor` field, or none) falls through.
412
+ const typeField = node.childForFieldName("type");
413
+ if (typeField) {
414
+ if (isMemberAccessNode(sup, typeField))
415
+ return typeField;
416
+ const unwrapped = unwrapNamedType(typeField, sup);
417
+ if (unwrapped)
418
+ return unwrapped;
419
+ }
326
420
  const constructor = node.childForFieldName("constructor") ?? node.child(0);
327
421
  if (constructor && isReceiverNameNode(sup, constructor.type)) {
328
422
  return constructor;
@@ -334,14 +428,85 @@ function constructorNameNode(node, sup) {
334
428
  }
335
429
  return null;
336
430
  }
431
+ const PHP_OBJECT_CREATION_KEYWORDS = {
432
+ self: "self",
433
+ static: "static",
434
+ parent: "parent",
435
+ };
436
+ export function phpObjectCreationKeyword(node, source, sup) {
437
+ if (sup.id !== "php")
438
+ return null;
439
+ let creation = node;
440
+ while (creation && creation.type !== "object_creation_expression") {
441
+ if (creation.type === "method_declaration" ||
442
+ creation.type === "function_definition" ||
443
+ creation.type === "class_declaration") {
444
+ return null;
445
+ }
446
+ creation = creation.parent;
447
+ }
448
+ if (!creation)
449
+ return null;
450
+ const nameNode = constructorNameNode(creation, sup);
451
+ if (!nameNode)
452
+ return null;
453
+ const onName = node === creation || (node.startIndex >= nameNode.startIndex && node.endIndex <= nameNode.endIndex);
454
+ if (!onName)
455
+ return null;
456
+ const keyword = PHP_OBJECT_CREATION_KEYWORDS[foldPhpIdentifierCase(sliceText(nameNode, source))];
457
+ if (!keyword)
458
+ return null;
459
+ const container = nearestMemberContainer(creation);
460
+ const classNode = container?.type === "class_declaration" ? container : null;
461
+ return { keyword, nameNode, classNode };
462
+ }
463
+ /** Members-declaring symbol whose name node is this container's name, when that match is unique. */
464
+ export function memberContainerDef(mod, container) {
465
+ const nameNode = container.childForFieldName("name");
466
+ if (!nameNode)
467
+ return null;
468
+ const matches = mod.locals.filter((local) => declaresMembers(local) && local.range.start.index === nameNode.startIndex);
469
+ return matches.length === 1 ? (matches[0] ?? null) : null;
470
+ }
337
471
  function rubyNewReceiverNameNode(node, source, sup) {
338
472
  if (!new RegExp(String.raw `^(?:${RUBY_CONSTANT_SOURCE})\.new$`, "u").test(sliceText(node, source)))
339
473
  return null;
340
474
  return node.namedChildren.find((child) => isReceiverNameNode(sup, child.type) || child.type === "constant") ?? null;
341
475
  }
476
+ const NULLISH_TYPE_TEXT = new Set(["undefined", "null", "void"]);
477
+ /**
478
+ * The `typeof import("spec")` type query a TypeScript annotation names, ignoring `| undefined` and
479
+ * `| null`: such a binding holds the module namespace of `spec`.
480
+ */
481
+ export function typescriptImportTypeQuery(annotation) {
482
+ let current = annotation;
483
+ while (current?.type === "type_annotation")
484
+ current = current.namedChildren[0] ?? null;
485
+ if (current?.type === "union_type") {
486
+ const members = current.namedChildren.filter((member) => !NULLISH_TYPE_TEXT.has(member.text.trim()));
487
+ current = members.length === 1 ? members[0] : null;
488
+ }
489
+ if (current?.type !== "type_query")
490
+ return null;
491
+ const call = current.namedChildren[0];
492
+ return call?.type === "call_expression" && call.childForFieldName("function")?.type === "import" ? current : null;
493
+ }
494
+ /** The module specifier of a `typeof import("spec")` type query. */
495
+ export function importTypeQuerySpecifier(typeQuery) {
496
+ const argument = typeQuery.namedChildren[0]?.childForFieldName("arguments")?.namedChildren[0];
497
+ if (argument?.type !== "string")
498
+ return null;
499
+ return argument.namedChildren.find((child) => child.type === "string_fragment")?.text ?? null;
500
+ }
342
501
  export function unwrapNamedType(node, sup) {
343
502
  let current = node;
344
503
  while (current) {
504
+ if (current.type === "union_type") {
505
+ // `Store | undefined` and `Store | null` still prove `Store` for a member call.
506
+ const members = current.namedChildren.filter((member) => !NULLISH_TYPE_TEXT.has(member.text.trim()));
507
+ current = members.length === 1 ? members[0] : null;
508
+ continue;
509
+ }
345
510
  if (current.type === "type_annotation" ||
346
511
  current.type === "named_type" ||
347
512
  current.type === "user_type" ||
@@ -358,6 +523,16 @@ export function unwrapNamedType(node, sup) {
358
523
  current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
359
524
  continue;
360
525
  }
526
+ if (current.type === "qualified_name") {
527
+ // C#'s `Outer.Inner` names the nested type by its last segment. PHP also parses a
528
+ // namespaced name as `qualified_name`, but as one flat token with no `name` field, so an
529
+ // absent field leaves `current` as that whole node instead of nulling the result out.
530
+ const segment = current.childForFieldName("name");
531
+ if (!segment)
532
+ break;
533
+ current = segment;
534
+ continue;
535
+ }
361
536
  break;
362
537
  }
363
538
  if (!current)
@@ -367,6 +542,34 @@ export function unwrapNamedType(node, sup) {
367
542
  }
368
543
  return null;
369
544
  }
545
+ /**
546
+ * Kotlin extension-function receiver type, e.g. `Widget` in `fun Widget.describe(): String`.
547
+ * The receiver type is an unfielded `user_type` positioned before the function's own `name`;
548
+ * an ordinary function or class member declares no such node.
549
+ */
550
+ export function kotlinExtensionReceiverTypeNode(node, sup) {
551
+ if (node.type !== "function_declaration")
552
+ return null;
553
+ const nameNode = node.childForFieldName("name");
554
+ if (!nameNode)
555
+ return null;
556
+ const receiverType = node.namedChildren.find((child) => child.startIndex < nameNode.startIndex && (child.type === "user_type" || child.type === "nullable_type"));
557
+ return receiverType ? unwrapNamedType(receiverType, sup) : null;
558
+ }
559
+ /**
560
+ * Self-type name node of a Rust `impl` block: `Circle` in `impl Circle`, `impl Shape for
561
+ * Circle`, `impl<T> Box<T>`, or `impl Shape for &Circle`. The `type` field always names the
562
+ * self type (the `trait` field names the implemented trait), and `unwrapNamedType` strips
563
+ * generic and reference wrappers down to the base type identifier. Shared by member
564
+ * ownership in the detailed graph and receiver-member navigation so both attribute an
565
+ * impl method to the same owner.
566
+ */
567
+ export function rustImplSelfTypeNode(implItem, sup) {
568
+ if (implItem.type !== "impl_item")
569
+ return null;
570
+ const typeNode = implItem.childForFieldName("type");
571
+ return typeNode ? unwrapNamedType(typeNode, sup) : null;
572
+ }
370
573
  function capitalizedCallTypeName(expr, source, sup) {
371
574
  if (expr.type !== "call" && expr.type !== "call_expression")
372
575
  return null;
@@ -395,11 +598,21 @@ function compositeLiteralTypeName(expr, source, sup) {
395
598
  return null;
396
599
  current = operand;
397
600
  }
398
- if (current.type !== "composite_literal" && current.type !== "struct_initializer")
601
+ // tree-sitter-go composite_literal, tree-sitter-zig struct_initializer, tree-sitter-rust
602
+ // struct_expression: `Type { field: value }` / `Type{ .field = value }`.
603
+ if (current.type !== "composite_literal" &&
604
+ current.type !== "struct_initializer" &&
605
+ current.type !== "struct_expression") {
399
606
  return null;
607
+ }
400
608
  const typeNode = current.childForFieldName("type") ??
401
- current.namedChildren.find((child) => child.type === "type_identifier" || child.type === "identifier") ??
609
+ current.namedChildren.find((child) => child.type === "type_identifier" ||
610
+ child.type === "identifier" ||
611
+ child.type === sup.nodeTypes.memberExpression) ??
402
612
  null;
613
+ // A qualified literal type (Zig `ns.Struct{...}`) has no dedicated `type` field and is not a
614
+ // simple named type either; `unwrapNamedType` rejects it, so the member-access node itself is
615
+ // kept so the caller can resolve it the same way as any other qualified expression.
403
616
  return typeNode ? (unwrapNamedType(typeNode, sup) ?? typeNode) : null;
404
617
  }
405
618
  /**
@@ -455,16 +668,18 @@ function bindingValueExpression(node) {
455
668
  ]);
456
669
  return node.namedChildren.find((child) => expressionTypes.has(child.type)) ?? null;
457
670
  }
458
- function declaredTypeNameNode(node, sup) {
671
+ export function declaredTypeNameNode(node, sup) {
459
672
  const typeField = node.childForFieldName("type");
460
673
  if (typeField)
461
- return unwrapNamedType(typeField, sup);
674
+ return unwrapNamedType(typeField, sup) ?? typeField;
462
675
  const typedChild = node.namedChildren.find((child) => child.type === "named_type" ||
463
676
  child.type === "user_type" ||
464
677
  child.type === "type_annotation" ||
465
678
  child.type === "type");
466
679
  if (typedChild)
467
- return unwrapNamedType(typedChild, sup);
680
+ return unwrapNamedType(typedChild, sup) ?? typedChild;
681
+ if (node.type === "let_declaration")
682
+ return null;
468
683
  const ids = node.namedChildren.filter((child) => isReceiverNameNode(sup, child.type) || child.type === "type_identifier" || child.type === "name");
469
684
  if (ids.length >= 2)
470
685
  return unwrapNamedType(ids[0], sup);
@@ -542,6 +757,13 @@ function bindingProof(node, receiverName, source, sup) {
542
757
  return { status: "none" };
543
758
  if (!bindingDeclaresReceiverName(node, receiverName, source, sup))
544
759
  return { status: "none" };
760
+ const annotation = isJsTsLanguage(sup.id) ? node.childForFieldName("type") : null;
761
+ const annotated = annotation ? (unwrapNamedType(annotation, sup) ?? typescriptImportTypeQuery(annotation)) : null;
762
+ if (annotated)
763
+ return { status: "declared", node: annotated };
764
+ const declared = declaredTypeNameNode(node, sup);
765
+ if (declared)
766
+ return { status: "declared", node: declared };
545
767
  const typeNode = constructionTypeFromBinding(node, receiverName, source, sup);
546
768
  if (typeNode)
547
769
  return { status: "type", node: typeNode };
@@ -551,17 +773,26 @@ function isSkippableBindingContainer(node, receiver) {
551
773
  return BINDING_CONTAINER_TYPES.has(node.type) && !containsIndex(node, receiver.startIndex);
552
774
  }
553
775
  function findPriorConstructorInContainer(node, receiver, receiverName, source, sup) {
554
- let constructor = null;
776
+ let typeEvidence = null;
555
777
  let sawUnproven = false;
778
+ let declared = false;
556
779
  const visit = (current) => {
557
780
  if (current.startIndex >= receiver.startIndex)
558
781
  return true;
559
782
  if (current !== node && isSkippableBindingContainer(current, receiver))
560
783
  return true;
561
784
  const proof = bindingProof(current, receiverName, source, sup);
785
+ if (proof.status === "declared") {
786
+ typeEvidence = { typeNode: proof.node, origin: "declared-type" };
787
+ declared = isJsTsLanguage(sup.id);
788
+ return true;
789
+ }
790
+ // A later assignment to an annotated binding cannot change its declared type.
791
+ if (declared && proof.status !== "none")
792
+ return true;
562
793
  if (proof.status === "unproven") {
563
- if (constructor) {
564
- constructor = null;
794
+ if (typeEvidence) {
795
+ typeEvidence = null;
565
796
  return false;
566
797
  }
567
798
  sawUnproven = true;
@@ -569,14 +800,14 @@ function findPriorConstructorInContainer(node, receiver, receiverName, source, s
569
800
  }
570
801
  if (proof.status === "type") {
571
802
  if (sawUnproven) {
572
- constructor = null;
803
+ typeEvidence = null;
573
804
  return false;
574
805
  }
575
- if (constructor && sliceText(constructor, source) !== sliceText(proof.node, source)) {
576
- constructor = null;
806
+ if (typeEvidence && sliceText(typeEvidence.typeNode, source) !== sliceText(proof.node, source)) {
807
+ typeEvidence = null;
577
808
  return false;
578
809
  }
579
- constructor = proof.node;
810
+ typeEvidence = { typeNode: proof.node, origin: "constructor" };
580
811
  return true;
581
812
  }
582
813
  for (const child of current.namedChildren) {
@@ -586,7 +817,7 @@ function findPriorConstructorInContainer(node, receiver, receiverName, source, s
586
817
  return true;
587
818
  };
588
819
  visit(node);
589
- return constructor;
820
+ return typeEvidence;
590
821
  }
591
822
  function bindingContainerDeclaresNameBefore(node, receiver, receiverName, source, sup) {
592
823
  const visit = (current) => {
@@ -594,7 +825,10 @@ function bindingContainerDeclaresNameBefore(node, receiver, receiverName, source
594
825
  return false;
595
826
  if (current !== node && isSkippableBindingContainer(current, receiver))
596
827
  return false;
597
- if (BINDING_DECLARATION_TYPES.has(current.type) &&
828
+ // A JavaScript/TypeScript assignment updates an existing binding; it declares nothing.
829
+ const declaresNewBinding = !(isJsTsLanguage(sup.id) && current.type === "assignment_expression");
830
+ if (declaresNewBinding &&
831
+ BINDING_DECLARATION_TYPES.has(current.type) &&
598
832
  bindingDeclaresReceiverName(current, receiverName, source, sup)) {
599
833
  return true;
600
834
  }
@@ -625,79 +859,402 @@ function findVisiblePriorConstructor(receiver, receiverName, source, sup) {
625
859
  }
626
860
  return findPriorConstructorInContainer(rootOf(receiver), receiver, receiverName, source, sup);
627
861
  }
628
- /**
629
- * Resolves the node naming the type a receiver expression was constructed from, or
630
- * null when no constructor is proven for it. Shared with detailed symbol-graph call
631
- * extraction so `goto` and resolved `calls` edges accept the same receiver forms.
632
- */
633
- export function receiverConstructorExpression(obj, source, sup) {
862
+ /** Constructor or declared type visible at a receiver, without resolving its owner. */
863
+ function receiverTypeEvidence(obj, source, sup) {
634
864
  const direct = constructionTypeName(obj, source, sup);
635
- if (direct)
636
- return direct;
637
865
  if (!isReceiverNameNode(sup, obj.type))
638
- return null;
866
+ return direct ? { typeNode: direct, origin: "constructor" } : null;
639
867
  const receiverName = sliceText(obj, source);
868
+ if (direct && !bindsLocalValue(obj, receiverName, source, sup)) {
869
+ return { typeNode: direct, origin: "constructor" };
870
+ }
640
871
  return findVisiblePriorConstructor(obj, receiverName, source, sup);
641
872
  }
642
- function ownTypeMemberScope(receiverName) {
643
- return INSTANCE_RECEIVER_KEYWORDS.has(receiverName) ? "instance" : "any";
873
+ /** Syntax naming the type of a constructed or declared receiver. */
874
+ export function receiverConstructorExpression(obj, source, sup) {
875
+ return receiverTypeEvidence(obj, source, sup)?.typeNode ?? null;
876
+ }
877
+ /** Identifier segments in a C++ qualified name, excluding template arguments. */
878
+ export function cppQualifiedNameSegments(node, source) {
879
+ return cppQualifiedTextSegments(sliceText(node, source));
880
+ }
881
+ /** `::`-separated segments of a C++ qualified name, ignoring `::` inside template arguments and dropping them. */
882
+ export function cppQualifiedTextSegments(text) {
883
+ const segments = [];
884
+ let segmentStart = 0;
885
+ let templateDepth = 0;
886
+ for (let index = 0; index < text.length; index += 1) {
887
+ const char = text[index];
888
+ if (char === "<") {
889
+ templateDepth += 1;
890
+ continue;
891
+ }
892
+ if (char === ">") {
893
+ templateDepth = Math.max(0, templateDepth - 1);
894
+ continue;
895
+ }
896
+ if (char !== ":" || text[index + 1] !== ":" || templateDepth !== 0)
897
+ continue;
898
+ const segment = text.slice(segmentStart, index).trim();
899
+ if (segment)
900
+ segments.push(segment.replace(/<.*$/u, "").trim());
901
+ segmentStart = index + 2;
902
+ index += 1;
903
+ }
904
+ const finalSegment = text.slice(segmentStart).trim();
905
+ if (finalSegment)
906
+ segments.push(finalSegment.replace(/<.*$/u, "").trim());
907
+ return segments.filter(Boolean);
908
+ }
909
+ /** Exact namespace/type path that qualifies a C++ out-of-line function definition. */
910
+ export function cppOutOfLineOwnerPath(node, source, sup) {
911
+ if (sup.id !== "cpp")
912
+ return null;
913
+ let current = node;
914
+ while (current) {
915
+ if (current.type === "function_definition") {
916
+ let declarator = current.childForFieldName("declarator");
917
+ while (declarator) {
918
+ if (declarator.type === "qualified_identifier") {
919
+ const path = cppQualifiedNameSegments(declarator, source);
920
+ path.pop();
921
+ if (!sliceText(declarator, source).trimStart().startsWith("::")) {
922
+ const namespaces = [];
923
+ let parent = current.parent;
924
+ while (parent) {
925
+ if (parent.type === "namespace_definition") {
926
+ const name = parent.childForFieldName("name");
927
+ if (name)
928
+ namespaces.push(cppQualifiedNameSegments(name, source));
929
+ }
930
+ parent = parent.parent;
931
+ }
932
+ for (const namespace of namespaces.reverse())
933
+ path.unshift(...namespace);
934
+ }
935
+ return path.length ? path : null;
936
+ }
937
+ const nested = declarator.childForFieldName("declarator") ?? declarator.namedChildren.at(-1);
938
+ if (!nested || nested.id === declarator.id)
939
+ break;
940
+ declarator = nested;
941
+ }
942
+ return null;
943
+ }
944
+ current = current.parent;
945
+ }
946
+ return null;
947
+ }
948
+ /** Unqualified member name from a C++ out-of-line function definition. */
949
+ export function cppOutOfLineMemberName(node, source, sup) {
950
+ if (sup.id !== "cpp")
951
+ return null;
952
+ let current = node;
953
+ while (current) {
954
+ if (current.type === "function_definition") {
955
+ const nameNode = cppFunctionDeclaratorName(current, sup);
956
+ return nameNode ? sliceText(nameNode, source) : null;
957
+ }
958
+ current = current.parent;
959
+ }
960
+ return null;
961
+ }
962
+ function sameSyntaxNode(left, right) {
963
+ if (!left)
964
+ return false;
965
+ if (left.id !== undefined && right.id !== undefined)
966
+ return left.id === right.id;
967
+ return left.type === right.type && left.startIndex === right.startIndex && left.endIndex === right.endIndex;
968
+ }
969
+ function cppFunctionDeclaratorName(node, sup) {
970
+ const functionDeclarator = node.type === "function_declarator" ? node : findFirstNodeByType(node, "function_declarator");
971
+ let current = functionDeclarator?.childForFieldName("declarator") ?? null;
972
+ while (current) {
973
+ if (isIdentifierType(sup, current.type) || current.type === "operator_name" || current.type === "destructor_name") {
974
+ return current;
975
+ }
976
+ let name = current.childForFieldName("name");
977
+ while (name?.childForFieldName("name"))
978
+ name = name.childForFieldName("name");
979
+ if (name &&
980
+ (isIdentifierType(sup, name.type) || name.type === "operator_name" || name.type === "destructor_name")) {
981
+ return name;
982
+ }
983
+ const nested = current.childForFieldName("declarator");
984
+ if (!nested || nested.id === current.id)
985
+ return null;
986
+ current = nested;
987
+ }
988
+ return null;
989
+ }
990
+ function cppMemberArityFromAncestor(node) {
991
+ let current = node;
992
+ while (current) {
993
+ const arity = declarationMemberArity(current, "cpp");
994
+ if (arity !== undefined)
995
+ return arity;
996
+ current = current.parent;
997
+ }
998
+ return undefined;
999
+ }
1000
+ function collectCppMemberDeclarations(node, ownerNode, localName, ownerSource, sup, expectedArity, out) {
1001
+ if ((node.type === "field_declaration" || node.type === "declaration") &&
1002
+ sameSyntaxNode(nearestMemberContainer(node), ownerNode)) {
1003
+ const nameNode = cppFunctionDeclaratorName(node, sup);
1004
+ if (nameNode &&
1005
+ sup.normalizeIdentifier(sliceText(nameNode, ownerSource)) === sup.normalizeIdentifier(localName) &&
1006
+ declarationMemberArity(node, sup.id) === expectedArity) {
1007
+ out.push({ node, nameNode });
1008
+ }
1009
+ return;
1010
+ }
1011
+ for (const child of node.namedChildren) {
1012
+ collectCppMemberDeclarations(child, ownerNode, localName, ownerSource, sup, expectedArity, out);
1013
+ }
644
1014
  }
645
1015
  /**
646
- * Classifies a receiver as the declaring type, a supertype, or a named/constructed type.
647
- * Returns null when the receiver cannot be proven.
648
- * Named-local constructor lookup is memoized per enclosing function and receiver text.
1016
+ * Finds the unique in-class declaration corresponding to a C++ out-of-line member
1017
+ * definition. Name and arity must both match so overloads do not collapse.
649
1018
  */
650
- export function classifyReceiver(sup, receiver, source, proofCache, cacheScope, accessNode) {
651
- const keywords = MEMBER_ACCESS_ROWS[sup.id]?.receiverKeywords;
652
- const text = sliceText(receiver, source).trim();
653
- if (!text)
1019
+ export function cppOutOfLineMemberDeclarationNode(definitionNameNode, localName, ownerNameNode, ownerSource, sup) {
1020
+ if (sup.id !== "cpp")
654
1021
  return null;
655
- if (keywords?.own.includes(text))
656
- return { kind: "own-type", memberScope: ownTypeMemberScope(text) };
657
- if (keywords?.supertype.includes(text))
658
- return { kind: "supertype", memberScope: "any" };
1022
+ const ownerNode = nearestMemberContainer(ownerNameNode);
1023
+ if (!ownerNode)
1024
+ return null;
1025
+ const expectedArity = cppMemberArityFromAncestor(definitionNameNode);
1026
+ const declarations = [];
1027
+ collectCppMemberDeclarations(ownerNode, ownerNode, localName, ownerSource, sup, expectedArity, declarations);
1028
+ return declarations.length === 1 ? declarations[0] : null;
1029
+ }
1030
+ export function nodeDeclaresStatic(node, source) {
1031
+ if (node.type === "singleton_method") {
1032
+ const receiver = node.childForFieldName("object") ?? node.childForFieldName("receiver") ?? node.namedChildren[0];
1033
+ return !!receiver && sliceText(receiver, source).trim() === "self";
1034
+ }
1035
+ if (node.type === "static" || node.type === "static_modifier")
1036
+ return true;
1037
+ if (node.type === "storage_class_specifier" || node.type === "modifier" || node.type === "property_modifier") {
1038
+ return sliceText(node, source).trim() === "static";
1039
+ }
1040
+ if (node.type === "class") {
1041
+ const parentType = node.parent?.type;
1042
+ return (parentType === "function_declaration" ||
1043
+ parentType === "property_declaration" ||
1044
+ parentType === "subscript_declaration");
1045
+ }
1046
+ if (node.type === "modifiers") {
1047
+ for (let childIndex = 0;; childIndex += 1) {
1048
+ const child = node.child(childIndex);
1049
+ if (!child)
1050
+ break;
1051
+ if (nodeDeclaresStatic(child, source))
1052
+ return true;
1053
+ }
1054
+ }
1055
+ return false;
1056
+ }
1057
+ export function declarationNodeIsStatic(node, source) {
1058
+ if (nodeDeclaresStatic(node, source))
1059
+ return true;
1060
+ for (let childIndex = 0;; childIndex += 1) {
1061
+ const child = node.child(childIndex);
1062
+ if (!child)
1063
+ return false;
1064
+ if (nodeDeclaresStatic(child, source))
1065
+ return true;
1066
+ }
1067
+ }
1068
+ export function nodeInStaticMemberContext(node, source) {
1069
+ const container = nearestMemberContainer(node);
1070
+ if (!container)
1071
+ return false;
1072
+ let current = node;
1073
+ while (current && current !== container) {
1074
+ if (declarationNodeIsStatic(current, source))
1075
+ return true;
1076
+ current = current.parent;
1077
+ }
1078
+ return false;
1079
+ }
1080
+ const JS_TS_DYNAMIC_THIS_FUNCTION_TYPES = {
1081
+ function: true,
1082
+ function_declaration: true,
1083
+ function_expression: true,
1084
+ generator_function: true,
1085
+ generator_function_declaration: true,
1086
+ method_definition: true,
1087
+ };
1088
+ /**
1089
+ * Ordinary JS/TS functions and object-literal methods own `this`/`super`; arrows preserve the
1090
+ * enclosing class member's receiver. Crossing one of those dynamic boundaries makes the class
1091
+ * receiver unproven.
1092
+ */
1093
+ export function keywordReceiverCrossesDynamicBoundary(sup, node) {
1094
+ if (!isJsTsLanguage(sup.id))
1095
+ return false;
1096
+ const container = nearestMemberContainer(node);
1097
+ if (!container)
1098
+ return false;
1099
+ let current = node.parent;
1100
+ while (current && current !== container) {
1101
+ if (JS_TS_DYNAMIC_THIS_FUNCTION_TYPES[current.type]) {
1102
+ const directlyOwnedClassMethod = current.type === "method_definition" &&
1103
+ current.parent?.type === "class_body" &&
1104
+ current.parent.parent?.startIndex === container.startIndex;
1105
+ return !directlyOwnedClassMethod;
1106
+ }
1107
+ current = current.parent;
1108
+ }
1109
+ return false;
1110
+ }
1111
+ export function keywordReceiverMemberScope(sup, receiverName, node, source) {
1112
+ if (!hasStaticMemberDistinction(sup.id))
1113
+ return "any";
1114
+ if (nodeInStaticMemberContext(node, source))
1115
+ return "static";
1116
+ const kind = keywordReceiverKind(sup.id, receiverName);
1117
+ if (kind === "supertype")
1118
+ return "instance";
1119
+ return ownReceiverMemberScope(sup.id, receiverName) ?? "any";
1120
+ }
1121
+ /**
1122
+ * The leftmost identifier of a C# chain of plain identifiers joined by `.` (`P` in `P.Inner.Mix`),
1123
+ * or `null` when `node` has a call, index, keyword, or type arguments. When that identifier binds
1124
+ * nothing, the chain is a namespace-qualified type name.
1125
+ */
1126
+ export function csharpDottedNameRoot(node) {
1127
+ if (node.type === "identifier")
1128
+ return node;
1129
+ if (node.type !== "member_access_expression")
1130
+ return null;
1131
+ const object = node.childForFieldName("expression");
1132
+ if (!object || node.childForFieldName("name")?.type !== "identifier")
1133
+ return null;
1134
+ return csharpDottedNameRoot(object);
1135
+ }
1136
+ /** Classify a receiver from syntax and consumer-proven import bindings. */
1137
+ export function classifyReceiver(sup, receiver, source, proofCache, cacheScope, accessNode, hasLexicalBinding, classifyImport) {
1138
+ const text = receiverKeywordText(sup, receiver, source, hasLexicalBinding);
1139
+ if (!text)
1140
+ return { kind: "unknown", receiver };
1141
+ const keywordKind = keywordReceiverKind(sup.id, text);
1142
+ if (keywordKind) {
1143
+ if (keywordReceiverCrossesDynamicBoundary(sup, accessNode))
1144
+ return { kind: "unknown", receiver };
1145
+ const memberScope = keywordReceiverMemberScope(sup, text, accessNode, source);
1146
+ return keywordKind === "own" ? { kind: "own-type", memberScope } : { kind: "supertype", memberScope };
1147
+ }
659
1148
  const receiverIsName = isReceiverNameNode(sup, receiver.type);
660
- const cacheKey = `${cacheScope}\u0000${text}`;
661
- let proof = proofCache.get(cacheKey);
1149
+ const importProof = receiverIsName ? classifyImport?.(text, receiver) : null;
1150
+ if (importProof === "module-import")
1151
+ return { kind: "module-import", receiver };
1152
+ const cacheKey = proofCache ? cacheScope + "\u0000" + text : "";
1153
+ let proof = proofCache?.get(cacheKey);
662
1154
  if (!proof) {
663
- const constructed = receiverConstructorExpression(receiver, source, sup);
1155
+ const typeEvidence = receiverTypeEvidence(receiver, source, sup);
664
1156
  proof = {
665
- constructed,
666
- locallyBound: !constructed && receiverIsName && bindsLocalValue(receiver, text, source, sup),
1157
+ typeEvidence,
1158
+ locallyBound: !typeEvidence && receiverIsName && bindsLocalValue(receiver, text, source, sup),
667
1159
  };
668
- proofCache.set(cacheKey, proof);
1160
+ proofCache?.set(cacheKey, proof);
669
1161
  }
670
- if (proof.constructed) {
1162
+ if (proof.typeEvidence) {
1163
+ const { typeNode, origin } = proof.typeEvidence;
671
1164
  return {
672
1165
  kind: "named-type",
673
- typeName: sliceText(proof.constructed, source),
1166
+ proof: origin,
1167
+ typeName: sliceText(typeNode, source),
1168
+ typeNode,
674
1169
  memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
1170
+ constructed: origin === "constructor",
675
1171
  };
676
1172
  }
677
- if (!receiverIsName)
678
- return null;
679
- // A name bound by a local or parameter is a value, not a type. Without this guard
680
- // `Example::shared()` would still be attributed to a colliding parameter named Example.
681
- if (proof.locallyBound)
682
- return null;
683
- // Dotted `Cfg.load()` is not proof: the identifier may be a value. Type-scoped `::`
684
- // is the remaining named-type proof. Ruby capitalized names are `constant` tokens
685
- // even when they name a parameter, so `constant` is not itself type proof.
1173
+ if (importProof === "static-type") {
1174
+ return { kind: "named-type", proof: "static-type", typeName: text, typeNode: receiver, memberScope: "static" };
1175
+ }
1176
+ if (!receiverIsName || proof.locallyBound)
1177
+ return { kind: "unknown", receiver };
1178
+ // Dotted `Cfg.load()` is not proof in languages where the identifier may be a
1179
+ // value. Type-scoped `::` is one named-type proof; C# `Box.Left()` is another
1180
+ // because a capitalized unbound name is the static type receiver. Ruby
1181
+ // capitalized names are `constant` tokens even when they name a parameter, so
1182
+ // `constant` is not itself type proof.
686
1183
  const property = getMemberAccessParts(sup, accessNode).property;
687
1184
  const between = property ? source.slice(receiver.endIndex, property.startIndex) : "";
688
1185
  const typeScoped = TYPE_SCOPED_ACCESS_TYPES[accessNode.type] === true || between.includes("::");
689
- if (receiver.type !== "type_identifier" && !typeScoped)
690
- return null;
1186
+ if (receiver.type !== "type_identifier" && !typeScoped) {
1187
+ // A capitalized bare name is type proof where construction already types
1188
+ // `Box()` as a Box, and for static type-name receivers (`Box.Left()`).
1189
+ // The named type must still resolve to a members-declaring definition
1190
+ // before any call edge is recorded, so a name alone never invents a target.
1191
+ if (!capitalizedTypeReceiverName(sup, receiver, text))
1192
+ return { kind: "unknown", receiver };
1193
+ return {
1194
+ kind: "named-type",
1195
+ proof: "static-type",
1196
+ typeName: text,
1197
+ typeNode: receiver,
1198
+ memberScope: UNBOUND_INSTANCE_CALL_LANGUAGE_IDS[sup.id] ? "any" : "static",
1199
+ };
1200
+ }
691
1201
  return {
692
1202
  kind: "named-type",
1203
+ proof: "static-type",
693
1204
  typeName: text,
1205
+ typeNode: receiver,
694
1206
  memberScope: hasStaticMemberDistinction(sup.id) && typeScoped ? "static" : "any",
695
1207
  };
696
1208
  }
1209
+ /**
1210
+ * Languages whose runtime allows an instance member to be invoked through a type
1211
+ * name (`Box.instanceMethod(args)` is a real unbound call), so a type-named
1212
+ * receiver restricts nothing about static versus instance members.
1213
+ */
1214
+ const UNBOUND_INSTANCE_CALL_LANGUAGE_IDS = {
1215
+ python: true,
1216
+ };
1217
+ /**
1218
+ * Languages whose dotted type-name receivers (`Box.Left()`) name the type itself.
1219
+ * Distinct from `capitalizedCall`, which also treats `Box()` as construction.
1220
+ */
1221
+ const STATIC_TYPE_NAME_RECEIVER_LANGUAGE_IDS = {
1222
+ csharp: true,
1223
+ java: true,
1224
+ js: true,
1225
+ kotlin: true,
1226
+ ts: true,
1227
+ ruby: true,
1228
+ tsx: true,
1229
+ };
1230
+ /** Whether a receiver name is capitalized like a type in a capitalized-name language. */
1231
+ function capitalizedTypeReceiverName(sup, receiver, text) {
1232
+ if (LANGUAGE_CONSTRUCTION_FORMS[sup.id]?.capitalizedCall !== true &&
1233
+ !STATIC_TYPE_NAME_RECEIVER_LANGUAGE_IDS[sup.id]) {
1234
+ return false;
1235
+ }
1236
+ if (!isReceiverNameNode(sup, receiver.type))
1237
+ return false;
1238
+ const first = text[0];
1239
+ return !!first && first === first.toUpperCase() && first !== first.toLowerCase();
1240
+ }
697
1241
  /** Whether a resolved definition can declare callable members. */
698
1242
  export function declaresMembers(def) {
699
1243
  return def.kind === SymbolKind.Class || def.kind === SymbolKind.Interface || def.kind === SymbolKind.TypeAlias;
700
1244
  }
1245
+ /** Whether a C++ definition denotes a class, struct, or union that can own methods. */
1246
+ export function isCppMemberContainerDefinition(tree, def) {
1247
+ const position = {
1248
+ row: Math.max(0, def.range.start.line - 1),
1249
+ column: Math.max(0, def.range.start.column - 1),
1250
+ };
1251
+ const nameNode = tree.rootNode.descendantForPosition(position, position);
1252
+ const container = nearestMemberContainer(nameNode);
1253
+ if (!container || CPP_MEMBER_CONTAINER_TYPES[container.type] === undefined)
1254
+ return false;
1255
+ const containerName = container.childForFieldName("name");
1256
+ return containerName?.startPosition.row === position.row && containerName.startPosition.column === position.column;
1257
+ }
701
1258
  /** Nearest enclosing declaration that lexically owns `node` as a member. */
702
1259
  export function nearestMemberContainer(node) {
703
1260
  let current = node.parent;
@@ -708,29 +1265,168 @@ export function nearestMemberContainer(node) {
708
1265
  }
709
1266
  return null;
710
1267
  }
711
- /** Positional argument count of a call, ignoring comments. */
712
- export function callArgumentCount(callNode) {
713
- const explicit = callNode.childForFieldName("arguments") ?? callNode.childForFieldName("argument_list");
714
- let argumentNode = explicit ?? (callNode.namedChildren ?? []).find((child) => CALL_ARGUMENT_NODE_TYPES[child.type]) ?? null;
1268
+ /** Positional argument count of a call, including Kotlin/Swift trailing lambdas. */
1269
+ export function callArgumentCount(callNode, source) {
1270
+ // Kotlin wraps `pick(1) { }` in an outer call node whose only other child is the
1271
+ // callee call; the trailing lambda belongs to the inner call's argument list.
1272
+ let scope = callNode;
1273
+ for (let wrapper = trailingLambdaWrapper(scope); wrapper; wrapper = trailingLambdaWrapper(scope)) {
1274
+ scope = wrapper;
1275
+ }
1276
+ let argumentNode = callNode.childForFieldName("arguments") ??
1277
+ callNode.childForFieldName("argument_list") ??
1278
+ (callNode.namedChildren ?? []).find((child) => CALL_ARGUMENT_NODE_TYPES[child.type]) ??
1279
+ null;
715
1280
  if (argumentNode?.type === "call_suffix") {
716
1281
  argumentNode = (argumentNode.namedChildren ?? []).find((child) => child.type === "value_arguments") ?? null;
717
1282
  }
718
- if (!argumentNode)
719
- return 0;
720
- return (argumentNode.namedChildren ?? []).filter((argument) => argument.type !== "comment").length;
1283
+ if (!argumentNode) {
1284
+ // Swift allows a call suffix with only a trailing lambda (`pick { }`), and Kotlin
1285
+ // `pick { }` keeps the lambda directly on the call node: no argument list exists.
1286
+ const suffix = (callNode.namedChildren ?? []).find((child) => child.type === "call_suffix");
1287
+ return ((suffix ?? scope).namedChildren ?? []).filter((child) => TRAILING_LAMBDA_NODE_TYPES[child.type] && child.startIndex >= callNode.startIndex).length;
1288
+ }
1289
+ let count = (argumentNode.namedChildren ?? []).filter((argument) => argument.type !== "comment").length;
1290
+ const trailingEnd = argumentNode.parent?.type === "call_suffix" ? argumentNode.parent.endIndex : scope.endIndex;
1291
+ if (trailingEnd > argumentNode.endIndex && containsTrailingLambdaNode(scope, argumentNode.endIndex, trailingEnd)) {
1292
+ const trailing = countTrailingClosureArguments(source.slice(argumentNode.endIndex, trailingEnd));
1293
+ // A null scan means the trailing-closure count is unknown, so the whole call
1294
+ // arity is unknown rather than the parenthesized count alone.
1295
+ if (trailing === null)
1296
+ return null;
1297
+ count += trailing;
1298
+ }
1299
+ return count;
721
1300
  }
722
- function parseDefNodeId(id) {
723
- const indexSep = id.lastIndexOf("::");
724
- if (indexSep <= 0)
1301
+ /** Trailing lambda nodes across the supported grammars. */
1302
+ const TRAILING_LAMBDA_NODE_TYPES = {
1303
+ annotated_lambda: true, // Kotlin wraps the lambda on the outer call node.
1304
+ lambda_literal: true, // Swift keeps trailing lambdas inside `call_suffix`.
1305
+ };
1306
+ /** Call nodes that can wrap a callee call plus a Kotlin trailing lambda. */
1307
+ const TRAILING_LAMBDA_WRAPPER_TYPES = {
1308
+ call: true,
1309
+ call_expression: true,
1310
+ };
1311
+ /**
1312
+ * The outer call node attaching a trailing lambda to `node`, or null. The wrapper
1313
+ * never carries its own argument list, which distinguishes it from a chained call.
1314
+ */
1315
+ function trailingLambdaWrapper(node) {
1316
+ const parent = node.parent;
1317
+ if (!parent || !TRAILING_LAMBDA_WRAPPER_TYPES[parent.type])
725
1318
  return null;
726
- const index = Number(id.slice(indexSep + 2));
727
- if (!Number.isFinite(index))
1319
+ const children = parent.namedChildren ?? [];
1320
+ if (children.some((child) => CALL_ARGUMENT_NODE_TYPES[child.type]))
728
1321
  return null;
729
- const rest = id.slice(0, indexSep);
730
- const nameSep = rest.lastIndexOf("::");
731
- if (nameSep <= 0)
1322
+ return children.some((child) => TRAILING_LAMBDA_NODE_TYPES[child.type]) ? parent : null;
1323
+ }
1324
+ /** Whether a trailing lambda node overlaps `[start, end)` anywhere under `node`. */
1325
+ function containsTrailingLambdaNode(node, start, end) {
1326
+ for (const child of node.namedChildren ?? []) {
1327
+ if (child.endIndex <= start || child.startIndex >= end)
1328
+ continue;
1329
+ if (TRAILING_LAMBDA_NODE_TYPES[child.type])
1330
+ return true;
1331
+ if (containsTrailingLambdaNode(child, start, end))
1332
+ return true;
1333
+ }
1334
+ return false;
1335
+ }
1336
+ /** End index after a Swift trailing-closure label and its colon, or null when absent. */
1337
+ function trailingClosureLabelEnd(text, startIndex) {
1338
+ if (text[startIndex] === "`") {
1339
+ const escapedEnd = text.indexOf("`", startIndex + 1);
1340
+ if (escapedEnd < 0 || text[escapedEnd + 1] !== ":")
1341
+ return null;
1342
+ return escapedEnd + 2;
1343
+ }
1344
+ const identifier = /^[_\p{ID_Start}][_\p{ID_Continue}]*/u.exec(text.slice(startIndex));
1345
+ if (!identifier)
732
1346
  return null;
733
- return { file: rest.slice(0, nameSep), name: rest.slice(nameSep + 2), index };
1347
+ const colonIndex = startIndex + identifier[0].length;
1348
+ return text[colonIndex] === ":" ? colonIndex + 1 : null;
1349
+ }
1350
+ /**
1351
+ * Counts the top-level `{ ... }` blocks in trailing call text, one per trailing
1352
+ * closure, or null when the text is not a well-formed trailing-closure run.
1353
+ * Shared with call-compatibility extraction so both paths count identically.
1354
+ */
1355
+ export function countTrailingClosureArguments(text) {
1356
+ let startIndex = 0;
1357
+ let count = 0;
1358
+ while (startIndex < text.length) {
1359
+ while (/\s/.test(text[startIndex] ?? "")) {
1360
+ startIndex += 1;
1361
+ }
1362
+ if (startIndex === text.length) {
1363
+ return count;
1364
+ }
1365
+ if (text[startIndex] !== "{") {
1366
+ const labelEnd = trailingClosureLabelEnd(text, startIndex);
1367
+ if (labelEnd === null)
1368
+ return null;
1369
+ startIndex = labelEnd;
1370
+ while (/\s/.test(text[startIndex] ?? "")) {
1371
+ startIndex += 1;
1372
+ }
1373
+ if (text[startIndex] !== "{")
1374
+ return null;
1375
+ }
1376
+ let braceDepth = 0;
1377
+ let quote = null;
1378
+ let escaped = false;
1379
+ let closed = false;
1380
+ for (let index = startIndex; index < text.length; index += 1) {
1381
+ const char = text[index];
1382
+ if (quote) {
1383
+ if (escaped) {
1384
+ escaped = false;
1385
+ continue;
1386
+ }
1387
+ if (char === "\\") {
1388
+ escaped = true;
1389
+ continue;
1390
+ }
1391
+ if (char === quote) {
1392
+ quote = null;
1393
+ }
1394
+ continue;
1395
+ }
1396
+ const commentEnd = findCommentEnd(text, index);
1397
+ if (commentEnd !== null) {
1398
+ if (commentEnd < 0) {
1399
+ return null;
1400
+ }
1401
+ index = commentEnd - 1;
1402
+ continue;
1403
+ }
1404
+ if (char === '"' || char === "'" || char === "`") {
1405
+ quote = char;
1406
+ continue;
1407
+ }
1408
+ if (char === "{") {
1409
+ braceDepth += 1;
1410
+ continue;
1411
+ }
1412
+ if (char === "}") {
1413
+ braceDepth -= 1;
1414
+ if (braceDepth < 0) {
1415
+ return null;
1416
+ }
1417
+ if (!braceDepth) {
1418
+ startIndex = index + 1;
1419
+ count += 1;
1420
+ closed = true;
1421
+ break;
1422
+ }
1423
+ }
1424
+ }
1425
+ if (!closed) {
1426
+ return null;
1427
+ }
1428
+ }
1429
+ return count;
734
1430
  }
735
1431
  function loadSource(file, cache) {
736
1432
  const cached = cache.get(file);
@@ -746,20 +1442,6 @@ function loadSource(file, cache) {
746
1442
  return "";
747
1443
  }
748
1444
  }
749
- function memberIdLooksStatic(memberId, sourceCache) {
750
- const parsed = parseDefNodeId(memberId);
751
- if (!parsed)
752
- return false;
753
- const source = loadSource(parsed.file, sourceCache);
754
- if (!source)
755
- return false;
756
- const beforeBrace = source.lastIndexOf("{", parsed.index);
757
- const beforeSemi = source.lastIndexOf(";", parsed.index);
758
- const beforeClose = source.lastIndexOf("}", parsed.index);
759
- const declStart = Math.max(beforeBrace, beforeSemi, beforeClose);
760
- const prefix = source.slice(declStart + 1, parsed.index);
761
- return /(?:^|[^\w$])static(?:$|[^\w$])/.test(prefix) || /(?:^|[^\w$])def\s+self\s*\./.test(prefix);
762
- }
763
1445
  function inferCallMemberScope(site, sourceCache) {
764
1446
  const source = loadSource(site.file, sourceCache);
765
1447
  if (!source)
@@ -774,22 +1456,108 @@ function inferCallMemberScope(site, sourceCache) {
774
1456
  return "instance";
775
1457
  if (/\)\s*\.\s*$/.test(before))
776
1458
  return "instance";
777
- // HeritageEdges does not yet copy classifyReceiver.memberScope onto candidates.
778
- // A lowercase dotted receiver is an instance value (`c.StaticMethod()`), not a type.
1459
+ // Older serialized candidates lack memberScope. Infer the common dotted-receiver cases.
779
1460
  if (/(?:^|[^A-Za-z0-9_$])[a-z_][A-Za-z0-9_]*\s*\.\s*$/.test(before))
780
1461
  return "instance";
781
1462
  if (/(?:^|[^A-Za-z0-9_$])[A-Z][A-Za-z0-9_]*\s*\.\s*$/.test(before))
782
1463
  return "static";
783
1464
  return "any";
784
1465
  }
1466
+ function callSiteKey(callerId, site) {
1467
+ const { start, end } = site.range;
1468
+ return `${callerId}\u0000${site.file}\u0000${start.line}:${start.column}:${start.index ?? ""}-${end.line}:${end.column}:${end.index ?? ""}`;
1469
+ }
1470
+ /** Prove overriding member pairs only for hierarchy receiver calls. */
1471
+ export async function inheritedReceiverMemberSignatures(graph, candidates, definitions, ownerAnchors, accessibleMembers, languageExtensions, sameParameterTypes) {
1472
+ const signatures = new Map();
1473
+ const membersByOwner = new Map();
1474
+ const ownerByMember = new Map();
1475
+ const parentsByOwner = new Map();
1476
+ for (const edge of graph.edges) {
1477
+ if (edge.label === "member_of") {
1478
+ ownerByMember.set(edge.from, edge.to);
1479
+ if (definitions.has(edge.from)) {
1480
+ const members = membersByOwner.get(edge.to) ?? [];
1481
+ members.push(edge.from);
1482
+ membersByOwner.set(edge.to, members);
1483
+ }
1484
+ }
1485
+ else if (edge.label && HIERARCHY_LABELS[edge.label]) {
1486
+ const parents = parentsByOwner.get(edge.from) ?? [];
1487
+ parents.push(edge.to);
1488
+ parentsByOwner.set(edge.from, parents);
1489
+ }
1490
+ }
1491
+ for (const [owner, accessible] of accessibleMembers) {
1492
+ const members = membersByOwner.get(owner) ?? [];
1493
+ for (const id of accessible)
1494
+ if (definitions.has(id) && !members.includes(id))
1495
+ members.push(id);
1496
+ membersByOwner.set(owner, members);
1497
+ }
1498
+ const checkedPairs = new Set();
1499
+ const checkedGroups = new Set();
1500
+ const separator = "\0";
1501
+ for (const candidate of candidates) {
1502
+ if (!inheritsMemberOverloads(supportForFileWithoutHeaderSample(candidate.site.file, languageExtensions)?.id ?? "")) {
1503
+ continue;
1504
+ }
1505
+ const rawOwner = candidate.ownerId ?? ownerByMember.get(candidate.callerId);
1506
+ if (!rawOwner)
1507
+ continue;
1508
+ const owner = ownerAnchors.get(rawOwner) ?? rawOwner;
1509
+ // Override pairs are a fact of the declarations, not of this call: an override that rejects
1510
+ // the argument count still hides the base declaration it overrides.
1511
+ const group = `${owner}\0${candidate.memberName}\0${candidate.viaSupertypes}`;
1512
+ if (checkedGroups.has(group))
1513
+ continue;
1514
+ checkedGroups.add(group);
1515
+ let level = candidate.viaSupertypes ? (parentsByOwner.get(owner) ?? []) : [owner];
1516
+ const seen = new Set([owner]);
1517
+ const shallower = [];
1518
+ for (let depth = 0; depth < 16 && level.length; depth += 1) {
1519
+ const current = [];
1520
+ const next = [];
1521
+ for (const id of level) {
1522
+ for (const memberId of membersByOwner.get(id) ?? []) {
1523
+ if (graph.nodes.get(memberId)?.name === candidate.memberName)
1524
+ current.push(memberId);
1525
+ }
1526
+ for (const parent of parentsByOwner.get(id) ?? []) {
1527
+ if (seen.has(parent))
1528
+ continue;
1529
+ seen.add(parent);
1530
+ next.push(parent);
1531
+ }
1532
+ }
1533
+ for (const derivedId of shallower) {
1534
+ const derived = definitions.get(derivedId);
1535
+ for (const inheritedId of current) {
1536
+ const pair = derivedId + separator + inheritedId;
1537
+ if (checkedPairs.has(pair))
1538
+ continue;
1539
+ checkedPairs.add(pair);
1540
+ if (!(await sameParameterTypes(derived, definitions.get(inheritedId))))
1541
+ continue;
1542
+ const inherited = signatures.get(derivedId) ?? new Set();
1543
+ inherited.add(inheritedId);
1544
+ signatures.set(derivedId, inherited);
1545
+ }
1546
+ }
1547
+ shallower.push(...current);
1548
+ level = next;
1549
+ }
1550
+ }
1551
+ return signatures;
1552
+ }
785
1553
  /**
786
1554
  * Records proven `calls` edges for deferred receiver invocations.
787
1555
  * Ambiguous names at a level stop the walk.
788
1556
  * `super`/`base`/`parent` follow class `extends` ancestors only.
789
1557
  */
790
- export function emitReceiverCallEdges(graph, candidates, recordEdge) {
1558
+ export function emitReceiverCallEdges(graph, candidates, recordEdge, memberScopes = new Map(), nodeAliases = new Map(), memberArities = new Map(), ownerAnchors = new Map(), accessibleMembers = new Map(), fileHiddenMemberIds = new Set(), acceptsCallTarget, callableIdentities = new Map(), languageExtensions, overridingSignatures, isReceiverMemberVisible) {
791
1559
  if (!candidates.length)
792
- return;
1560
+ return [];
793
1561
  const membersByOwner = new Map();
794
1562
  const ownerByMember = new Map();
795
1563
  const supertypesByOwner = new Map();
@@ -814,69 +1582,150 @@ export function emitReceiverCallEdges(graph, candidates, recordEdge) {
814
1582
  if (label === "extends")
815
1583
  pushUnique(classAncestorsByOwner, edge.from, edge.to);
816
1584
  }
817
- const nextOwners = (ownerId, viaSupertypes) => {
818
- if (!viaSupertypes)
819
- return supertypesByOwner.get(ownerId) ?? [];
820
- return (classAncestorsByOwner.get(ownerId) ?? []).filter((id) => graph.nodes.get(id)?.kind === "class");
1585
+ // Receiver-local access does not change the nominal type's membership edges.
1586
+ for (const [ownerId, memberIds] of accessibleMembers) {
1587
+ for (const memberId of memberIds)
1588
+ pushUnique(membersByOwner, ownerId, memberId);
1589
+ }
1590
+ let activeCandidate;
1591
+ const facts = new Map();
1592
+ for (const [ownerId, ids] of membersByOwner) {
1593
+ for (const id of ids) {
1594
+ const canonicalId = canonicalMemberId(id, nodeAliases);
1595
+ const indexed = callableIdentities.get(id) ?? callableIdentities.get(canonicalId);
1596
+ const bounds = memberArities.get(id) ?? memberArities.get(canonicalId);
1597
+ facts.set(id, {
1598
+ key: indexed?.key ?? canonicalId,
1599
+ owner: indexed?.owner ?? ownerId,
1600
+ kind: indexed?.kind ?? "function",
1601
+ arity: bounds ? { minArgs: bounds.min, maxArgs: bounds.max } : null,
1602
+ ...(indexed?.role ? { role: indexed.role } : {}),
1603
+ });
1604
+ }
1605
+ }
1606
+ const model = {
1607
+ ownerKey: (id) => id,
1608
+ members: (id) => membersByOwner.get(id) ?? [],
1609
+ supertypes: (id, classOnly) => {
1610
+ if (!classOnly)
1611
+ return supertypesByOwner.get(id) ?? [];
1612
+ return (classAncestorsByOwner.get(id) ?? []).filter((base) => graph.nodes.get(base)?.kind === "class");
1613
+ },
1614
+ name: (id) => graph.nodes.get(id)?.name ?? graph.nodes.get(canonicalMemberId(id, nodeAliases))?.name ?? "",
1615
+ key: (id) => facts.get(id)?.key ?? canonicalMemberId(id, nodeAliases),
1616
+ callable: (id) => facts.get(id),
1617
+ scope: (id) => memberScopes.get(id) ?? memberScopes.get(canonicalMemberId(id, nodeAliases)) ?? "any",
1618
+ visible: (id, useFile) => {
1619
+ const canonicalId = canonicalMemberId(id, nodeAliases);
1620
+ const node = graph.nodes.get(id) ?? graph.nodes.get(canonicalId);
1621
+ if (!node || (node.kind !== "function" && !node.callable))
1622
+ return false;
1623
+ if (isReceiverMemberVisible && !isReceiverMemberVisible(canonicalId, useFile))
1624
+ return false;
1625
+ if ((fileHiddenMemberIds.has(id) || fileHiddenMemberIds.has(canonicalId)) &&
1626
+ fileIdentityKey(node.file) !== fileIdentityKey(useFile))
1627
+ return false;
1628
+ return (!activeCandidate.goPackagePeerFiles ||
1629
+ isGoExportedMemberName("go", node.name) ||
1630
+ activeCandidate.goPackagePeerFiles.has(node.file));
1631
+ },
1632
+ sameSignature: (a, b) => overridingSignatures?.get(a)?.has(b) ?? false,
821
1633
  };
1634
+ const callTargetsBySite = new Map();
1635
+ for (const edge of graph.edges) {
1636
+ if (edge.label !== "calls" || !edge.site)
1637
+ continue;
1638
+ const key = callSiteKey(edge.from, edge.site);
1639
+ const targets = callTargetsBySite.get(key);
1640
+ if (targets)
1641
+ targets.add(edge.to);
1642
+ else
1643
+ callTargetsBySite.set(key, new Set([edge.to]));
1644
+ }
1645
+ const rejectedCallSites = new Set();
822
1646
  const sourceCache = new Map();
823
1647
  for (const candidate of candidates) {
824
- const owner = candidate.ownerId ?? ownerByMember.get(candidate.callerId);
825
- if (!owner)
1648
+ const siteKey = callSiteKey(candidate.callerId, candidate.site);
1649
+ const existingTargets = callTargetsBySite.get(siteKey) ?? new Set();
1650
+ if (existingTargets.size > 1) {
1651
+ rejectedCallSites.add(siteKey);
826
1652
  continue;
1653
+ }
1654
+ const rawOwner = candidate.ownerId ?? ownerByMember.get(candidate.callerId);
1655
+ if (!rawOwner)
1656
+ continue;
1657
+ // Shared-owner anchors redirect Swift extension and C# partial owners to the
1658
+ // coalesced type identity so lookup starts on the whole member set.
1659
+ const owner = ownerAnchors.get(rawOwner) ?? rawOwner;
827
1660
  const memberScope = candidate.memberScope ?? inferCallMemberScope(candidate.site, sourceCache);
828
- let level = candidate.viaSupertypes ? nextOwners(owner, true) : [owner];
829
- const visited = new Set(level);
830
- for (let depth = 0; depth < MAX_SUPERTYPE_DEPTH && level.length; depth += 1) {
831
- const lookup = provenMemberTarget(graph, membersByOwner, level, candidate, memberScope, sourceCache);
832
- if (lookup.status === "unique") {
833
- recordEdge(candidate.callerId, lookup.memberId, "calls", candidate.site);
834
- break;
1661
+ const languageId = supportForFileWithoutHeaderSample(candidate.site.file, languageExtensions)?.id ?? "";
1662
+ activeCandidate = candidate;
1663
+ const lookup = selectMember([owner], model, {
1664
+ name: candidate.memberName,
1665
+ argumentCount: candidate.argumentCount,
1666
+ scope: memberScope,
1667
+ useFile: candidate.site.file,
1668
+ phpCaseInsensitive: !!candidate.caseInsensitiveMemberName,
1669
+ separateMemberScopes: hasSeparateMemberScopes(languageId),
1670
+ startAtAncestor: candidate.viaSupertypes,
1671
+ inheritOverloads: inheritsMemberOverloads(languageId),
1672
+ });
1673
+ let receiverDisposition = lookup.status === "unique" ? "resolved" : lookup.status;
1674
+ if (lookup.status === "unique") {
1675
+ const memberId = canonicalMemberId(lookup.member, nodeAliases);
1676
+ if (acceptsCallTarget && !acceptsCallTarget(memberId, candidate)) {
1677
+ receiverDisposition = "ambiguous";
1678
+ if (existingTargets.size)
1679
+ rejectedCallSites.add(siteKey);
835
1680
  }
836
- if (lookup.status === "ambiguous")
837
- break;
838
- const next = [];
839
- for (const ownerId of level) {
840
- for (const supertype of nextOwners(ownerId, candidate.viaSupertypes)) {
841
- if (visited.has(supertype))
842
- continue;
843
- visited.add(supertype);
844
- next.push(supertype);
1681
+ else {
1682
+ receiverDisposition = "resolved";
1683
+ const combinedTargets = new Set(existingTargets);
1684
+ combinedTargets.add(memberId);
1685
+ if (combinedTargets.size === 1) {
1686
+ if (!existingTargets.size && recordEdge(candidate.callerId, memberId, "calls", candidate.site)) {
1687
+ existingTargets.add(memberId);
1688
+ callTargetsBySite.set(siteKey, existingTargets);
1689
+ }
845
1690
  }
1691
+ else
1692
+ rejectedCallSites.add(siteKey);
1693
+ }
1694
+ }
1695
+ else if (lookup.status === "ambiguous" && existingTargets.size) {
1696
+ rejectedCallSites.add(siteKey);
1697
+ }
1698
+ if (receiverDisposition === "none") {
1699
+ if (candidate.fallbackTargetId && !existingTargets.size) {
1700
+ recordEdge(candidate.callerId, candidate.fallbackTargetId, "calls", candidate.site);
1701
+ }
1702
+ else if (existingTargets.size) {
1703
+ rejectedCallSites.add(siteKey);
846
1704
  }
847
- level = next;
848
1705
  }
849
1706
  }
850
- }
851
- /**
852
- * The single callable member named by `candidate` across `owners`.
853
- * `none` means this depth has no name match and the walk may continue.
854
- * `ambiguous` means this depth matched the name but could not prove one member,
855
- * including arity ambiguity, and the walk must stop.
856
- */
857
- function provenMemberTarget(graph, membersByOwner, owners, candidate, memberScope, sourceCache) {
858
- const matches = new Set();
859
- for (const ownerId of owners) {
860
- for (const memberId of membersByOwner.get(ownerId) ?? []) {
861
- const node = graph.nodes.get(memberId);
862
- if (!node || node.kind !== "function" || node.name !== candidate.memberName)
863
- continue;
864
- if (memberScope === "static" && !memberIdLooksStatic(memberId, sourceCache))
865
- continue;
866
- if (memberScope === "instance" && memberIdLooksStatic(memberId, sourceCache))
1707
+ const removed = [];
1708
+ if (rejectedCallSites.size) {
1709
+ let writeIndex = 0;
1710
+ for (const edge of graph.edges) {
1711
+ if (edge.label === "calls" && edge.site && rejectedCallSites.has(callSiteKey(edge.from, edge.site))) {
1712
+ removed.push(edge);
867
1713
  continue;
868
- matches.add(memberId);
1714
+ }
1715
+ graph.edges[writeIndex] = edge;
1716
+ writeIndex += 1;
869
1717
  }
1718
+ graph.edges.length = writeIndex;
870
1719
  }
871
- if (!matches.size)
872
- return { status: "none" };
873
- if (matches.size === 1) {
874
- const [memberId] = matches;
875
- return { status: "unique", memberId: memberId };
876
- }
877
- const byArity = [...matches].filter((memberId) => graph.nodes.get(memberId)?.memberArity === candidate.argumentCount);
878
- if (byArity.length === 1)
879
- return { status: "unique", memberId: byArity[0] };
880
- return { status: "ambiguous" };
1720
+ return removed;
1721
+ }
1722
+ function canonicalMemberId(id, aliases) {
1723
+ let current = id;
1724
+ const seen = new Set();
1725
+ while (aliases.has(current) && !seen.has(current)) {
1726
+ seen.add(current);
1727
+ current = aliases.get(current);
1728
+ }
1729
+ return current;
881
1730
  }
882
1731
  //# sourceMappingURL=receiver-calls.js.map