@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,16 +1,517 @@
1
+ import { CSHARP_SUPPORT, supportForFileWithoutHeaderSample } from "../languages.js";
1
2
  import { isJsTsLanguage } from "../languages/js-family.js";
2
3
  import { isPythonReceiverAttributeAssignmentName } from "../languages/definitions/python.js";
3
4
  import { sliceText } from "../util/ast.js";
5
+ import { foldPhpIdentifierCase } from "../util/identifiers.js";
4
6
  import { fileIdentityKey } from "../util/paths.js";
5
- import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isReceiverNameNode, memberAccessTraversalTypes, } from "../util/member-access.js";
6
- import { isKeywordReceiver, supportsReceiverMemberNavigation } from "../util/member-access-tables.js";
7
- import { declaresMembers, hasStaticMemberDistinction, nearestMemberContainer, receiverConstructorExpression, unwrapNamedType, } from "../graphs/symbol-graph-detailed/receiver-calls.js";
7
+ import { collectMemberAccessChain, getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, isReceiverNameNode, memberAccessTraversalTypes, } from "../util/member-access.js";
8
+ import { MEMBER_ACCESS_ROWS, supportsReceiverMemberNavigation } from "../util/member-access-tables.js";
9
+ import { typescriptCallableContainerKey, typescriptMergedNamespaceContainers } from "./ts-callables.js";
10
+ import { effectiveExplicitBinding, isExpandedStarBinding, resolveStarImportedName, resolveStarImportedNamespace, starImportPrecedence, } from "./star-import-precedence.js";
11
+ import { classifyReceiver, cppOutOfLineOwnerPath, cppQualifiedNameSegments, declarationIsStaticEquivalent, declarationNodeIsStatic, declaredTypeNameNode, declaresMembers, hasStaticMemberDistinction, memberContainerDef, nearestMemberContainer, isUnprovenHeritageExpression, kotlinExtensionReceiverTypeNode, csharpDottedNameRoot, nodeInStaticMemberContext, importTypeQuerySpecifier, rustImplSelfTypeNode, supportsStaticMemberScope, TRANSPARENT_MEMBER_CONTAINER_TYPES, unwrapNamedType, } from "../graphs/symbol-graph-detailed/receiver-calls.js";
12
+ import { getCallArgumentCount, memberLookupBinding } from "../languages/callable-arity.js";
13
+ import { getCompilationUnitPeers, getPackageDeclarationName } from "./compilation-units.js";
14
+ import { isExportedDeclaration, isJvmPackageSymbolVisible, isPrivateDeclaration, isGoExportedMemberName, isSwiftCrossFileHiddenSharedOwnerMember, } from "./declaration-visibility.js";
8
15
  import { ensureParsedContext } from "./parse-context.js";
16
+ import { csharpLookupName, csharpQualifiedNameNode, findClosestScopeBinding, getOrBuildScopeIndex, resolveNamedDefinition, } from "./navigation-local.js";
17
+ import { resolveCppQualifiedMemberContainer, cppFunctionHasImplicitThis } from "./navigation-cpp.js";
9
18
  import { okGoToResult } from "./navigation-provenance.js";
10
- import { resolveExport, resolveImported } from "./navigation-resolve.js";
19
+ import { comparePhpReferenceNames, findPhpImportAlias } from "./navigation-php.js";
20
+ import { resolveIndexedPhpClassReference, resolvePhpNamespaceSymbol } from "./php-namespace-symbols.js";
21
+ import { cjsRequireValueBinding, memberContainerForDefinition, resolveCsharpQualifiedName, resolveExport, resolveImported, resolvePhpExportByImportType, resolveImportTypeMember, } from "./navigation-resolve.js";
22
+ import { CSHARP_PARTIAL_CONTAINER_TYPES, getSharedOwnerIdentity, isSwiftExtensionContainer, sharedOwnerCanUseMembers, } from "./shared-owner-identity.js";
23
+ import { hasSeparateMemberScopes, inheritsMemberOverloads, selectMember, } from "./member-selection.js";
11
24
  import { SymbolKind, } from "./types.js";
