@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,17 +1,32 @@
1
+ import { SymbolKind } from "../../indexer/types.js";
2
+ import { getCompilationUnitPeers } from "../../indexer/compilation-units.js";
3
+ import { isExportedDeclaration, isGoExportedMemberName, isSwiftCrossFileHiddenSharedOwnerMember, isSwiftFileHiddenSharedOwnerMember, } from "../../indexer/declaration-visibility.js";
4
+ import { resolveCppQualifiedMemberContainer } from "../../indexer/navigation-cpp.js";
5
+ import { cppQualifiedOwnerHasImplicitThis, findTypeScriptNamespaceMemberCandidates, innermostNamespaceImport, isDirectKeywordMemberDeclaration, memberAcceptsCallAt, resolvePhpObjectCreationTarget, resolveRubyVisibleConstant, resolveSharedOwnerContainers, supportsDeclaredFieldChains, } from "../../indexer/navigation-goto.js";
6
+ import { findClosestScopeBinding } from "../../indexer/navigation-local.js";
7
+ import { findPhpImportAlias, inferPhpQualifiedReferenceImportType } from "../../indexer/navigation-php.js";
8
+ import { cjsRequireValueBinding, resolveImportTypeMember, resolvePhpExportByImportType, } from "../../indexer/navigation-resolve.js";
9
+ import { selectMember } from "../../indexer/member-selection.js";
10
+ import { effectiveExplicitBinding } from "../../indexer/star-import-precedence.js";
11
+ import { isSwiftConstrainedExtension, isSwiftExtensionContainer, selectCsharpPartialRepresentative, } from "../../indexer/shared-owner-identity.js";
12
+ import { isJsTsLanguage } from "../../languages/js-family.js";
13
+ import { getCallArgumentCount, memberLookupBinding } from "../../languages/callable-arity.js";
1
14
  import { sliceText, toRange } from "../../util/ast.js";
2
- import { getMemberAccessParts } from "../../util/member-access.js";
15
+ import { getMemberAccessParts, isMemberAccessNode, rustTokenTreeHoldsExpressions, rustTokenTreeNameFollowsSeparator, } from "../../util/member-access.js";
16
+ import { foldPhpIdentifierCase } from "../../util/identifiers.js";
17
+ import { MEMBER_ACCESS_ROWS, } from "../../util/member-access-tables.js";
3
18
  import { fileIdentityKey } from "../../util/paths.js";
4
19
  import { defNodeId, nodeForDef } from "../symbol-graph.js";
5
- import { collectNodesByType, findFirstNodeByType, isIdentifierType } from "./ast.js";
6
- import { CALL_ARGUMENT_NODE_TYPES, callArgumentCount, classifyReceiver, declaresMembers, nearestMemberContainer, receiverCallAccess, } from "./receiver-calls.js";
20
+ import { collectNodesByType, declarationMemberArity, findFirstNodeByType, isIdentifierType } from "./ast.js";
21
+ import { CALL_ARGUMENT_NODE_TYPES, classifyReceiver, constructionTypeName, declarationIsStaticEquivalent, declarationNodeIsStatic, cppOutOfLineOwnerPath, cppOutOfLineMemberDeclarationNode, cppQualifiedNameSegments, declaresMembers, isUnprovenHeritageExpression, kotlinExtensionReceiverTypeNode, memberContainerDef, nearestMemberContainer, nodeInStaticMemberContext, phpObjectCreationKeyword, receiverCallAccess, rustImplSelfTypeNode, supportsImplicitSelfMemberCalls, supportsReceiverMemberOverloads, importTypeQuerySpecifier, } from "./receiver-calls.js";
7
22
  function ensureNode(context, def) {
8
23
  const id = defNodeId(def);
9
24
  if (!context.nodes.has(id))
10
25
  context.nodes.set(id, nodeForDef(def));
11
26
  return id;
12
27
  }