25
+ const DECLARED_FIELD_CHAIN_LANGUAGES = {
26
+ ts: true,
27
+ tsx: true,
28
+ java: true,
29
+ csharp: true,
30
+ kotlin: true,
31
+ };
32
+ /** Type-syntax nodes that wrap a declared type name together with its qualifier. */
33
+ const QUALIFIED_TYPE_NODE_TYPES = {
34
+ qualified_name: true,
35
+ scoped_type_identifier: true,
36
+ nested_type_identifier: true,
37
+ user_type: true,
38
+ generic_name: true,
39
+ generic_type: true,
40
+ };
41
+ /**
42
+ * The full spelling of a declared type, e.g. `B.Repo` for `B.Repo<T>`: the last segment alone
43
+ * would resolve to a same-named type of another namespace.
44
+ */
45
+ function qualifiedDeclaredTypeText(typeName, source) {
46
+ let top = typeName;
47
+ for (let parent = typeName.parent; parent && QUALIFIED_TYPE_NODE_TYPES[parent.type]; parent = parent.parent) {
48
+ top = parent;
49
+ }
50
+ let text = sliceText(top, source).replace(/\s+/g, "");
51
+ for (let previous = ""; previous !== text;) {
52
+ previous = text;
53
+ text = text.replace(/<[^<>]*>/g, "");
54
+ }
55
+ return text;
56
+ }
57
+ /** Type-parameter list nodes across the TypeScript, Java, C#, and Kotlin grammars. */
58
+ const TYPE_PARAMETER_LIST_TYPES = {
59
+ type_parameters: true,
60
+ type_parameter_list: true,
61
+ };
62
+ /** Names of the generic type parameters declared by `node` and its enclosing declarations. */
63
+ function typeParameterNamesInScope(node, source) {
64
+ const names = new Set();
65
+ for (let current = node; current; current = current.parent) {
66
+ for (const list of current.namedChildren) {
67
+ if (!TYPE_PARAMETER_LIST_TYPES[list.type])
68
+ continue;
69
+ for (const parameter of list.namedChildren) {
70
+ const name = parameter.childForFieldName("name") ??
71
+ parameter.namedChildren.find((child) => child.type === "identifier" || child.type === "type_identifier");
72
+ if (name)
73
+ names.add(sliceText(name, source));
74
+ }
75
+ }
76
+ }
77
+ return names;
78
+ }
79
+ export function supportsDeclaredFieldChains(languageId) {
80
+ return !!DECLARED_FIELD_CHAIN_LANGUAGES[languageId];
81
+ }
82
+ function noLexicalBinding() {
83
+ return false;
84
+ }
85
+ /** A Rust named `use crate::mod` binding names the indexed module, not a class export. */
86
+ export function resolveRustModuleNamespace(index, binding) {
87
+ if (binding.kind !== "named" || typeof binding.resolved !== "string")
88
+ return null;
89
+ const owner = index.byFile.get(fileIdentityKey(binding.resolved));
90
+ if (!owner)
91
+ return null;
92
+ const modules = owner.imports.filter((candidate) => candidate.kind === "namespace" && candidate.localNS === binding.imported);
93
+ if (modules.length !== 1)
94
+ return null;
95
+ const resolved = modules[0]?.resolved;
96
+ return typeof resolved === "string" ? resolved : null;
97
+ }
98
+ /**
99
+ * One bound for every receiver-hierarchy walk in this module: keyword `super`/`parent` lookup,
100
+ * Go struct embedding, and Python base classes. Each walk keeps its own visited set, so this is a
101
+ * resource bound rather than a cycle guard; keeping a single constant stops the three walks from
102
+ * drifting to different semantic cutoffs.
103
+ */
104
+ const RECEIVER_HIERARCHY_DEPTH = 16;
105
+ function collectSharedOwnerContainers(root, languageId, out) {
106
+ if (languageId === "csharp") {
107
+ if (CSHARP_PARTIAL_CONTAINER_TYPES.has(root.type))
108
+ out.push(root);
109
+ }
110
+ else if (languageId === "swift") {
111
+ if (root.type === "class_declaration")
112
+ out.push(root);
113
+ }
114
+ for (const child of root.namedChildren ?? [])
115
+ collectSharedOwnerContainers(child, languageId, out);
116
+ }
117
+ const sharedOwnerContainersByRoot = new WeakMap();
118
+ function sharedOwnerContainersInTree(root, languageId) {
119
+ let byLanguage = sharedOwnerContainersByRoot.get(root);
120
+ if (!byLanguage) {
121
+ byLanguage = new Map();
122
+ sharedOwnerContainersByRoot.set(root, byLanguage);
123
+ }
124
+ const cached = byLanguage.get(languageId);
125
+ if (cached)
126
+ return cached;
127
+ const collected = [];
128
+ collectSharedOwnerContainers(root, languageId, collected);
129
+ byLanguage.set(languageId, collected);
130
+ return collected;
131
+ }
132
+ export async function resolveSharedOwnerContainers(params) {
133
+ const { index, ownerFile, ownerContainer, ownerSource, languageId } = params;
134
+ if (languageId !== "csharp" && languageId !== "swift")
135
+ return [];
136
+ const ownerIdentity = getSharedOwnerIdentity(ownerContainer, ownerSource, languageId, ownerFile);
137
+ if (!ownerIdentity)
138
+ return [];
139
+ // A C# `file` owner has only same-file parts, so no other file is a candidate peer.
140
+ const peers = ownerIdentity.fileLocalTo
141
+ ? { files: new Set([ownerFile]), complete: true }
142
+ : getCompilationUnitPeers(index, ownerFile);
143
+ const out = [];
144
+ const seen = new Set();
145
+ const ownerIsExtension = languageId === "swift" ? isSwiftExtensionContainer(ownerContainer, ownerSource) : false;
146
+ const ownerKey = fileIdentityKey(ownerFile);
147
+ const units = [];
148
+ for (const file of peers.files) {
149
+ const peer = index.byFile.get(fileIdentityKey(file));
150
+ if (peer)
151
+ units.push(peer);
152
+ }
153
+ for (const peer of units) {
154
+ let peerContext;
155
+ try {
156
+ peerContext = await ensureParsedContext(peer.file, index.parsed?.get(fileIdentityKey(peer.file)), index.languageExtensions);
157
+ }
158
+ catch {
159
+ continue;
160
+ }
161
+ if (peerContext.sup.id !== languageId)
162
+ continue;
163
+ const containers = sharedOwnerContainersInTree(peerContext.tree.rootNode, languageId);
164
+ for (const container of containers) {
165
+ if (fileIdentityKey(peer.file) === ownerKey &&
166
+ container.startIndex === ownerContainer.startIndex &&
167
+ container.endIndex === ownerContainer.endIndex) {
168
+ continue;
169
+ }
170
+ const identity = getSharedOwnerIdentity(container, peerContext.source, languageId, peer.file);
171
+ if (!identity || !sharedOwnerCanUseMembers(ownerIdentity, identity))
172
+ continue;
173
+ if (languageId === "swift") {
174
+ const peerIsExtension = isSwiftExtensionContainer(container, peerContext.source);
175
+ if (!ownerIsExtension && !peerIsExtension)
176
+ continue;
177
+ }
178
+ const key = fileIdentityKey(peer.file) + ":" + container.startIndex + ":" + container.endIndex;
179
+ if (seen.has(key))
180
+ continue;
181
+ seen.add(key);
182
+ out.push({ file: peer.file, container, context: peerContext, module: peer });
183
+ }
184
+ }
185
+ return out;
186
+ }
187
+ /**
188
+ * Unit-boundary completeness for a C# partial or Swift type/extension member. Its other
189
+ * owner parts, and therefore its uses, are bounded by `getCompilationUnitPeers`, so an
190
+ * unproven unit boundary leaves the member's reference set incomplete. Returns null when
191
+ * the member's owner cannot be shared across files.
192
+ */
193
+ export async function sharedOwnerMemberUnitComplete(index, def) {
194
+ if (!def.isMember)
195
+ return null;
196
+ let context;
197
+ try {
198
+ context = await ensureParsedContext(def.file, index.parsed?.get(fileIdentityKey(def.file)), index.languageExtensions);
199
+ }
200
+ catch {
201
+ return null;
202
+ }
203
+ const languageId = context.sup.id;
204
+ if (languageId !== "csharp" && languageId !== "swift")
205
+ return null;
206
+ const nameNode = nameNodeForDef(context, def);
207
+ const container = nameNode ? nearestMemberContainer(nameNode) : null;
208
+ const identity = container ? getSharedOwnerIdentity(container, context.source, languageId, def.file) : null;
209
+ if (!identity)
210
+ return null;
211
+ // File-local owners have no parts in other files, so the reference set is complete.
212
+ if (identity.fileLocalTo)
213
+ return true;
214
+ // A C# member is reachable through a qualified owner (`P.Box`) from any namespace, so use the
215
+ // same qualified peer relation as reference candidate discovery.
216
+ return getCompilationUnitPeers(index, def.file, languageId === "csharp" ? { csharpQualifiedName: true } : undefined)
217
+ .complete;
218
+ }
219
+ /**
220
+ * Other C# `partial` type parts that share owner identity with `def`.
221
+ * Reference collection treats them as one type so uses that resolve to the
222
+ * coalesced representative still match a query started on any part.
223
+ */
224
+ export async function findCsharpPartialTypeEquivalents(index, def) {
225
+ if (!declaresMembers(def))
226
+ return [];
227
+ const module = index.byFile.get(fileIdentityKey(def.file));
228
+ if (!module)
229
+ return [];
230
+ let context;
231
+ try {
232
+ context = await ensureParsedContext(def.file, index.parsed?.get(fileIdentityKey(def.file)), index.languageExtensions);
233
+ }
234
+ catch {
235
+ return [];
236
+ }
237
+ if (context.sup.id !== "csharp")
238
+ return [];
239
+ const start = def.range.start;
240
+ const nameNode = context.tree.rootNode.descendantForPosition({ row: start.line - 1, column: start.column - 1 }, { row: start.line - 1, column: start.column - 1 });
241
+ const container = nearestMemberContainer(nameNode);
242
+ if (!container)
243
+ return [];
244
+ const peers = await resolveSharedOwnerContainers({
245
+ index,
246
+ ownerFile: def.file,
247
+ ownerContainer: container,
248
+ ownerSource: context.source,
249
+ languageId: "csharp",
250
+ });
251
+ const out = [];
252
+ for (const peer of peers) {
253
+ const peerName = peer.container.childForFieldName("name");
254
+ if (!peerName)
255
+ continue;
256
+ const peerDef = peer.module.locals.find((local) => declaresMembers(local) && local.range.start.index === peerName.startIndex);
257
+ if (peerDef)
258
+ out.push(peerDef);
259
+ }
260
+ return out;
261
+ }
262
+ /** Reusable shared-owner member lookup for keyword navigation and receiver graphs. */
263
+ export async function findSharedOwnerMemberDefinitions(params) {
264
+ const { index, ownerFile, ownerContainer, ownerSource, languageId, member, memberScope } = params;
265
+ const peers = await resolveSharedOwnerContainers({ index, ownerFile, ownerContainer, ownerSource, languageId });
266
+ const out = [];
267
+ for (const peer of peers) {
268
+ const predicate = !memberScope || memberScope === "any"
269
+ ? undefined
270
+ : (local) => matchesReceiverMemberScope(local, memberScope, peer.context, peer.container);
271
+ const hits = findDirectLocalsWithinNode(peer.module.locals, member, peer.container, peer.context, peer.context.sup.normalizeIdentifier, predicate);
272
+ for (const hit of hits) {
273
+ const hitNode = nameNodeForDef(peer.context, hit);
274
+ if (languageId === "swift" && fileIdentityKey(ownerFile) !== fileIdentityKey(peer.file)) {
275
+ if (!hitNode || isSwiftCrossFileHiddenSharedOwnerMember(languageId, ownerFile, peer.file, hitNode))
276
+ continue;
277
+ }
278
+ if (!out.includes(hit))
279
+ out.push(hit);
280
+ }
281
+ }
282
+ return out;
283
+ }
284
+ function nameNodeForDef(context, def) {
285
+ const start = def.range.start;
286
+ const index = start.index;
287
+ if (index !== undefined)
288
+ return context.tree.rootNode.descendantForIndex(index, index);
289
+ const position = { row: start.line - 1, column: start.column - 1 };
290
+ return context.tree.rootNode.descendantForPosition(position, position);
291
+ }
292
+ function enclosingImportScope(declarationName) {
293
+ let current = declarationName;
294
+ while (current && current.type !== "variable_declaration" && current.type !== "using_directive") {
295
+ current = current.parent;
296
+ }
297
+ return current?.parent ?? null;
298
+ }
299
+ /**
300
+ * Rewrites a valid C# `using X = Namespace; X::Target` lookup into the dotted form
301
+ * export resolution already understands. `global::` and ordinary dotted names keep
302
+ * their source spelling; an unknown alias stays `X::Target` instead of a bare name.
303
+ */
304
+ export function csharpAliasQualifiedLookupName(node, source, fallback, imports) {
305
+ const raw = csharpLookupName(node, source, fallback);
306
+ if (raw.startsWith("global::"))
307
+ return raw;
308
+ const chainNode = csharpQualifiedNameNode(node);
309
+ if (!chainNode || !raw.includes("::"))
310
+ return raw;
311
+ const names = [];
312
+ let current = chainNode;
313
+ let base = null;
314
+ while (current && (current.type === "qualified_name" || current.type === "alias_qualified_name")) {
315
+ const parts = getMemberAccessParts(CSHARP_SUPPORT, current);
316
+ base = parts.object ?? base;
317
+ let property = parts.property;
318
+ if (property?.type === "generic_name") {
319
+ property = property.childForFieldName("name") ?? property.namedChildren[0] ?? property;
320
+ }
321
+ if (property?.type === "identifier")
322
+ names.push(sliceText(property, source));
323
+ current = base;
324
+ }
325
+ if (!base || !isReceiverNameNode(CSHARP_SUPPORT, base.type) || !names.length)
326
+ return raw;
327
+ const alias = sliceText(base, source);
328
+ if (alias === "global")
329
+ return raw;
330
+ const imported = innermostNamespaceImport(imports, alias, base, CSHARP_SUPPORT.normalizeIdentifier);
331
+ if (!imported)
332
+ return raw;
333
+ return `${imported.from}.${[...names].reverse().join(".")}`;
334
+ }
335
+ /**
336
+ * Innermost in-scope namespace import bound to `alias`. `normalize` applies the language's
337
+ * identifier equality (C# `@X` and `X` are one alias); the default compares exact spelling.
338
+ */
339
+ export function innermostNamespaceImport(imports, alias, useNode, normalize = (name) => name) {
340
+ const normalizedAlias = normalize(alias);
341
+ const matches = imports.filter((candidate) => candidate.kind === "namespace" && normalize(candidate.localNS) === normalizedAlias);
342
+ if (!matches.length)
343
+ return undefined;
344
+ let root = useNode;
345
+ while (root.parent)
346
+ root = root.parent;
347
+ let best;
348
+ let bestScopeSpan = Number.POSITIVE_INFINITY;
349
+ let bestStart = -1;
350
+ for (const match of matches) {
351
+ const start = match.localRange?.start.index;
352
+ if (start === undefined)
353
+ continue;
354
+ let nameNode = root;
355
+ for (;;) {
356
+ const child = nameNode.namedChildren.find((candidate) => candidate.startIndex <= start && start < candidate.endIndex);
357
+ if (!child)
358
+ break;
359
+ nameNode = child;
360
+ }
361
+ const scope = enclosingImportScope(nameNode);
362
+ if (!scope)
363
+ continue;
364
+ if (start > useNode.startIndex && scope.parent)
365
+ continue;
366
+ if (scope.startIndex > useNode.startIndex || scope.endIndex < useNode.endIndex)
367
+ continue;
368
+ const span = scope.endIndex - scope.startIndex;
369
+ if (span < bestScopeSpan || (span === bestScopeSpan && start >= bestStart)) {
370
+ bestScopeSpan = span;
371
+ bestStart = start;
372
+ best = match;
373
+ }
374
+ }
375
+ if (best)
376
+ return best;
377
+ const unlocated = matches.filter((match) => match.localRange?.start.index === undefined);
378
+ if (unlocated.length === 1)
379
+ return unlocated[0];
380
+ const files = new Map();
381
+ for (const match of unlocated) {
382
+ if (typeof match.resolved !== "string")
383
+ continue;
384
+ const key = fileIdentityKey(match.resolved);
385
+ if (!files.has(key))
386
+ files.set(key, match);
387
+ }
388
+ if (files.size === 1)
389
+ return [...files.values()][0];
390
+ return undefined;
391
+ }
392
+ function rubyScopeResolutionPath(node, source) {
393
+ if (node.type !== "constant")
394
+ return null;
395
+ const owner = node.parent;
396
+ if (owner?.type !== "scope_resolution")
397
+ return null;
398
+ const ownerName = owner.childForFieldName("name");
399
+ if (!ownerName || ownerName.startIndex !== node.startIndex || ownerName.endIndex !== node.endIndex)
400
+ return null;
401
+ // `Outer::Inner::Tool` nests scope_resolution on `scope`, so flatten from the
402
+ // clicked name instead of stopping at the first nested scope.
403
+ const segments = [];
404
+ let current = owner;
405
+ while (current?.type === "scope_resolution") {
406
+ const name = current.childForFieldName("name");
407
+ const scope = current.childForFieldName("scope");
408
+ if (!name || name.type !== "constant")
409
+ return null;
410
+ const text = sliceText(name, source);
411
+ if (!text)
412
+ return null;
413
+ segments.unshift(text);
414
+ current = scope;
415
+ }
416
+ if (!current || current.type !== "constant" || segments.length === 0)
417
+ return null;
418
+ const root = sliceText(current, source);
419
+ if (!root)
420
+ return null;
421
+ return { path: `${root}::${segments.join("::")}`, root };
422
+ }
423
+ /**
424
+ * `Outer::Inner::Tool` is one constant path. Nested classes are exported under that
425
+ * path, not as bare `Tool`, so the chain has to ask for the qualified export.
426
+ */
427
+ function resolveRubyQualifiedConstantDefinition(index, mod, node, source) {
428
+ const qualified = rubyScopeResolutionPath(node, source);
429
+ if (!qualified)
430
+ return null;
431
+ const files = [];
432
+ const seen = new Set();
433
+ const add = (file) => {
434
+ if (!file)
435
+ return;
436
+ const key = fileIdentityKey(file);
437
+ if (seen.has(key))
438
+ return;
439
+ seen.add(key);
440
+ files.push(file);
441
+ };
442
+ for (const imp of mod.imports) {
443
+ if (imp.kind === "namespace" && imp.localNS === qualified.root && typeof imp.resolved === "string") {
444
+ add(imp.resolved);
445
+ }
446
+ }
447
+ add(mod.file);
448
+ const hits = [];
449
+ for (const file of files) {
450
+ const hit = resolveExport(index, file, qualified.path, { allowLocalFallback: false });
451
+ if (hit?.kind !== "resolved")
452
+ continue;
453
+ if (hits.some((candidate) => fileIdentityKey(candidate.file) === fileIdentityKey(hit.def.file) &&
454
+ candidate.localName === hit.def.localName &&
455
+ candidate.range.start.line === hit.def.range.start.line &&
456
+ candidate.range.start.column === hit.def.range.start.column)) {
457
+ continue;
458
+ }
459
+ hits.push(hit.def);
460
+ }
461
+ if (hits.length !== 1)
462
+ return null;
463
+ return okGoToResult(index, hits[0], {
464
+ via: { exportedName: qualified.path },
465
+ resolution: "member-access",
466
+ confidence: "medium",
467
+ });
468
+ }
469
+ /** A fully qualified JVM package symbol, never a same-spelled type from another package. */
470
+ function resolveJvmPackageSymbol(index, packageName, symbolName, languageId, useFile) {
471
+ const samePackage = getPackageDeclarationName(index, useFile, languageId) === packageName;
472
+ let target;
473
+ for (const candidate of index.byFile.values()) {
474
+ const targetLanguage = supportForFileWithoutHeaderSample(candidate.file, index.languageExtensions)?.id;
475
+ if (targetLanguage !== "java" && targetLanguage !== "kotlin")
476
+ continue;
477
+ if (getPackageDeclarationName(index, candidate.file, targetLanguage) !== packageName)
478
+ continue;
479
+ for (const entry of candidate.exports) {
480
+ if (entry.type !== "local" ||
481
+ entry.exportedAs !== symbolName ||
482
+ entry.target.isMember ||
483
+ !isJvmPackageSymbolVisible(entry.target, targetLanguage, languageId, samePackage))
484
+ continue;
485
+ if (target &&
486
+ (target.file !== entry.target.file || target.range.start.index !== entry.target.range.start.index)) {
487
+ return undefined;
488
+ }
489
+ target = entry.target;
490
+ }
491
+ }
492
+ return target;
493
+ }
494
+ /** Package paths only bind when the leftmost name is not a lexical value or imported alias. */
495
+ function resolveJvmPackageExpression(index, sup, source, expr, resolveLexicalBinding, useFile) {
496
+ if (sup.id !== "java" && sup.id !== "kotlin")
497
+ return null;
498
+ const chain = collectMemberAccessChain({ sup, source, chainNode: expr });
499
+ if (!chain || !isReceiverNameNode(sup, chain.base.type) || resolveLexicalBinding?.(chain.base))
500
+ return null;
501
+ const parts = [sliceText(chain.base, source), ...chain.names.toReversed()];
502
+ const member = parts.pop();
503
+ if (!member || !parts.every((part) => /^[\p{L}_][\p{L}\p{N}_]*$/u.test(part)))
504
+ return null;
505
+ const target = resolveJvmPackageSymbol(index, parts.join("."), member, sup.id, useFile);
506
+ return target ? { kind: "resolved", def: target } : null;
507
+ }
12
508
  export async function resolveMemberAccessDefinition(params) {
13
- const { index, mod, node, source, sup, resolveLexicalBinding } = params;
509
+ const { index, mod, node, source, tree, sup, resolveLexicalBinding } = params;
510
+ if (sup.id === "ruby") {
511
+ const qualified = resolveRubyQualifiedConstantDefinition(index, mod, node, source);
512
+ if (qualified)
513
+ return qualified;
514
+ }
14
515
  const parent = node.parent;
15
516
  if (!parent || !sup.supportsCrossModuleSymbols) {
16
517
  return null;
@@ -26,46 +527,148 @@ export async function resolveMemberAccessDefinition(params) {
26
527
  return null;
27
528
  const { object: obj, property: prop } = getMemberAccessParts(sup, memberNode);
28
529
  const optionalMemberTypes = memberAccessTraversalTypes(sup);
530
+ // Only the outermost access is the callee; an inner hop (`A.B` in `A.B.C()`) is not called.
531
+ const callArgumentCountFor = (expr) => expr.id === memberNode.id
532
+ ? (getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined)
533
+ : undefined;
29
534
  const resolveExpression = async (expr) => {
30
535
  const exprIsId = isReceiverNameNode(sup, expr.type) && !isMemberAccessNode(sup, expr);
31
536
  if (exprIsId) {
32
- const lexicalBinding = resolveLexicalBinding?.(expr);
33
- if (lexicalBinding)
34
- return { kind: "resolved", def: lexicalBinding };
537
+ const aliasQualifier = sup.id === "csharp" &&
538
+ expr.parent?.type === "alias_qualified_name" &&
539
+ getMemberAccessParts(sup, expr.parent).object?.id === expr.id;
540
+ if (!aliasQualifier) {
541
+ const lexicalBinding = resolveLexicalBinding?.(expr);
542
+ if (lexicalBinding)
543
+ return { kind: "resolved", def: lexicalBinding };
544
+ }
35
545
  const exprName = sliceText(expr, source);
36
- const imp = mod.imports.find((candidate) => (candidate.kind === "named" && candidate.local === exprName) ||
37
- (candidate.kind === "default" && candidate.local === exprName) ||
38
- (candidate.kind === "namespace" && candidate.localNS === exprName));
546
+ let imp;
547
+ if (sup.id === "php") {
548
+ imp = findPhpImportAlias(mod.imports, exprName, "class") ?? undefined;
549
+ }
550
+ else if (sup.id === "zig") {
551
+ imp = innermostNamespaceImport(mod.imports, exprName, expr);
552
+ if (!imp) {
553
+ imp = mod.imports.find((candidate) => (candidate.kind === "named" || candidate.kind === "default") && candidate.local === exprName);
554
+ }
555
+ }
556
+ else if (sup.id === "csharp") {
557
+ if (aliasQualifier) {
558
+ if (exprName !== "global")
559
+ imp = innermostNamespaceImport(mod.imports, exprName, expr, sup.normalizeIdentifier);
560
+ if (!imp)
561
+ return null;
562
+ }
563
+ else {
564
+ imp = innermostNamespaceImport(mod.imports, exprName, expr, sup.normalizeIdentifier);
565
+ if (!imp) {
566
+ imp = mod.imports.find((candidate) => (candidate.kind === "named" || candidate.kind === "default") &&
567
+ candidate.local === exprName &&
568
+ !isExpandedStarBinding(candidate, mod.imports));
569
+ }
570
+ }
571
+ }
572
+ else {
573
+ imp = effectiveExplicitBinding(mod.imports, sup.id, (candidate) => ((candidate.kind === "named" || candidate.kind === "default") && candidate.local === exprName) ||
574
+ (candidate.kind === "namespace" && candidate.localNS === exprName));
575
+ if (!imp && isJsTsLanguage(sup.id)) {
576
+ imp = innermostNamespaceImport(mod.imports, exprName, expr);
577
+ }
578
+ }
39
579
  if (imp) {
40
580
  if (imp.kind === "namespace") {
581
+ if (imp.mechanism === "cjs" && typeof imp.resolved === "string") {
582
+ const classValue = cjsRequireValueBinding(index, imp.resolved);
583
+ if (classValue)
584
+ return { kind: "resolved", def: classValue };
585
+ }
41
586
  return {
42
587
  kind: "namespace",
43
588
  file: typeof imp.resolved === "string" ? imp.resolved.replace(/\\/g, "/") : imp.resolved?.external || "",
44
589
  };
45
590
  }
591
+ if (sup.id === "php" && imp.kind === "named" && typeof imp.resolved === "string") {
592
+ const result = resolvePhpExportByImportType(index, imp.resolved, imp.imported, "class");
593
+ if (result)
594
+ return result;
595
+ }
596
+ if (sup.id === "rust") {
597
+ const moduleFile = resolveRustModuleNamespace(index, imp);
598
+ if (moduleFile)
599
+ return { kind: "namespace", file: moduleFile };
600
+ }
46
601
  const result = resolveImported(index, imp, imp.kind === "named" ? imp.imported : "default");
47
602
  if (result) {
48
603
  if ("namespace" in result) {
49
604
  return { kind: "namespace", file: result.namespace };
50
605
  }
51
- return { kind: "resolved", def: result };
606
+ const container = asMemberContainer(index, result);
607
+ return { kind: "resolved", def: container ?? result };
52
608
  }
609
+ // Last-wins precedence (Python): the explicit import rebound the name, and an
610
+ // unresolved winner stays unresolved instead of falling back to an older star import.
611
+ if (starImportPrecedence(sup.id) === "last-wins")
612
+ return null;
53
613
  }
54
- const local = mod.locals.find((candidate) => candidate.localName === exprName);
55
- if (local)
56
- return { kind: "resolved", def: local };
57
- for (const starImport of mod.imports.filter((candidate) => candidate.kind === "star")) {
58
- const result = resolveImported(index, starImport, exprName);
59
- if (result) {
60
- if ("namespace" in result) {
61
- return { kind: "namespace", file: result.namespace };
62
- }
63
- return { kind: "resolved", def: result };
614
+ if (sup.id === "csharp") {
615
+ const local = resolveExport(index, mod.file, exprName, { referenceIndex: expr.startIndex });
616
+ if (local)
617
+ return local;
618
+ }
619
+ else {
620
+ const local = mod.locals.find((candidate) => {
621
+ if (candidate.localName === exprName)
622
+ return true;
623
+ return (sup.id === "php" &&
624
+ declaresMembers(candidate) &&
625
+ foldPhpIdentifierCase(candidate.localName) === foldPhpIdentifierCase(exprName));
626
+ });
627
+ if (local)
628
+ return { kind: "resolved", def: local };
629
+ if (sup.id === "java" || sup.id === "kotlin" || sup.id === "swift") {
630
+ const peer = resolveExport(index, mod.file, exprName);
631
+ if (peer)
632
+ return peer;
633
+ }
634
+ else if (sup.id === "php") {
635
+ const phpClass = resolveIndexedPhpClassReference(index, source, tree, expr, exprName, mod.imports);
636
+ if (phpClass)
637
+ return { kind: "resolved", def: phpClass };
64
638
  }
65
639
  }
640
+ const starDecision = resolveStarImportedName(index, mod, sup.id, exprName);
641
+ if (starDecision.status === "resolved")
642
+ return { kind: "resolved", def: starDecision.definition };
643
+ if (starDecision.status === "ambiguous")
644
+ return null;
645
+ const starNamespaceDecision = resolveStarImportedNamespace(index, mod, sup.id, exprName);
646
+ if (starNamespaceDecision.status === "resolved") {
647
+ return { kind: "namespace", file: starNamespaceDecision.namespace };
648
+ }
649
+ if (starNamespaceDecision.status === "ambiguous")
650
+ return null;
66
651
  return null;
67
652
  }
68
653
  if (optionalMemberTypes.has(expr.type)) {
654
+ // A Python unaliased dotted import (`import a.b`) binds only the first segment `a`,
655
+ // resolved to the leaf module `a.b` names; the source can only ever repeat that whole
656
+ // dotted phrase to reach it again (`a.b.symbol(...)`), never a bare intermediate segment
657
+ // on its own. Recognize that literal phrase up front so the chain walk below lands on the
658
+ // leaf module the import machinery already resolved, instead of treating each dot as an
659
+ // ordinary member-access hop and failing on the segment duplicating the import's spelling.
660
+ if (sup.id === "python") {
661
+ const dottedText = sliceText(expr, source);
662
+ if (dottedText.includes(".")) {
663
+ const dottedImport = mod.imports.find((imp) => imp.kind === "namespace" &&
664
+ imp.mechanism === "python" &&
665
+ imp.from === dottedText &&
666
+ typeof imp.resolved === "string");
667
+ if (dottedImport && typeof dottedImport.resolved === "string") {
668
+ return { kind: "namespace", file: dottedImport.resolved.replace(/\\/g, "/") };
669
+ }
670
+ }
671
+ }
69
672
  const parts = getMemberAccessParts(sup, expr);
70
673
  const subObj = parts.object;
71
674
  let subProp = parts.property;
@@ -74,16 +677,48 @@ export async function resolveMemberAccessDefinition(params) {
74
677
  }
75
678
  if (subObj && subProp) {
76
679
  const base = await resolveExpression(subObj);
680
+ if (!base) {
681
+ const qualified = resolveJvmPackageExpression(index, sup, source, expr, resolveLexicalBinding, mod.file);
682
+ if (qualified)
683
+ return qualified;
684
+ }
77
685
  const memberName = sliceText(subProp, source);
686
+ // `P.Mix` in `P.Mix.M()`: when the leftmost name binds nothing, a C# dotted name is a
687
+ // namespace-qualified type, which qualified export lookup resolves across every file that
688
+ // declares the namespace.
689
+ const dottedRoot = !base && sup.id === "csharp" ? csharpDottedNameRoot(expr) : null;
690
+ if (dottedRoot && !resolveLexicalBinding?.(dottedRoot)) {
691
+ return resolveCsharpQualifiedName(index, mod, sliceText(expr, source).replace(/\s+/gu, ""), expr.startIndex);
692
+ }
78
693
  if (base?.kind === "namespace") {
694
+ if (!isGoExportedMemberName(sup.id, memberName))
695
+ return null;
79
696
  return resolveExport(index, base.file, memberName, { allowLocalFallback: false });
80
697
  }
81
698
  if (base?.kind === "resolved") {
82
- if (sup.id === "java") {
83
- const memberDef = await resolveMemberDefinitionForBase(index, base.def, memberName);
699
+ if (sup.id === "go") {
700
+ const receiver = await resolveReceiverDefinition(index, subObj, source, sup, resolveExpression, mod, undefined, base);
701
+ if (receiver && declaresMembers(receiver.def)) {
702
+ const context = await ensureParsedContext(receiver.def.file, undefined, index.languageExtensions);
703
+ const embedded = goEmbeddedTypeNames(receiver.def.localName, context, context.sup.normalizeIdentifier);
704
+ if (embedded.includes(memberName)) {
705
+ const ownerModule = index.byFile.get(fileIdentityKey(receiver.def.file));
706
+ const named = ownerModule
707
+ ? resolveNamedDefinition(index, ownerModule, ownerModule.file, context.sup, memberName)
708
+ : null;
709
+ if (named?.status === "ok") {
710
+ const type = asMemberContainer(index, named.definition);
711
+ if (type)
712
+ return { kind: "resolved", def: type };
713
+ }
714
+ }
715
+ }
716
+ }
717
+ if (sup.id === "java" || sup.id === "csharp") {
718
+ const memberDef = await resolveMemberDefinitionForBase(index, base.def, memberName, callArgumentCountFor(expr));
84
719
  return memberDef ? { kind: "resolved", def: memberDef } : null;
85
720
  }
86
- if (sup.id === "ruby") {
721
+ if (sup.id === "ruby" && declaresMembers(base.def)) {
87
722
  const memberDef = await resolveMemberDefinitionForBase(index, base.def, memberName);
88
723
  if (memberDef)
89
724
  return { kind: "resolved", def: memberDef };
@@ -100,18 +735,39 @@ export async function resolveMemberAccessDefinition(params) {
100
735
  const subProp = expr.childForFieldName("name") ?? expr.child(2);
101
736
  if (subObj && subProp) {
102
737
  const base = await resolveExpression(subObj);
738
+ if (!base) {
739
+ const qualified = resolveJvmPackageExpression(index, sup, source, expr, resolveLexicalBinding, mod.file);
740
+ if (qualified)
741
+ return qualified;
742
+ }
103
743
  const memberName = sliceText(subProp, source);
104
744
  if (base?.kind === "namespace") {
105
745
  return resolveExport(index, base.file, memberName, { allowLocalFallback: false });
106
746
  }
107
747
  if (base?.kind === "resolved") {
108
- const memberDef = await resolveMemberDefinitionForBase(index, base.def, memberName);
748
+ const memberDef = await resolveMemberDefinitionForBase(index, base.def, memberName, callArgumentCountFor(expr));
109
749
  return memberDef ? { kind: "resolved", def: memberDef } : null;
110
750
  }
111
751
  }
112
752
  }
113
753
  return null;
114
754
  };
755
+ const receiverHasLexicalBinding = sup.id === "python"
756
+ ? (callee) => {
757
+ const scope = getOrBuildScopeIndex(index, mod.file, source, sup, mod, tree);
758
+ return !!findClosestScopeBinding(scope, sliceText(callee, source), callee, sup);
759
+ }
760
+ : noLexicalBinding;
761
+ const resolvedReceiver = obj && prop && node.id === prop.id ? await resolveExpression(obj) : null;
762
+ const receiverProof = obj && prop && node.id === prop.id
763
+ ? classifyReceiver(sup, obj, source, null, 0, memberNode, receiverHasLexicalBinding, () => {
764
+ if (resolvedReceiver?.kind === "namespace")
765
+ return "module-import";
766
+ if (resolvedReceiver?.kind === "resolved" && declaresMembers(resolvedReceiver.def))
767
+ return "static-type";
768
+ return null;
769
+ })
770
+ : null;
115
771
  const chain = await resolveExpression(memberNode);
116
772
  if (chain && prop && node.id === prop.id) {
117
773
  if (chain.kind === "resolved") {
@@ -133,12 +789,10 @@ export async function resolveMemberAccessDefinition(params) {
133
789
  }
134
790
  }
135
791
  }
136
- const receiverName = obj ? sliceText(obj, source) : "";
137
- const implicitClassReceiver = isKeywordReceiver(sup.id, receiverName);
138
- if (obj && prop && node.id === prop.id && (supportsReceiverMemberNavigation(sup.id) || implicitClassReceiver)) {
792
+ if (obj && prop && node.id === prop.id && supportsReceiverMemberNavigation(sup.id)) {
139
793
  const member = sliceText(prop, source);
140
794
  if (sup.id === "python") {
141
- const memberDef = await resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression);
795
+ const memberDef = await resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression, receiverProof);
142
796
  if (!memberDef)
143
797
  return null;
144
798
  return okGoToResult(index, memberDef, {
@@ -147,11 +801,9 @@ export async function resolveMemberAccessDefinition(params) {
147
801
  confidence: "medium",
148
802
  });
149
803
  }
150
- if (!sup.membersAreImplicitlyInScope && implicitClassReceiver) {
151
- const classContainer = findEnclosingClassContainer(node);
152
- const memberDef = classContainer
153
- ? findLocalWithinNode(mod.locals, member, classContainer, sup.normalizeIdentifier)
154
- : undefined;
804
+ const keywordScope = receiverProof?.kind === "own-type" || receiverProof?.kind === "supertype" ? receiverProof.memberScope : "any";
805
+ if (receiverProof?.kind === "own-type") {
806
+ const memberDef = await resolveKeywordReceiverMember(index, mod, node, member, keywordScope, false, getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined);
155
807
  if (memberDef) {
156
808
  return okGoToResult(index, memberDef, {
157
809
  via: { exportedName: member },
@@ -159,8 +811,74 @@ export async function resolveMemberAccessDefinition(params) {
159
811
  confidence: "medium",
160
812
  });
161
813
  }
814
+ const outOfLineOwnerPath = cppOutOfLineOwnerPath(node, source, sup);
815
+ const outOfLineOwner = outOfLineOwnerPath
816
+ ? await resolveCppQualifiedMemberContainer(index, mod, outOfLineOwnerPath)
817
+ : null;
818
+ if (outOfLineOwner) {
819
+ const outOfLineMember = await resolveKeywordReceiverMember(index, mod, node, member, keywordScope, false, getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined, outOfLineOwner);
820
+ if (outOfLineMember) {
821
+ return okGoToResult(index, outOfLineMember, {
822
+ resolution: "exact",
823
+ confidence: "high",
824
+ });
825
+ }
826
+ }
827
+ // A failed `self` lookup is not a license to bind an unrelated same-file
828
+ // extension member by its bare name (including an unproven where clause).
829
+ if (sup.id === "swift")
830
+ return { status: "not_found", reason: "No matching Swift member definition" };
831
+ }
832
+ else if (receiverProof?.kind === "supertype") {
833
+ const memberDef = await resolveKeywordReceiverMember(index, mod, node, member, keywordScope, true, getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined);
834
+ if (!memberDef)
835
+ return { status: "not_found", reason: "No matching supertype member definition" };
836
+ return okGoToResult(index, memberDef, {
837
+ via: { exportedName: member },
838
+ resolution: "member-access",
839
+ confidence: "medium",
840
+ });
841
+ }
842
+ if (sup.id === "cpp" && memberNode.type === "qualified_identifier") {
843
+ // `a::C::run` nests `C::run` inside `a::(...)`; only the outermost node carries the full owner.
844
+ let outermost = memberNode;
845
+ while (outermost.parent?.type === "qualified_identifier")
846
+ outermost = outermost.parent;
847
+ // The declarator of an out-of-line definition (`int Box<T>::f() {}`) names the declaration
848
+ // itself, not a member call; the declaration lookup below resolves it.
849
+ if (outermost.parent?.type === "function_declarator")
850
+ return null;
851
+ const qualified = cppQualifiedNameSegments(outermost, source);
852
+ const ownerPath = qualified.slice(0, -1);
853
+ const owner = await resolveCppQualifiedMemberContainer(index, mod, ownerPath);
854
+ if (owner) {
855
+ const knownArgumentCount = getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined;
856
+ // Inside a member function, `Owner::member()` can name an instance member of the class or a
857
+ // base through the implicit `this`; elsewhere only static members qualify.
858
+ const implicitThis = await cppQualifiedOwnerHasImplicitThis(index, mod, memberNode, source, sup, owner);
859
+ const memberScope = implicitThis ? "any" : "static";
860
+ const memberDef = await resolveKeywordReceiverMember(index, mod, node, member, memberScope, false, knownArgumentCount, owner);
861
+ return memberDef
862
+ ? okGoToResult(index, memberDef, { resolution: "member-access", confidence: "high" })
863
+ : { status: "not_found", reason: "No matching C++ static member definition" };
864
+ }
865
+ // A qualifier that is not a class (a namespace) names a free function, which the qualified
866
+ // function lookup resolves; the short name must not be read as a same-named class receiver.
867
+ return null;
162
868
  }
163
- const receiver = await resolveReceiverDefinition(obj, source, sup, resolveExpression, mod);
869
+ const importType = isJsTsLanguage(sup.id) && receiverProof?.kind === "named-type" ? receiverProof.typeNode : null;
870
+ const importSpecifier = importType?.type === "type_query" ? importTypeQuerySpecifier(importType) : null;
871
+ if (importSpecifier) {
872
+ const memberDef = resolveImportTypeMember(index, mod.file, importSpecifier, member);
873
+ return memberDef
874
+ ? okGoToResult(index, memberDef, {
875
+ via: { exportedName: member },
876
+ resolution: "member-access",
877
+ confidence: "medium",
878
+ })
879
+ : null;
880
+ }
881
+ const receiver = await resolveReceiverDefinition(index, obj, source, sup, resolveExpression, mod, receiverProof, resolvedReceiver);
164
882
  if (receiver) {
165
883
  const objDef = receiver.def;
166
884
  const targetContext = await ensureParsedContext(objDef.file, undefined, index.languageExtensions);
@@ -185,14 +903,50 @@ export async function resolveMemberAccessDefinition(params) {
185
903
  const memberPredicate = receiver.memberScope === "any"
186
904
  ? undefined
187
905
  : (local) => matchesReceiverMemberScope(local, receiver.memberScope, targetContext, container);
906
+ const knownArgumentCount = getCallArgumentCount({ languageId: sup.id, source, call: memberNode.parent ?? memberNode }) ?? undefined;
188
907
  let memberDef;
189
- if (receiver.runtimeTypeOnly || targetContext.sup.id === "java") {
190
- memberDef = findDirectLocalWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier, memberPredicate);
908
+ const hierarchyLanguage = isJsTsLanguage(targetContext.sup.id) ||
909
+ targetContext.sup.id === "ruby" ||
910
+ targetContext.sup.id === "cpp" ||
911
+ targetContext.sup.id === "csharp" ||
912
+ targetContext.sup.id === "java" ||
913
+ targetContext.sup.id === "kotlin" ||
914
+ targetContext.sup.id === "php" ||
915
+ targetContext.sup.id === "swift";
916
+ if (hierarchyLanguage && declaresMembers(objDef) && !receiver.runtimeTypeOnly) {
917
+ const report = { named: false, ambiguous: false };
918
+ memberDef = await resolveKeywordReceiverMember(index, mod, node, member, receiver.memberScope, false, knownArgumentCount, objDef, report);
919
+ if (!memberDef && report.named)
920
+ return { status: "not_found", reason: "No unique receiver member" };
921
+ }
922
+ if (!memberDef &&
923
+ (targetContext.sup.id === "ts" || targetContext.sup.id === "tsx") &&
924
+ (container.type === "internal_module" || container.type === "module")) {
925
+ memberDef = await findReceiverMemberDefinition(index, targetModule.locals, member, objDef, container, targetContext, normalizeIdentifier, receiver.memberScope, knownArgumentCount);
191
926
  }
192
- else {
193
- memberDef = findReceiverMemberDefinition(targetModule.locals, member, objDef, container, targetContext, normalizeIdentifier, receiver.memberScope);
927
+ else if (!memberDef && (receiver.runtimeTypeOnly || targetContext.sup.id === "java")) {
928
+ const candidates = findDirectLocalsWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier, memberPredicate);
929
+ const selected = selectMember([objDef], indexedMemberModel(index, candidates, targetContext.sup.id), {
930
+ name: member,
931
+ argumentCount: knownArgumentCount ?? null,
932
+ scope: "any",
933
+ useFile: mod.file,
934
+ phpCaseInsensitive: targetContext.sup.id === "php",
935
+ keepUniqueArityMismatch: true,
936
+ });
937
+ memberDef = selected.status === "unique" ? selected.member : undefined;
938
+ }
939
+ else if (!memberDef) {
940
+ memberDef = await findReceiverMemberDefinition(index, targetModule.locals, member, objDef, container, targetContext, normalizeIdentifier, receiver.memberScope, knownArgumentCount);
194
941
  }
195
- if (memberDef) {
942
+ const memberContext = memberDef && fileIdentityKey(memberDef.file) !== fileIdentityKey(objDef.file)
943
+ ? await ensureParsedContext(memberDef.file, undefined, index.languageExtensions)
944
+ : targetContext;
945
+ if (memberDef &&
946
+ (sup.id === "cpp" ||
947
+ isGoExportedMemberName(sup.id, member) ||
948
+ getCompilationUnitPeers(index, mod.file).files.has(memberDef.file)) &&
949
+ !crossFilePeerMemberHidden(mod.file, memberDef, memberContext)) {
196
950
  return okGoToResult(index, memberDef, {
197
951
  via: { exportedName: member },
198
952
  resolution: "member-access",
@@ -205,17 +959,1077 @@ export async function resolveMemberAccessDefinition(params) {
205
959
  }
206
960
  return null;
207
961
  }
208
- function findEnclosingClassContainer(node) {
209
- return nearestMemberContainer(node);
962
+ function findEnclosingClassContainer(node) {
963
+ return nearestMemberContainer(node);
964
+ }
965
+ function keywordClassKey(def) {
966
+ const start = def.range.start;
967
+ return `${fileIdentityKey(def.file)}:${start.index ?? `${start.line}:${start.column}`}`;
968
+ }
969
+ function keywordContainerKey(file, container) {
970
+ return `${fileIdentityKey(file)}:${container.startIndex}:${container.endIndex}`;
971
+ }
972
+ function peelTypeWrappers(node) {
973
+ let current = node;
974
+ while (current) {
975
+ if (current.type === "type_annotation" ||
976
+ current.type === "named_type" ||
977
+ current.type === "user_type" ||
978
+ current.type === "type" ||
979
+ current.type === "parenthesized_type" ||
980
+ current.type === "pointer_type" ||
981
+ current.type === "reference_type" ||
982
+ current.type === "optional_type" ||
983
+ current.type === "nullable_type" ||
984
+ current.type === "generic_type" ||
985
+ current.type === "generic_name") {
986
+ current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
987
+ continue;
988
+ }
989
+ break;
990
+ }
991
+ return current ?? node;
992
+ }
993
+ function isSimpleTypeNameNode(node, sup) {
994
+ return isReceiverNameNode(sup, node.type) || node.type === "type_identifier" || node.type === "name";
995
+ }
996
+ function parseCppBaseType(node, source) {
997
+ let current = node;
998
+ while (current.type === "base_class_clause" ||
999
+ current.type === "access_specifier" ||
1000
+ current.type === "virtual_specifier" ||
1001
+ current.type === "type_descriptor") {
1002
+ const nested = current.namedChildren.at(-1);
1003
+ if (!nested || nested.id === current.id)
1004
+ break;
1005
+ current = nested;
1006
+ }
1007
+ const names = cppQualifiedNameSegments(current, source);
1008
+ return names.length ? { base: names[0], path: names.slice(1) } : null;
1009
+ }
1010
+ function collectDeclaredBaseTypes(container, source, sup, superclassOnly = false) {
1011
+ const ancestry = MEMBER_ACCESS_ROWS[sup.id]?.receiverAncestry;
1012
+ if (!ancestry || (ancestry.clauses.length === 0 && !ancestry.mixinCalls?.length))
1013
+ return [];
1014
+ const bases = [];
1015
+ const seen = new Set();
1016
+ let usedFirstMatch = false;
1017
+ const addSimple = (name, invoked) => {
1018
+ if (!name || seen.has(name))
1019
+ return;
1020
+ seen.add(name);
1021
+ bases.push(invoked ? { kind: "simple", name, invoked } : { kind: "simple", name });
1022
+ };
1023
+ const addQualified = (base, path, invoked) => {
1024
+ if (!base || path.length === 0)
1025
+ return;
1026
+ const key = `${base}.${path.join(".")}`;
1027
+ if (seen.has(key))
1028
+ return;
1029
+ seen.add(key);
1030
+ bases.push(invoked ? { kind: "qualified", base, path, invoked } : { kind: "qualified", base, path });
1031
+ };
1032
+ const collectType = (node, invoked) => {
1033
+ const core = peelTypeWrappers(node);
1034
+ if (core.type === "constructor_invocation") {
1035
+ // Kotlin writes the superclass as a constructor invocation (`Base()`); its callees are
1036
+ // superclass entries, while bare types in the same base list are interfaces.
1037
+ for (const child of core.namedChildren) {
1038
+ if (child.type === "value_arguments")
1039
+ continue;
1040
+ collectType(child, true);
1041
+ }
1042
+ return;
1043
+ }
1044
+ // A computed heritage expression can name the runtime base factory rather than a class.
1045
+ // Its descendants do not prove an inheritance edge.
1046
+ if (isUnprovenHeritageExpression(core))
1047
+ return;
1048
+ if (sup.id === "cpp" && core.type === "base_class_clause") {
1049
+ for (const child of core.namedChildren) {
1050
+ if (child.type === "access_specifier" || child.type === "virtual_specifier")
1051
+ continue;
1052
+ collectType(child, invoked);
1053
+ }
1054
+ return;
1055
+ }
1056
+ if (sup.id === "cpp") {
1057
+ const qualified = parseCppBaseType(core, source);
1058
+ if (qualified) {
1059
+ if (qualified.path.length)
1060
+ addQualified(qualified.base, qualified.path, invoked);
1061
+ else
1062
+ addSimple(qualified.base, invoked);
1063
+ return;
1064
+ }
1065
+ }
1066
+ const unwrapped = unwrapNamedType(core, sup);
1067
+ if (unwrapped) {
1068
+ addSimple(sliceText(unwrapped, source), invoked);
1069
+ return;
1070
+ }
1071
+ if (isMemberAccessNode(sup, core)) {
1072
+ const chain = collectMemberAccessChain({ sup, source, chainNode: core });
1073
+ if (chain && isSimpleTypeNameNode(chain.base, sup) && chain.names.length) {
1074
+ addQualified(sliceText(chain.base, source), [...chain.names].reverse(), invoked);
1075
+ }
1076
+ return;
1077
+ }
1078
+ if (memberAccessTraversalTypes(sup).has(core.type))
1079
+ return;
1080
+ for (const child of core.namedChildren) {
1081
+ if (child.type === "type_arguments")
1082
+ continue;
1083
+ collectType(child, invoked);
1084
+ }
1085
+ };
1086
+ const consider = (node) => {
1087
+ for (const rule of ancestry.clauses) {
1088
+ if (node.type !== rule.nodeType)
1089
+ continue;
1090
+ if (superclassOnly && !rule.supertype)
1091
+ continue;
1092
+ if (superclassOnly && rule.supertype === "first-match") {
1093
+ if (usedFirstMatch)
1094
+ continue;
1095
+ usedFirstMatch = true;
1096
+ }
1097
+ let target = node;
1098
+ if (superclassOnly && rule.supertype === "first-child") {
1099
+ target = target.namedChildren[0] ?? target;
1100
+ }
1101
+ collectType(target, false);
1102
+ }
1103
+ if (superclassOnly || node.type !== "call" || !ancestry.mixinCalls?.length)
1104
+ return;
1105
+ if (node.childForFieldName("receiver"))
1106
+ return;
1107
+ const methodNode = node.childForFieldName("method");
1108
+ const methodName = methodNode ? sliceText(methodNode, source) : undefined;
1109
+ if (!methodName || !ancestry.mixinCalls.includes(methodName))
1110
+ return;
1111
+ const args = node.childForFieldName("arguments");
1112
+ if (args)
1113
+ collectType(args, false);
1114
+ };
1115
+ for (const child of container.namedChildren) {
1116
+ consider(child);
1117
+ for (const grand of child.namedChildren)
1118
+ consider(grand);
1119
+ }
1120
+ return bases;
1121
+ }
1122
+ function asMemberContainer(index, def) {
1123
+ return memberContainerForDefinition(index, def);
1124
+ }
1125
+ function importedMemberContainer(index, result) {
1126
+ if (!result || "namespace" in result)
1127
+ return undefined;
1128
+ return asMemberContainer(index, result);
1129
+ }
1130
+ function resolveNamedMemberContainer(index, mod, name, normalize) {
1131
+ const typedLocals = memberDeclaringLocals(mod, name, normalize);
1132
+ const topLevel = typedLocals.filter((local) => !local.isMember);
1133
+ const candidates = topLevel.length ? topLevel : typedLocals;
1134
+ if (candidates.length === 1)
1135
+ return candidates[0];
1136
+ if (candidates.length > 1)
1137
+ return undefined;
1138
+ const normalizedName = normalize(name);
1139
+ const languageId = supportForFileWithoutHeaderSample(mod.file, index.languageExtensions)?.id;
1140
+ const explicitBinding = effectiveExplicitBinding(mod.imports, languageId ?? "", (binding) => (binding.kind === "named" || binding.kind === "default") && normalize(binding.local) === normalizedName);
1141
+ if (explicitBinding?.kind === "named") {
1142
+ const container = importedMemberContainer(index, resolveImported(index, explicitBinding, explicitBinding.imported));
1143
+ if (container)
1144
+ return container;
1145
+ }
1146
+ else if (explicitBinding?.kind === "default") {
1147
+ const container = importedMemberContainer(index, resolveImported(index, explicitBinding, "default"));
1148
+ if (container)
1149
+ return container;
1150
+ }
1151
+ if (languageId) {
1152
+ const starDecision = resolveStarImportedName(index, mod, languageId, name);
1153
+ if (starDecision.status === "ambiguous")
1154
+ return undefined;
1155
+ if (starDecision.status === "resolved") {
1156
+ const container = asMemberContainer(index, starDecision.definition);
1157
+ if (container)
1158
+ return container;
1159
+ }
1160
+ }
1161
+ const exported = resolveExport(index, mod.file, name, { allowLocalFallback: false });
1162
+ if (exported?.kind === "resolved")
1163
+ return asMemberContainer(index, exported.def);
1164
+ return undefined;
1165
+ }
1166
+ async function resolveQualifiedMemberContainer(index, mod, baseName, path, normalize, sup) {
1167
+ if (path.length === 0)
1168
+ return undefined;
1169
+ if (sup.id === "cpp") {
1170
+ return (await resolveCppQualifiedMemberContainer(index, mod, [baseName, ...path])) ?? undefined;
1171
+ }
1172
+ const namespaceImports = mod.imports.filter((imp) => imp.kind === "namespace" && normalize(imp.localNS) === normalize(baseName));
1173
+ if (namespaceImports.length !== 1)
1174
+ return undefined;
1175
+ const resolved = namespaceImports[0].resolved;
1176
+ let file = typeof resolved === "string" ? resolved : undefined;
1177
+ if (!file)
1178
+ return undefined;
1179
+ for (let partIndex = 0; partIndex < path.length; partIndex += 1) {
1180
+ const part = path[partIndex];
1181
+ const last = partIndex === path.length - 1;
1182
+ const hit = resolveExport(index, file, part, { allowLocalFallback: false });
1183
+ if (!hit)
1184
+ return undefined;
1185
+ if (hit.kind === "namespace") {
1186
+ if (last)
1187
+ return undefined;
1188
+ file = hit.file;
1189
+ continue;
1190
+ }
1191
+ if (!last)
1192
+ return undefined;
1193
+ return asMemberContainer(index, hit.def);
1194
+ }
1195
+ return undefined;
1196
+ }
1197
+ function nodeContainsUnprovenHeritage(node) {
1198
+ if (isUnprovenHeritageExpression(node))
1199
+ return true;
1200
+ return node.namedChildren.some((child) => nodeContainsUnprovenHeritage(child));
1201
+ }
1202
+ /** A heritage or mixin clause whose type expression is not a resolvable name. */
1203
+ function containerHeritageIsUnproven(container, source, sup) {
1204
+ const ancestry = MEMBER_ACCESS_ROWS[sup.id]?.receiverAncestry;
1205
+ if (!ancestry)
1206
+ return false;
1207
+ const clauseTypes = new Set(ancestry.clauses.map((rule) => rule.nodeType));
1208
+ const nodes = [];
1209
+ for (const child of container.namedChildren) {
1210
+ nodes.push(child);
1211
+ for (const grand of child.namedChildren)
1212
+ nodes.push(grand);
1213
+ }
1214
+ if (nodes.some((node) => clauseTypes.has(node.type) && nodeContainsUnprovenHeritage(node)))
1215
+ return true;
1216
+ const mixinCalls = ancestry.mixinCalls;
1217
+ if (!mixinCalls?.length)
1218
+ return false;
1219
+ return nodes.some((node) => {
1220
+ if (node.type !== "call" || node.childForFieldName("receiver"))
1221
+ return false;
1222
+ const methodNode = node.childForFieldName("method");
1223
+ const methodName = methodNode ? sliceText(methodNode, source) : undefined;
1224
+ if (!methodName || !mixinCalls.includes(methodName))
1225
+ return false;
1226
+ const args = node.childForFieldName("arguments");
1227
+ return !!args && nodeContainsUnprovenHeritage(args);
1228
+ });
1229
+ }
1230
+ function definitionForContainer(mod, container) {
1231
+ const nameNode = container.childForFieldName("name");
1232
+ if (!nameNode)
1233
+ return undefined;
1234
+ const matches = mod.locals.filter((local) => declaresMembers(local) && local.range.start.index === nameNode.startIndex);
1235
+ return matches.length === 1 ? matches[0] : undefined;
1236
+ }
1237
+ async function resolveReceiverTypeName(index, mod, sup, typeName) {
1238
+ const trimmed = typeName.trim().replace(/^\\+/, "");
1239
+ if (!trimmed)
1240
+ return undefined;
1241
+ const normalize = sup.normalizeIdentifier;
1242
+ for (const separator of ["::", "\\", "."]) {
1243
+ if (!trimmed.includes(separator))
1244
+ continue;
1245
+ const parts = trimmed.split(separator).filter(Boolean);
1246
+ if (parts.length < 2)
1247
+ return undefined;
1248
+ return resolveQualifiedMemberContainer(index, mod, parts[0], parts.slice(1), normalize, sup);
1249
+ }
1250
+ return resolveNamedMemberContainer(index, mod, trimmed, normalize);
1251
+ }
1252
+ async function resolveDeclaredBase(index, mod, sup, base) {
1253
+ const normalize = sup.normalizeIdentifier;
1254
+ if (base.kind === "simple")
1255
+ return resolveNamedMemberContainer(index, mod, base.name, normalize);
1256
+ return resolveQualifiedMemberContainer(index, mod, base.base, base.path, normalize, sup);
1257
+ }
1258
+ /**
1259
+ * True when `def` and every resolved supertype lack a direct `memberName`. An unresolved
1260
+ * supertype, an unreadable declaration, or a declared member returns false.
1261
+ */
1262
+ async function hierarchyOmitsMember(index, def, memberName, memberScope, seen) {
1263
+ const containerDef = asMemberContainer(index, def);
1264
+ if (!containerDef)
1265
+ return false;
1266
+ const start = containerDef.range.start;
1267
+ const key = `${fileIdentityKey(containerDef.file)}:${start.index ?? `${start.line}:${start.column}`}`;
1268
+ if (seen.has(key))
1269
+ return true;
1270
+ seen.add(key);
1271
+ const ref = await keywordClassRefFromDef(index, containerDef);
1272
+ if (!ref)
1273
+ return false;
1274
+ const normalize = ref.context.sup.normalizeIdentifier;
1275
+ const memberPredicate = memberScope === "any"
1276
+ ? undefined
1277
+ : (local) => matchesReceiverMemberScope(local, memberScope, ref.context, ref.container);
1278
+ if (findDirectLocalsWithinNode(ref.module.locals, memberName, ref.container, ref.context, normalize, memberPredicate)
1279
+ .length > 0) {
1280
+ return false;
1281
+ }
1282
+ if (ref.context.sup.id === "csharp" || ref.context.sup.id === "swift") {
1283
+ const shared = await findSharedOwnerMemberDefinitions({
1284
+ index,
1285
+ ownerFile: containerDef.file,
1286
+ ownerContainer: ref.container,
1287
+ ownerSource: ref.context.source,
1288
+ languageId: ref.context.sup.id,
1289
+ member: memberName,
1290
+ memberScope,
1291
+ });
1292
+ if (shared.length > 0)
1293
+ return false;
1294
+ }
1295
+ if (containerHeritageIsUnproven(ref.container, ref.context.source, ref.context.sup))
1296
+ return false;
1297
+ const bases = collectDeclaredBaseTypes(ref.container, ref.context.source, ref.context.sup, false);
1298
+ for (const base of bases) {
1299
+ const baseDef = await resolveDeclaredBase(index, ref.module, ref.context.sup, base);
1300
+ if (!baseDef)
1301
+ return false;
1302
+ if (!(await hierarchyOmitsMember(index, baseDef, memberName, memberScope, seen)))
1303
+ return false;
1304
+ }
1305
+ return true;
1306
+ }
1307
+ /**
1308
+ * A classified receiver (`new Widget()`, a named type, `this`, or `super`) excludes a failed
1309
+ * member lookup only when its type resolves to a member-declaring definition, no supertype is
1310
+ * unresolved, and that type does not declare `memberName`. Otherwise the site stays unproven.
1311
+ */
1312
+ export async function provenClassifiedReceiverOmitsMember(index, fileId, parsed, accessNode, objectNode, memberName) {
1313
+ const mod = index.byFile.get(fileIdentityKey(fileId));
1314
+ if (!mod)
1315
+ return false;
1316
+ const receiver = classifyReceiver(parsed.sup, objectNode, parsed.source, new Map(), accessNode.startIndex, accessNode, (callee) => {
1317
+ const scope = getOrBuildScopeIndex(index, fileId, parsed.source, parsed.sup, mod, parsed.tree);
1318
+ return !!findClosestScopeBinding(scope, sliceText(callee, parsed.source), callee, parsed.sup);
1319
+ });
1320
+ if (receiver.kind === "unknown" || receiver.kind === "module-import")
1321
+ return false;
1322
+ if (receiver.kind === "named-type") {
1323
+ const def = await resolveReceiverTypeName(index, mod, parsed.sup, receiver.typeName);
1324
+ if (!def)
1325
+ return false;
1326
+ return hierarchyOmitsMember(index, def, memberName, receiver.memberScope, new Set());
1327
+ }
1328
+ const container = nearestMemberContainer(accessNode);
1329
+ if (!container)
1330
+ return false;
1331
+ if (receiver.kind === "supertype") {
1332
+ if (containerHeritageIsUnproven(container, parsed.source, parsed.sup))
1333
+ return false;
1334
+ const bases = collectDeclaredBaseTypes(container, parsed.source, parsed.sup, true);
1335
+ if (!bases.length)
1336
+ return false;
1337
+ const seen = new Set();
1338
+ for (const base of bases) {
1339
+ const baseDef = await resolveDeclaredBase(index, mod, parsed.sup, base);
1340
+ if (!baseDef)
1341
+ return false;
1342
+ if (!(await hierarchyOmitsMember(index, baseDef, memberName, receiver.memberScope, seen)))
1343
+ return false;
1344
+ }
1345
+ return true;
1346
+ }
1347
+ const def = definitionForContainer(mod, container);
1348
+ if (!def)
1349
+ return false;
1350
+ return hierarchyOmitsMember(index, def, memberName, receiver.memberScope, new Set());
1351
+ }
1352
+ async function keywordClassRefFromDef(index, def) {
1353
+ const module = index.byFile.get(fileIdentityKey(def.file));
1354
+ if (!module)
1355
+ return null;
1356
+ const context = await ensureParsedContext(def.file, undefined, index.languageExtensions);
1357
+ const start = def.range.start;
1358
+ const position = {
1359
+ row: start.line - 1,
1360
+ column: start.column - 1,
1361
+ };
1362
+ const nameNode = context.tree.rootNode.descendantForPosition(position, position);
1363
+ const container = nearestMemberContainer(nameNode);
1364
+ if (!container)
1365
+ return null;
1366
+ return { file: def.file, container, context, module };
1367
+ }
1368
+ async function keywordClassRefFromNode(index, mod, node) {
1369
+ const context = await ensureParsedContext(mod.file, undefined, index.languageExtensions);
1370
+ const memberNode = context.tree.rootNode.descendantForPosition(node.startPosition, node.startPosition);
1371
+ const container = findEnclosingClassContainer(memberNode);
1372
+ if (!container)
1373
+ return null;
1374
+ return { file: mod.file, container, context, module: mod };
1375
+ }
1376
+ function crossFilePeerMemberHidden(useFile, memberDef, targetContext) {
1377
+ const languageId = targetContext.sup.id;
1378
+ if (languageId !== "java" && languageId !== "kotlin" && languageId !== "swift")
1379
+ return false;
1380
+ const start = memberDef.range.start;
1381
+ const position = { row: Math.max(0, start.line - 1), column: Math.max(0, start.column - 1) };
1382
+ const nameNode = targetContext.tree.rootNode.descendantForPosition(position, position);
1383
+ if (!nameNode)
1384
+ return false;
1385
+ if (languageId === "swift") {
1386
+ return isSwiftCrossFileHiddenSharedOwnerMember(languageId, useFile, memberDef.file, nameNode);
1387
+ }
1388
+ if (fileIdentityKey(useFile) === fileIdentityKey(memberDef.file))
1389
+ return false;
1390
+ return !isExportedDeclaration(languageId, nameNode);
1391
+ }
1392
+ async function baseRefsFromContainer(index, mod, container, source, sup, superclassOnly, tree) {
1393
+ const bases = collectDeclaredBaseTypes(container, source, sup, superclassOnly);
1394
+ const refs = [];
1395
+ const seen = new Set();
1396
+ const normalize = (name) => {
1397
+ const normalized = sup.normalizeIdentifier(name);
1398
+ return sup.id === "php" ? foldPhpIdentifierCase(normalized) : normalized;
1399
+ };
1400
+ for (const base of bases) {
1401
+ let def = base.kind === "simple"
1402
+ ? resolveNamedMemberContainer(index, mod, base.name, normalize)
1403
+ : await resolveQualifiedMemberContainer(index, mod, base.base, base.path, normalize, sup);
1404
+ if (!def && base.kind === "simple" && sup.id !== "php") {
1405
+ const named = resolveNamedDefinition(index, mod, mod.file, sup, base.name, undefined, container.startIndex);
1406
+ if (named?.status === "ok")
1407
+ def = asMemberContainer(index, named.definition);
1408
+ }
1409
+ if (!def && sup.id === "php" && base.kind === "simple") {
1410
+ def = resolvePhpNamespaceSymbol(index, source, tree, container, base.name, mod.imports, "class") ?? undefined;
1411
+ }
1412
+ if (!def)
1413
+ continue;
1414
+ const ref = await keywordClassRefFromDef(index, def);
1415
+ if (!ref)
1416
+ continue;
1417
+ // `super`, `base`, and `parent` follow class ancestors only. An own receiver also inherits
1418
+ // interface or protocol members, so apply the class-only filter only to supertype lookup.
1419
+ const interfaceLike = ref.container.type === "interface_declaration" ||
1420
+ ref.container.type === "protocol_declaration" ||
1421
+ ref.container.type === "trait_item" ||
1422
+ /^(?:interface|protocol|trait)\b/.test(sliceText(ref.container, ref.context.source).trimStart());
1423
+ if (superclassOnly && (def.kind !== SymbolKind.Class || interfaceLike))
1424
+ continue;
1425
+ // Kotlin classifies interfaces as SymbolKind.Class too, so the superclass is identified
1426
+ // syntactically: `Base()` is a constructor invocation, while bare delegation-specifier
1427
+ // entries (`Face`, `by` delegations) are interfaces. Interface-only super lookup stays
1428
+ // unresolved, while an own receiver can inherit their default members.
1429
+ if (superclassOnly && sup.id === "kotlin" && !base.invoked)
1430
+ continue;
1431
+ const key = keywordClassKey(def);
1432
+ if (seen.has(key))
1433
+ continue;
1434
+ seen.add(key);
1435
+ refs.push(ref);
1436
+ }
1437
+ return refs;
1438
+ }
1439
+ async function resolveKeywordReceiverMember(index, mod, node, member, memberScope, startAtAncestor, knownArgumentCount, explicitClassDef, report) {
1440
+ const current = explicitClassDef
1441
+ ? await keywordClassRefFromDef(index, explicitClassDef)
1442
+ : await keywordClassRefFromNode(index, mod, node);
1443
+ if (!current)
1444
+ return undefined;
1445
+ const spansHierarchy = inheritsMemberOverloads(current.context.sup.id);
1446
+ const ownerKey = (ref) => keywordContainerKey(ref.file, ref.container);
1447
+ const preloadHiddenNames = isJsTsLanguage(current.context.sup.id) && knownArgumentCount !== undefined;
1448
+ const memberKey = (def) => `${fileIdentityKey(def.file)}:${def.range.start.index}`;
1449
+ const parentsByKey = new Map();
1450
+ const membersByKey = new Map();
1451
+ const scopeByMember = new Map();
1452
+ const visible = new Set();
1453
+ let level = [current];
1454
+ const seen = new Set([ownerKey(current)]);
1455
+ for (let depth = 0; depth < RECEIVER_HIERARCHY_DEPTH && level.length; depth += 1) {
1456
+ const next = [];
1457
+ let nameFound = false;
1458
+ for (const ref of level) {
1459
+ const key = ownerKey(ref);
1460
+ const matches = [];
1461
+ if (!startAtAncestor || depth) {
1462
+ appendDirectKeywordMembers(ref.module.locals, member, ref.container, ref.context, ref.context.sup.normalizeIdentifier, undefined, matches);
1463
+ if (isJsTsLanguage(ref.context.sup.id) && ref.container.type === "interface_declaration") {
1464
+ const owner = memberContainerDef(ref.module, ref.container);
1465
+ if (owner) {
1466
+ for (const hit of typescriptMergedInterfaceMemberCandidates(ref.module.locals, member, owner, ref.container, ref.context, ref.context.sup.normalizeIdentifier, undefined)) {
1467
+ if (!matches.includes(hit))
1468
+ matches.push(hit);
1469
+ }
1470
+ }
1471
+ }
1472
+ if (ref.context.sup.id === "csharp" || ref.context.sup.id === "swift") {
1473
+ const shared = await resolveSharedOwnerContainers({
1474
+ index,
1475
+ ownerFile: ref.file,
1476
+ ownerContainer: ref.container,
1477
+ ownerSource: ref.context.source,
1478
+ languageId: ref.context.sup.id,
1479
+ });
1480
+ for (const peer of shared) {
1481
+ const peerMatches = [];
1482
+ appendDirectKeywordMembers(peer.module.locals, member, peer.container, peer.context, peer.context.sup.normalizeIdentifier, undefined, peerMatches);
1483
+ for (const hit of peerMatches) {
1484
+ if (peer.context.sup.id === "swift" && crossFilePeerMemberHidden(mod.file, hit, peer.context))
1485
+ continue;
1486
+ matches.push(hit);
1487
+ scopeByMember.set(hit, hasStaticModifier(hit, peer.context, peer.container) ? "static" : "instance");
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+ membersByKey.set(key, matches);
1493
+ for (const hit of matches) {
1494
+ if (!scopeByMember.has(hit)) {
1495
+ scopeByMember.set(hit, hasStaticModifier(hit, ref.context, ref.container) ? "static" : "instance");
1496
+ }
1497
+ if (spansHierarchy && (startAtAncestor || depth) && (await isUninheritedPrivateMember(index, mod, node, hit))) {
1498
+ continue;
1499
+ }
1500
+ visible.add(hit);
1501
+ nameFound = true;
1502
+ }
1503
+ if (nameFound && !spansHierarchy && !preloadHiddenNames)
1504
+ continue;
1505
+ const bases = await baseRefsFromContainer(index, ref.module, ref.container, ref.context.source, ref.context.sup, startAtAncestor, ref.context.tree);
1506
+ parentsByKey.set(key, bases);
1507
+ for (const base of bases) {
1508
+ const baseKey = ownerKey(base);
1509
+ if (seen.has(baseKey))
1510
+ continue;
1511
+ seen.add(baseKey);
1512
+ next.push(base);
1513
+ }
1514
+ }
1515
+ if (nameFound && !spansHierarchy && !preloadHiddenNames)
1516
+ break;
1517
+ level = next;
1518
+ }
1519
+ const sameSignatures = new Map();
1520
+ if (spansHierarchy) {
1521
+ const all = [...membersByKey.values()].flat().filter((candidate) => visible.has(candidate));
1522
+ for (let left = 0; left < all.length; left += 1) {
1523
+ for (let right = left + 1; right < all.length; right += 1) {
1524
+ const a = all[left];
1525
+ const b = all[right];
1526
+ if (!(await sameParameterTypes(index, a, b)))
1527
+ continue;
1528
+ const aKey = memberKey(a);
1529
+ const bKey = memberKey(b);
1530
+ const identical = sameSignatures.get(aKey) ?? new Set();
1531
+ identical.add(bKey);
1532
+ sameSignatures.set(aKey, identical);
1533
+ }
1534
+ }
1535
+ }
1536
+ const model = {
1537
+ ownerKey,
1538
+ members: (ref) => membersByKey.get(ownerKey(ref)) ?? [],
1539
+ supertypes: (ref) => parentsByKey.get(ownerKey(ref)) ?? [],
1540
+ name: (def) => def.localName,
1541
+ key: (def) => def.callable?.key ?? memberKey(def),
1542
+ callable: (def) => {
1543
+ const facts = def.callable;
1544
+ if (!facts || memberLookupBinding(current.context.sup.id) !== "unbound")
1545
+ return facts;
1546
+ return facts.unboundArity ? { ...facts, arity: facts.unboundArity } : facts;
1547
+ },
1548
+ scope: (def) => scopeByMember.get(def) ?? "any",
1549
+ visible: (def) => visible.has(def),
1550
+ sameSignature: (a, b) => sameSignatures.get(memberKey(a))?.has(memberKey(b)) ?? false,
1551
+ };
1552
+ const selected = selectMember([current], model, {
1553
+ name: member,
1554
+ argumentCount: knownArgumentCount ?? null,
1555
+ scope: memberScope,
1556
+ useFile: mod.file,
1557
+ startAtAncestor,
1558
+ keepUniqueArityMismatch: !startAtAncestor,
1559
+ inheritOverloads: spansHierarchy,
1560
+ phpCaseInsensitive: current.context.sup.id === "php",
1561
+ separateMemberScopes: hasSeparateMemberScopes(current.context.sup.id),
1562
+ });
1563
+ if (report) {
1564
+ report.named = selected.named;
1565
+ report.ambiguous = selected.status === "ambiguous";
1566
+ }
1567
+ return selected.status === "unique" ? selected.member : undefined;
1568
+ }
1569
+ /** The parameter list of a Java, Kotlin, or C# method declaration. */
1570
+ async function memberParameterList(index, def) {
1571
+ const context = await ensureParsedContext(def.file, index.parsed?.get(fileIdentityKey(def.file)), index.languageExtensions).catch(() => null);
1572
+ const start = def.range.start.index;
1573
+ if (!context || start === undefined)
1574
+ return null;
1575
+ const declaration = context.tree.rootNode.descendantForIndex(start, def.range.end.index ?? start).parent;
1576
+ return (declaration?.childForFieldName("parameters") ??
1577
+ declaration?.namedChildren.find((child) => child.type === "function_value_parameters") ??
1578
+ null);
1579
+ }
1580
+ /** Parameter type texts of a Java, Kotlin, or C# method; null when a type cannot be read. */
1581
+ async function memberParameterTypes(index, def) {
1582
+ const parameters = await memberParameterList(index, def);
1583
+ if (!parameters)
1584
+ return null;
1585
+ const types = [];
1586
+ for (const parameter of parameters.namedChildren) {
1587
+ const type = parameter.childForFieldName("type") ?? parameter.namedChildren.at(-1);
1588
+ if (!type)
1589
+ return null;
1590
+ types.push(type.text.replace(/\s+/g, ""));
1591
+ }
1592
+ return types;
1593
+ }
1594
+ /** The import that binds a type name in a module, as text; empty when no import binds it. */
1595
+ function importedTypeSource(module, name) {
1596
+ for (const imp of module.imports) {
1597
+ if (imp.kind !== "named" || imp.local !== name)
1598
+ continue;
1599
+ const target = typeof imp.resolved === "string" ? imp.resolved : (imp.resolved?.external ?? "");
1600
+ return `${target}:${imp.imported}`;
1601
+ }
1602
+ return "";
1603
+ }
1604
+ /** Type parameter names declared by a method or any type enclosing it. */
1605
+ async function typeParameterNamesAround(index, def) {
1606
+ const names = new Set();
1607
+ const context = await ensureParsedContext(def.file, index.parsed?.get(fileIdentityKey(def.file)), index.languageExtensions).catch(() => null);
1608
+ const start = def.range.start.index;
1609
+ if (!context || start === undefined)
1610
+ return names;
1611
+ let current = context.tree.rootNode.descendantForIndex(start, def.range.end.index ?? start);
1612
+ for (; current; current = current.parent) {
1613
+ const parameters = current.childForFieldName("type_parameters") ??
1614
+ current.namedChildren.find((child) => child.type === "type_parameters" || child.type === "type_parameter_list");
1615
+ if (!parameters)
1616
+ continue;
1617
+ for (const parameter of parameters.namedChildren) {
1618
+ const name = parameter.childForFieldName("name") ??
1619
+ parameter.namedChildren.find((child) => /identifier/u.test(child.type)) ??
1620
+ (/identifier/u.test(parameter.type) ? parameter : null);
1621
+ if (name)
1622
+ names.add(name.text);
1623
+ }
1624
+ }
1625
+ return names;
1626
+ }
1627
+ /** Built-in parameter types whose spelling names one type in every file. */
1628
+ const BUILTIN_PARAMETER_TYPES = {
1629
+ java: new Set([
1630
+ "int",
1631
+ "long",
1632
+ "short",
1633
+ "byte",
1634
+ "char",
1635
+ "boolean",
1636
+ "float",
1637
+ "double",
1638
+ "String",
1639
+ "Object",
1640
+ "Integer",
1641
+ "Long",
1642
+ "Boolean",
1643
+ "Double",
1644
+ "Float",
1645
+ "Short",
1646
+ "Byte",
1647
+ "Character",
1648
+ ]),
1649
+ kotlin: new Set(["Int", "Long", "Short", "Byte", "Char", "Boolean", "Float", "Double", "String", "Any", "Unit"]),
1650
+ csharp: new Set([
1651
+ "int",
1652
+ "long",
1653
+ "short",
1654
+ "byte",
1655
+ "char",
1656
+ "bool",
1657
+ "float",
1658
+ "double",
1659
+ "decimal",
1660
+ "string",
1661
+ "object",
1662
+ "uint",
1663
+ "ulong",
1664
+ "ushort",
1665
+ "sbyte",
1666
+ ]),
1667
+ };
1668
+ /**
1669
+ * Whether two methods take the same parameter types, so the one in a derived class overrides the
1670
+ * other. Equal spelling is proof only within one file or for built-in types; elsewhere each
1671
+ * spelling must resolve to the same declaration from its own file.
1672
+ */
1673
+ export async function sameParameterTypes(index, left, right) {
1674
+ // A type parameter (`T`) names a different type in each declaration after substitution, so
1675
+ // equal spelling proves nothing.
1676
+ const [leftGenerics, rightGenerics] = await Promise.all([
1677
+ typeParameterNamesAround(index, left),
1678
+ typeParameterNamesAround(index, right),
1679
+ ]);
1680
+ const [leftTypes, rightTypes] = await Promise.all([
1681
+ memberParameterTypes(index, left),
1682
+ memberParameterTypes(index, right),
1683
+ ]);
1684
+ if (!leftTypes || !rightTypes || leftTypes.length !== rightTypes.length)
1685
+ return false;
1686
+ const sameFile = fileIdentityKey(left.file) === fileIdentityKey(right.file);
1687
+ const leftContext = await ensureParsedContext(left.file, index.parsed?.get(fileIdentityKey(left.file)), index.languageExtensions).catch(() => null);
1688
+ if (!leftContext)
1689
+ return false;
1690
+ for (let at = 0; at < leftTypes.length; at += 1) {
1691
+ const text = leftTypes[at];
1692
+ if (text !== rightTypes[at])
1693
+ return false;
1694
+ const typeNames = text.match(/[\p{L}_][\p{L}\p{N}_]*/gu) ?? [];
1695
+ if (typeNames.some((typeName) => leftGenerics.has(typeName) || rightGenerics.has(typeName)))
1696
+ return false;
1697
+ // One Java or Kotlin file declares one package; a C# file can open several namespaces, so the
1698
+ // same spelling there still needs resolution.
1699
+ if (sameFile && leftContext.sup.id !== "csharp")
1700
+ continue;
1701
+ const base = text
1702
+ .replace(/<.*$/su, "")
1703
+ .replace(/[?\[\].]+$/u, "")
1704
+ .split(".")
1705
+ .pop() ?? text;
1706
+ if (BUILTIN_PARAMETER_TYPES[leftContext.sup.id]?.has(base))
1707
+ continue;
1708
+ const rightContext = await ensureParsedContext(right.file, index.parsed?.get(fileIdentityKey(right.file)), index.languageExtensions).catch(() => null);
1709
+ const leftModule = index.byFile.get(fileIdentityKey(left.file));
1710
+ const rightModule = index.byFile.get(fileIdentityKey(right.file));
1711
+ if (!rightContext || !leftModule || !rightModule)
1712
+ return false;
1713
+ // Resolve at each declaration so a C# spelling reads its own namespace region.
1714
+ const leftType = resolveNamedDefinition(index, leftModule, left.file, leftContext.sup, base, undefined, left.range.start.index);
1715
+ const rightType = resolveNamedDefinition(index, rightModule, right.file, rightContext.sup, base, undefined, right.range.start.index);
1716
+ if (leftType?.status !== "ok" && rightType?.status !== "ok") {
1717
+ // Neither names a project type: both files must name it through the same import (or none).
1718
+ if (importedTypeSource(leftModule, base) !== importedTypeSource(rightModule, base))
1719
+ return false;
1720
+ continue;
1721
+ }
1722
+ if (leftType?.status !== "ok" || rightType?.status !== "ok")
1723
+ return false;
1724
+ if (fileIdentityKey(leftType.definition.file) !== fileIdentityKey(rightType.definition.file) ||
1725
+ leftType.definition.range.start.index !== rightType.definition.range.start.index) {
1726
+ return false;
1727
+ }
1728
+ }
1729
+ return true;
1730
+ }
1731
+ /**
1732
+ * Validate an unqualified member use against its actual lexical owner, including shared
1733
+ * owner parts in other files and inherited members. Swift checks every bare name; C#, Java, and
1734
+ * Kotlin check only bare call callees. A static context reaches only static members.
1735
+ */
1736
+ /** The callee of a receiverless call (`f()`), which may name a member through the implicit `this`. */
1737
+ export function implicitSelfCallee(languageId, call) {
1738
+ if (languageId === "csharp")
1739
+ return call.type === "invocation_expression" ? call.childForFieldName("function") : null;
1740
+ if (languageId === "java") {
1741
+ if (call.type !== "method_invocation" || call.childForFieldName("object"))
1742
+ return null;
1743
+ return call.childForFieldName("name");
1744
+ }
1745
+ if (languageId === "kotlin")
1746
+ return call.type === "call_expression" ? (call.namedChildren[0] ?? null) : null;
1747
+ return null;
1748
+ }
1749
+ export async function resolveImplicitSelfMember(index, mod, node, name, source, languageId) {
1750
+ const call = node.parent ?? node;
1751
+ if (languageId !== "swift" && implicitSelfCallee(languageId, call)?.id !== node.id)
1752
+ return undefined;
1753
+ const jvm = languageId === "java" || languageId === "kotlin";
1754
+ const staticScoped = languageId === "csharp" || jvm;
1755
+ const memberScope = staticScoped && nodeInStaticMemberContext(node, source) ? "static" : "any";
1756
+ const argumentCount = getCallArgumentCount({ languageId, source, call }) ?? undefined;
1757
+ const report = { named: false, ambiguous: false };
1758
+ const member = await resolveKeywordReceiverMember(index, mod, node, name, memberScope, false, argumentCount, undefined, report);
1759
+ if (member)
1760
+ return member;
1761
+ // Two inherited overloads of one arity are ambiguous without type ranking; in Java and C# any
1762
+ // inherited method of that name hides imports even when none accepts the call.
1763
+ if (report.ambiguous || (report.named && (languageId === "java" || languageId === "csharp")))
1764
+ return null;
1765
+ if (memberScope !== "static" || !jvm)
1766
+ return undefined;
1767
+ // In a static context an inherited instance method still shadows a static import or package
1768
+ // function; the call is invalid, so it has no target.
1769
+ const instanceReport = { named: false, ambiguous: false };
1770
+ const instance = await resolveKeywordReceiverMember(index, mod, node, name, "any", false, argumentCount, undefined, instanceReport);
1771
+ // Any inherited instance method of that name hides the import, even when none applies.
1772
+ return instance || instanceReport.named ? null : undefined;
1773
+ }
1774
+ /** Whether an inherited JVM member is inaccessible through this receiver. */
1775
+ async function isUninheritedPrivateMember(index, mod, use, member) {
1776
+ const container = findEnclosingClassContainer(use);
1777
+ const start = member.range.start.index ?? -1;
1778
+ const ownMember = !!container &&
1779
+ fileIdentityKey(member.file) === fileIdentityKey(mod.file) &&
1780
+ start >= container.startIndex &&
1781
+ start < container.endIndex;
1782
+ if (ownMember)
1783
+ return false;
1784
+ if (member.javaPackagePrivate && !member.javaProtectedMember) {
1785
+ const memberPackage = getPackageDeclarationName(index, member.file, "java");
1786
+ const useLanguage = supportForFileWithoutHeaderSample(mod.file, index.languageExtensions)?.id;
1787
+ const usePackage = getPackageDeclarationName(index, mod.file, useLanguage === "kotlin" ? "kotlin" : "java");
1788
+ if (memberPackage !== usePackage)
1789
+ return true;
1790
+ }
1791
+ const parsed = await ensureParsedContext(member.file, index.parsed?.get(fileIdentityKey(member.file)), index.languageExtensions).catch(() => null);
1792
+ const nameNode = parsed?.tree.rootNode.descendantForIndex(start, member.range.end.index ?? start);
1793
+ return !!parsed && !!nameNode && isPrivateDeclaration(parsed.sup.id, nameNode);
1794
+ }
1795
+ /**
1796
+ * Whether `Owner::member()` at `use` can reach an instance member of `owner` through an implicit
1797
+ * `this`: the enclosing function is a non-static member function of `owner` or of a class that
1798
+ * derives from `owner` through proven bases. Any other context can only name a static member.
1799
+ */
1800
+ export async function cppQualifiedOwnerHasImplicitThis(index, mod, use, source, sup, owner) {
1801
+ const definition = cppEnclosingFunctionDefinition(use);
1802
+ if (!definition || !(await cppFunctionHasImplicitThis(index, mod, definition, source, sup)))
1803
+ return false;
1804
+ const outOfLinePath = cppOutOfLineOwnerPath(definition, source, sup);
1805
+ const enclosingDef = outOfLinePath ? await resolveCppQualifiedMemberContainer(index, mod, outOfLinePath) : null;
1806
+ const enclosing = enclosingDef
1807
+ ? await keywordClassRefFromDef(index, enclosingDef)
1808
+ : await keywordClassRefFromNode(index, mod, definition);
1809
+ const target = await keywordClassRefFromDef(index, owner);
1810
+ if (!enclosing || !target)
1811
+ return false;
1812
+ const targetKey = keywordContainerKey(target.file, target.container);
1813
+ const visited = new Set();
1814
+ let level = [enclosing];
1815
+ for (let depth = 0; depth < RECEIVER_HIERARCHY_DEPTH && level.length; depth += 1) {
1816
+ const next = [];
1817
+ for (const candidate of level) {
1818
+ const key = keywordContainerKey(candidate.file, candidate.container);
1819
+ if (key === targetKey)
1820
+ return true;
1821
+ if (visited.has(key))
1822
+ continue;
1823
+ visited.add(key);
1824
+ next.push(...(await baseRefsFromContainer(index, candidate.module, candidate.container, candidate.context.source, candidate.context.sup, false, candidate.context.tree)));
1825
+ }
1826
+ level = next;
1827
+ }
1828
+ return false;
1829
+ }
1830
+ /** The C++ function definition enclosing a use, if any. */
1831
+ export function cppEnclosingFunctionDefinition(node) {
1832
+ for (let current = node.parent; current; current = current.parent) {
1833
+ if (current.type === "function_definition")
1834
+ return current;
1835
+ }
1836
+ return null;
1837
+ }
1838
+ /** Proven unqualified member call from an out-of-line C++ method definition. */
1839
+ export async function resolveCppOutOfLineImplicitMember(index, mod, node, name, source, sup, requireAcceptedArity = false) {
1840
+ if (node.parent?.type !== "call_expression" || node.parent.childForFieldName("function")?.id !== node.id) {
1841
+ return undefined;
1842
+ }
1843
+ const ownerPath = cppOutOfLineOwnerPath(node, source, sup);
1844
+ const owner = ownerPath ? await resolveCppQualifiedMemberContainer(index, mod, ownerPath) : null;
1845
+ if (!owner)
1846
+ return undefined;
1847
+ const argumentCount = getCallArgumentCount({ languageId: "cpp", source, call: node.parent }) ?? undefined;
1848
+ const enclosingFunction = cppEnclosingFunctionDefinition(node);
1849
+ const memberScope = enclosingFunction && (await cppFunctionHasImplicitThis(index, mod, enclosingFunction, source, sup))
1850
+ ? "any"
1851
+ : "static";
1852
+ const matching = await resolveKeywordReceiverMember(index, mod, node, name, memberScope, false, argumentCount, owner);
1853
+ // A class member hides a same-named global even when this call cannot accept its arity. The
1854
+ // only member is still the call's target for navigation; an ambiguous overload set is not.
1855
+ const member = matching ??
1856
+ (argumentCount === undefined
1857
+ ? undefined
1858
+ : await resolveKeywordReceiverMember(index, mod, node, name, memberScope, false, undefined, owner));
1859
+ if (!member) {
1860
+ // In a static member function, an instance member still hides a same-named global: the call
1861
+ // is ill-formed, so neither consumer may fall back to the global.
1862
+ const hidden = memberScope === "static" &&
1863
+ (await resolveKeywordReceiverMember(index, mod, node, name, "any", false, undefined, owner));
1864
+ return hidden ? null : undefined;
1865
+ }
1866
+ // The call graph records no edge for a call its target cannot accept. `null` means a member hides
1867
+ // the name but is not the call's target, so no consumer may fall back to a same-named free function.
1868
+ const rejected = requireAcceptedArity &&
1869
+ argumentCount !== undefined &&
1870
+ !receiverMemberAcceptsArgumentCount(index, member, argumentCount);
1871
+ return rejected ? null : member;
210
1872
  }
211
1873
  export { supportsReceiverCallEdges, supportsReceiverMemberNavigation } from "../util/member-access-tables.js";
212
1874
  function memberDeclaringLocals(mod, typeName, normalize) {
213
1875
  const normalized = normalize(typeName);
214
1876
  return mod.locals.filter((local) => normalize(local.localName) === normalized && declaresMembers(local));
215
1877
  }
216
- async function resolveReceiverDefinition(obj, source, sup, resolveExpression, mod) {
217
- const constructor = receiverConstructorExpression(obj, source, sup);
1878
+ /**
1879
+ * Ruby constant visible the same way go-to-definition resolves a bare `Widget`:
1880
+ * a same-file declaration, or the class a `require` brought in. Not project-wide.
1881
+ */
1882
+ export function resolveRubyVisibleConstant(index, mod, sup, typeName) {
1883
+ if (sup.id !== "ruby")
1884
+ return null;
1885
+ const resolved = resolveNamedDefinition(index, mod, mod.file, sup, typeName);
1886
+ if (resolved?.status !== "ok")
1887
+ return null;
1888
+ return declaresMembers(resolved.definition) ? resolved.definition : null;
1889
+ }
1890
+ /** Proven PHP `extends` base, using the same simple-name lookup as `parent::`. */
1891
+ function resolvePhpProvenBaseClass(index, mod, classNode, source, sup) {
1892
+ const bases = collectDeclaredBaseTypes(classNode, source, sup, true);
1893
+ if (bases.length !== 1)
1894
+ return null;
1895
+ const base = bases[0];
1896
+ if (!base || base.kind !== "simple")
1897
+ return null;
1898
+ const normalize = (name) => foldPhpIdentifierCase(sup.normalizeIdentifier(name));
1899
+ return resolveNamedMemberContainer(index, mod, base.name, normalize) ?? null;
1900
+ }
1901
+ /**
1902
+ * Class named by `new self()`, `new static()`, or `new parent()`.
1903
+ * `self` and `static` are the enclosing class. `parent` is the proven base.
1904
+ * Returns null when the keyword is not proven, so a class named `Parent` cannot win.
1905
+ */
1906
+ export function resolvePhpObjectCreationTarget(index, mod, keyword, source, sup) {
1907
+ if (!keyword.classNode)
1908
+ return null;
1909
+ if (keyword.keyword === "self" || keyword.keyword === "static") {
1910
+ return memberContainerDef(mod, keyword.classNode);
1911
+ }
1912
+ return resolvePhpProvenBaseClass(index, mod, keyword.classNode, source, sup);
1913
+ }
1914
+ function enclosingRubyMethod(node) {
1915
+ let current = node.parent;
1916
+ while (current) {
1917
+ if (current.type === "method" || current.type === "singleton_method")
1918
+ return current;
1919
+ current = current.parent;
1920
+ }
1921
+ return null;
1922
+ }
1923
+ /** Bare `super` / `super()` targets the same-named method on a proven superclass. */
1924
+ export async function resolveRubySuperDefinition(index, mod, node, source, sup) {
1925
+ if (sup.id !== "ruby" || node.type !== "super")
1926
+ return undefined;
1927
+ const method = enclosingRubyMethod(node);
1928
+ const nameNode = method?.childForFieldName("name") ?? null;
1929
+ if (!nameNode)
1930
+ return undefined;
1931
+ const member = sliceText(nameNode, source);
1932
+ if (!member)
1933
+ return undefined;
1934
+ return resolveKeywordReceiverMember(index, mod, node, member, "any", true);
1935
+ }
1936
+ /** Follow a Swift typealias only when its right-hand side is a single indexed nominal type. */
1937
+ async function resolveSwiftAliasContainer(index, alias) {
1938
+ let current = alias;
1939
+ const seen = new Set();
1940
+ while (current.kind === SymbolKind.TypeAlias) {
1941
+ const key = `${fileIdentityKey(current.file)}:${current.range.start.index}`;
1942
+ if (seen.has(key))
1943
+ return undefined;
1944
+ seen.add(key);
1945
+ const mod = index.byFile.get(fileIdentityKey(current.file));
1946
+ if (!mod)
1947
+ return undefined;
1948
+ const context = await ensureParsedContext(current.file, index.parsed?.get(fileIdentityKey(current.file)), index.languageExtensions);
1949
+ if (context.sup.id !== "swift")
1950
+ return undefined;
1951
+ const declaration = nameNodeForDef(context, current)?.parent;
1952
+ if (declaration?.type !== "typealias_declaration") {
1953
+ return declaration?.type === "class_declaration" && declaresMembers(current) ? current : undefined;
1954
+ }
1955
+ const target = declaration.namedChildren.find((child) => child.type === "user_type");
1956
+ const named = target ? unwrapNamedType(target, context.sup) : null;
1957
+ if (!named || target?.namedChildren.length !== 1)
1958
+ return undefined;
1959
+ const targetName = sliceText(named, context.source);
1960
+ const namedTarget = resolveNamedDefinition(index, mod, mod.file, context.sup, targetName, undefined, declaration.startIndex);
1961
+ const next = resolveNamedMemberContainer(index, mod, targetName, context.sup.normalizeIdentifier) ??
1962
+ (namedTarget?.status === "ok" ? asMemberContainer(index, namedTarget.definition) : undefined);
1963
+ if (!next)
1964
+ return undefined;
1965
+ current = next;
1966
+ }
1967
+ return declaresMembers(current) ? current : undefined;
1968
+ }
1969
+ async function resolveReceiverDefinition(index, obj, source, sup, resolveExpression, mod, proof, resolvedDirect) {
1970
+ const direct = resolvedDirect === undefined ? await resolveExpression(obj) : resolvedDirect;
1971
+ const receiver = proof ??
1972
+ classifyReceiver(sup, obj, source, null, 0, obj.parent ?? obj, noLexicalBinding, () => {
1973
+ if (direct?.kind === "namespace")
1974
+ return "module-import";
1975
+ if (direct?.kind === "resolved" && declaresMembers(direct.def))
1976
+ return "static-type";
1977
+ return null;
1978
+ });
1979
+ if (receiver.kind === "module-import")
1980
+ return null;
1981
+ if (supportsDeclaredFieldChains(sup.id) && isMemberAccessNode(sup, obj)) {
1982
+ const directType = direct?.kind === "resolved" ? asMemberContainer(index, direct.def) : undefined;
1983
+ if (!directType) {
1984
+ const { object, property } = getMemberAccessParts(sup, obj);
1985
+ if (!object || !property)
1986
+ return null;
1987
+ const owner = await resolveReceiverDefinition(index, object, source, sup, resolveExpression, mod);
1988
+ if (!owner || owner.runtimeTypeOnly)
1989
+ return null;
1990
+ const field = await resolveKeywordReceiverMember(index, mod, property, sliceText(property, source), owner.memberScope, false, undefined, owner.def);
1991
+ if (!field || field.kind !== SymbolKind.Variable || !field.isMember)
1992
+ return null;
1993
+ const fieldContext = await ensureParsedContext(field.file, undefined, index.languageExtensions);
1994
+ const name = nameNodeForDef(fieldContext, field);
1995
+ let declaration = name?.parent ?? null;
1996
+ if (declaration?.type === "variable_declarator")
1997
+ declaration = declaration.parent;
1998
+ if (!declaration)
1999
+ return null;
2000
+ const annotatedType = declaredTypeNameNode(declaration, fieldContext.sup);
2001
+ if (!annotatedType)
2002
+ return null;
2003
+ const fieldModule = index.byFile.get(fileIdentityKey(field.file));
2004
+ if (!fieldModule)
2005
+ return null;
2006
+ const typeText = qualifiedDeclaredTypeText(annotatedType, fieldContext.source);
2007
+ // A type parameter in scope (`class Host<Repo>`) is not a nominal type; bounds are not solved.
2008
+ if (typeParameterNamesInScope(declaration, fieldContext.source).has(typeText.split(/[.:]/)[0]))
2009
+ return null;
2010
+ const type = await resolveReceiverTypeName(index, fieldModule, fieldContext.sup, typeText);
2011
+ return type ? { def: type, memberScope: "instance" } : null;
2012
+ }
2013
+ }
2014
+ if (receiver.kind === "own-type") {
2015
+ const container = nearestMemberContainer(obj);
2016
+ const owner = container ? definitionForContainer(mod, container) : undefined;
2017
+ return owner ? { def: owner, memberScope: receiver.memberScope } : null;
2018
+ }
2019
+ const constructor = receiver.kind === "named-type" && receiver.proof !== "static-type" ? receiver.typeNode : null;
218
2020
  if (constructor) {
2021
+ if (sup.id === "cpp") {
2022
+ const qualifiedType = cppQualifiedNameSegments(constructor, source);
2023
+ if (qualifiedType.length > 1) {
2024
+ const def = await resolveCppQualifiedMemberContainer(index, mod, qualifiedType);
2025
+ if (def) {
2026
+ return {
2027
+ def,
2028
+ memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
2029
+ };
2030
+ }
2031
+ }
2032
+ }
219
2033
  const typeName = sliceText(constructor, source);
220
2034
  const typedLocals = memberDeclaringLocals(mod, typeName, sup.normalizeIdentifier);
221
2035
  if (typedLocals.length === 1) {
@@ -224,13 +2038,42 @@ async function resolveReceiverDefinition(obj, source, sup, resolveExpression, mo
224
2038
  memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
225
2039
  };
226
2040
  }
2041
+ if (sup.id === "go") {
2042
+ const named = resolveNamedDefinition(index, mod, mod.file, sup, typeName, undefined, constructor.startIndex);
2043
+ const peer = named?.status === "ok" ? asMemberContainer(index, named.definition) : undefined;
2044
+ if (peer)
2045
+ return { def: peer, memberScope: "any" };
2046
+ }
2047
+ if (sup.id === "php") {
2048
+ const normalizeTypeName = (name) => foldPhpIdentifierCase(sup.normalizeIdentifier(name));
2049
+ const namedContainer = resolveNamedMemberContainer(index, mod, typeName, normalizeTypeName);
2050
+ if (namedContainer) {
2051
+ return {
2052
+ def: namedContainer,
2053
+ memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
2054
+ };
2055
+ }
2056
+ }
227
2057
  const result = await resolveExpression(constructor);
228
- if (result?.kind === "resolved" && declaresMembers(result.def)) {
2058
+ const constructed = result?.kind === "resolved" ? asMemberContainer(index, result.def) : undefined;
2059
+ if (constructed) {
229
2060
  return {
230
- def: result.def,
2061
+ def: constructed,
231
2062
  memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
232
2063
  };
233
2064
  }
2065
+ // Ruby `require` exposes a class as a namespace import. A bare constant already
2066
+ // resolves through resolveNamedDefinition; `Klass.new` must use that same path
2067
+ // so goto, references, and call edges agree. Same-file classes returned above.
2068
+ if (sup.id === "ruby" && typedLocals.length === 0) {
2069
+ const rubyType = resolveRubyVisibleConstant(index, mod, sup, typeName);
2070
+ if (rubyType) {
2071
+ return {
2072
+ def: rubyType,
2073
+ memberScope: hasStaticMemberDistinction(sup.id) ? "instance" : "any",
2074
+ };
2075
+ }
2076
+ }
234
2077
  if (typedLocals[0]) {
235
2078
  return {
236
2079
  def: typedLocals[0],
@@ -238,13 +2081,19 @@ async function resolveReceiverDefinition(obj, source, sup, resolveExpression, mo
238
2081
  };
239
2082
  }
240
2083
  }
241
- const direct = await resolveExpression(obj);
242
- if (direct?.kind === "resolved" && declaresMembers(direct.def)) {
243
- if (isJsTsLanguage(sup.id) && direct.def.kind === SymbolKind.TypeAlias) {
244
- return { def: direct.def, memberScope: "any", runtimeTypeOnly: true };
2084
+ if (sup.id === "swift" && direct?.kind === "resolved" && direct.def.kind === SymbolKind.TypeAlias) {
2085
+ const aliased = await resolveSwiftAliasContainer(index, direct.def);
2086
+ if (aliased)
2087
+ return { def: aliased, memberScope: "static" };
2088
+ return null;
2089
+ }
2090
+ const directContainer = direct?.kind === "resolved" ? asMemberContainer(index, direct.def) : undefined;
2091
+ if (directContainer) {
2092
+ if (isJsTsLanguage(sup.id) && directContainer.kind === SymbolKind.TypeAlias) {
2093
+ return { def: directContainer, memberScope: "any", runtimeTypeOnly: true };
245
2094
  }
246
- const memberScope = hasStaticMemberDistinction(sup.id) ? "static" : "any";
247
- return { def: direct.def, memberScope };
2095
+ const memberScope = supportsStaticMemberScope(sup.id) ? "static" : "any";
2096
+ return { def: directContainer, memberScope };
248
2097
  }
249
2098
  if (isJsTsLanguage(sup.id) && isReceiverNameNode(sup, obj.type)) {
250
2099
  return null;
@@ -254,7 +2103,25 @@ async function resolveReceiverDefinition(obj, source, sup, resolveExpression, mo
254
2103
  }
255
2104
  return null;
256
2105
  }
257
- async function resolveMemberDefinitionForBase(index, baseDef, member) {
2106
+ /** Whether a type-qualified access (`Util.M`) can name `def`: a nested type or a static member. */
2107
+ async function reachableThroughTypeName(index, def) {
2108
+ if (declaresMembers(def))
2109
+ return true;
2110
+ const context = await ensureParsedContext(def.file, index.parsed?.get(fileIdentityKey(def.file)), index.languageExtensions);
2111
+ const nameNode = nameNodeForDef(context, def);
2112
+ if (!nameNode)
2113
+ return false;
2114
+ return hasStaticModifier(def, context, nearestMemberContainer(nameNode) ?? context.tree.rootNode);
2115
+ }
2116
+ /**
2117
+ * A member declared directly in the type `baseDef` names (`Util.Two`), including the other parts
2118
+ * of a C# partial type, or inherited through it. Same-named overloads are narrowed to members a
2119
+ * type name reaches (static members and nested types) when the base is a type, then chosen by
2120
+ * the call's argument count; without a count, or when several accept it, the lookup is
2121
+ * ambiguous. A sole reachable candidate is kept even when the count does not fit, as for other
2122
+ * calls; the graph records no edge for it. Ruby reopens a method by redefining it, so it keeps the first match.
2123
+ */
2124
+ async function resolveMemberDefinitionForBase(index, baseDef, member, knownArgumentCount) {
258
2125
  const targetContext = await ensureParsedContext(baseDef.file, undefined, index.languageExtensions);
259
2126
  const start = baseDef.range.start;
260
2127
  const targetPosition = {
@@ -268,37 +2135,169 @@ async function resolveMemberDefinitionForBase(index, baseDef, member) {
268
2135
  const targetModule = index.byFile.get(fileIdentityKey(baseDef.file));
269
2136
  if (!targetModule)
270
2137
  return undefined;
2138
+ const languageId = targetContext.sup.id;
271
2139
  const normalizeIdentifier = targetContext.sup.normalizeIdentifier;
272
- const directHit = findDirectLocalWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier);
273
- if (directHit)
274
- return directHit;
275
- if (targetContext.sup.id === "java")
2140
+ const candidates = findDirectLocalsWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier);
2141
+ if (languageId === "csharp") {
2142
+ const partialParts = await findSharedOwnerMemberDefinitions({
2143
+ index,
2144
+ ownerFile: baseDef.file,
2145
+ ownerContainer: container,
2146
+ ownerSource: targetContext.source,
2147
+ languageId,
2148
+ member,
2149
+ });
2150
+ for (const hit of partialParts) {
2151
+ if (!candidates.includes(hit))
2152
+ candidates.push(hit);
2153
+ }
2154
+ }
2155
+ if (candidates.length) {
2156
+ let reachable = candidates;
2157
+ if (languageId !== "ruby" && candidates.length > 1) {
2158
+ reachable = [];
2159
+ for (const candidate of candidates) {
2160
+ if (!declaresMembers(baseDef) || (await reachableThroughTypeName(index, candidate)))
2161
+ reachable.push(candidate);
2162
+ }
2163
+ }
2164
+ const selected = selectMember([baseDef], indexedMemberModel(index, reachable, languageId), {
2165
+ name: member,
2166
+ argumentCount: knownArgumentCount ?? null,
2167
+ scope: "any",
2168
+ useFile: baseDef.file,
2169
+ phpCaseInsensitive: languageId === "php",
2170
+ firstDeclarationWins: languageId === "ruby",
2171
+ keepUniqueArityMismatch: true,
2172
+ });
2173
+ return selected.status === "unique" ? selected.member : undefined;
2174
+ }
2175
+ if (languageId === "java")
276
2176
  return undefined;
277
- return findReceiverMemberDefinition(targetModule.locals, member, baseDef, container, targetContext, normalizeIdentifier);
2177
+ return await findReceiverMemberDefinition(index, targetModule.locals, member, baseDef, container, targetContext, normalizeIdentifier);
2178
+ }
2179
+ function typescriptMergedInterfaceMemberCandidates(locals, member, receiverDef, container, targetContext, normalizeIdentifier, predicate) {
2180
+ const matches = findDirectLocalsWithinNode(locals, member, container, targetContext, normalizeIdentifier, predicate);
2181
+ if (!isJsTsLanguage(targetContext.sup.id) || container.type !== "interface_declaration")
2182
+ return matches;
2183
+ const receiverStart = receiverDef.range.start.index ?? 0;
2184
+ const receiverEnd = receiverDef.range.end.index ?? receiverStart;
2185
+ const receiverContainerKey = typescriptCallableContainerKey(targetContext.tree, receiverStart, receiverEnd);
2186
+ const seenBodies = new Set();
2187
+ const appendMembers = (interfaceDeclaration) => {
2188
+ const body = interfaceDeclaration.childForFieldName("body");
2189
+ if (!body)
2190
+ return;
2191
+ const bodyKey = typescriptCallableContainerKey(targetContext.tree, body.startIndex, body.endIndex);
2192
+ if (seenBodies.has(bodyKey))
2193
+ return;
2194
+ seenBodies.add(bodyKey);
2195
+ for (const candidate of findDirectLocalsWithinNode(locals, member, interfaceDeclaration, targetContext, normalizeIdentifier, predicate)) {
2196
+ if (!matches.includes(candidate))
2197
+ matches.push(candidate);
2198
+ }
2199
+ };
2200
+ const normalizedReceiverName = normalizeIdentifier(receiverDef.localName);
2201
+ for (const local of locals) {
2202
+ if (normalizeIdentifier(local.localName) !== normalizedReceiverName)
2203
+ continue;
2204
+ const start = local.range.start.index;
2205
+ if (start === undefined)
2206
+ continue;
2207
+ const end = local.range.end.index ?? start;
2208
+ if (typescriptCallableContainerKey(targetContext.tree, start, end) !== receiverContainerKey)
2209
+ continue;
2210
+ const nameNode = targetContext.tree.rootNode.descendantForIndex(start, end);
2211
+ const interfaceDeclaration = nameNode.parent;
2212
+ if (interfaceDeclaration?.type !== "interface_declaration")
2213
+ continue;
2214
+ appendMembers(interfaceDeclaration);
2215
+ }
2216
+ return matches;
2217
+ }
2218
+ /** Same-name namespace reopenings, excluding members of a decoy namespace or nested owner. */
2219
+ export function findTypeScriptNamespaceMemberCandidates(locals, member, receiverDef, context) {
2220
+ if (!isJsTsLanguage(context.sup.id))
2221
+ return [];
2222
+ const containers = typescriptMergedNamespaceContainers(context.tree, locals, receiverDef);
2223
+ const matches = [];
2224
+ for (const container of containers) {
2225
+ for (const candidate of findDirectLocalsWithinNode(locals, member, container, context, context.sup.normalizeIdentifier)) {
2226
+ if (!matches.includes(candidate))
2227
+ matches.push(candidate);
2228
+ }
2229
+ }
2230
+ return matches;
278
2231
  }
279
- function findReceiverMemberDefinition(locals, member, receiverDef, container, targetContext, normalizeIdentifier, memberScope = "any") {
2232
+ async function findReceiverMemberDefinition(index, locals, member, receiverDef, container, targetContext, normalizeIdentifier, memberScope = "any", knownArgumentCount) {
280
2233
  const memberPredicate = memberScope === "any"
281
2234
  ? undefined
282
2235
  : (local) => matchesReceiverMemberScope(local, memberScope, targetContext, container);
283
- const containerHit = memberScope === "any"
284
- ? findLocalWithinNode(locals, member, container, normalizeIdentifier)
285
- : findDirectLocalWithinNode(locals, member, container, targetContext, normalizeIdentifier, memberPredicate);
286
- if (containerHit)
287
- return containerHit;
2236
+ if ((targetContext.sup.id === "ts" || targetContext.sup.id === "tsx") &&
2237
+ (container.type === "internal_module" || container.type === "module")) {
2238
+ const candidates = findTypeScriptNamespaceMemberCandidates(locals, member, receiverDef, targetContext);
2239
+ const selected = selectMember([receiverDef], indexedMemberModel(index, candidates, targetContext.sup.id), {
2240
+ name: member,
2241
+ argumentCount: knownArgumentCount ?? null,
2242
+ scope: "any",
2243
+ useFile: receiverDef.file,
2244
+ keepUniqueArityMismatch: true,
2245
+ });
2246
+ return selected.status === "unique" ? selected.member : undefined;
2247
+ }
2248
+ const allReceiverMatches = typescriptMergedInterfaceMemberCandidates(locals, member, receiverDef, container, targetContext, normalizeIdentifier, memberPredicate);
2249
+ if (targetContext.sup.id === "csharp" || targetContext.sup.id === "swift") {
2250
+ const shared = await findSharedOwnerMemberDefinitions({
2251
+ index,
2252
+ ownerFile: receiverDef.file,
2253
+ ownerContainer: container,
2254
+ ownerSource: targetContext.source,
2255
+ languageId: targetContext.sup.id,
2256
+ member,
2257
+ memberScope,
2258
+ });
2259
+ for (const hit of shared) {
2260
+ if (!allReceiverMatches.includes(hit))
2261
+ allReceiverMatches.push(hit);
2262
+ }
2263
+ }
2264
+ if (allReceiverMatches.length) {
2265
+ const selected = selectMember([receiverDef], indexedMemberModel(index, allReceiverMatches, targetContext.sup.id), {
2266
+ name: member,
2267
+ argumentCount: knownArgumentCount ?? null,
2268
+ scope: "any",
2269
+ useFile: receiverDef.file,
2270
+ phpCaseInsensitive: targetContext.sup.id === "php",
2271
+ keepUniqueArityMismatch: true,
2272
+ });
2273
+ return selected.status === "unique" ? selected.member : undefined;
2274
+ }
288
2275
  if (targetContext.sup.id === "rust") {
289
- const implNode = findRustImplForType(targetContext.tree.rootNode, receiverDef.localName, targetContext.source);
290
- return implNode ? findLocalWithinNode(locals, member, implNode, normalizeIdentifier) : undefined;
2276
+ return selectRustReceiverMember(index, receiverDef, member, targetContext, locals, knownArgumentCount);
291
2277
  }
292
2278
  if (targetContext.sup.id === "go") {
293
- return findGoReceiverMember(locals, member, receiverDef.localName, targetContext, normalizeIdentifier);
2279
+ return selectGoReceiverMember(index, receiverDef, member, targetContext.sup.normalizeIdentifier, knownArgumentCount);
2280
+ }
2281
+ if (targetContext.sup.id === "kotlin") {
2282
+ const extensionMatches = kotlinExtensionFunctionsNamedOnType(locals, member, receiverDef.localName, targetContext, normalizeIdentifier);
2283
+ if (extensionMatches.length) {
2284
+ const selected = selectMember([receiverDef], indexedMemberModel(index, extensionMatches, targetContext.sup.id), {
2285
+ name: member,
2286
+ argumentCount: knownArgumentCount ?? null,
2287
+ scope: "any",
2288
+ useFile: receiverDef.file,
2289
+ keepUniqueArityMismatch: true,
2290
+ });
2291
+ return selected.status === "unique" ? selected.member : undefined;
2292
+ }
294
2293
  }
295
2294
  return undefined;
296
2295
  }
297
- function findLocalWithinNode(locals, member, node, normalizeIdentifier = (name) => name, predicate) {
2296
+ function findLocalsWithinNode(locals, member, node, normalizeIdentifier = (name) => name, predicate) {
298
2297
  const containerStart = node.startIndex;
299
2298
  const containerEnd = node.endIndex;
300
2299
  const normalizedMember = normalizeIdentifier(member);
301
- return locals.find((local) => {
2300
+ return locals.filter((local) => {
302
2301
  const startIndex = local.range.start.index;
303
2302
  const endIndex = local.range.end.index;
304
2303
  return (normalizeIdentifier(local.localName) === normalizedMember &&
@@ -314,22 +2313,50 @@ function matchesReceiverMemberScope(local, memberScope, targetContext, container
314
2313
  return true;
315
2314
  return hasStaticModifier(local, targetContext, container) === (memberScope === "static");
316
2315
  }
317
- function nodeDeclaresStatic(node, source) {
318
- if (node.type === "static" || node.type === "static_modifier")
2316
+ /**
2317
+ * Whether a member found for a receiverless call can accept that call's argument count. Unknown
2318
+ * counts and unknown arities accept.
2319
+ */
2320
+ export function memberAcceptsCallAt(index, member, callee, source, languageId) {
2321
+ const argumentCount = getCallArgumentCount({ languageId, source, call: callee.parent ?? callee });
2322
+ if (argumentCount === null)
319
2323
  return true;
320
- if (node.type === "storage_class_specifier" || node.type === "modifier" || node.type === "property_modifier") {
321
- return sliceText(node, source).trim() === "static";
322
- }
323
- if (node.type === "modifiers") {
324
- for (let childIndex = 0;; childIndex += 1) {
325
- const child = node.child(childIndex);
326
- if (!child)
327
- break;
328
- if (nodeDeclaresStatic(child, source))
329
- return true;
330
- }
331
- }
332
- return false;
2324
+ return receiverMemberAcceptsArgumentCount(index, member, argumentCount) !== false;
2325
+ }
2326
+ function receiverMemberAcceptsArgumentCount(index, def, argumentCount) {
2327
+ const languageId = supportForFileWithoutHeaderSample(def.file, index.languageExtensions)?.id;
2328
+ if (!languageId)
2329
+ return undefined;
2330
+ const callable = def.callable ??
2331
+ index.byFile
2332
+ .get(fileIdentityKey(def.file))
2333
+ ?.locals.find((local) => local.range.start.index === def.range.start.index && local.localName === def.localName)
2334
+ ?.callable;
2335
+ const range = memberLookupBinding(languageId) === "unbound" ? (callable?.unboundArity ?? callable?.arity) : callable?.arity;
2336
+ if (!range)
2337
+ return undefined;
2338
+ return argumentCount >= range.minArgs && (range.maxArgs === null || argumentCount <= range.maxArgs);
2339
+ }
2340
+ /** Indexed owner membership and callable facts for direct and merged-owner lookup. */
2341
+ function indexedMemberModel(index, members, languageId) {
2342
+ return {
2343
+ ownerKey: keywordClassKey,
2344
+ members: () => members,
2345
+ supertypes: () => [],
2346
+ name: (def) => def.localName,
2347
+ key: (def) => def.callable?.key ?? keywordClassKey(def),
2348
+ callable: (def) => {
2349
+ const facts = def.callable ??
2350
+ index.byFile
2351
+ .get(fileIdentityKey(def.file))
2352
+ ?.locals.find((local) => local.range.start.index === def.range.start.index && local.localName === def.localName)?.callable;
2353
+ if (!facts || memberLookupBinding(languageId) !== "unbound" || !facts.unboundArity)
2354
+ return facts;
2355
+ return { ...facts, arity: facts.unboundArity };
2356
+ },
2357
+ scope: () => "any",
2358
+ visible: () => true,
2359
+ };
333
2360
  }
334
2361
  function hasStaticModifier(local, targetContext, container) {
335
2362
  const position = {
@@ -337,19 +2364,21 @@ function hasStaticModifier(local, targetContext, container) {
337
2364
  column: local.range.start.column - 1,
338
2365
  };
339
2366
  let current = targetContext.tree.rootNode.descendantForPosition(position, position);
2367
+ if (declarationIsStaticEquivalent(targetContext.sup.id, current))
2368
+ return true;
340
2369
  while (current && current !== container) {
341
- for (let childIndex = 0;; childIndex += 1) {
342
- const child = current.child(childIndex);
343
- if (!child)
344
- break;
345
- if (nodeDeclaresStatic(child, targetContext.source))
346
- return true;
347
- }
2370
+ if (targetContext.sup.id === "php" && (current.type === "const_declaration" || current.type === "enum_case"))
2371
+ return true;
2372
+ if (declarationNodeIsStatic(current, targetContext.source))
2373
+ return true;
348
2374
  current = current.parent;
349
2375
  }
350
2376
  return false;
351
2377
  }
352
2378
  const NESTED_MEMBER_LOCAL_CONTAINERS = new Set([
2379
+ "formal_parameters",
2380
+ "parameter_list",
2381
+ "parameters",
353
2382
  "block",
354
2383
  "class",
355
2384
  "class_declaration",
@@ -368,14 +2397,22 @@ const NESTED_MEMBER_LOCAL_CONTAINERS = new Set([
368
2397
  "module",
369
2398
  "statement_block",
370
2399
  ]);
371
- function findDirectLocalWithinNode(locals, member, container, targetContext, normalizeIdentifier, predicate) {
2400
+ function matchesReceiverMemberName(local, normalizedMember, targetContext, normalizeIdentifier) {
2401
+ const localName = normalizeIdentifier(local.localName);
2402
+ if (targetContext.sup.id === "php") {
2403
+ return comparePhpReferenceNames(normalizedMember, localName, { symbolKind: local.kind }) === "equivalent";
2404
+ }
2405
+ return localName === normalizedMember;
2406
+ }
2407
+ function findDirectLocalsWithinNode(locals, member, container, targetContext, normalizeIdentifier, predicate) {
2408
+ const matches = [];
372
2409
  const containerStart = container.startIndex;
373
2410
  const containerEnd = container.endIndex;
374
2411
  const normalizedMember = normalizeIdentifier(member);
375
2412
  for (const local of locals) {
376
2413
  const startIndex = local.range.start.index;
377
2414
  const endIndex = local.range.end.index;
378
- if (normalizeIdentifier(local.localName) !== normalizedMember ||
2415
+ if (!matchesReceiverMemberName(local, normalizedMember, targetContext, normalizeIdentifier) ||
379
2416
  startIndex === undefined ||
380
2417
  endIndex === undefined ||
381
2418
  startIndex < containerStart ||
@@ -391,8 +2428,18 @@ function findDirectLocalWithinNode(locals, member, container, targetContext, nor
391
2428
  let isDeclarationParent = true;
392
2429
  while (current && current !== container) {
393
2430
  const isDirectBody = (current.type === "statement_block" || current.type === "block") && current.parent === container;
2431
+ // A transparent container (Kotlin's `companion object`) donates its body's members to its
2432
+ // own enclosing class; the grammar never lets one nest under any other declaration, so its
2433
+ // body never counts as evidence of a foreign nested class here.
2434
+ const isTransparentBody = current.type === "class_body" &&
2435
+ !!current.parent &&
2436
+ TRANSPARENT_MEMBER_CONTAINER_TYPES[current.parent.type] === true;
2437
+ const definingDeclarator = current.type === "function_definition" ? current.childForFieldName("declarator") : null;
2438
+ const isOwnFunctionDeclaration = !!definingDeclarator && definingDeclarator.startIndex <= startIndex && definingDeclarator.endIndex >= endIndex;
394
2439
  if (!isDeclarationParent &&
395
2440
  !isDirectBody &&
2441
+ !isOwnFunctionDeclaration &&
2442
+ !isTransparentBody &&
396
2443
  ((current.type === "class_body" && current.parent !== container) ||
397
2444
  NESTED_MEMBER_LOCAL_CONTAINERS.has(current.type))) {
398
2445
  current = null;
@@ -402,30 +2449,196 @@ function findDirectLocalWithinNode(locals, member, container, targetContext, nor
402
2449
  current = current.parent;
403
2450
  }
404
2451
  if (current && (!predicate || predicate(local)))
405
- return local;
2452
+ matches.push(local);
406
2453
  }
407
- return undefined;
2454
+ return matches;
408
2455
  }
409
- function findRustImplForType(root, typeName, source) {
410
- let found = null;
411
- const visit = (node) => {
412
- if (node.type === "impl_item") {
413
- const text = sliceText(node, source);
414
- if (new RegExp(`^\\s*impl\\s+${escapeRegExp(typeName)}\\b`).test(text)) {
415
- found = node;
416
- return false;
417
- }
2456
+ function appendDirectKeywordMembers(locals, member, container, targetContext, normalizeIdentifier, predicate, matches) {
2457
+ const containerStart = container.startIndex;
2458
+ const containerEnd = container.endIndex;
2459
+ const normalizedMember = normalizeIdentifier(member);
2460
+ for (const local of locals) {
2461
+ const startIndex = local.range.start.index;
2462
+ const endIndex = local.range.end.index;
2463
+ if (!matchesReceiverMemberName(local, normalizedMember, targetContext, normalizeIdentifier) ||
2464
+ startIndex === undefined ||
2465
+ endIndex === undefined ||
2466
+ startIndex < containerStart ||
2467
+ endIndex > containerEnd) {
2468
+ continue;
418
2469
  }
419
- for (const child of node.namedChildren) {
420
- if (!visit(child))
421
- return false;
2470
+ const start = local.range.start;
2471
+ const position = {
2472
+ row: start.line - 1,
2473
+ column: start.column - 1,
2474
+ };
2475
+ const declarationNode = targetContext.tree.rootNode.descendantForPosition(position, position);
2476
+ if (!isDirectKeywordMemberDeclaration(declarationNode, container) || (predicate && !predicate(local))) {
2477
+ continue;
422
2478
  }
2479
+ matches.push(local);
2480
+ }
2481
+ }
2482
+ const SWIFT_PARAMETER_OWNER_TYPES = {
2483
+ init_declaration: true,
2484
+ function_declaration: true,
2485
+ deinit_declaration: true,
2486
+ subscript_declaration: true,
2487
+ lambda_literal: true,
2488
+ protocol_function_declaration: true,
2489
+ };
2490
+ /**
2491
+ * Swift parameters and function-body locals share the type's byte span, but
2492
+ * `self.name` names the member. A parameter or local that shadows the bare name
2493
+ * is not a member candidate. Only `simple_identifier` names are Swift.
2494
+ */
2495
+ function isSwiftShadowingNonMember(declarationNode) {
2496
+ if (declarationNode.type !== "simple_identifier")
2497
+ return false;
2498
+ let current = declarationNode.parent;
2499
+ while (current) {
2500
+ if (current.type === "parameter" && current.parent && SWIFT_PARAMETER_OWNER_TYPES[current.parent.type]) {
2501
+ return true;
2502
+ }
2503
+ if (current.type === "function_body" ||
2504
+ current.type === "lambda_literal" ||
2505
+ current.type === "computed_property" ||
2506
+ current.type === "willset_didset_block") {
2507
+ return true;
2508
+ }
2509
+ if (current.type === "class_declaration" ||
2510
+ current.type === "protocol_declaration" ||
2511
+ current.type === "enum_class_body") {
2512
+ return false;
2513
+ }
2514
+ current = current.parent;
2515
+ }
2516
+ return false;
2517
+ }
2518
+ /** Parameter lists whose entries are locals of the function, not members of its type. */
2519
+ const PARAMETER_LIST_TYPES = new Set([
2520
+ "formal_parameters",
2521
+ "parameter_list",
2522
+ "parameters",
2523
+ "function_value_parameters",
2524
+ ]);
2525
+ /**
2526
+ * A parameter that also declares a property of the enclosing type: a TypeScript parameter
2527
+ * property (`constructor(readonly path: string)`) or a PHP promoted constructor property.
2528
+ */
2529
+ function isPropertyParameter(declarationNode, list) {
2530
+ let parameter = declarationNode;
2531
+ while (parameter && parameter.parent !== list)
2532
+ parameter = parameter.parent;
2533
+ if (!parameter)
2534
+ return false;
2535
+ if (parameter.type === "property_promotion_parameter")
423
2536
  return true;
2537
+ return parameter.namedChildren.some((child) => child.type === "accessibility_modifier" || child.type === "override_modifier" || child.text === "readonly");
2538
+ }
2539
+ export function isDirectKeywordMemberDeclaration(declarationNode, container) {
2540
+ if (isSwiftShadowingNonMember(declarationNode))
2541
+ return false;
2542
+ if (nearestMemberContainer(declarationNode) !== container)
2543
+ return false;
2544
+ let functionDepth = 0;
2545
+ let current = declarationNode;
2546
+ while (current && current !== container) {
2547
+ // Swift local functions can nest inside a member; only the outer function is a member.
2548
+ if (current.type === "function_declaration" && ++functionDepth > 1)
2549
+ return false;
2550
+ const isMethodBody = (current.type === "block" || current.type === "compound_statement" || current.type === "statement_block") &&
2551
+ current.parent !== container;
2552
+ if (isMethodBody)
2553
+ return false;
2554
+ // A method parameter is a local of that method, unless it also declares a property.
2555
+ if (PARAMETER_LIST_TYPES.has(current.type))
2556
+ return isPropertyParameter(declarationNode, current);
2557
+ current = current.parent;
2558
+ }
2559
+ return current === container;
2560
+ }
2561
+ /**
2562
+ * Every Rust `impl` block whose self type is `typeName`, across inherent (`impl Circle`),
2563
+ * trait (`impl Shape for Circle`), and generic (`impl<T> Box<T>`) forms. The shared
2564
+ * self-type extraction keeps navigation and detailed-graph member ownership in agreement.
2565
+ */
2566
+ function findRustImplsForType(root, typeName, source, sup) {
2567
+ const normalized = sup.normalizeIdentifier(typeName);
2568
+ const found = [];
2569
+ const visit = (node) => {
2570
+ if (node.type === "impl_item") {
2571
+ const selfType = rustImplSelfTypeNode(node, sup);
2572
+ if (selfType && sup.normalizeIdentifier(sliceText(selfType, source)) === normalized)
2573
+ found.push(node);
2574
+ }
2575
+ for (const child of node.namedChildren)
2576
+ visit(child);
424
2577
  };
425
2578
  visit(root);
426
2579
  return found;
427
2580
  }
428
- const GO_EMBED_DEPTH = 16;
2581
+ async function selectRustReceiverMember(index, receiverDef, member, context, locals, knownArgumentCount) {
2582
+ const inherent = [];
2583
+ const implemented = [];
2584
+ const traitMembers = new Map();
2585
+ const traitOwners = [];
2586
+ const module = index.byFile.get(fileIdentityKey(receiverDef.file));
2587
+ if (!module)
2588
+ return undefined;
2589
+ for (const impl of findRustImplsForType(context.tree.rootNode, receiverDef.localName, context.source, context.sup)) {
2590
+ const self = rustImplSelfTypeNode(impl, context.sup);
2591
+ const trait = impl.namedChildren.find((child) => child.type === "type_identifier" && child.id !== self?.id);
2592
+ const target = trait ? implemented : inherent;
2593
+ appendDirectKeywordMembers(locals, member, impl, context, context.sup.normalizeIdentifier, undefined, target);
2594
+ if (!trait)
2595
+ continue;
2596
+ const traitName = sliceText(trait, context.source);
2597
+ const traitDef = resolveNamedMemberContainer(index, module, traitName, context.sup.normalizeIdentifier);
2598
+ if (!traitDef)
2599
+ continue;
2600
+ const ref = await keywordClassRefFromDef(index, traitDef);
2601
+ if (!ref || ref.container.type !== "trait_item")
2602
+ continue;
2603
+ const key = keywordClassKey(traitDef);
2604
+ if (traitMembers.has(key))
2605
+ continue;
2606
+ const matches = [];
2607
+ appendDirectKeywordMembers(ref.module.locals, member, ref.container, ref.context, ref.context.sup.normalizeIdentifier, undefined, matches);
2608
+ traitMembers.set(key, matches);
2609
+ traitOwners.push(key);
2610
+ }
2611
+ const model = {
2612
+ ownerKey: (owner) => owner,
2613
+ members: (owner) => {
2614
+ if (owner === "inherent")
2615
+ return inherent;
2616
+ if (owner === "implemented")
2617
+ return implemented;
2618
+ return traitMembers.get(owner) ?? [];
2619
+ },
2620
+ supertypes: (owner) => {
2621
+ if (owner === "type")
2622
+ return ["inherent"];
2623
+ if (owner === "inherent")
2624
+ return ["implemented"];
2625
+ return owner === "implemented" ? traitOwners : [];
2626
+ },
2627
+ name: (def) => context.sup.normalizeIdentifier(def.localName),
2628
+ key: (def) => def.callable?.key ?? keywordClassKey(def),
2629
+ callable: (def) => def.callable,
2630
+ scope: () => "any",
2631
+ visible: () => true,
2632
+ };
2633
+ const selected = selectMember(["type"], model, {
2634
+ name: context.sup.normalizeIdentifier(member),
2635
+ argumentCount: knownArgumentCount ?? null,
2636
+ scope: "any",
2637
+ useFile: receiverDef.file,
2638
+ keepUniqueArityMismatch: true,
2639
+ });
2640
+ return selected.status === "unique" ? selected.member : undefined;
2641
+ }
429
2642
  function goMethodReceiverTypeName(methodNode, source, sup) {
430
2643
  const receiver = methodNode.childForFieldName("receiver");
431
2644
  if (!receiver)
@@ -487,9 +2700,10 @@ function goMethodsNamedOnType(locals, member, typeName, targetContext, normalize
487
2700
  if (node.type === "method_declaration") {
488
2701
  const receiverType = goMethodReceiverTypeName(node, targetContext.source, targetContext.sup);
489
2702
  if (receiverType && normalizeIdentifier(receiverType) === normalizeIdentifier(typeName)) {
490
- const local = findLocalWithinNode(locals, member, node, normalizeIdentifier);
491
- if (local && !matches.includes(local))
492
- matches.push(local);
2703
+ for (const local of findLocalsWithinNode(locals, member, node, normalizeIdentifier)) {
2704
+ if (!matches.includes(local))
2705
+ matches.push(local);
2706
+ }
493
2707
  }
494
2708
  return;
495
2709
  }
@@ -499,47 +2713,105 @@ function goMethodsNamedOnType(locals, member, typeName, targetContext, normalize
499
2713
  visit(targetContext.tree.rootNode);
500
2714
  return matches;
501
2715
  }
502
- function findGoReceiverMember(locals, member, typeName, targetContext, normalizeIdentifier) {
503
- const visited = new Set();
504
- let level = [typeName];
505
- for (let depth = 0; depth < GO_EMBED_DEPTH && level.length; depth += 1) {
506
- const matches = [];
2716
+ /**
2717
+ * Kotlin extension functions declared `fun Type.member()` for a receiver type, searched across
2718
+ * the receiver type's own declaring file the same way `goMethodsNamedOnType` searches Go's file
2719
+ * for a receiver method. An ordinary class member never carries a receiver-type prefix, so this
2720
+ * never matches a real member and cannot shadow one.
2721
+ */
2722
+ function kotlinExtensionFunctionsNamedOnType(locals, member, typeName, targetContext, normalizeIdentifier) {
2723
+ const matches = [];
2724
+ const normalizedType = normalizeIdentifier(typeName);
2725
+ const visit = (node) => {
2726
+ if (node.type === "function_declaration") {
2727
+ const receiverType = kotlinExtensionReceiverTypeNode(node, targetContext.sup);
2728
+ if (receiverType && normalizeIdentifier(sliceText(receiverType, targetContext.source)) === normalizedType) {
2729
+ for (const local of findLocalsWithinNode(locals, member, node, normalizeIdentifier)) {
2730
+ if (!matches.includes(local))
2731
+ matches.push(local);
2732
+ }
2733
+ }
2734
+ return;
2735
+ }
2736
+ for (const child of node.namedChildren)
2737
+ visit(child);
2738
+ };
2739
+ visit(targetContext.tree.rootNode);
2740
+ return matches;
2741
+ }
2742
+ async function selectGoReceiverMember(index, receiverDef, member, normalizeIdentifier, knownArgumentCount) {
2743
+ const peers = getCompilationUnitPeers(index, receiverDef.file).files;
2744
+ const files = await Promise.all([...peers].map(async (file) => {
2745
+ const module = index.byFile.get(fileIdentityKey(file));
2746
+ if (!module)
2747
+ return null;
2748
+ const context = await ensureParsedContext(file, index.parsed?.get(fileIdentityKey(file)), index.languageExtensions);
2749
+ return context.sup.id === "go" ? { module, context } : null;
2750
+ }));
2751
+ const contexts = files.filter((file) => file !== null);
2752
+ const members = new Map();
2753
+ const embedded = new Map();
2754
+ const seen = new Set();
2755
+ let level = [receiverDef.localName];
2756
+ for (let depth = 0; depth < RECEIVER_HIERARCHY_DEPTH && level.length; depth += 1) {
507
2757
  const next = [];
508
- for (const currentType of level) {
509
- if (visited.has(currentType))
2758
+ for (const typeName of level) {
2759
+ if (seen.has(typeName))
510
2760
  continue;
511
- visited.add(currentType);
512
- for (const method of goMethodsNamedOnType(locals, member, currentType, targetContext, normalizeIdentifier)) {
513
- if (!matches.includes(method))
514
- matches.push(method);
515
- }
516
- for (const embedded of goEmbeddedTypeNames(currentType, targetContext, normalizeIdentifier)) {
517
- if (!visited.has(embedded) && !next.includes(embedded))
518
- next.push(embedded);
2761
+ seen.add(typeName);
2762
+ const matches = [];
2763
+ const bases = [];
2764
+ for (const { module, context } of contexts) {
2765
+ const normalize = context.sup.normalizeIdentifier;
2766
+ matches.push(...goMethodsNamedOnType(module.locals, member, typeName, context, normalize));
2767
+ const spec = goTypeSpecNamed(context.tree.rootNode, typeName, context.source, normalize);
2768
+ if (!spec)
2769
+ continue;
2770
+ matches.push(...findDirectLocalsWithinNode(module.locals, member, spec, context, normalize).filter((def) => def.isMember));
2771
+ for (const base of goEmbeddedTypeNames(typeName, context, normalize)) {
2772
+ if (!bases.includes(base))
2773
+ bases.push(base);
2774
+ if (!seen.has(base) && !next.includes(base))
2775
+ next.push(base);
2776
+ }
519
2777
  }
2778
+ members.set(typeName, matches);
2779
+ embedded.set(typeName, bases);
520
2780
  }
521
- if (matches.length === 1)
522
- return matches[0];
523
- if (matches.length > 1)
524
- return undefined;
525
2781
  level = next;
526
2782
  }
527
- return undefined;
2783
+ const model = {
2784
+ ownerKey: (owner) => owner,
2785
+ members: (owner) => members.get(owner) ?? [],
2786
+ supertypes: (owner) => embedded.get(owner) ?? [],
2787
+ name: (def) => normalizeIdentifier(def.localName),
2788
+ key: (def) => def.callable?.key ?? keywordClassKey(def),
2789
+ callable: (def) => def.callable,
2790
+ scope: () => "any",
2791
+ visible: () => true,
2792
+ };
2793
+ const selected = selectMember([receiverDef.localName], model, {
2794
+ name: normalizeIdentifier(member),
2795
+ argumentCount: knownArgumentCount ?? null,
2796
+ scope: "any",
2797
+ useFile: receiverDef.file,
2798
+ keepUniqueArityMismatch: true,
2799
+ });
2800
+ return selected.status === "unique" ? selected.member : undefined;
528
2801
  }
529
- const PYTHON_SUPERTYPE_DEPTH = 16;
530
2802
  function pythonClassKey(def) {
531
2803
  const start = def.range.start;
532
2804
  return `${fileIdentityKey(def.file)}:${start.index ?? `${start.line}:${start.column}`}`;
533
2805
  }
534
- async function resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression) {
535
- const classRef = await pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression);
2806
+ async function resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression, proof) {
2807
+ const classRef = await pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression, proof);
536
2808
  if (!classRef)
537
2809
  return undefined;
538
- return lookupPythonClassMember(index, classRef, member);
2810
+ return lookupPythonClassMember(index, classRef.ref, member, classRef.startAtSupertype);
539
2811
  }
540
- async function pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression) {
541
- const receiverName = sliceText(obj, source);
542
- if (receiverName === "self" || receiverName === "cls") {
2812
+ async function pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression, proof) {
2813
+ const receiver = proof ?? classifyReceiver(sup, obj, source, null, 0, obj.parent ?? obj, noLexicalBinding);
2814
+ if (receiver.kind === "own-type" || receiver.kind === "supertype") {
543
2815
  const container = findEnclosingClassContainer(node);
544
2816
  if (!container)
545
2817
  return null;
@@ -559,10 +2831,11 @@ async function pythonReceiverClassRef(index, mod, node, obj, source, sup, resolv
559
2831
  });
560
2832
  if (!def)
561
2833
  return null;
562
- return pythonClassRefFromDef(index, def);
2834
+ const ref = await pythonClassRefFromDef(index, def);
2835
+ return ref ? { ref, startAtSupertype: receiver.kind === "supertype" } : null;
563
2836
  }
564
2837
  let classDef;
565
- const constructor = receiverConstructorExpression(obj, source, sup);
2838
+ const constructor = receiver.kind === "named-type" && receiver.proof !== "static-type" ? receiver.typeNode : null;
566
2839
  if (constructor) {
567
2840
  const result = await resolveExpression(constructor);
568
2841
  if (result?.kind === "resolved" && result.def.kind === SymbolKind.Class) {
@@ -577,7 +2850,8 @@ async function pythonReceiverClassRef(index, mod, node, obj, source, sup, resolv
577
2850
  }
578
2851
  if (!classDef)
579
2852
  return null;
580
- return pythonClassRefFromDef(index, classDef);
2853
+ const ref = await pythonClassRefFromDef(index, classDef);
2854
+ return ref ? { ref, startAtSupertype: false } : null;
581
2855
  }
582
2856
  async function pythonClassRefFromDef(index, def) {
583
2857
  const module = index.byFile.get(fileIdentityKey(def.file));
@@ -599,13 +2873,13 @@ async function pythonClassRefFromDef(index, def) {
599
2873
  }
600
2874
  function pythonMembersOnClass(classRef, member) {
601
2875
  const normalizeIdentifier = classRef.context.sup.normalizeIdentifier;
602
- const direct = findDirectLocalWithinNode(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
603
- if (direct)
604
- return [direct];
605
- const attribute = findPythonInstanceAttributeWithinClass(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
606
- return attribute ? [attribute] : [];
2876
+ const direct = findDirectLocalsWithinNode(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
2877
+ if (direct.length)
2878
+ return direct;
2879
+ return findPythonInstanceAttributesWithinClass(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
607
2880
  }
608
- function findPythonInstanceAttributeWithinClass(locals, member, container, targetContext, normalizeIdentifier) {
2881
+ function findPythonInstanceAttributesWithinClass(locals, member, container, targetContext, normalizeIdentifier) {
2882
+ const matches = [];
609
2883
  const containerStart = container.startIndex;
610
2884
  const containerEnd = container.endIndex;
611
2885
  const normalizedMember = normalizeIdentifier(member);
@@ -626,9 +2900,9 @@ function findPythonInstanceAttributeWithinClass(locals, member, container, targe
626
2900
  };
627
2901
  const nameNode = targetContext.tree.rootNode.descendantForPosition(position, position);
628
2902
  if (isPythonReceiverAttributeAssignmentName(nameNode))
629
- return local;
2903
+ matches.push(local);
630
2904
  }
631
- return undefined;
2905
+ return matches;
632
2906
  }
633
2907
  function pythonBaseIdentifierNodes(classNode) {
634
2908
  const bases = classNode.childForFieldName("superclasses") ??
@@ -664,17 +2938,15 @@ function resolvePythonNamedClass(index, mod, name) {
664
2938
  return candidates[0];
665
2939
  if (candidates.length > 1)
666
2940
  return undefined;
667
- for (const imp of mod.imports) {
668
- if (imp.kind === "named" && imp.local === name) {
669
- const result = resolveImported(index, imp, imp.imported);
670
- if (result && !("namespace" in result) && result.kind === SymbolKind.Class)
671
- return result;
672
- }
673
- if (imp.kind === "star") {
674
- const result = resolveImported(index, imp, name);
675
- if (result && !("namespace" in result) && result.kind === SymbolKind.Class)
676
- return result;
677
- }
2941
+ const explicitBinding = effectiveExplicitBinding(mod.imports, "python", (binding) => binding.kind === "named" && binding.local === name);
2942
+ if (explicitBinding?.kind === "named") {
2943
+ const result = resolveImported(index, explicitBinding, explicitBinding.imported);
2944
+ if (result && !("namespace" in result) && result.kind === SymbolKind.Class)
2945
+ return result;
2946
+ }
2947
+ const starDecision = resolveStarImportedName(index, mod, "python", name);
2948
+ if (starDecision.status === "resolved") {
2949
+ return starDecision.definition.kind === SymbolKind.Class ? starDecision.definition : undefined;
678
2950
  }
679
2951
  const exported = resolveExport(index, mod.file, name, { preferredKind: SymbolKind.Class, allowLocalFallback: false });
680
2952
  if (exported?.kind === "resolved" && exported.def.kind === SymbolKind.Class)
@@ -699,33 +2971,26 @@ async function pythonBaseClassRefs(index, classRef) {
699
2971
  }
700
2972
  return refs;
701
2973
  }
702
- async function lookupPythonClassMember(index, start, member) {
703
- const own = pythonMembersOnClass(start, member);
704
- if (own.length === 1)
705
- return own[0];
706
- if (own.length > 1)
707
- return undefined;
708
- let level = await pythonBaseClassRefs(index, start);
709
- const visited = new Set([pythonClassKey(start.def), ...level.map((base) => pythonClassKey(base.def))]);
710
- for (let depth = 0; depth < PYTHON_SUPERTYPE_DEPTH && level.length; depth += 1) {
711
- const matches = [];
712
- const seenMatch = new Set();
713
- for (const base of level) {
714
- for (const hit of pythonMembersOnClass(base, member)) {
715
- const key = pythonClassKey(hit);
716
- if (seenMatch.has(key))
717
- continue;
718
- seenMatch.add(key);
719
- matches.push(hit);
720
- }
2974
+ async function lookupPythonClassMember(index, start, member, startAtSupertype = false) {
2975
+ const membersByOwner = new Map();
2976
+ const parentsByOwner = new Map();
2977
+ const visited = new Set([pythonClassKey(start.def)]);
2978
+ let level = [start];
2979
+ for (let depth = 0; depth < RECEIVER_HIERARCHY_DEPTH && level.length; depth += 1) {
2980
+ let named = false;
2981
+ for (const ref of level) {
2982
+ const members = startAtSupertype && !depth ? [] : pythonMembersOnClass(ref, member);
2983
+ membersByOwner.set(pythonClassKey(ref.def), members);
2984
+ if (members.length)
2985
+ named = true;
721
2986
  }
722
- if (matches.length === 1)
723
- return matches[0];
724
- if (matches.length > 1)
725
- return undefined;
2987
+ if (named)
2988
+ break;
726
2989
  const next = [];
727
- for (const base of level) {
728
- for (const parent of await pythonBaseClassRefs(index, base)) {
2990
+ for (const ref of level) {
2991
+ const parents = await pythonBaseClassRefs(index, ref);
2992
+ parentsByOwner.set(pythonClassKey(ref.def), parents);
2993
+ for (const parent of parents) {
729
2994
  const key = pythonClassKey(parent.def);
730
2995
  if (visited.has(key))
731
2996
  continue;
@@ -735,9 +3000,23 @@ async function lookupPythonClassMember(index, start, member) {
735
3000
  }
736
3001
  level = next;
737
3002
  }
738
- return undefined;
739
- }
740
- function escapeRegExp(value) {
741
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3003
+ const model = {
3004
+ ownerKey: (ref) => pythonClassKey(ref.def),
3005
+ members: (ref) => membersByOwner.get(pythonClassKey(ref.def)) ?? [],
3006
+ supertypes: (ref) => parentsByOwner.get(pythonClassKey(ref.def)) ?? [],
3007
+ name: (def) => def.localName,
3008
+ key: (def) => def.callable?.key ?? pythonClassKey(def),
3009
+ callable: (def) => def.callable,
3010
+ scope: () => "any",
3011
+ visible: () => true,
3012
+ };
3013
+ const selected = selectMember([start], model, {
3014
+ name: member,
3015
+ argumentCount: null,
3016
+ scope: "any",
3017
+ useFile: start.def.file,
3018
+ startAtAncestor: startAtSupertype,
3019
+ });
3020
+ return selected.status === "unique" ? selected.member : undefined;
742
3021
  }
743
3022
  //# sourceMappingURL=navigation-goto.js.map