13
- function markImplementationTarget(context, id, declarationNode, def) {
14
- const declaration = sliceText(declarationNode, context.source);
28
+ function markImplementationTarget(context, id, declarationNode, declarationSource, def) {
29
+ const declaration = sliceText(declarationNode, declarationSource);
15
30
  const nameIndex = declaration.indexOf(def.localName);
16
31
  const prefix = nameIndex >= 0 ? declaration.slice(0, nameIndex) : declaration;
17
32
  if (!/\b(?:abstract|virtual|override)\b/.test(prefix))
@@ -21,27 +36,49 @@ function markImplementationTarget(context, id, declarationNode, def) {
21
36
  node.implementationTarget = true;
22
37
  }
23
38
  function markMemberArity(context, id, declarationNode) {
24
- let parameters = declarationNode.childForFieldName("parameters");
25
- if (!parameters) {
26
- for (const type of [
27
- "formal_parameters",
28
- "parameter_list",
29
- "parameters",
30
- "method_parameters",
31
- "function_parameter_clause",
32
- ]) {
33
- parameters = findFirstNodeByType(declarationNode, type);
34
- if (parameters)
35
- break;
36
- }
37
- }
38
- if (!parameters)
39
+ const arity = declarationMemberArity(declarationNode, context.sup.id);
40
+ if (arity === undefined)
39
41
  return;
40
- const arity = (parameters.namedChildren ?? []).filter((child) => child.type !== "comment").length;
41
42
  const node = context.nodes.get(id);
42
43
  if (node)
43
44
  node.memberArity = arity;
44
45
  }
46
+ function mergeCppCallableShapes(...defs) {
47
+ let merged;
48
+ for (const def of defs) {
49
+ const arity = def?.callable?.arity;
50
+ if (!arity)
51
+ continue;
52
+ if (!merged) {
53
+ merged = { min: arity.minArgs, max: arity.maxArgs };
54
+ continue;
55
+ }
56
+ merged.min = Math.min(merged.min, arity.minArgs);
57
+ if (merged.max === null || arity.maxArgs === null)
58
+ merged.max = null;
59
+ else
60
+ merged.max = Math.max(merged.max, arity.maxArgs);
61
+ }
62
+ return merged;
63
+ }
64
+ /** The member call form determines whether a declared receiver takes an argument. */
65
+ function acceptedMemberArityRange(context, def) {
66
+ if (!supportsReceiverMemberOverloads(context.sup.id))
67
+ return undefined;
68
+ const callable = def.callable;
69
+ const range = memberLookupBinding(context.sup.id) === "unbound" ? (callable?.unboundArity ?? callable?.arity) : callable?.arity;
70
+ return range ? { min: range.minArgs, max: range.maxArgs } : undefined;
71
+ }
72
+ function recordMemberLookupIdentity(context, definitionId, memberId, memberScope, arityRange) {
73
+ context.receiverMemberScopes.set(definitionId, memberScope);
74
+ if (memberId !== definitionId)
75
+ context.receiverMemberScopes.set(memberId, memberScope);
76
+ if (!arityRange)
77
+ return;
78
+ context.receiverMemberArities.set(definitionId, arityRange);
79
+ if (memberId !== definitionId)
80
+ context.receiverMemberArities.set(memberId, arityRange);
81
+ }
45
82
  function recordDefEdge(context, fromId, target, label, siteNode) {
46
83
  const toId = ensureNode(context, target);
47
84
  return context.recordEdge(fromId, toId, label, siteNode ? { file: context.moduleEntry.file, range: toRange(siteNode) } : undefined);
@@ -56,10 +93,27 @@ function tryResolveChain(context, node, fromId, label = "uses") {
56
93
  }
57
94
  /** Records an edge for a resolvable target node. Returns whether a target was resolved. */
58
95
  function tryResolveNode(context, node, fromId, label) {
59
- if (isIdentifierType(context.sup, node.type) || node.type === "type_identifier") {
96
+ if (context.sup.id === "cpp" && node.type === "qualified_identifier") {
97
+ const name = cppQualifiedNameSegments(node, context.source).join("::");
98
+ const target = context.resolveIdentifier(name, node);
99
+ if (target) {
100
+ recordDefEdge(context, fromId, target, label, node);
101
+ return true;
102
+ }
103
+ return false;
104
+ }
105
+ if (isIdentifierType(context.sup, node.type) ||
106
+ node.type === "type_identifier" ||
107
+ (context.sup.id === "csharp" && (node.type === "qualified_name" || node.type === "alias_qualified_name")) ||
108
+ (context.sup.id === "php" && (node.type === "qualified_name" || node.type === "relative_name")) ||
109
+ (context.sup.id === "cpp" && (node.type === "operator_name" || node.type === "destructor_name"))) {
60
110
  const name = sliceText(node, context.source);
61
111
  const target = context.resolveIdentifier(name, node);
62
112
  if (target) {
113
+ // Zig struct declarations require an explicit type receiver (`Self.helper()`).
114
+ // An unqualified identifier is not a call to a member of its enclosing struct.
115
+ if (label === "calls" && context.sup.id === "zig" && target.isMember)
116
+ return false;
63
117
  recordDefEdge(context, fromId, target, label, node);
64
118
  return true;
65
119
  }
@@ -69,6 +123,32 @@ function tryResolveNode(context, node, fromId, label) {
69
123
  }
70
124
  return false;
71
125
  }
126
+ /**
127
+ * Rust macro arguments stay unparsed token trees, so `println!("{}", greet())` never forms a
128
+ * call node even though goto resolves the identifier. An `identifier` directly followed by a
129
+ * `(` group is a call in the argument list, resolved like a bare call. The macro's own name
130
+ * sits outside the token tree and is never a call; a `!` gap marks a nested macro invocation,
131
+ * and a `.` or `::` gap marks a member or path receiver that raw tokens cannot prove, matching
132
+ * navigation's refusals inside token trees.
133
+ */
134
+ function recordRustMacroArgumentCalls(context, tokenTree, fromId) {
135
+ if (!rustTokenTreeHoldsExpressions(tokenTree))
136
+ return;
137
+ const children = tokenTree.namedChildren;
138
+ for (let index = 0; index + 1 < children.length; index += 1) {
139
+ const name = children[index];
140
+ const args = children[index + 1];
141
+ if (name.type !== "identifier" || args.type !== "token_tree")
142
+ continue;
143
+ if (!args.text.startsWith("("))
144
+ continue;
145
+ if (context.source.slice(name.endIndex, args.startIndex).trim())
146
+ continue;
147
+ if (rustTokenTreeNameFollowsSeparator(name))
148
+ continue;
149
+ tryResolveNode(context, name, fromId, "calls");
150
+ }
151
+ }
72
152
  function getCallTarget(node) {
73
153
  const explicitTarget = node.childForFieldName("function") ??
74
154
  node.childForFieldName("callee") ??
@@ -76,6 +156,11 @@ function getCallTarget(node) {
76
156
  node.childForFieldName("method") ??
77
157
  node.childForFieldName("member") ??
78
158
  node.childForFieldName("expression");
159
+ // tree-sitter-typescript parses `await f<T>(x)` as a call whose callee is `await f`; the awaited
160
+ // value is the call's result, so the callee is `f`.
161
+ if (explicitTarget?.type === "await_expression" && node.childForFieldName("type_arguments")) {
162
+ return explicitTarget.namedChildren[0] ?? null;
163
+ }
79
164
  if (explicitTarget)
80
165
  return explicitTarget;
81
166
  // Kotlin and Swift calls name no callee field, so the sole non-argument child is it.
@@ -83,15 +168,18 @@ function getCallTarget(node) {
83
168
  return nonArgumentChildren.length === 1 ? (nonArgumentChildren[0] ?? null) : null;
84
169
  }
85
170
  function getNewTarget(node) {
86
- return (node.childForFieldName("constructor") ??
87
- node.childForFieldName("type") ??
88
- node.childForFieldName("name") ??
89
- node.namedChildren.find((child) => child.type === "type_identifier") ??
90
- node.child(0));
171
+ const field = node.childForFieldName("constructor") ?? node.childForFieldName("type") ?? node.childForFieldName("name");
172
+ if (field)
173
+ return field;
174
+ // PHP `new Base()` has no type field; the type is a `name` / `qualified_name` child and
175
+ // `child(0)` is the `new` keyword, which is not a type.
176
+ const namedType = node.namedChildren.find((child) => child.type === "type_identifier" ||
177
+ child.type === "name" ||
178
+ child.type === "qualified_name" ||
179
+ child.type === "relative_name");
180
+ return namedType ?? node.child(0);
91
181
  }
92
182
  export function emitPythonDecoratorEdges(context, rootNode) {
93
- if (context.sup.id !== "python")
94
- return;
95
183
  const addDecoratorUses = (node) => {
96
184
  if (node.type === "decorated_definition") {
97
185
  const fn = node.namedChildren.find((child) => child.type === "function_definition");
@@ -151,34 +239,220 @@ export function emitPythonDecoratorEdges(context, rootNode) {
151
239
  };
152
240
  addDecoratorUses(rootNode);
153
241
  }
154
- export function emitMemberOwnershipEdges(context, functionNodes, classNodes) {
242
+ /** Whether a function declaration can participate in class member lookup and ownership. */
243
+ function isClassMemberFunction(fn) {
244
+ return fn.node.type !== "local_function_statement";
245
+ }
246
+ export async function emitMemberOwnershipEdges(context, functionNodes, classNodes) {
155
247
  for (const fn of functionNodes) {
156
- const ownerDef = memberOwnerDef(context, fn, classNodes);
157
- if (!ownerDef)
248
+ const owner = await memberOwner(context, fn, classNodes);
249
+ if (!owner)
158
250
  continue;
159
- const memberId = ensureNode(context, fn.def);
160
- markImplementationTarget(context, memberId, fn.node, fn.def);
161
- markMemberArity(context, memberId, fn.node);
162
- recordDefEdge(context, memberId, ownerDef, "member_of");
251
+ const outOfLineDeclaration = owner.cppOutOfLine
252
+ ? await cppOutOfLineMemberDeclaration(context, fn, owner.def)
253
+ : null;
254
+ const definitionId = ensureNode(context, fn.def);
255
+ let memberDef = fn.def;
256
+ if (outOfLineDeclaration) {
257
+ const declarationModule = context.index.byFile.get(fileIdentityKey(owner.def.file));
258
+ const declarationDef = declarationModule?.locals.find((candidate) => candidate.localName === fn.def.localName &&
259
+ candidate.kind === fn.def.kind &&
260
+ candidate.range.start.index === outOfLineDeclaration.nameNode.startIndex &&
261
+ candidate.range.end.index === outOfLineDeclaration.nameNode.endIndex);
262
+ if (declarationDef)
263
+ memberDef = declarationDef;
264
+ }
265
+ const memberId = ensureNode(context, memberDef);
266
+ if (definitionId !== memberId)
267
+ context.nodeAliases.set(definitionId, memberId);
268
+ if (context.sup.id === "java" || context.sup.id === "kotlin" || context.sup.id === "swift") {
269
+ const declarationNode = outOfLineDeclaration?.node ?? fn.node;
270
+ const hidden = context.sup.id === "swift"
271
+ ? isSwiftFileHiddenSharedOwnerMember(context.sup.id, declarationNode)
272
+ : !isExportedDeclaration(context.sup.id, declarationNode);
273
+ if (hidden) {
274
+ context.fileHiddenMemberIds.add(memberId);
275
+ if (definitionId !== memberId)
276
+ context.fileHiddenMemberIds.add(definitionId);
277
+ }
278
+ }
279
+ markImplementationTarget(context, memberId, outOfLineDeclaration?.node ?? fn.node, outOfLineDeclaration?.source ?? context.source, fn.def);
280
+ const arityNode = outOfLineDeclaration?.node ?? fn.node;
281
+ markMemberArity(context, definitionId, arityNode);
282
+ if (memberId !== definitionId)
283
+ markMemberArity(context, memberId, arityNode);
284
+ const memberScope = memberScopeForDefinition(context, fn, owner.cppOutOfLine, outOfLineDeclaration);
285
+ const outOfLineMember = outOfLineDeclaration ? memberDef : undefined;
286
+ const arityRange = context.sup.id === "cpp"
287
+ ? mergeCppCallableShapes(fn.def, outOfLineMember)
288
+ : acceptedMemberArityRange(context, memberDef);
289
+ recordMemberLookupIdentity(context, definitionId, memberId, memberScope, arityRange);
290
+ recordDefEdge(context, definitionId, owner.def, "member_of");
291
+ await emitSharedOwnerMembershipEdges(context, owner, definitionId, fn.node);
292
+ }
293
+ }
294
+ /** Owner def of a shared-owner container, matched by its declaration name range. */
295
+ function sharedOwnerPeerDef(peer, callerFile) {
296
+ const nameNode = peer.container.childForFieldName("name");
297
+ if (!nameNode)
298
+ return null;
299
+ const def = peer.module.locals.find((local) => declaresMembers(local) && local.range.start.index === nameNode.startIndex);
300
+ if (!def)
301
+ return null;
302
+ if (!callerFile)
303
+ return { def, isExtension: isSwiftExtensionContainer(peer.container, peer.context.source) };
304
+ const visibleMemberIds = [];
305
+ for (const local of peer.module.locals) {
306
+ const start = local.range.start.index;
307
+ if (start === undefined || start < peer.container.startIndex || start >= peer.container.endIndex)
308
+ continue;
309
+ const name = peer.context.tree.rootNode.descendantForIndex(start, start);
310
+ if (!isDirectKeywordMemberDeclaration(name, peer.container))
311
+ continue;
312
+ if (isSwiftCrossFileHiddenSharedOwnerMember("swift", callerFile, peer.file, name))
313
+ continue;
314
+ visibleMemberIds.push(defNodeId(local));
315
+ }
316
+ return { def, isExtension: isSwiftExtensionContainer(peer.container, peer.context.source), visibleMemberIds };
317
+ }
318
+ /**
319
+ * C# partial declarations and unconstrained Swift extensions share type membership
320
+ * across proven peers. Constrained Swift extensions instead retain their own members
321
+ * and record only the peer members their lexical owner can use. This keeps unproven
322
+ * receivers from inheriting constrained members while preserving calls inside the
323
+ * extension. Same-named types in other namespaces or paths remain separate.
324
+ */
325
+ async function emitSharedOwnerMembershipEdges(context, owner, definitionId, memberNode) {
326
+ const container = owner.container;
327
+ if (!container)
328
+ return;
329
+ if (context.sup.id !== "csharp" && context.sup.id !== "swift")
330
+ return;
331
+ const isExtension = context.sup.id === "swift" && isSwiftExtensionContainer(container, context.source);
332
+ // Swift base types already own their full member set; only extensions and C#
333
+ // partials reach across owner declarations. Non-partial C# containers resolve
334
+ // to no peers inside the shared-owner relation.
335
+ // Constrained extensions can use nominal members but cannot donate their own
336
+ // members to every instance of the nominal type without proving the where clause.
337
+ const constrained = context.sup.id === "swift" && isSwiftConstrainedExtension(container, context.source);
338
+ if (constrained && context.sharedOwnerAccessibleMembers.has(defNodeId(owner.def)))
339
+ return;
340
+ const cacheKey = `${fileIdentityKey(context.moduleEntry.file)}\u0000${container.startIndex}\u0000${container.endIndex}`;
341
+ let peers = context.sharedOwnerPeers.get(cacheKey);
342
+ if (!peers) {
343
+ peers = resolveSharedOwnerContainers({
344
+ index: context.index,
345
+ ownerFile: context.moduleEntry.file,
346
+ ownerContainer: container,
347
+ ownerSource: context.source,
348
+ languageId: context.sup.id,
349
+ }).then((resolved) => resolved
350
+ .map((peer) => sharedOwnerPeerDef(peer, constrained ? context.moduleEntry.file : undefined))
351
+ .filter((peer) => !!peer));
352
+ context.sharedOwnerPeers.set(cacheKey, peers);
353
+ }
354
+ const peerDefs = await peers;
355
+ if (constrained) {
356
+ const ownerId = defNodeId(owner.def);
357
+ const accessible = context.sharedOwnerAccessibleMembers.get(ownerId) ?? new Set();
358
+ for (const peer of peerDefs)
359
+ for (const memberId of peer.visibleMemberIds ?? [])
360
+ accessible.add(memberId);
361
+ context.sharedOwnerAccessibleMembers.set(ownerId, accessible);
362
+ return;
363
+ }
364
+ for (const peer of peerDefs) {
365
+ if (isSwiftCrossFileHiddenSharedOwnerMember(context.sup.id, peer.def.file, context.moduleEntry.file, memberNode)) {
366
+ continue;
367
+ }
368
+ recordDefEdge(context, definitionId, peer.def, "member_of");
369
+ }
370
+ if (isExtension) {
371
+ const anchor = peerDefs.find((peer) => !peer.isExtension);
372
+ context.sharedOwnerAnchors.set(defNodeId(owner.def), defNodeId(anchor ? anchor.def : owner.def));
373
+ return;
374
+ }
375
+ if (context.sup.id === "csharp" && peerDefs.length) {
376
+ const representative = selectCsharpPartialRepresentative([owner.def, ...peerDefs.map((peer) => peer.def)]);
377
+ context.sharedOwnerAnchors.set(defNodeId(owner.def), defNodeId(representative));
378
+ }
379
+ }
380
+ function memberScopeForDefinition(context, fn, cppOutOfLine, outOfLineDeclaration) {
381
+ if (outOfLineDeclaration) {
382
+ return declarationNodeIsStatic(outOfLineDeclaration.node, outOfLineDeclaration.source) ? "static" : "instance";
163
383
  }
384
+ if (cppOutOfLine)
385
+ return "any";
386
+ // Kotlin has no `static` keyword; a member of a `companion object` or a named `object`
387
+ // declaration is the language's static-equivalent mechanism (reachable as `Outer.member()`).
388
+ if (declarationIsStaticEquivalent(context.sup.id, fn.node))
389
+ return "static";
390
+ const declarationNode = fn.node.parent?.type === "public_field_definition" || fn.node.parent?.type === "field_definition"
391
+ ? fn.node.parent
392
+ : fn.node;
393
+ return declarationNodeIsStatic(declarationNode, context.source) ? "static" : "instance";
164
394
  }
165
- /** Lexical class body, or the named Go receiver type for an out-of-line method. */
166
- function memberOwnerDef(context, fn, classNodes) {
395
+ /** Lexical type body, named Go receiver type, or named C++ out-of-line owner. */
396
+ async function memberOwner(context, fn, classNodes) {
397
+ if (!isClassMemberFunction(fn))
398
+ return null;
167
399
  if (context.sup.id === "go" && fn.node.type === "method_declaration") {
168
- return goMethodReceiverTypeDef(context, fn.node);
400
+ const def = goMethodReceiverTypeDef(context, fn.node);
401
+ return def ? { def, container: null, cppOutOfLine: false } : null;
169
402
  }
170
403
  const owners = classNodes
171
404
  .filter((candidate) => candidate.node.startIndex <= fn.node.startIndex && candidate.node.endIndex >= fn.node.endIndex)
172
405
  .sort((left, right) => left.node.endIndex - left.node.startIndex - (right.node.endIndex - right.node.startIndex));
173
- if (owners[0]?.def)
174
- return owners[0].def;
406
+ if (owners[0]?.def) {
407
+ if (!isDirectKeywordMemberDeclaration(fn.node, owners[0].node))
408
+ return null;
409
+ return { def: owners[0].def, container: owners[0].node, cppOutOfLine: false };
410
+ }
411
+ if (context.sup.id === "cpp") {
412
+ const ownerPath = cppOutOfLineOwnerPath(fn.node, context.source, context.sup);
413
+ const def = ownerPath
414
+ ? await resolveCppQualifiedMemberContainer(context.index, context.moduleEntry, ownerPath, context.loadParsedFile)
415
+ : null;
416
+ return def ? { def, container: null, cppOutOfLine: true } : null;
417
+ }
418
+ if (context.sup.id === "kotlin") {
419
+ // `fun Widget.describe()` is a top-level declaration outside Widget's own body, so it is
420
+ // never one of `owners` above; its receiver-type prefix is the only proof of ownership.
421
+ const receiverTypeNode = kotlinExtensionReceiverTypeNode(fn.node, context.sup);
422
+ if (!receiverTypeNode)
423
+ return null;
424
+ const def = resolveNamedType(context, sliceText(receiverTypeNode, context.source), receiverTypeNode);
425
+ return def ? { def, container: null, cppOutOfLine: false } : null;
426
+ }
427
+ if (context.sup.id === "rust") {
428
+ // A Rust impl method sits beside its self type, not inside it (like Go's receiver type);
429
+ // the `impl` block's self type is the owner, and only direct impl members count.
430
+ const container = nearestMemberContainer(fn.node);
431
+ if (!container || container.type !== "impl_item" || !isDirectKeywordMemberDeclaration(fn.node, container)) {
432
+ return null;
433
+ }
434
+ const nameNode = rustImplSelfTypeNode(container, context.sup);
435
+ const def = nameNode ? resolveNamedType(context, sliceText(nameNode, context.source), nameNode) : null;
436
+ return def ? { def, container, cppOutOfLine: false } : null;
437
+ }
175
438
  if (context.sup.id !== "zig")
176
439
  return null;
177
440
  const container = nearestMemberContainer(fn.node);
178
441
  if (container?.type !== "struct_declaration")
179
442
  return null;
180
443
  const name = container.parent?.namedChildren.find((child) => child.type === "identifier");
181
- return name ? resolveNamedType(context, sliceText(name, context.source), name) : null;
444
+ const def = name ? resolveNamedType(context, sliceText(name, context.source), name) : null;
445
+ return def ? { def, container, cppOutOfLine: false } : null;
446
+ }
447
+ async function cppOutOfLineMemberDeclaration(context, fn, ownerDef) {
448
+ const parsed = await context.loadParsedFile(ownerDef.file);
449
+ const startIndex = ownerDef.range.start.index;
450
+ const endIndex = ownerDef.range.end.index;
451
+ if (!parsed || startIndex === undefined || endIndex === undefined)
452
+ return null;
453
+ const ownerNameNode = parsed.tree.rootNode.descendantForIndex(startIndex, endIndex);
454
+ const declaration = cppOutOfLineMemberDeclarationNode(fn.node, fn.def.localName, ownerNameNode, parsed.source, context.sup);
455
+ return declaration ? { node: declaration.node, nameNode: declaration.nameNode, source: parsed.source } : null;
182
456
  }
183
457
  /** Receiver type of `func (b *T) M()` / `func (b T) M()`, unwrapped through pointers. */
184
458
  function goMethodReceiverTypeDef(context, methodNode) {
@@ -208,16 +482,347 @@ function unwrapGoNamedType(node) {
208
482
  return current?.type === "type_identifier" ? current : null;
209
483
  }
210
484
  /** Type-like defs only, so a PHP `use function` alias cannot steal `Example::m()`. */
211
- function resolveNamedType(context, name, node) {
485
+ function resolveNamedType(context, name, node, rubyConstructed = false) {
486
+ // A Go composite literal or Zig struct initializer can name a qualified cross-file type
487
+ // (`pkg.Type{}` / `ns.Type{}`); the receiver's typeName is then dotted text, not one
488
+ // identifier, so resolve the chain directly instead of treating it as a plain name.
489
+ if ((context.sup.id === "go" || context.sup.id === "zig") && context.optionalMemberTypes.has(node.type)) {
490
+ const qualified = context.resolveMemberChainTarget(node);
491
+ return qualified && declaresMembers(qualified) ? qualified : null;
492
+ }
212
493
  const target = context.resolveIdentifier(name, node);
213
494
  if (target && declaresMembers(target))
214
495
  return target;
215
496
  // A parameter/annotation type name is a closer scope binding than the class it names.
216
497
  const normalized = context.sup.normalizeIdentifier(name);
217
498
  const typed = context.moduleEntry.locals.filter((local) => context.sup.normalizeIdentifier(local.localName) === normalized && declaresMembers(local));
218
- return typed.length === 1 ? typed[0] : null;
499
+ if (typed.length === 1)
500
+ return typed[0];
501
+ const imported = context.aliasToTargetDef.get(name);
502
+ if (imported && declaresMembers(imported))
503
+ return imported;
504
+ // A constructed `Klass.new` type, or (Ruby only) a bare capitalized constant receiver
505
+ // (`Calc.add(1, 2)`), uses Ruby's bare-constant visibility, and only when this file does not
506
+ // already have several classes of that name. Inheritance names stay on resolveIdentifier so
507
+ // an unproven superclass is not invented.
508
+ const triesRubyVisibleConstant = rubyConstructed || context.sup.id === "ruby";
509
+ if (!triesRubyVisibleConstant || typed.length > 1)
510
+ return null;
511
+ return resolveRubyVisibleConstant(context.index, context.moduleEntry, context.sup, name);
512
+ }
513
+ /**
514
+ * Zig's static-receiver call form (`module.Type.member()`): the receiver is itself a qualified
515
+ * member-access node naming a type through another file's export (`counter.Counter` in
516
+ * `counter.Counter.zero()`). `classifyReceiver` only proves an identifier or keyword receiver,
517
+ * so this resolves the receiver's own chain directly and defers the member lookup through the
518
+ * same cross-file receiver-call pipeline every other member call uses.
519
+ */
520
+ function recordZigQualifiedTypeReceiverCall(context, node, access, fromId) {
521
+ const typeDef = context.resolveMemberChainTarget(access.receiver);
522
+ if (!typeDef || !declaresMembers(typeDef))
523
+ return false;
524
+ const memberName = sliceText(access.property, context.source);
525
+ if (!memberName)
526
+ return false;
527
+ const argumentCount = supportsReceiverMemberOverloads(context.sup.id)
528
+ ? getCallArgumentCount({ languageId: context.sup.id, source: context.source, call: node })
529
+ : null;
530
+ context.receiverCalls.push({
531
+ callerId: fromId,
532
+ ownerId: ensureNode(context, typeDef),
533
+ viaSupertypes: false,
534
+ memberName,
535
+ argumentCount,
536
+ site: { file: context.moduleEntry.file, range: toRange(access.property) },
537
+ memberScope: "any",
538
+ });
539
+ return true;
540
+ }
541
+ /**
542
+ * Go's `d.Base.Run()`: `d.Base` explicitly names an embedded field to reach a promoted method
543
+ * that a derived type's own same-named method would otherwise shadow, Go's equivalent of
544
+ * `super`/`base`. `classifyReceiver` only proves an identifier or keyword receiver, so a
545
+ * dotted `d.Base` receiver is never classified. This resolves `d`'s own type, confirms `Base`
546
+ * is really a nameless embedded field declared on it (not an unrelated named field that merely
547
+ * shares the name), then defers the member lookup through the same cross-file receiver-call
548
+ * pipeline every other member call uses. Limited to a same-file owner declaration: the AST
549
+ * needed to read the field list is only synchronously available there.
550
+ */
551
+ function recordGoEmbeddedFieldReceiverCall(context, access, fromId, hasLexicalBinding) {
552
+ const parts = getMemberAccessParts(context.sup, access.receiver);
553
+ const objectNode = parts.object;
554
+ const fieldNode = parts.property;
555
+ if (!objectNode || !fieldNode || !isIdentifierType(context.sup, fieldNode.type))
556
+ return false;
557
+ const ownerBinding = classifyReceiver(context.sup, objectNode, context.source, null, 0, access.receiver, hasLexicalBinding);
558
+ if (ownerBinding?.kind !== "named-type")
559
+ return false;
560
+ const ownerDef = resolveNamedType(context, ownerBinding.typeName, ownerBinding.typeNode, ownerBinding.constructed);
561
+ if (!ownerDef || fileIdentityKey(ownerDef.file) !== fileIdentityKey(context.moduleEntry.file))
562
+ return false;
563
+ const embeds = MEMBER_ACCESS_ROWS.go?.receiverAncestry?.embeds;
564
+ if (!embeds)
565
+ return false;
566
+ const start = ownerDef.range.start.index ?? 0;
567
+ const nameNode = context.tree.rootNode.descendantForIndex(start, ownerDef.range.end.index ?? start);
568
+ const declaration = nameNode.parent;
569
+ const declaredType = declaration?.childForFieldName("type");
570
+ if (!declaration || !declaredType)
571
+ return false;
572
+ const fieldName = sliceText(fieldNode, context.source);
573
+ for (const rule of embeds) {
574
+ if (declaredType.type !== rule.body)
575
+ continue;
576
+ const list = rule.memberList ? findFirstNodeByType(declaredType, rule.memberList) : declaredType;
577
+ if (!list)
578
+ continue;
579
+ for (const member of list.namedChildren ?? []) {
580
+ if (member.type !== rule.member)
581
+ continue;
582
+ if (rule.nameless && member.childForFieldName("name"))
583
+ continue;
584
+ const specifier = rule.typeField ? member.childForFieldName(rule.typeField) : member;
585
+ if (!specifier || sliceText(specifier, context.source) !== fieldName)
586
+ continue;
587
+ const embeddedDef = context.resolveIdentifier(fieldName, specifier);
588
+ if (!embeddedDef || !declaresMembers(embeddedDef))
589
+ return false;
590
+ const memberName = sliceText(access.property, context.source);
591
+ if (!memberName)
592
+ return false;
593
+ context.receiverCalls.push({
594
+ callerId: fromId,
595
+ ownerId: ensureNode(context, embeddedDef),
596
+ viaSupertypes: false,
597
+ memberName,
598
+ argumentCount: null,
599
+ site: { file: context.moduleEntry.file, range: toRange(access.property) },
600
+ memberScope: "any",
601
+ });
602
+ return true;
603
+ }
604
+ }
605
+ return false;
606
+ }
607
+ /**
608
+ * Collection can attach an arrow to any same-name local when the binding site is
609
+ * not that local (`obj.helper = () => 1` beside `const helper = 1`). Prove that
610
+ * this function is the value of `fn.def` itself: the declarator name is that
611
+ * definition, or an identifier assignment resolves to it. Member and pattern
612
+ * left-hand sides do not prove a local binding.
613
+ */
614
+ function provesCallableBinding(context, fn) {
615
+ const parent = fn.node.parent;
616
+ if (!parent)
617
+ return false;
618
+ const start = fn.def.range.start.index;
619
+ const end = fn.def.range.end.index;
620
+ if (start === undefined || end === undefined)
621
+ return false;
622
+ const sameNodeRange = (candidate) => !!candidate && candidate.startIndex === fn.node.startIndex && candidate.endIndex === fn.node.endIndex;
623
+ if ((parent.type === "variable_declarator" ||
624
+ parent.type === "public_field_definition" ||
625
+ parent.type === "field_definition") &&
626
+ sameNodeRange(parent.childForFieldName("value"))) {
627
+ const bindingName = parent.childForFieldName("name") ?? parent.childForFieldName("property");
628
+ return (!!bindingName &&
629
+ (isIdentifierType(context.sup, bindingName.type) || context.propertyIdentifierTypes.includes(bindingName.type)) &&
630
+ bindingName.startIndex === start &&
631
+ bindingName.endIndex === end);
632
+ }
633
+ if (parent.type === "assignment_expression" && sameNodeRange(parent.childForFieldName("right"))) {
634
+ const left = parent.childForFieldName("left");
635
+ if (!left || !isIdentifierType(context.sup, left.type))
636
+ return false;
637
+ const resolved = context.resolveIdentifier(sliceText(left, context.source), left);
638
+ return !!resolved && defNodeId(resolved) === defNodeId(fn.def);
639
+ }
640
+ return false;
641
+ }
642
+ /**
643
+ * Whether a resolved member can be a `calls` target: a function, a class, or a binding the
644
+ * declaration pass proved holds a function. A plain value (`export const value = 1`) is not.
645
+ */
646
+ /** A JS/TS class is not callable without `new`; construction is an `instantiates` edge instead. */
647
+ function isCallTarget(context, def) {
648
+ return def.kind === SymbolKind.Function || !!context.nodes.get(defNodeId(def))?.callable;
649
+ }
650
+ /**
651
+ * A member of a proven same-file TS namespace receiver, selected with navigation's container and
652
+ * overload rules. `undefined` means the receiver is not such a namespace.
653
+ */
654
+ function resolveTypeScriptNamespaceMember(context, call, receiverNode, property) {
655
+ if ((context.sup.id !== "ts" && context.sup.id !== "tsx") || !isIdentifierType(context.sup, receiverNode.type))
656
+ return undefined;
657
+ const receiver = context.resolveIdentifier(sliceText(receiverNode, context.source), receiverNode);
658
+ if (!receiver || fileIdentityKey(receiver.file) !== fileIdentityKey(context.moduleEntry.file))
659
+ return undefined;
660
+ const member = sliceText(property, context.source);
661
+ const candidates = findTypeScriptNamespaceMemberCandidates(context.moduleEntry.locals, member, receiver, context);
662
+ if (!candidates.length)
663
+ return undefined;
664
+ const selected = selectMember([receiver], {
665
+ ownerKey: (def) => def.callable?.owner ?? fileIdentityKey(def.file),
666
+ members: () => candidates,
667
+ supertypes: () => [],
668
+ name: (def) => def.localName,
669
+ key: (def) => def.callable?.key ?? `${fileIdentityKey(def.file)}:${def.range.start.index}`,
670
+ callable: (def) => def.callable,
671
+ scope: () => "any",
672
+ visible: () => true,
673
+ }, {
674
+ name: member,
675
+ argumentCount: getCallArgumentCount({ languageId: context.sup.id, source: context.source, call }),
676
+ scope: "any",
677
+ useFile: context.moduleEntry.file,
678
+ });
679
+ return selected.status === "unique" ? selected.member : null;
680
+ }
681
+ function recordTypeScriptNamespaceCall(context, call, access, fromId) {
682
+ const selected = resolveTypeScriptNamespaceMember(context, call, access.receiver, access.property);
683
+ if (selected === undefined)
684
+ return false;
685
+ if (selected && isCallTarget(context, selected))
686
+ recordDefEdge(context, fromId, selected, "calls", access.property);
687
+ return true;
688
+ }
689
+ /** `new N.C()` on a same-file TS namespace constructs the namespace's class. */
690
+ function recordTypeScriptNamespaceConstruction(context, node, target, fromId) {
691
+ if (!isMemberAccessNode(context.sup, target))
692
+ return false;
693
+ const { object, property } = getMemberAccessParts(context.sup, target);
694
+ if (!object || !property)
695
+ return false;
696
+ const selected = resolveTypeScriptNamespaceMember(context, node, object, property);
697
+ if (selected === undefined)
698
+ return false;
699
+ if (selected?.kind === SymbolKind.Class)
700
+ recordDefEdge(context, fromId, selected, "instantiates", property);
701
+ return true;
702
+ }
703
+ /** A member call on a `typeof import("spec")` binding names that module's export. */
704
+ function recordImportTypeCall(context, access, fromId, proof) {
705
+ if (!isJsTsLanguage(context.sup.id))
706
+ return false;
707
+ const importType = proof.kind === "named-type" ? proof.typeNode : null;
708
+ const specifier = importType?.type === "type_query" ? importTypeQuerySpecifier(importType) : null;
709
+ if (!specifier)
710
+ return false;
711
+ const member = sliceText(access.property, context.source);
712
+ const target = resolveImportTypeMember(context.index, context.moduleEntry.file, specifier, member);
713
+ if (target && isCallTarget(context, target))
714
+ recordDefEdge(context, fromId, target, "calls", access.property);
715
+ return true;
716
+ }
717
+ /** Swift `Foo()` / `Worker(name:)` is construction. Record `instantiates` and skip the call path. */
718
+ function recordSwiftCapitalizedConstruction(context, node, fromId) {
719
+ const constructed = constructionTypeName(node, context.source, context.sup);
720
+ if (!constructed)
721
+ return false;
722
+ const name = sliceText(constructed, context.source);
723
+ // An inherited method can share a type's name; a deferred member lookup decides after the walk.
724
+ if (context.resolveName(name, constructed)?.status === "deferred")
725
+ return false;
726
+ const target = context.resolveIdentifier(name, constructed);
727
+ if (!target || !declaresMembers(target))
728
+ return false;
729
+ recordDefEdge(context, fromId, target, "instantiates", constructed);
730
+ return true;
731
+ }
732
+ function recordGoBuiltinConstruction(context, node, fromId) {
733
+ const callTarget = getCallTarget(node);
734
+ const calleeName = callTarget && isIdentifierType(context.sup, callTarget.type) ? sliceText(callTarget, context.source) : null;
735
+ if (calleeName !== "new" && calleeName !== "make")
736
+ return undefined;
737
+ const argList = node.childForFieldName("arguments") ?? node.childForFieldName("argument_list");
738
+ const typeNode = argList?.namedChildren?.find((child) => child.type === "type_identifier") ?? null;
739
+ if (typeNode)
740
+ tryResolveNode(context, typeNode, fromId, "instantiates");
741
+ return false;
742
+ }
743
+ function recordRubySuper(context, fn, superNode, fromId) {
744
+ const container = nearestMemberContainer(fn.node);
745
+ if (!container || container.type !== "class")
746
+ return;
747
+ const owner = memberContainerDef(context.moduleEntry, container);
748
+ if (!owner)
749
+ return;
750
+ context.receiverCalls.push({
751
+ callerId: fromId,
752
+ ownerId: ensureNode(context, owner),
753
+ viaSupertypes: true,
754
+ memberName: fn.def.localName,
755
+ argumentCount: null,
756
+ site: { file: context.moduleEntry.file, range: toRange(superNode) },
757
+ memberScope: "any",
758
+ });
219
759
  }
220
- export function emitFunctionBodyEdges(context, functionNodes) {
760
+ function recordRubyCall(context, node, fromId, resolveCallTarget) {
761
+ if (node.type !== "call")
762
+ return undefined;
763
+ const methodNode = node.childForFieldName("method");
764
+ const receiverNode = node.childForFieldName("receiver");
765
+ const methodName = methodNode ? sliceText(methodNode, context.source) : null;
766
+ if (methodName === "new" && receiverNode) {
767
+ const recorded = tryResolveNode(context, receiverNode, fromId, "instantiates");
768
+ if (!recorded) {
769
+ const rubyType = resolveRubyVisibleConstant(context.index, context.moduleEntry, context.sup, sliceText(receiverNode, context.source));
770
+ if (rubyType)
771
+ recordDefEdge(context, fromId, rubyType, "instantiates", receiverNode);
772
+ }
773
+ return false;
774
+ }
775
+ if (methodNode?.type === "super")
776
+ return true;
777
+ if (methodNode) {
778
+ resolveCallTarget(node, methodNode);
779
+ return false;
780
+ }
781
+ const callee = getCallTarget(node);
782
+ if (callee?.type === "super")
783
+ return true;
784
+ resolveCallTarget(node, callee);
785
+ return false;
786
+ }
787
+ /** Specialized syntax stays with its language; the common walker only dispatches these hooks. */
788
+ export const SPECIALIZED_EDGE_PASSES = {
789
+ python: { beforeModule: emitPythonDecoratorEdges },
790
+ rust: {
791
+ afterModule: emitRustImplEdges,
792
+ onNode(context, _fn, node, fromId) {
793
+ if (node.type === "token_tree")
794
+ recordRustMacroArgumentCalls(context, node, fromId);
795
+ return undefined;
796
+ },
797
+ },
798
+ go: {
799
+ onReceiverCall(context, access, fromId, hasLexicalBinding) {
800
+ return (context.optionalMemberTypes.has(access.receiver.type) &&
801
+ recordGoEmbeddedFieldReceiverCall(context, access, fromId, hasLexicalBinding));
802
+ },
803
+ onCall: recordGoBuiltinConstruction,
804
+ },
805
+ ruby: {
806
+ onNode(context, fn, node, fromId) {
807
+ if (node.type !== "super")
808
+ return undefined;
809
+ recordRubySuper(context, fn, node, fromId);
810
+ return true;
811
+ },
812
+ onCall: recordRubyCall,
813
+ },
814
+ swift: {
815
+ onCall(context, node, fromId) {
816
+ return recordSwiftCapitalizedConstruction(context, node, fromId) ? true : undefined;
817
+ },
818
+ },
819
+ };
820
+ export async function emitFunctionBodyEdges(context, functionNodes) {
821
+ const specialized = SPECIALIZED_EDGE_PASSES[context.sup.id];
822
+ const qualifiedConstructionTargets = [];
823
+ // C# calls through a dotted receiver (`P.Mix.M()`, `Imported.Outer.Inner.M()`): navigation's
824
+ // member-access resolution decides the target after the walk, so both consumers agree.
825
+ const dottedReceiverCalls = [];
221
826
  const callNodeTypes = new Set([
222
827
  "call_expression",
223
828
  "call",
@@ -229,21 +834,29 @@ export function emitFunctionBodyEdges(context, functionNodes) {
229
834
  "nullsafe_member_call_expression",
230
835
  "scoped_call_expression",
231
836
  ]);
232
- const newNodeTypes = new Set([
233
- "new_expression",
234
- "object_creation_expression",
235
- "struct_expression",
236
- "composite_literal",
237
- ]);
238
- // Receiver typing and lexical member lookup are only needed once a receiver call
239
- // fails the cheaper identifier and import-chain resolution, so both are lazy.
837
+ const newNodeTypes = {
838
+ new_expression: true,
839
+ object_creation_expression: true,
840
+ struct_expression: true,
841
+ composite_literal: true,
842
+ // tree-sitter-zig's own struct-literal node, e.g. `Widget{}` or a qualified `ns.Widget{}`.
843
+ struct_initializer: true,
844
+ };
845
+ // Receiver typing and lexical member lookup are initialized only for receiver calls.
846
+ const receiverProofs = new Map();
847
+ const hasLexicalBinding = (callee) => {
848
+ const scope = context.index.scopeCache.get(fileIdentityKey(context.moduleEntry.file));
849
+ return !scope || !!findClosestScopeBinding(scope, sliceText(callee, context.source), callee, context.sup);
850
+ };
240
851
  let membersByContainer;
241
852
  const lexicalMembers = (container) => {
242
853
  if (!membersByContainer) {
243
854
  membersByContainer = new Map();
244
855
  for (const candidate of functionNodes) {
856
+ if (!isClassMemberFunction(candidate))
857
+ continue;
245
858
  const owner = nearestMemberContainer(candidate.node);
246
- if (!owner)
859
+ if (!owner || !isDirectKeywordMemberDeclaration(candidate.node, owner))
247
860
  continue;
248
861
  const members = membersByContainer.get(owner.startIndex);
249
862
  if (members)
@@ -254,10 +867,21 @@ export function emitFunctionBodyEdges(context, functionNodes) {
254
867
  }
255
868
  return membersByContainer.get(container.startIndex) ?? [];
256
869
  };
257
- const receiverProofs = new Map();
258
870
  for (const fn of functionNodes) {
871
+ const phpCaseInsensitive = context.sup.id === "php";
259
872
  const fromId = ensureNode(context, fn.def);
873
+ const provenNode = context.nodes.get(fromId);
874
+ // Function-valued bindings (`const helper = () => 1`) keep their `variable` kind;
875
+ // the callable metadata records that this binding was proven to hold a function.
876
+ if (provenNode && provenNode.kind !== "function" && provesCallableBinding(context, fn)) {
877
+ provenNode.callable = true;
878
+ context.noteCallableName(fn.name, context.sup.id === "php");
879
+ }
260
880
  const seenAliases = new Set();
881
+ // Calls whose target needs an async member lookup (C++ out-of-line owner members, included
882
+ // C/C++ declarations of one callable); settled after the walk.
883
+ const deferredCalls = [];
884
+ const qualifiedCppCalls = [];
261
885
  const nestedFunctions = new Set(functionNodes
262
886
  .filter((candidate) => candidate.node !== fn.node &&
263
887
  candidate.node.startIndex >= fn.node.startIndex &&
@@ -267,12 +891,28 @@ export function emitFunctionBodyEdges(context, functionNodes) {
267
891
  if (context.membersOnly || !isIdentifierType(context.sup, node.type))
268
892
  return;
269
893
  const name = sliceText(node, context.source);
894
+ if (context.sup.id === "php") {
895
+ // Resolve the occurrence's namespace; a plain-name map cannot distinguish PHP roles.
896
+ const importType = inferPhpQualifiedReferenceImportType(node) ?? "const";
897
+ const aliasName = importType === "const" ? name : foldPhpIdentifierCase(name);
898
+ const seenKey = `${importType}:${aliasName}`;
899
+ if (seenAliases.has(seenKey))
900
+ return;
901
+ seenAliases.add(seenKey);
902
+ const phpImport = findPhpImportAlias(context.moduleEntry.imports, name, importType);
903
+ if (!phpImport || typeof phpImport.resolved !== "string")
904
+ return;
905
+ const resolved = resolvePhpExportByImportType(context.index, phpImport.resolved, phpImport.imported, importType);
906
+ if (resolved?.kind === "resolved")
907
+ recordDefEdge(context, fromId, resolved.def, "uses");
908
+ return;
909
+ }
270
910
  if (seenAliases.has(name))
271
911
  return;
272
912
  let target = context.aliasToTargetDef.get(name) ?? null;
273
913
  if (!target) {
274
914
  const modFile = context.aliasToTargetModule.get(name);
275
- if (modFile) {
915
+ if (modFile && context.moduleAliasIsUnshadowed(name, node)) {
276
916
  let exportedName = null;
277
917
  const parent = node.parent;
278
918
  if (parent &&
@@ -284,7 +924,7 @@ export function emitFunctionBodyEdges(context, functionNodes) {
284
924
  }
285
925
  if (exportedName) {
286
926
  target = context.resolveExportFrom(modFile, exportedName);
287
- if (!target) {
927
+ if (!target && (context.sup.id !== "go" || isGoExportedMemberName(context.sup.id, exportedName))) {
288
928
  const targetModule = context.index.byFile.get(fileIdentityKey(modFile));
289
929
  target = (targetModule?.locals ?? []).find((local) => local.localName === exportedName) ?? null;
290
930
  }
@@ -304,22 +944,44 @@ export function emitFunctionBodyEdges(context, functionNodes) {
304
944
  recordDefEdge(context, fromId, targetDef, "uses");
305
945
  }
306
946
  };
947
+ const classifyImport = (name, node) => {
948
+ if (isJsTsLanguage(context.sup.id) && isIdentifierType(context.sup, node.type)) {
949
+ const imported = effectiveExplicitBinding(context.moduleEntry.imports, context.sup.id, (candidate) => candidate.kind === "namespace" && candidate.localNS === name, node.startIndex) ?? innermostNamespaceImport(context.moduleEntry.imports, name, node);
950
+ if (imported?.mechanism === "cjs" && typeof imported.resolved === "string") {
951
+ const value = cjsRequireValueBinding(context.index, imported.resolved);
952
+ const lexical = value ? context.resolveIdentifier(name, node) : null;
953
+ if (value && declaresMembers(value) && lexical && defNodeId(value) === defNodeId(lexical)) {
954
+ return "static-type";
955
+ }
956
+ return "module-import";
957
+ }
958
+ }
959
+ if (context.aliasToTargetModule.has(name) && context.moduleAliasIsUnshadowed(name, node)) {
960
+ return "module-import";
961
+ }
962
+ return null;
963
+ };
307
964
  /**
308
965
  * Resolves a receiver method call against the receiver's type. Members declared
309
966
  * alongside the caller resolve here; anything needing another module's members
310
967
  * becomes a deferred candidate.
311
968
  */
312
- const recordReceiverCall = (node, access) => {
969
+ const recordReceiverCall = (node, access, forcedMemberScope, proof) => {
313
970
  const memberName = sliceText(access.property, context.source);
314
- if (!memberName || !context.hasCallableNamed(memberName))
971
+ if (!memberName)
315
972
  return;
316
- const binding = classifyReceiver(context.sup, access.receiver, context.source, receiverProofs, fn.node.startIndex, access.accessNode);
317
- if (!binding)
973
+ const binding = proof ??
974
+ classifyReceiver(context.sup, access.receiver, context.source, receiverProofs, fn.node.startIndex, access.accessNode, hasLexicalBinding, classifyImport);
975
+ if (binding.kind === "module-import" || binding.kind === "unknown")
318
976
  return;
319
977
  const site = { file: context.moduleEntry.file, range: toRange(access.property) };
320
- const argumentCount = callArgumentCount(node);
978
+ // Shared call-count facts treat unproven spread expansions as unknown (null),
979
+ // so overload selection never fabricates an argument count.
980
+ const argumentCount = supportsReceiverMemberOverloads(context.sup.id)
981
+ ? getCallArgumentCount({ languageId: context.sup.id, source: context.source, call: node })
982
+ : null;
321
983
  if (binding.kind === "named-type") {
322
- const typeDef = resolveNamedType(context, binding.typeName, access.receiver);
984
+ const typeDef = resolveNamedType(context, binding.typeName, binding.typeNode, binding.constructed);
323
985
  if (!typeDef)
324
986
  return;
325
987
  context.receiverCalls.push({
@@ -329,26 +991,89 @@ export function emitFunctionBodyEdges(context, functionNodes) {
329
991
  memberName,
330
992
  argumentCount,
331
993
  site,
994
+ memberScope: forcedMemberScope ?? binding.memberScope,
995
+ ...(context.sup.id === "go" && !isGoExportedMemberName(context.sup.id, memberName)
996
+ ? { goPackagePeerFiles: getCompilationUnitPeers(context.index, context.moduleEntry.file).files }
997
+ : {}),
998
+ caseInsensitiveMemberName: phpCaseInsensitive,
332
999
  });
333
1000
  return;
334
1001
  }
335
1002
  if (binding.kind === "own-type") {
336
1003
  const container = nearestMemberContainer(fn.node);
337
1004
  const declared = container
338
- ? lexicalMembers(container).filter((candidate) => candidate.def.localName === memberName)
1005
+ ? lexicalMembers(container).filter((candidate) => {
1006
+ const candidateName = candidate.def.localName;
1007
+ const nameMatches = phpCaseInsensitive
1008
+ ? foldPhpIdentifierCase(candidateName) === foldPhpIdentifierCase(memberName)
1009
+ : candidateName === memberName;
1010
+ if (!nameMatches)
1011
+ return false;
1012
+ if (binding.memberScope === "any")
1013
+ return true;
1014
+ return declarationNodeIsStatic(candidate.node, context.source) === (binding.memberScope === "static");
1015
+ })
339
1016
  : [];
340
1017
  if (declared.length === 1) {
341
- recordDefEdge(context, fromId, declared[0].def, "calls", access.property);
342
- return;
1018
+ const unique = declared[0];
1019
+ recordDefEdge(context, fromId, unique.def, "calls", access.property);
1020
+ // File-hidden Swift members stay off cross-file shared owners. Skipping the
1021
+ // coalesced deferred lookup keeps a same-container private call from being stripped.
1022
+ if (isSwiftFileHiddenSharedOwnerMember(context.sup.id, unique.node))
1023
+ return;
343
1024
  }
344
1025
  }
1026
+ const receiverContainer = nearestMemberContainer(access.accessNode);
1027
+ const receiverContainerName = receiverContainer?.childForFieldName("name");
1028
+ const receiverOwnerDef = receiverContainerName
1029
+ ? context.moduleEntry.locals.find((local) => local.range.start.index === receiverContainerName.startIndex && declaresMembers(local))
1030
+ : undefined;
345
1031
  context.receiverCalls.push({
346
1032
  callerId: fromId,
347
- ownerId: null,
1033
+ ownerId: receiverOwnerDef ? ensureNode(context, receiverOwnerDef) : null,
348
1034
  viaSupertypes: binding.kind === "supertype",
349
1035
  memberName,
350
1036
  argumentCount,
351
1037
  site,
1038
+ memberScope: binding.memberScope,
1039
+ caseInsensitiveMemberName: phpCaseInsensitive,
1040
+ });
1041
+ };
1042
+ /**
1043
+ * A bare call inside a member function carries no receiver syntax, but in
1044
+ * languages where that implicitly targets `this` it can still name an
1045
+ * inherited member. Deferred like `recordReceiverCall`'s own-type/supertype
1046
+ * candidates so cross-file base-type members resolve once every module's
1047
+ * `member_of` and hierarchy edges are known.
1048
+ */
1049
+ const recordImplicitSelfMemberCall = (node, callee, fallbackDef = null) => {
1050
+ if (!supportsImplicitSelfMemberCalls(context.sup.id) || !isIdentifierType(context.sup, callee.type))
1051
+ return;
1052
+ const container = nearestMemberContainer(fn.node);
1053
+ const containerName = container?.childForFieldName("name");
1054
+ const ownerDef = containerName
1055
+ ? context.moduleEntry.locals.find((local) => local.range.start.index === containerName.startIndex && declaresMembers(local))
1056
+ : undefined;
1057
+ if (!ownerDef)
1058
+ return;
1059
+ const memberName = sliceText(callee, context.source);
1060
+ if (!memberName)
1061
+ return;
1062
+ const argumentCount = supportsReceiverMemberOverloads(context.sup.id)
1063
+ ? getCallArgumentCount({ languageId: context.sup.id, source: context.source, call: node })
1064
+ : null;
1065
+ context.receiverCalls.push({
1066
+ callerId: fromId,
1067
+ ownerId: ensureNode(context, ownerDef),
1068
+ viaSupertypes: false,
1069
+ memberName,
1070
+ argumentCount,
1071
+ site: { file: context.moduleEntry.file, range: toRange(callee) },
1072
+ // A static caller can only reach a static bare member; an instance caller
1073
+ // may bare-call either, matching C#'s unqualified invocation rules.
1074
+ memberScope: nodeInStaticMemberContext(fn.node, context.source) ? "static" : "any",
1075
+ caseInsensitiveMemberName: phpCaseInsensitive,
1076
+ fallbackTargetId: fallbackDef ? ensureNode(context, fallbackDef) : undefined,
352
1077
  });
353
1078
  };
354
1079
  /**
@@ -360,46 +1085,116 @@ export function emitFunctionBodyEdges(context, functionNodes) {
360
1085
  const resolveCallTarget = (node, callee) => {
361
1086
  const access = receiverCallAccess(context.sup, node, callee);
362
1087
  if (access) {
363
- if (!tryResolveChain(context, access.accessNode, fromId, "calls"))
364
- recordReceiverCall(node, access);
1088
+ if (recordTypeScriptNamespaceCall(context, node, access, fromId))
1089
+ return;
1090
+ const typeScopedCppCall = context.sup.id === "cpp" &&
1091
+ context.source.slice(access.receiver.endIndex, access.property.startIndex).includes("::");
1092
+ if (typeScopedCppCall) {
1093
+ const qualifiedName = cppQualifiedNameSegments(access.accessNode, context.source).join("::");
1094
+ const qualifiedTarget = context.resolveIdentifier(qualifiedName, access.property);
1095
+ // Whether the owner is a class, and whether the caller has an implicit `this` of that class,
1096
+ // needs the exact qualified path, so the decision waits until the function body is walked.
1097
+ qualifiedCppCalls.push({
1098
+ node,
1099
+ access,
1100
+ target: qualifiedTarget,
1101
+ ownerPath: qualifiedName.split("::").slice(0, -1),
1102
+ });
1103
+ return;
1104
+ }
1105
+ const receiverProof = classifyReceiver(context.sup, access.receiver, context.source, receiverProofs, fn.node.startIndex, access.accessNode, hasLexicalBinding, classifyImport);
1106
+ if (recordImportTypeCall(context, access, fromId, receiverProof))
1107
+ return;
1108
+ if (supportsDeclaredFieldChains(context.sup.id) && isMemberAccessNode(context.sup, access.receiver)) {
1109
+ dottedReceiverCalls.push({ fromId, access });
1110
+ return;
1111
+ }
1112
+ if (receiverProof.kind === "own-type" || receiverProof.kind === "supertype") {
1113
+ recordReceiverCall(node, access, undefined, receiverProof);
1114
+ return;
1115
+ }
1116
+ if (context.sup.id === "swift" &&
1117
+ isIdentifierType(context.sup, access.receiver.type) &&
1118
+ context.resolveIdentifier(sliceText(access.receiver, context.source), access.receiver)?.kind ===
1119
+ SymbolKind.TypeAlias) {
1120
+ dottedReceiverCalls.push({ fromId, access });
1121
+ return;
1122
+ }
1123
+ if (tryResolveChain(context, access.accessNode, fromId, "calls"))
1124
+ return;
1125
+ if (context.sup.id === "zig" &&
1126
+ context.optionalMemberTypes.has(access.receiver.type) &&
1127
+ recordZigQualifiedTypeReceiverCall(context, node, access, fromId)) {
1128
+ return;
1129
+ }
1130
+ if (specialized?.onReceiverCall?.(context, access, fromId, hasLexicalBinding))
1131
+ return;
1132
+ const javaConstructionType = context.sup.id === "java" && access.receiver.type === "object_creation_expression"
1133
+ ? constructionTypeName(access.receiver, context.source, context.sup)
1134
+ : null;
1135
+ if (context.sup.id === "java" &&
1136
+ javaConstructionType &&
1137
+ isMemberAccessNode(context.sup, javaConstructionType)) {
1138
+ dottedReceiverCalls.push({ fromId, access });
1139
+ return;
1140
+ }
1141
+ if (context.sup.id === "kotlin" &&
1142
+ (isIdentifierType(context.sup, access.receiver.type) || access.receiver.type === "navigation_expression") &&
1143
+ !context.resolveIdentifier(sliceText(access.receiver, context.source), access.receiver)) {
1144
+ dottedReceiverCalls.push({ fromId, access });
1145
+ return;
1146
+ }
1147
+ recordReceiverCall(node, access, undefined, receiverProof);
365
1148
  return;
366
1149
  }
367
- if (callee)
368
- tryResolveNode(context, callee, fromId, "calls");
1150
+ if (!callee)
1151
+ return;
1152
+ // A name whose lookup waits on an async member step (implicit `this`/`self`, C++ out-of-line
1153
+ // owners, included C/C++ declarations) settles after the walk exactly as navigation does.
1154
+ if (isIdentifierType(context.sup, callee.type)) {
1155
+ const name = sliceText(callee, context.source);
1156
+ const resolution = context.resolveName(name, callee);
1157
+ if (resolution?.status === "deferred") {
1158
+ deferredCalls.push({ callee, name, resolution });
1159
+ return;
1160
+ }
1161
+ }
1162
+ if (!tryResolveNode(context, callee, fromId, "calls"))
1163
+ recordImplicitSelfMemberCall(node, callee);
369
1164
  };
370
1165
  const recordCallOrInstantiation = (node) => {
1166
+ const nodeResult = specialized?.onNode?.(context, fn, node, fromId);
1167
+ if (nodeResult !== undefined)
1168
+ return nodeResult;
371
1169
  if (callNodeTypes.has(node.type)) {
372
- if (context.sup.id === "go") {
373
- const callTarget = getCallTarget(node);
374
- const calleeName = callTarget && isIdentifierType(context.sup, callTarget.type) ? sliceText(callTarget, context.source) : null;
375
- if (calleeName === "new" || calleeName === "make") {
376
- const argList = node.childForFieldName("arguments") ?? node.childForFieldName("argument_list");
377
- const typeNode = argList?.namedChildren?.find((child) => child.type === "type_identifier") ?? null;
378
- if (typeNode) {
379
- tryResolveNode(context, typeNode, fromId, "instantiates");
380
- }
381
- return false;
382
- }
1170
+ const callResult = specialized?.onCall?.(context, node, fromId, resolveCallTarget);
1171
+ if (callResult !== undefined)
1172
+ return callResult;
1173
+ resolveCallTarget(node, getCallTarget(node));
1174
+ }
1175
+ if (newNodeTypes[node.type]) {
1176
+ const keyword = phpObjectCreationKeyword(node, context.source, context.sup);
1177
+ if (keyword) {
1178
+ const created = resolvePhpObjectCreationTarget(context.index, context.moduleEntry, keyword, context.source, context.sup);
1179
+ if (created)
1180
+ recordDefEdge(context, fromId, created, "instantiates", keyword.nameNode);
383
1181
  }
384
- if (context.sup.id === "ruby" && node.type === "call") {
385
- const methodNode = node.childForFieldName("method");
386
- const receiverNode = node.childForFieldName("receiver");
387
- const methodName = methodNode ? sliceText(methodNode, context.source) : null;
388
- if (methodName === "new" && receiverNode) {
389
- tryResolveNode(context, receiverNode, fromId, "instantiates");
390
- return false;
391
- }
392
- if (methodNode) {
393
- resolveCallTarget(node, methodNode);
394
- return false;
1182
+ else {
1183
+ const target = constructionTypeName(node, context.source, context.sup) ?? getNewTarget(node);
1184
+ if (target) {
1185
+ if (recordTypeScriptNamespaceConstruction(context, node, target, fromId))
1186
+ return true;
1187
+ const property = isMemberAccessNode(context.sup, target)
1188
+ ? getMemberAccessParts(context.sup, target).property
1189
+ : null;
1190
+ if ((context.sup.id === "java" || context.sup.id === "csharp") && property) {
1191
+ qualifiedConstructionTargets.push({ fromId, member: property, target });
1192
+ }
1193
+ else {
1194
+ tryResolveNode(context, target, fromId, "instantiates");
1195
+ }
395
1196
  }
396
1197
  }
397
- resolveCallTarget(node, getCallTarget(node));
398
- }
399
- if (newNodeTypes.has(node.type)) {
400
- const target = getNewTarget(node);
401
- if (target)
402
- tryResolveNode(context, target, fromId, "instantiates");
403
1198
  }
404
1199
  return true;
405
1200
  };
@@ -413,11 +1208,54 @@ export function emitFunctionBodyEdges(context, functionNodes) {
413
1208
  walkFunctionBody(child, allowChildCallProcessing);
414
1209
  };
415
1210
  walkFunctionBody(fn.node, true);
1211
+ for (const call of deferredCalls) {
1212
+ const target = await context.settleName(call.name, call.callee, call.resolution);
1213
+ // Swift `Foo()` whose deferred lookup settles on a type is construction.
1214
+ const label = context.sup.id === "swift" && target && declaresMembers(target) ? "instantiates" : "calls";
1215
+ if (target)
1216
+ recordDefEdge(context, fromId, target, label, call.callee);
1217
+ }
1218
+ for (const call of qualifiedCppCalls) {
1219
+ const owner = call.ownerPath.length
1220
+ ? await resolveCppQualifiedMemberContainer(context.index, context.moduleEntry, call.ownerPath, context.loadParsedFile)
1221
+ : null;
1222
+ if (!owner) {
1223
+ // A namespace (or no) qualifier names the free function directly.
1224
+ if (call.target)
1225
+ recordDefEdge(context, fromId, call.target, "calls", call.access.property);
1226
+ continue;
1227
+ }
1228
+ const implicitThis = await cppQualifiedOwnerHasImplicitThis(context.index, context.moduleEntry, call.access.accessNode, context.source, context.sup, owner);
1229
+ if (implicitThis && call.target) {
1230
+ recordDefEdge(context, fromId, call.target, "calls", call.access.property);
1231
+ }
1232
+ else {
1233
+ // Without an implicit `this` of the owner, `Owner::member()` can only name a static member.
1234
+ recordReceiverCall(call.node, call.access, implicitThis ? "any" : "static");
1235
+ }
1236
+ }
1237
+ }
1238
+ for (const { fromId, access } of dottedReceiverCalls) {
1239
+ const member = await context.resolveMemberAccessTarget(access.property);
1240
+ // The graph records no edge for a call its target cannot accept, as for other member calls.
1241
+ if (member && memberAcceptsCallAt(context.index, member, access.accessNode, context.source, context.sup.id)) {
1242
+ recordDefEdge(context, fromId, member, "calls", access.property);
1243
+ }
1244
+ }
1245
+ for (const target of qualifiedConstructionTargets) {
1246
+ const resolved = await context.resolveMemberAccessTarget(target.member);
1247
+ if (resolved) {
1248
+ recordDefEdge(context, target.fromId, resolved, "instantiates", target.member);
1249
+ }
1250
+ else {
1251
+ tryResolveNode(context, target.target, target.fromId, "instantiates");
1252
+ }
416
1253
  }
417
1254
  }
418
1255
  /** Qualifiers name a container, not another base type. */
419
1256
  const QUALIFIER_NAME_FIELD = {
420
1257
  qualified_name: "name", // C#: Namespace.Base, Outer.Inner
1258
+ alias_qualified_name: "name", // C#: X::Base, global::Namespace.Base
421
1259
  qualified_identifier: "name", // C++: ns::Base
422
1260
  scope_resolution: "name", // Ruby: Module::Base
423
1261
  qualified_type: "name", // Go: pkg.Base
@@ -504,9 +1342,19 @@ function narrowBaseSpecifierNode(node) {
504
1342
  }
505
1343
  /** Collect one type identifier per direct base or interface specifier. */
506
1344
  function collectBaseSpecifierIdentifiers(node, sup, out) {
1345
+ if (isUnprovenHeritageExpression(node))
1346
+ return;
507
1347
  if (BASE_TYPE_IGNORED_TYPES[node.type])
508
1348
  return;
1349
+ if (sup.id === "cpp" && node.type === "qualified_identifier") {
1350
+ out.push(node);
1351
+ return;
1352
+ }
509
1353
  const narrowed = narrowBaseSpecifierNode(node);
1354
+ if ((sup.id === "ts" || sup.id === "tsx") && narrowed.type === "member_expression") {
1355
+ out.push(narrowed);
1356
+ return;
1357
+ }
510
1358
  if (isIdentifierType(sup, narrowed.type) || narrowed.type === "type_identifier") {
511
1359
  out.push(narrowed);
512
1360
  return;
@@ -514,19 +1362,39 @@ function collectBaseSpecifierIdentifiers(node, sup, out) {
514
1362
  for (const child of narrowed.namedChildren ?? [])
515
1363
  collectBaseSpecifierIdentifiers(child, sup, out);
516
1364
  }
517
- function recordIdentifierRelations(context, fromId, container, relationForTarget) {
1365
+ async function recordIdentifierRelations(context, fromId, container, relationForTarget) {
518
1366
  const identifiers = [];
519
1367
  collectBaseSpecifierIdentifiers(container, context.sup, identifiers);
520
1368
  const seen = new Set();
521
1369
  for (const [index, identifier] of identifiers.entries()) {
522
- const target = context.resolveIdentifier(sliceText(identifier, context.source), identifier);
1370
+ let target;
1371
+ if (context.sup.id === "cpp" && identifier.type === "qualified_identifier") {
1372
+ const qualifiedPath = cppQualifiedNameSegments(identifier, context.source);
1373
+ target = await resolveCppQualifiedMemberContainer(context.index, context.moduleEntry, qualifiedPath, context.loadParsedFile);
1374
+ if (!target && qualifiedPath.length > 1) {
1375
+ target = context.resolveIdentifier(qualifiedPath.join("::"), identifier);
1376
+ }
1377
+ }
1378
+ else if ((context.sup.id === "ts" || context.sup.id === "tsx") && identifier.type === "member_expression") {
1379
+ const qualified = context.resolveMemberChainTarget(identifier);
1380
+ target = qualified && declaresMembers(qualified) ? qualified : null;
1381
+ }
1382
+ else {
1383
+ const name = sliceText(identifier, context.source);
1384
+ target = context.resolveIdentifier(name, identifier);
1385
+ // Ruby `require` publishes a top-level constant, not a nested one. Reuse the
1386
+ // same visibility as goto so `class Worker < Base` follows the required class.
1387
+ if (!target && context.sup.id === "ruby") {
1388
+ target = resolveRubyVisibleConstant(context.index, context.moduleEntry, context.sup, name);
1389
+ }
1390
+ }
523
1391
  if (!target)
524
1392
  continue;
525
1393
  const targetId = defNodeId(target);
526
1394
  if (seen.has(targetId))
527
1395
  continue;
528
1396
  seen.add(targetId);
529
- recordDefEdge(context, fromId, target, relationForTarget(target, index), identifier);
1397
+ recordDefEdge(context, fromId, target, relationForTarget(target, index, identifier), identifier);
530
1398
  }
531
1399
  }
532
1400
  const RUBY_NESTED_SCOPE_TYPES = new Set(["class", "module", "method", "singleton_method", "block", "do_block"]);
@@ -540,68 +1408,24 @@ function collectDirectCallsExcludingNestedScopes(node, out) {
540
1408
  collectDirectCallsExcludingNestedScopes(child, out);
541
1409
  }
542
1410
  }
543
- const TYPESCRIPT_INHERITANCE_RULES = {
544
- clauses: [
545
- // The value field is the superclass expression; the sibling type_arguments
546
- // field holds super-call type arguments, which are not base types.
547
- { type: "extends_clause", label: "extends", field: "value" },
548
- { type: "implements_clause", label: "implements" },
549
- ],
550
- };
551
- /**
552
- * Per-language class hierarchy forms. The grammar and the language runtime are
553
- * the only sources of these node names: JavaScript emits `class_heritage` for
554
- * `extends`, while TypeScript emits `extends_clause` and `implements_clause`.
555
- */
556
- const INHERITANCE_RULES = {
557
- js: { clauses: [{ type: "class_heritage", label: "extends" }] },
558
- ts: TYPESCRIPT_INHERITANCE_RULES,
559
- tsx: TYPESCRIPT_INHERITANCE_RULES,
560
- java: {
561
- clauses: [
562
- { type: "superclass", label: "extends" },
563
- { type: "super_interfaces", label: "implements" },
564
- ],
565
- },
566
- csharp: { clauses: [{ type: "base_list", label: "superclass-first" }] },
567
- kotlin: { clauses: [{ type: "delegation_specifiers", label: "superclass-first" }] },
568
- swift: { clauses: [{ type: "inheritance_specifier", label: "superclass-first", each: true }] },
569
- python: { clauses: [{ type: "argument_list", label: "extends" }] },
570
- php: {
571
- clauses: [
572
- { type: "base_clause", label: "extends" },
573
- { type: "class_interface_clause", label: "implements" },
574
- { type: "use_declaration", label: "trait", each: true },
575
- ],
576
- },
577
- ruby: {
578
- clauses: [{ type: "superclass", label: "extends" }],
579
- mixinCalls: ["include", "extend", "prepend"],
580
- },
581
- cpp: { clauses: [{ type: "base_class_clause", label: "extends" }] },
582
- go: {
583
- clauses: [],
584
- embeds: [
585
- { body: "interface_type", member: "type_elem" },
586
- {
587
- body: "struct_type",
588
- memberList: "field_declaration_list",
589
- member: "field_declaration",
590
- typeField: "type",
591
- nameless: true,
592
- },
593
- ],
594
- },
595
- };
596
- function baseClauseRelation(label, target, index, interfaceIds) {
1411
+ function baseClauseRelation(label, target, index, interfaceIds, identifier, kotlin) {
597
1412
  if (label !== "superclass-first")
598
1413
  return label;
1414
+ if (kotlin) {
1415
+ let current = identifier.parent;
1416
+ while (current && current.type !== "delegation_specifiers") {
1417
+ if (current.type === "constructor_invocation")
1418
+ return "extends";
1419
+ current = current.parent;
1420
+ }
1421
+ return "implements";
1422
+ }
599
1423
  if (interfaceIds.has(defNodeId(target)) || index > 0)
600
1424
  return "implements";
601
1425
  return "extends";
602
1426
  }
603
1427
  /** Records `implements` for every embedded type of a Go interface or struct declaration. */
604
- function recordEmbedRelations(context, fromId, declaration, embeds) {
1428
+ async function recordEmbedRelations(context, fromId, declaration, embeds) {
605
1429
  const declaredType = declaration.childForFieldName("type");
606
1430
  if (!declaredType)
607
1431
  return;
@@ -619,12 +1443,12 @@ function recordEmbedRelations(context, fromId, declaration, embeds) {
619
1443
  const specifier = rule.typeField ? member.childForFieldName(rule.typeField) : member;
620
1444
  if (!specifier)
621
1445
  continue;
622
- recordIdentifierRelations(context, fromId, specifier, () => "implements");
1446
+ await recordIdentifierRelations(context, fromId, specifier, () => "implements");
623
1447
  }
624
1448
  }
625
1449
  }
626
- export function emitClassInheritanceEdges(context, classNodes) {
627
- const rules = INHERITANCE_RULES[context.sup.id];
1450
+ export async function emitClassInheritanceEdges(context, classNodes) {
1451
+ const rules = MEMBER_ACCESS_ROWS[context.sup.id]?.receiverAncestry;
628
1452
  if (!rules)
629
1453
  return;
630
1454
  const interfaceIds = new Set(classNodes
@@ -635,20 +1459,27 @@ export function emitClassInheritanceEdges(context, classNodes) {
635
1459
  .map((candidate) => defNodeId(candidate.def)));
636
1460
  for (const cls of classNodes) {
637
1461
  const fromId = ensureNode(context, cls.def);
638
- markImplementationTarget(context, fromId, cls.node, cls.def);
1462
+ markImplementationTarget(context, fromId, cls.node, context.source, cls.def);
1463
+ if ((context.sup.id === "ts" || context.sup.id === "tsx") && cls.node.type === "class_declaration") {
1464
+ const heritage = cls.node.namedChildren.find((child) => child.type === "class_heritage");
1465
+ const superclass = heritage?.namedChildren.find((child) => child.type === "extends_clause");
1466
+ // TypeScript classes have one superclass. Invalid multi-base syntax proves neither target.
1467
+ if (superclass && superclass.namedChildren.length > 1)
1468
+ continue;
1469
+ }
639
1470
  for (const rule of rules.clauses) {
640
1471
  const clauses = [];
641
1472
  if (rule.each) {
642
- collectNodesByType(cls.node, rule.type, clauses);
1473
+ collectNodesByType(cls.node, rule.nodeType, clauses);
643
1474
  }
644
1475
  else {
645
- const found = findFirstNodeByType(cls.node, rule.type);
1476
+ const found = findFirstNodeByType(cls.node, rule.nodeType);
646
1477
  if (found)
647
1478
  clauses.push(found);
648
1479
  }
649
1480
  for (const clause of clauses) {
650
1481
  const specifiers = rule.field ? (clause.childForFieldName(rule.field) ?? clause) : clause;
651
- recordIdentifierRelations(context, fromId, specifiers, (target, index) => baseClauseRelation(rule.label, target, index, interfaceIds));
1482
+ await recordIdentifierRelations(context, fromId, specifiers, (target, index, identifier) => baseClauseRelation(rule.relation, target, index, interfaceIds, identifier, context.sup.id === "kotlin"));
652
1483
  }
653
1484
  }
654
1485
  if (rules.mixinCalls) {
@@ -663,16 +1494,14 @@ export function emitClassInheritanceEdges(context, classNodes) {
663
1494
  continue;
664
1495
  const args = call.childForFieldName("arguments");
665
1496
  if (args)
666
- recordIdentifierRelations(context, fromId, args, () => "mixin");
1497
+ await recordIdentifierRelations(context, fromId, args, () => "mixin");
667
1498
  }
668
1499
  }
669
1500
  if (rules.embeds)
670
- recordEmbedRelations(context, fromId, cls.node, rules.embeds);
1501
+ await recordEmbedRelations(context, fromId, cls.node, rules.embeds);
671
1502
  }
672
1503
  }
673
1504
  export function emitRustImplEdges(context, rootNode) {
674
- if (context.sup.id !== "rust")
675
- return;
676
1505
  const walkImpls = (node) => {
677
1506
  if (node.type === "impl_item") {
678
1507
  const typeIdentifiers = node.namedChildren?.filter((child) => child.type === "type_identifier") ?? [];