cgraphx 2.0.1 → 2.0.3

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 (701) hide show
  1. package/dist/.claude-template/FLOW-MAP.md +7 -5
  2. package/dist/.claude-template/commands/end.md +1 -1
  3. package/dist/.claude-template/skills/cgraphx-guide/SKILL.md +2 -1
  4. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +4 -2
  5. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.md +5 -2
  6. package/dist/.claude-template/skills/iboc-check/SKILL.md +116 -0
  7. package/dist/.claude-template/skills/iboc-check/filler-prompt.md +75 -0
  8. package/dist/.claude-template/skills/implementation/SKILL.md +7 -0
  9. package/dist/.claude-template/skills/init-project-guides/SKILL.md +1 -1
  10. package/dist/.claude-template/skills/run-api-test/references/db-verification.md +2 -2
  11. package/dist/.claude-template/skills/subagent-implement/SKILL.md +3 -2
  12. package/dist/.claude-template/skills/write-api/assets/template-request.bru +3 -3
  13. package/dist/.claude-template/skills/write-api/references/bru-format.md +6 -6
  14. package/dist/.claude-template/skills/write-delivery-guide/SKILL.md +97 -0
  15. package/dist/.claude-template/skills/write-delivery-guide/template-change-type.md +120 -0
  16. package/dist/.claude-template/skills/write-delivery-guide/template-multi-role-flow.md +148 -0
  17. package/dist/.claude-template/skills/write-unit-test-code/SKILL.md +23 -6
  18. package/dist/core/code/engine/cli/analyze-config.js +320 -0
  19. package/dist/core/code/engine/cli/analyze.js +1086 -0
  20. package/dist/core/code/engine/cli/cli-message.js +83 -0
  21. package/dist/core/code/engine/cli/detect-changes-format.js +58 -0
  22. package/dist/core/code/engine/cli/embedding-dims.js +43 -0
  23. package/dist/core/code/engine/cli/format-elapsed.js +12 -0
  24. package/dist/core/code/engine/cli/help-i18n.js +144 -0
  25. package/dist/core/code/engine/cli/i18n/en.js +110 -0
  26. package/dist/core/code/engine/cli/i18n/index.js +47 -0
  27. package/dist/core/code/engine/cli/i18n/resources.js +9 -0
  28. package/dist/core/code/engine/cli/i18n/zh-CN.js +110 -0
  29. package/dist/core/code/engine/cli/lazy-action.js +67 -0
  30. package/dist/core/code/engine/cli/optional-grammars.js +136 -0
  31. package/dist/core/code/engine/cli/resolve-invocation.js +76 -0
  32. package/dist/core/code/engine/cli/status.js +156 -0
  33. package/dist/core/code/engine/cli/tool.js +384 -0
  34. package/dist/core/code/engine/config/ignore-service.js +511 -0
  35. package/dist/core/code/engine/config/supported-languages.js +17 -0
  36. package/dist/core/code/engine/core/analysis-features.js +64 -0
  37. package/dist/core/code/engine/core/analyzer-identity.js +2171 -0
  38. package/dist/core/code/engine/core/git-staleness.js +180 -0
  39. package/dist/core/code/engine/core/graph/graph.js +180 -0
  40. package/dist/core/code/engine/core/graph/import-cycles.js +106 -0
  41. package/dist/core/code/engine/core/graph/types.js +2 -0
  42. package/dist/core/code/engine/core/index-freshness.js +12 -0
  43. package/dist/core/code/engine/core/ingestion/binding-accumulator.js +341 -0
  44. package/dist/core/code/engine/core/ingestion/call-extractors/configs/c-cpp.js +168 -0
  45. package/dist/core/code/engine/core/ingestion/call-extractors/configs/csharp.js +9 -0
  46. package/dist/core/code/engine/core/ingestion/call-extractors/configs/dart.js +8 -0
  47. package/dist/core/code/engine/core/ingestion/call-extractors/configs/go.js +8 -0
  48. package/dist/core/code/engine/core/ingestion/call-extractors/configs/jvm.js +54 -0
  49. package/dist/core/code/engine/core/ingestion/call-extractors/configs/php.js +8 -0
  50. package/dist/core/code/engine/core/ingestion/call-extractors/configs/python.js +8 -0
  51. package/dist/core/code/engine/core/ingestion/call-extractors/configs/ruby.js +8 -0
  52. package/dist/core/code/engine/core/ingestion/call-extractors/configs/rust.js +8 -0
  53. package/dist/core/code/engine/core/ingestion/call-extractors/configs/swift.js +8 -0
  54. package/dist/core/code/engine/core/ingestion/call-extractors/configs/typescript-javascript.js +11 -0
  55. package/dist/core/code/engine/core/ingestion/call-extractors/generic.js +62 -0
  56. package/dist/core/code/engine/core/ingestion/call-processor.js +503 -0
  57. package/dist/core/code/engine/core/ingestion/call-routing.js +98 -0
  58. package/dist/core/code/engine/core/ingestion/call-types.js +3 -0
  59. package/dist/core/code/engine/core/ingestion/cfg/callee-cell-format.js +45 -0
  60. package/dist/core/code/engine/core/ingestion/cfg/cfg-builder.js +202 -0
  61. package/dist/core/code/engine/core/ingestion/cfg/collect.js +81 -0
  62. package/dist/core/code/engine/core/ingestion/cfg/control-dependence.js +185 -0
  63. package/dist/core/code/engine/core/ingestion/cfg/control-flow-context.js +130 -0
  64. package/dist/core/code/engine/core/ingestion/cfg/emit.js +646 -0
  65. package/dist/core/code/engine/core/ingestion/cfg/post-dominators.js +182 -0
  66. package/dist/core/code/engine/core/ingestion/cfg/reaching-def-reason-codec.js +139 -0
  67. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs-graph.js +322 -0
  68. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs.js +792 -0
  69. package/dist/core/code/engine/core/ingestion/cfg/synthetic-escape.js +305 -0
  70. package/dist/core/code/engine/core/ingestion/cfg/traversal-result.js +6 -0
  71. package/dist/core/code/engine/core/ingestion/cfg/types.js +14 -0
  72. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp-harvest.js +545 -0
  73. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp.js +590 -0
  74. package/dist/core/code/engine/core/ingestion/cfg/visitors/call-site-harvest.js +356 -0
  75. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp-harvest.js +593 -0
  76. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp.js +871 -0
  77. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart-harvest.js +874 -0
  78. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart.js +840 -0
  79. package/dist/core/code/engine/core/ingestion/cfg/visitors/go-harvest.js +625 -0
  80. package/dist/core/code/engine/core/ingestion/cfg/visitors/go.js +642 -0
  81. package/dist/core/code/engine/core/ingestion/cfg/visitors/java-harvest.js +517 -0
  82. package/dist/core/code/engine/core/ingestion/cfg/visitors/java.js +816 -0
  83. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin-harvest.js +723 -0
  84. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin.js +813 -0
  85. package/dist/core/code/engine/core/ingestion/cfg/visitors/php-harvest.js +630 -0
  86. package/dist/core/code/engine/core/ingestion/cfg/visitors/php.js +725 -0
  87. package/dist/core/code/engine/core/ingestion/cfg/visitors/python-harvest.js +776 -0
  88. package/dist/core/code/engine/core/ingestion/cfg/visitors/python.js +562 -0
  89. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby-harvest.js +591 -0
  90. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby.js +760 -0
  91. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust-harvest.js +877 -0
  92. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust.js +562 -0
  93. package/dist/core/code/engine/core/ingestion/cfg/visitors/scope-tree-harvest.js +120 -0
  94. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift-harvest.js +683 -0
  95. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift.js +791 -0
  96. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript-harvest.js +1060 -0
  97. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript.js +587 -0
  98. package/dist/core/code/engine/core/ingestion/class-extractors/configs/c-cpp.js +77 -0
  99. package/dist/core/code/engine/core/ingestion/class-extractors/configs/csharp.js +24 -0
  100. package/dist/core/code/engine/core/ingestion/class-extractors/configs/dart.js +10 -0
  101. package/dist/core/code/engine/core/ingestion/class-extractors/configs/go.js +28 -0
  102. package/dist/core/code/engine/core/ingestion/class-extractors/configs/jvm.js +67 -0
  103. package/dist/core/code/engine/core/ingestion/class-extractors/configs/php.js +10 -0
  104. package/dist/core/code/engine/core/ingestion/class-extractors/configs/python.js +10 -0
  105. package/dist/core/code/engine/core/ingestion/class-extractors/configs/ruby.js +13 -0
  106. package/dist/core/code/engine/core/ingestion/class-extractors/configs/rust.js +10 -0
  107. package/dist/core/code/engine/core/ingestion/class-extractors/configs/swift.js +21 -0
  108. package/dist/core/code/engine/core/ingestion/class-extractors/configs/typescript-javascript.js +31 -0
  109. package/dist/core/code/engine/core/ingestion/class-extractors/generic.js +144 -0
  110. package/dist/core/code/engine/core/ingestion/class-types.js +2 -0
  111. package/dist/core/code/engine/core/ingestion/cluster-enricher.js +174 -0
  112. package/dist/core/code/engine/core/ingestion/community-processor.js +604 -0
  113. package/dist/core/code/engine/core/ingestion/constants.js +26 -0
  114. package/dist/core/code/engine/core/ingestion/cpp-ue-preprocessor.js +263 -0
  115. package/dist/core/code/engine/core/ingestion/csharp-namespace-gate.js +133 -0
  116. package/dist/core/code/engine/core/ingestion/di-extractors/index.js +38 -0
  117. package/dist/core/code/engine/core/ingestion/di-extractors/spring.js +310 -0
  118. package/dist/core/code/engine/core/ingestion/emit-references.js +244 -0
  119. package/dist/core/code/engine/core/ingestion/entry-point-scoring.js +201 -0
  120. package/dist/core/code/engine/core/ingestion/export-detection.js +244 -0
  121. package/dist/core/code/engine/core/ingestion/field-extractor.js +29 -0
  122. package/dist/core/code/engine/core/ingestion/field-extractors/configs/c-cpp.js +107 -0
  123. package/dist/core/code/engine/core/ingestion/field-extractors/configs/csharp.js +124 -0
  124. package/dist/core/code/engine/core/ingestion/field-extractors/configs/dart.js +99 -0
  125. package/dist/core/code/engine/core/ingestion/field-extractors/configs/go.js +102 -0
  126. package/dist/core/code/engine/core/ingestion/field-extractors/configs/helpers.js +198 -0
  127. package/dist/core/code/engine/core/ingestion/field-extractors/configs/jvm.js +172 -0
  128. package/dist/core/code/engine/core/ingestion/field-extractors/configs/php.js +67 -0
  129. package/dist/core/code/engine/core/ingestion/field-extractors/configs/python.js +94 -0
  130. package/dist/core/code/engine/core/ingestion/field-extractors/configs/ruby.js +79 -0
  131. package/dist/core/code/engine/core/ingestion/field-extractors/configs/rust.js +55 -0
  132. package/dist/core/code/engine/core/ingestion/field-extractors/configs/swift.js +93 -0
  133. package/dist/core/code/engine/core/ingestion/field-extractors/configs/typescript-javascript.js +59 -0
  134. package/dist/core/code/engine/core/ingestion/field-extractors/generic.js +147 -0
  135. package/dist/core/code/engine/core/ingestion/field-extractors/typescript.js +266 -0
  136. package/dist/core/code/engine/core/ingestion/field-types.js +3 -0
  137. package/dist/core/code/engine/core/ingestion/filesystem-walker.js +136 -0
  138. package/dist/core/code/engine/core/ingestion/finalize-orchestrator.js +159 -0
  139. package/dist/core/code/engine/core/ingestion/framework-detection.js +432 -0
  140. package/dist/core/code/engine/core/ingestion/frameworks/spring/analysis-features.js +38 -0
  141. package/dist/core/code/engine/core/ingestion/frameworks/spring/annotation-arguments.js +234 -0
  142. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop-candidates.js +88 -0
  143. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop.js +487 -0
  144. package/dist/core/code/engine/core/ingestion/frameworks/spring/auto-configuration.js +21 -0
  145. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-candidates.js +189 -0
  146. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-catalog.js +32 -0
  147. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-factories.js +73 -0
  148. package/dist/core/code/engine/core/ingestion/frameworks/spring/conditionals.js +323 -0
  149. package/dist/core/code/engine/core/ingestion/frameworks/spring/config-bindings.js +119 -0
  150. package/dist/core/code/engine/core/ingestion/frameworks/spring/di-metadata.js +385 -0
  151. package/dist/core/code/engine/core/ingestion/frameworks/spring/resource-injection.js +96 -0
  152. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/c-cpp.js +17 -0
  153. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/csharp.js +46 -0
  154. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/dart.js +59 -0
  155. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/go.js +30 -0
  156. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/jvm.js +73 -0
  157. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/php.js +19 -0
  158. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/python.js +45 -0
  159. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/ruby.js +20 -0
  160. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/rust.js +58 -0
  161. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/swift.js +94 -0
  162. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/typescript-javascript.js +26 -0
  163. package/dist/core/code/engine/core/ingestion/import-resolvers/csharp.js +128 -0
  164. package/dist/core/code/engine/core/ingestion/import-resolvers/go.js +50 -0
  165. package/dist/core/code/engine/core/ingestion/import-resolvers/jvm.js +112 -0
  166. package/dist/core/code/engine/core/ingestion/import-resolvers/php.js +80 -0
  167. package/dist/core/code/engine/core/ingestion/import-resolvers/python.js +75 -0
  168. package/dist/core/code/engine/core/ingestion/import-resolvers/resolver-factory.js +36 -0
  169. package/dist/core/code/engine/core/ingestion/import-resolvers/ruby.js +20 -0
  170. package/dist/core/code/engine/core/ingestion/import-resolvers/rust.js +79 -0
  171. package/dist/core/code/engine/core/ingestion/import-resolvers/standard.js +180 -0
  172. package/dist/core/code/engine/core/ingestion/import-resolvers/types.js +7 -0
  173. package/dist/core/code/engine/core/ingestion/import-resolvers/utils.js +153 -0
  174. package/dist/core/code/engine/core/ingestion/import-target-adapter.js +99 -0
  175. package/dist/core/code/engine/core/ingestion/language-config.js +391 -0
  176. package/dist/core/code/engine/core/ingestion/language-provider.js +25 -0
  177. package/dist/core/code/engine/core/ingestion/languages/c/arity-metadata.js +98 -0
  178. package/dist/core/code/engine/core/ingestion/languages/c/arity.js +21 -0
  179. package/dist/core/code/engine/core/ingestion/languages/c/capture-side-channel.js +69 -0
  180. package/dist/core/code/engine/core/ingestion/languages/c/captures.js +189 -0
  181. package/dist/core/code/engine/core/ingestion/languages/c/header-scan.js +58 -0
  182. package/dist/core/code/engine/core/ingestion/languages/c/import-decomposer.js +68 -0
  183. package/dist/core/code/engine/core/ingestion/languages/c/import-target.js +103 -0
  184. package/dist/core/code/engine/core/ingestion/languages/c/index.js +33 -0
  185. package/dist/core/code/engine/core/ingestion/languages/c/interpret.js +53 -0
  186. package/dist/core/code/engine/core/ingestion/languages/c/merge-bindings.js +26 -0
  187. package/dist/core/code/engine/core/ingestion/languages/c/query.js +210 -0
  188. package/dist/core/code/engine/core/ingestion/languages/c/scope-resolver.js +112 -0
  189. package/dist/core/code/engine/core/ingestion/languages/c/simple-hooks.js +24 -0
  190. package/dist/core/code/engine/core/ingestion/languages/c/static-linkage.js +109 -0
  191. package/dist/core/code/engine/core/ingestion/languages/c-cpp.js +506 -0
  192. package/dist/core/code/engine/core/ingestion/languages/cpp/adl.js +804 -0
  193. package/dist/core/code/engine/core/ingestion/languages/cpp/arity-metadata.js +258 -0
  194. package/dist/core/code/engine/core/ingestion/languages/cpp/arity.js +37 -0
  195. package/dist/core/code/engine/core/ingestion/languages/cpp/capture-side-channel.js +89 -0
  196. package/dist/core/code/engine/core/ingestion/languages/cpp/captures.js +1975 -0
  197. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-extractor.js +311 -0
  198. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-filter.js +210 -0
  199. package/dist/core/code/engine/core/ingestion/languages/cpp/conversion-rank.js +163 -0
  200. package/dist/core/code/engine/core/ingestion/languages/cpp/file-local-linkage.js +327 -0
  201. package/dist/core/code/engine/core/ingestion/languages/cpp/header-scan.js +53 -0
  202. package/dist/core/code/engine/core/ingestion/languages/cpp/import-decomposer.js +134 -0
  203. package/dist/core/code/engine/core/ingestion/languages/cpp/import-target.js +16 -0
  204. package/dist/core/code/engine/core/ingestion/languages/cpp/index.js +33 -0
  205. package/dist/core/code/engine/core/ingestion/languages/cpp/inline-namespaces.js +379 -0
  206. package/dist/core/code/engine/core/ingestion/languages/cpp/interpret.js +239 -0
  207. package/dist/core/code/engine/core/ingestion/languages/cpp/member-lookup.js +470 -0
  208. package/dist/core/code/engine/core/ingestion/languages/cpp/merge-bindings.js +32 -0
  209. package/dist/core/code/engine/core/ingestion/languages/cpp/query.js +763 -0
  210. package/dist/core/code/engine/core/ingestion/languages/cpp/range-bindings.js +230 -0
  211. package/dist/core/code/engine/core/ingestion/languages/cpp/scope-resolver.js +354 -0
  212. package/dist/core/code/engine/core/ingestion/languages/cpp/simple-hooks.js +67 -0
  213. package/dist/core/code/engine/core/ingestion/languages/cpp/two-phase-lookup.js +348 -0
  214. package/dist/core/code/engine/core/ingestion/languages/cpp/type-classifier.js +56 -0
  215. package/dist/core/code/engine/core/ingestion/languages/cpp/user-defined-conversions.js +128 -0
  216. package/dist/core/code/engine/core/ingestion/languages/csharp/accessor-unwrap.js +67 -0
  217. package/dist/core/code/engine/core/ingestion/languages/csharp/arity-metadata.js +49 -0
  218. package/dist/core/code/engine/core/ingestion/languages/csharp/arity.js +40 -0
  219. package/dist/core/code/engine/core/ingestion/languages/csharp/cache-stats.js +32 -0
  220. package/dist/core/code/engine/core/ingestion/languages/csharp/captures.js +557 -0
  221. package/dist/core/code/engine/core/ingestion/languages/csharp/import-decomposer.js +96 -0
  222. package/dist/core/code/engine/core/ingestion/languages/csharp/import-target.js +176 -0
  223. package/dist/core/code/engine/core/ingestion/languages/csharp/index.js +95 -0
  224. package/dist/core/code/engine/core/ingestion/languages/csharp/interpret.js +150 -0
  225. package/dist/core/code/engine/core/ingestion/languages/csharp/merge-bindings.js +58 -0
  226. package/dist/core/code/engine/core/ingestion/languages/csharp/namespace-siblings.js +708 -0
  227. package/dist/core/code/engine/core/ingestion/languages/csharp/qualified-type-names.js +62 -0
  228. package/dist/core/code/engine/core/ingestion/languages/csharp/query.js +578 -0
  229. package/dist/core/code/engine/core/ingestion/languages/csharp/receiver-binding.js +142 -0
  230. package/dist/core/code/engine/core/ingestion/languages/csharp/resolution-config.js +18 -0
  231. package/dist/core/code/engine/core/ingestion/languages/csharp/scope-resolver.js +84 -0
  232. package/dist/core/code/engine/core/ingestion/languages/csharp/simple-hooks.js +81 -0
  233. package/dist/core/code/engine/core/ingestion/languages/csharp.js +204 -0
  234. package/dist/core/code/engine/core/ingestion/languages/dart/arity-metadata.js +38 -0
  235. package/dist/core/code/engine/core/ingestion/languages/dart/arity.js +34 -0
  236. package/dist/core/code/engine/core/ingestion/languages/dart/built-ins.js +37 -0
  237. package/dist/core/code/engine/core/ingestion/languages/dart/cache-stats.js +30 -0
  238. package/dist/core/code/engine/core/ingestion/languages/dart/captures.js +1096 -0
  239. package/dist/core/code/engine/core/ingestion/languages/dart/expand-wildcards.js +34 -0
  240. package/dist/core/code/engine/core/ingestion/languages/dart/extension-type-preprocess.js +33 -0
  241. package/dist/core/code/engine/core/ingestion/languages/dart/import-target.js +68 -0
  242. package/dist/core/code/engine/core/ingestion/languages/dart/index.js +45 -0
  243. package/dist/core/code/engine/core/ingestion/languages/dart/interpret.js +101 -0
  244. package/dist/core/code/engine/core/ingestion/languages/dart/merge-bindings.js +42 -0
  245. package/dist/core/code/engine/core/ingestion/languages/dart/query.js +246 -0
  246. package/dist/core/code/engine/core/ingestion/languages/dart/receiver-binding.js +90 -0
  247. package/dist/core/code/engine/core/ingestion/languages/dart/scope-resolver.js +197 -0
  248. package/dist/core/code/engine/core/ingestion/languages/dart/signature-bindings.js +54 -0
  249. package/dist/core/code/engine/core/ingestion/languages/dart/simple-hooks.js +61 -0
  250. package/dist/core/code/engine/core/ingestion/languages/dart.js +138 -0
  251. package/dist/core/code/engine/core/ingestion/languages/go/arity-metadata.js +71 -0
  252. package/dist/core/code/engine/core/ingestion/languages/go/arity.js +17 -0
  253. package/dist/core/code/engine/core/ingestion/languages/go/cache-stats.js +21 -0
  254. package/dist/core/code/engine/core/ingestion/languages/go/captures.js +492 -0
  255. package/dist/core/code/engine/core/ingestion/languages/go/expand-wildcards.js +97 -0
  256. package/dist/core/code/engine/core/ingestion/languages/go/generic-type-parameters.js +146 -0
  257. package/dist/core/code/engine/core/ingestion/languages/go/import-decomposer.js +47 -0
  258. package/dist/core/code/engine/core/ingestion/languages/go/import-target.js +70 -0
  259. package/dist/core/code/engine/core/ingestion/languages/go/index.js +39 -0
  260. package/dist/core/code/engine/core/ingestion/languages/go/interface-impls.js +955 -0
  261. package/dist/core/code/engine/core/ingestion/languages/go/interpret.js +177 -0
  262. package/dist/core/code/engine/core/ingestion/languages/go/merge-bindings.js +21 -0
  263. package/dist/core/code/engine/core/ingestion/languages/go/method-owners.js +131 -0
  264. package/dist/core/code/engine/core/ingestion/languages/go/namespace-mirror.js +56 -0
  265. package/dist/core/code/engine/core/ingestion/languages/go/package-clause.js +79 -0
  266. package/dist/core/code/engine/core/ingestion/languages/go/package-siblings.js +83 -0
  267. package/dist/core/code/engine/core/ingestion/languages/go/query.js +298 -0
  268. package/dist/core/code/engine/core/ingestion/languages/go/range-binding.js +127 -0
  269. package/dist/core/code/engine/core/ingestion/languages/go/receiver-binding.js +24 -0
  270. package/dist/core/code/engine/core/ingestion/languages/go/scope-resolver.js +75 -0
  271. package/dist/core/code/engine/core/ingestion/languages/go/simple-hooks.js +31 -0
  272. package/dist/core/code/engine/core/ingestion/languages/go/type-binding.js +279 -0
  273. package/dist/core/code/engine/core/ingestion/languages/go.js +160 -0
  274. package/dist/core/code/engine/core/ingestion/languages/index.js +66 -0
  275. package/dist/core/code/engine/core/ingestion/languages/java/analysis-features.js +16 -0
  276. package/dist/core/code/engine/core/ingestion/languages/java/arity-metadata.js +43 -0
  277. package/dist/core/code/engine/core/ingestion/languages/java/arity.js +27 -0
  278. package/dist/core/code/engine/core/ingestion/languages/java/cache-stats.js +32 -0
  279. package/dist/core/code/engine/core/ingestion/languages/java/capture-side-channel.js +123 -0
  280. package/dist/core/code/engine/core/ingestion/languages/java/captures.js +791 -0
  281. package/dist/core/code/engine/core/ingestion/languages/java/import-decomposer.js +88 -0
  282. package/dist/core/code/engine/core/ingestion/languages/java/import-target.js +103 -0
  283. package/dist/core/code/engine/core/ingestion/languages/java/index.js +43 -0
  284. package/dist/core/code/engine/core/ingestion/languages/java/interpret.js +146 -0
  285. package/dist/core/code/engine/core/ingestion/languages/java/merge-bindings.js +43 -0
  286. package/dist/core/code/engine/core/ingestion/languages/java/package-facts.js +16 -0
  287. package/dist/core/code/engine/core/ingestion/languages/java/package-siblings.js +11 -0
  288. package/dist/core/code/engine/core/ingestion/languages/java/query.js +319 -0
  289. package/dist/core/code/engine/core/ingestion/languages/java/receiver-binding.js +98 -0
  290. package/dist/core/code/engine/core/ingestion/languages/java/scope-resolver.js +213 -0
  291. package/dist/core/code/engine/core/ingestion/languages/java/simple-hooks.js +39 -0
  292. package/dist/core/code/engine/core/ingestion/languages/java/spring-aop.js +53 -0
  293. package/dist/core/code/engine/core/ingestion/languages/java/spring-bean-metadata.js +11 -0
  294. package/dist/core/code/engine/core/ingestion/languages/java/spring-conditionals.js +52 -0
  295. package/dist/core/code/engine/core/ingestion/languages/java/spring-config-bindings.js +222 -0
  296. package/dist/core/code/engine/core/ingestion/languages/java/spring-di.js +165 -0
  297. package/dist/core/code/engine/core/ingestion/languages/java.js +192 -0
  298. package/dist/core/code/engine/core/ingestion/languages/javascript/arity.js +15 -0
  299. package/dist/core/code/engine/core/ingestion/languages/javascript/captures.js +1122 -0
  300. package/dist/core/code/engine/core/ingestion/languages/javascript/import-target.js +56 -0
  301. package/dist/core/code/engine/core/ingestion/languages/javascript/index.js +109 -0
  302. package/dist/core/code/engine/core/ingestion/languages/javascript/interpret.js +45 -0
  303. package/dist/core/code/engine/core/ingestion/languages/javascript/merge-bindings.js +21 -0
  304. package/dist/core/code/engine/core/ingestion/languages/javascript/query.js +659 -0
  305. package/dist/core/code/engine/core/ingestion/languages/javascript/scope-resolver.js +78 -0
  306. package/dist/core/code/engine/core/ingestion/languages/javascript/simple-hooks.js +44 -0
  307. package/dist/core/code/engine/core/ingestion/languages/jvm/package-facts.js +46 -0
  308. package/dist/core/code/engine/core/ingestion/languages/jvm/package-siblings.js +200 -0
  309. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity-metadata.js +23 -0
  310. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity.js +18 -0
  311. package/dist/core/code/engine/core/ingestion/languages/kotlin/cache-stats.js +21 -0
  312. package/dist/core/code/engine/core/ingestion/languages/kotlin/capture-side-channel.js +160 -0
  313. package/dist/core/code/engine/core/ingestion/languages/kotlin/captures.js +1262 -0
  314. package/dist/core/code/engine/core/ingestion/languages/kotlin/companion-scopes.js +72 -0
  315. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-decomposer.js +40 -0
  316. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-target.js +135 -0
  317. package/dist/core/code/engine/core/ingestion/languages/kotlin/index.js +26 -0
  318. package/dist/core/code/engine/core/ingestion/languages/kotlin/interpret.js +75 -0
  319. package/dist/core/code/engine/core/ingestion/languages/kotlin/merge-bindings.js +28 -0
  320. package/dist/core/code/engine/core/ingestion/languages/kotlin/owners.js +134 -0
  321. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-facts.js +16 -0
  322. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-siblings.js +11 -0
  323. package/dist/core/code/engine/core/ingestion/languages/kotlin/query.js +243 -0
  324. package/dist/core/code/engine/core/ingestion/languages/kotlin/receiver-binding.js +103 -0
  325. package/dist/core/code/engine/core/ingestion/languages/kotlin/scope-resolver.js +207 -0
  326. package/dist/core/code/engine/core/ingestion/languages/kotlin/simple-hooks.js +42 -0
  327. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-aop.js +68 -0
  328. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-bean-metadata.js +11 -0
  329. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-conditionals.js +53 -0
  330. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-di.js +304 -0
  331. package/dist/core/code/engine/core/ingestion/languages/kotlin.js +189 -0
  332. package/dist/core/code/engine/core/ingestion/languages/php/arity-metadata.js +66 -0
  333. package/dist/core/code/engine/core/ingestion/languages/php/arity.js +43 -0
  334. package/dist/core/code/engine/core/ingestion/languages/php/cache-stats.js +32 -0
  335. package/dist/core/code/engine/core/ingestion/languages/php/captures.js +1166 -0
  336. package/dist/core/code/engine/core/ingestion/languages/php/import-decomposer.js +238 -0
  337. package/dist/core/code/engine/core/ingestion/languages/php/import-target.js +213 -0
  338. package/dist/core/code/engine/core/ingestion/languages/php/index.js +85 -0
  339. package/dist/core/code/engine/core/ingestion/languages/php/interpret.js +256 -0
  340. package/dist/core/code/engine/core/ingestion/languages/php/merge-bindings.js +50 -0
  341. package/dist/core/code/engine/core/ingestion/languages/php/namespace-siblings.js +353 -0
  342. package/dist/core/code/engine/core/ingestion/languages/php/query.js +391 -0
  343. package/dist/core/code/engine/core/ingestion/languages/php/receiver-binding.js +135 -0
  344. package/dist/core/code/engine/core/ingestion/languages/php/scope-resolver.js +361 -0
  345. package/dist/core/code/engine/core/ingestion/languages/php/simple-hooks.js +116 -0
  346. package/dist/core/code/engine/core/ingestion/languages/php.js +302 -0
  347. package/dist/core/code/engine/core/ingestion/languages/python/arity-metadata.js +49 -0
  348. package/dist/core/code/engine/core/ingestion/languages/python/arity.js +41 -0
  349. package/dist/core/code/engine/core/ingestion/languages/python/cache-stats.js +34 -0
  350. package/dist/core/code/engine/core/ingestion/languages/python/captures.js +299 -0
  351. package/dist/core/code/engine/core/ingestion/languages/python/depends-references.js +68 -0
  352. package/dist/core/code/engine/core/ingestion/languages/python/import-decomposer.js +115 -0
  353. package/dist/core/code/engine/core/ingestion/languages/python/import-target.js +440 -0
  354. package/dist/core/code/engine/core/ingestion/languages/python/index-stats.js +30 -0
  355. package/dist/core/code/engine/core/ingestion/languages/python/index.js +96 -0
  356. package/dist/core/code/engine/core/ingestion/languages/python/interpret.js +430 -0
  357. package/dist/core/code/engine/core/ingestion/languages/python/merge-bindings.js +47 -0
  358. package/dist/core/code/engine/core/ingestion/languages/python/query.js +323 -0
  359. package/dist/core/code/engine/core/ingestion/languages/python/receiver-binding.js +310 -0
  360. package/dist/core/code/engine/core/ingestion/languages/python/scope-resolver.js +80 -0
  361. package/dist/core/code/engine/core/ingestion/languages/python/simple-hooks.js +53 -0
  362. package/dist/core/code/engine/core/ingestion/languages/python.js +140 -0
  363. package/dist/core/code/engine/core/ingestion/languages/ruby/arity.js +41 -0
  364. package/dist/core/code/engine/core/ingestion/languages/ruby/cache-stats.js +21 -0
  365. package/dist/core/code/engine/core/ingestion/languages/ruby/captures.js +864 -0
  366. package/dist/core/code/engine/core/ingestion/languages/ruby/import-target.js +88 -0
  367. package/dist/core/code/engine/core/ingestion/languages/ruby/index.js +29 -0
  368. package/dist/core/code/engine/core/ingestion/languages/ruby/interpret.js +115 -0
  369. package/dist/core/code/engine/core/ingestion/languages/ruby/merge-bindings.js +21 -0
  370. package/dist/core/code/engine/core/ingestion/languages/ruby/query.js +349 -0
  371. package/dist/core/code/engine/core/ingestion/languages/ruby/receiver-binding.js +70 -0
  372. package/dist/core/code/engine/core/ingestion/languages/ruby/scope-resolver.js +263 -0
  373. package/dist/core/code/engine/core/ingestion/languages/ruby/simple-hooks.js +68 -0
  374. package/dist/core/code/engine/core/ingestion/languages/ruby.js +215 -0
  375. package/dist/core/code/engine/core/ingestion/languages/rust/arity.js +16 -0
  376. package/dist/core/code/engine/core/ingestion/languages/rust/cache-stats.js +21 -0
  377. package/dist/core/code/engine/core/ingestion/languages/rust/captures.js +304 -0
  378. package/dist/core/code/engine/core/ingestion/languages/rust/import-decomposer.js +167 -0
  379. package/dist/core/code/engine/core/ingestion/languages/rust/import-target.js +108 -0
  380. package/dist/core/code/engine/core/ingestion/languages/rust/index.js +29 -0
  381. package/dist/core/code/engine/core/ingestion/languages/rust/interpret.js +201 -0
  382. package/dist/core/code/engine/core/ingestion/languages/rust/merge-bindings.js +21 -0
  383. package/dist/core/code/engine/core/ingestion/languages/rust/method-owners.js +76 -0
  384. package/dist/core/code/engine/core/ingestion/languages/rust/module-path.js +222 -0
  385. package/dist/core/code/engine/core/ingestion/languages/rust/qualified-call.js +482 -0
  386. package/dist/core/code/engine/core/ingestion/languages/rust/query.js +280 -0
  387. package/dist/core/code/engine/core/ingestion/languages/rust/range-binding.js +687 -0
  388. package/dist/core/code/engine/core/ingestion/languages/rust/receiver-binding.js +148 -0
  389. package/dist/core/code/engine/core/ingestion/languages/rust/scope-resolver.js +151 -0
  390. package/dist/core/code/engine/core/ingestion/languages/rust/simple-hooks.js +32 -0
  391. package/dist/core/code/engine/core/ingestion/languages/rust.js +183 -0
  392. package/dist/core/code/engine/core/ingestion/languages/swift/arity-metadata.js +44 -0
  393. package/dist/core/code/engine/core/ingestion/languages/swift/arity.js +45 -0
  394. package/dist/core/code/engine/core/ingestion/languages/swift/base-type.js +30 -0
  395. package/dist/core/code/engine/core/ingestion/languages/swift/cache-stats.js +32 -0
  396. package/dist/core/code/engine/core/ingestion/languages/swift/captures.js +594 -0
  397. package/dist/core/code/engine/core/ingestion/languages/swift/conditional-directive-preprocess.js +256 -0
  398. package/dist/core/code/engine/core/ingestion/languages/swift/implicit-imports.js +60 -0
  399. package/dist/core/code/engine/core/ingestion/languages/swift/import-decomposer.js +87 -0
  400. package/dist/core/code/engine/core/ingestion/languages/swift/import-target.js +84 -0
  401. package/dist/core/code/engine/core/ingestion/languages/swift/index.js +56 -0
  402. package/dist/core/code/engine/core/ingestion/languages/swift/interpret.js +93 -0
  403. package/dist/core/code/engine/core/ingestion/languages/swift/merge-bindings.js +51 -0
  404. package/dist/core/code/engine/core/ingestion/languages/swift/query.js +226 -0
  405. package/dist/core/code/engine/core/ingestion/languages/swift/receiver-binding.js +169 -0
  406. package/dist/core/code/engine/core/ingestion/languages/swift/scope-resolver.js +192 -0
  407. package/dist/core/code/engine/core/ingestion/languages/swift/sibling-type-bindings.js +68 -0
  408. package/dist/core/code/engine/core/ingestion/languages/swift/signature-bindings.js +69 -0
  409. package/dist/core/code/engine/core/ingestion/languages/swift/simple-hooks.js +65 -0
  410. package/dist/core/code/engine/core/ingestion/languages/swift/target-grouping.js +97 -0
  411. package/dist/core/code/engine/core/ingestion/languages/swift/target-siblings.js +74 -0
  412. package/dist/core/code/engine/core/ingestion/languages/swift.js +246 -0
  413. package/dist/core/code/engine/core/ingestion/languages/typescript/arity-metadata.js +106 -0
  414. package/dist/core/code/engine/core/ingestion/languages/typescript/arity.js +57 -0
  415. package/dist/core/code/engine/core/ingestion/languages/typescript/array-callback.js +58 -0
  416. package/dist/core/code/engine/core/ingestion/languages/typescript/cache-stats.js +34 -0
  417. package/dist/core/code/engine/core/ingestion/languages/typescript/captures.js +956 -0
  418. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-export-assignment.js +535 -0
  419. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-module-exports.js +196 -0
  420. package/dist/core/code/engine/core/ingestion/languages/typescript/import-decomposer.js +374 -0
  421. package/dist/core/code/engine/core/ingestion/languages/typescript/import-target.js +65 -0
  422. package/dist/core/code/engine/core/ingestion/languages/typescript/index.js +108 -0
  423. package/dist/core/code/engine/core/ingestion/languages/typescript/interpret.js +344 -0
  424. package/dist/core/code/engine/core/ingestion/languages/typescript/merge-bindings.js +161 -0
  425. package/dist/core/code/engine/core/ingestion/languages/typescript/nuxt-auto-imports.js +325 -0
  426. package/dist/core/code/engine/core/ingestion/languages/typescript/query.js +1328 -0
  427. package/dist/core/code/engine/core/ingestion/languages/typescript/receiver-binding.js +201 -0
  428. package/dist/core/code/engine/core/ingestion/languages/typescript/scope-resolver.js +293 -0
  429. package/dist/core/code/engine/core/ingestion/languages/typescript/simple-hooks.js +139 -0
  430. package/dist/core/code/engine/core/ingestion/languages/typescript.js +455 -0
  431. package/dist/core/code/engine/core/ingestion/languages/vue/captures.js +70 -0
  432. package/dist/core/code/engine/core/ingestion/languages/vue/import-target.js +61 -0
  433. package/dist/core/code/engine/core/ingestion/languages/vue/index.js +55 -0
  434. package/dist/core/code/engine/core/ingestion/languages/vue/scope-resolver.js +295 -0
  435. package/dist/core/code/engine/core/ingestion/languages/vue.js +96 -0
  436. package/dist/core/code/engine/core/ingestion/local-symbol-pruner.js +68 -0
  437. package/dist/core/code/engine/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  438. package/dist/core/code/engine/core/ingestion/method-extractors/configs/csharp.js +290 -0
  439. package/dist/core/code/engine/core/ingestion/method-extractors/configs/dart.js +392 -0
  440. package/dist/core/code/engine/core/ingestion/method-extractors/configs/go.js +179 -0
  441. package/dist/core/code/engine/core/ingestion/method-extractors/configs/jvm.js +350 -0
  442. package/dist/core/code/engine/core/ingestion/method-extractors/configs/php.js +306 -0
  443. package/dist/core/code/engine/core/ingestion/method-extractors/configs/python.js +312 -0
  444. package/dist/core/code/engine/core/ingestion/method-extractors/configs/ruby.js +289 -0
  445. package/dist/core/code/engine/core/ingestion/method-extractors/configs/rust.js +198 -0
  446. package/dist/core/code/engine/core/ingestion/method-extractors/configs/swift.js +286 -0
  447. package/dist/core/code/engine/core/ingestion/method-extractors/configs/typescript-javascript.js +341 -0
  448. package/dist/core/code/engine/core/ingestion/method-extractors/generic.js +209 -0
  449. package/dist/core/code/engine/core/ingestion/method-types.js +3 -0
  450. package/dist/core/code/engine/core/ingestion/model/field-registry.js +41 -0
  451. package/dist/core/code/engine/core/ingestion/model/index.js +52 -0
  452. package/dist/core/code/engine/core/ingestion/model/method-registry.js +138 -0
  453. package/dist/core/code/engine/core/ingestion/model/owned-members-lookup.js +46 -0
  454. package/dist/core/code/engine/core/ingestion/model/registration-table.js +234 -0
  455. package/dist/core/code/engine/core/ingestion/model/resolve.js +183 -0
  456. package/dist/core/code/engine/core/ingestion/model/scope-resolution-indexes.js +43 -0
  457. package/dist/core/code/engine/core/ingestion/model/semantic-model.js +179 -0
  458. package/dist/core/code/engine/core/ingestion/model/symbol-table.js +216 -0
  459. package/dist/core/code/engine/core/ingestion/model/type-registry.js +84 -0
  460. package/dist/core/code/engine/core/ingestion/mro-processor.js +709 -0
  461. package/dist/core/code/engine/core/ingestion/parsing-processor.js +312 -0
  462. package/dist/core/code/engine/core/ingestion/pipeline-phases/communities.js +69 -0
  463. package/dist/core/code/engine/core/ingestion/pipeline-phases/cross-file.js +71 -0
  464. package/dist/core/code/engine/core/ingestion/pipeline-phases/di.js +338 -0
  465. package/dist/core/code/engine/core/ingestion/pipeline-phases/http-api-calls.js +312 -0
  466. package/dist/core/code/engine/core/ingestion/pipeline-phases/index.js +54 -0
  467. package/dist/core/code/engine/core/ingestion/pipeline-phases/mro.js +40 -0
  468. package/dist/core/code/engine/core/ingestion/pipeline-phases/orm.js +78 -0
  469. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse-impl.js +1286 -0
  470. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse.js +41 -0
  471. package/dist/core/code/engine/core/ingestion/pipeline-phases/processes.js +193 -0
  472. package/dist/core/code/engine/core/ingestion/pipeline-phases/prune-local-symbols.js +29 -0
  473. package/dist/core/code/engine/core/ingestion/pipeline-phases/registry.js +52 -0
  474. package/dist/core/code/engine/core/ingestion/pipeline-phases/routes.js +409 -0
  475. package/dist/core/code/engine/core/ingestion/pipeline-phases/rpc-edges.js +301 -0
  476. package/dist/core/code/engine/core/ingestion/pipeline-phases/runner.js +207 -0
  477. package/dist/core/code/engine/core/ingestion/pipeline-phases/scan.js +49 -0
  478. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-aop.js +442 -0
  479. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-auto-configuration.js +264 -0
  480. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-config.js +440 -0
  481. package/dist/core/code/engine/core/ingestion/pipeline-phases/structure.js +38 -0
  482. package/dist/core/code/engine/core/ingestion/pipeline-phases/tools.js +89 -0
  483. package/dist/core/code/engine/core/ingestion/pipeline-phases/types.js +40 -0
  484. package/dist/core/code/engine/core/ingestion/pipeline.js +152 -0
  485. package/dist/core/code/engine/core/ingestion/process-processor.js +325 -0
  486. package/dist/core/code/engine/core/ingestion/resolve-references.js +205 -0
  487. package/dist/core/code/engine/core/ingestion/route-extractors/constant-resolver.js +135 -0
  488. package/dist/core/code/engine/core/ingestion/route-extractors/django-root-discovery.js +221 -0
  489. package/dist/core/code/engine/core/ingestion/route-extractors/django.js +428 -0
  490. package/dist/core/code/engine/core/ingestion/route-extractors/expo.js +39 -0
  491. package/dist/core/code/engine/core/ingestion/route-extractors/fastapi-router-bindings.js +264 -0
  492. package/dist/core/code/engine/core/ingestion/route-extractors/laravel.js +501 -0
  493. package/dist/core/code/engine/core/ingestion/route-extractors/middleware.js +175 -0
  494. package/dist/core/code/engine/core/ingestion/route-extractors/nextjs.js +81 -0
  495. package/dist/core/code/engine/core/ingestion/route-extractors/php.js +25 -0
  496. package/dist/core/code/engine/core/ingestion/route-extractors/python-const-resolver.js +307 -0
  497. package/dist/core/code/engine/core/ingestion/route-extractors/response-shapes.js +299 -0
  498. package/dist/core/code/engine/core/ingestion/route-extractors/route-path.js +71 -0
  499. package/dist/core/code/engine/core/ingestion/route-extractors/spring-shared.js +310 -0
  500. package/dist/core/code/engine/core/ingestion/route-extractors/spring.js +441 -0
  501. package/dist/core/code/engine/core/ingestion/scope-extractor-bridge.js +60 -0
  502. package/dist/core/code/engine/core/ingestion/scope-extractor.js +1373 -0
  503. package/dist/core/code/engine/core/ingestion/scope-resolution/contract/scope-resolver.js +282 -0
  504. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +72 -0
  505. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/edges.js +194 -0
  506. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/ids.js +472 -0
  507. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +49 -0
  508. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +43 -0
  509. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +274 -0
  510. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +93 -0
  511. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/callable-value-flow.js +1240 -0
  512. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/compound-receiver.js +1174 -0
  513. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/free-call-fallback.js +873 -0
  514. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/imported-return-types.js +226 -0
  515. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/mro.js +107 -0
  516. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/overload-narrowing.js +441 -0
  517. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/property-dispatch.js +122 -0
  518. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +1720 -0
  519. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/phase.js +395 -0
  520. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +208 -0
  521. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/registry.js +49 -0
  522. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/run.js +632 -0
  523. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +112 -0
  524. package/dist/core/code/engine/core/ingestion/scope-resolution/resolution-outcome.js +41 -0
  525. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/namespace-targets.js +81 -0
  526. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/walkers.js +1835 -0
  527. package/dist/core/code/engine/core/ingestion/scope-resolution/unresolved-receivers.js +242 -0
  528. package/dist/core/code/engine/core/ingestion/scope-resolution/utils/definition-id.js +22 -0
  529. package/dist/core/code/engine/core/ingestion/scope-resolution/workspace-index.js +151 -0
  530. package/dist/core/code/engine/core/ingestion/structure-processor.js +40 -0
  531. package/dist/core/code/engine/core/ingestion/tree-sitter-queries.js +2244 -0
  532. package/dist/core/code/engine/core/ingestion/ts-js-hoc-utils.js +115 -0
  533. package/dist/core/code/engine/core/ingestion/type-env.js +1136 -0
  534. package/dist/core/code/engine/core/ingestion/type-extractors/c-cpp.js +555 -0
  535. package/dist/core/code/engine/core/ingestion/type-extractors/csharp.js +570 -0
  536. package/dist/core/code/engine/core/ingestion/type-extractors/dart.js +372 -0
  537. package/dist/core/code/engine/core/ingestion/type-extractors/go.js +508 -0
  538. package/dist/core/code/engine/core/ingestion/type-extractors/jvm.js +875 -0
  539. package/dist/core/code/engine/core/ingestion/type-extractors/php.js +537 -0
  540. package/dist/core/code/engine/core/ingestion/type-extractors/python.js +477 -0
  541. package/dist/core/code/engine/core/ingestion/type-extractors/ruby.js +380 -0
  542. package/dist/core/code/engine/core/ingestion/type-extractors/rust.js +502 -0
  543. package/dist/core/code/engine/core/ingestion/type-extractors/shared.js +843 -0
  544. package/dist/core/code/engine/core/ingestion/type-extractors/swift.js +490 -0
  545. package/dist/core/code/engine/core/ingestion/type-extractors/types.js +2 -0
  546. package/dist/core/code/engine/core/ingestion/type-extractors/typescript.js +690 -0
  547. package/dist/core/code/engine/core/ingestion/utils/ast-helpers.js +1693 -0
  548. package/dist/core/code/engine/core/ingestion/utils/call-analysis.js +779 -0
  549. package/dist/core/code/engine/core/ingestion/utils/callable-flow-captures.js +932 -0
  550. package/dist/core/code/engine/core/ingestion/utils/callable-labels.js +49 -0
  551. package/dist/core/code/engine/core/ingestion/utils/deferred-resolution-profile.js +151 -0
  552. package/dist/core/code/engine/core/ingestion/utils/effective-ram.js +67 -0
  553. package/dist/core/code/engine/core/ingestion/utils/env.js +60 -0
  554. package/dist/core/code/engine/core/ingestion/utils/event-loop.js +9 -0
  555. package/dist/core/code/engine/core/ingestion/utils/graph-sort.js +103 -0
  556. package/dist/core/code/engine/core/ingestion/utils/heap-probe.js +45 -0
  557. package/dist/core/code/engine/core/ingestion/utils/heritage-marker.js +47 -0
  558. package/dist/core/code/engine/core/ingestion/utils/line-base.js +24 -0
  559. package/dist/core/code/engine/core/ingestion/utils/max-file-size.js +59 -0
  560. package/dist/core/code/engine/core/ingestion/utils/method-props.js +198 -0
  561. package/dist/core/code/engine/core/ingestion/utils/qualified-name.js +73 -0
  562. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-captures.js +60 -0
  563. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-codec.js +188 -0
  564. package/dist/core/code/engine/core/ingestion/utils/scope-tree-walk.js +36 -0
  565. package/dist/core/code/engine/core/ingestion/utils/symbol-labels.js +48 -0
  566. package/dist/core/code/engine/core/ingestion/utils/template-arguments.js +187 -0
  567. package/dist/core/code/engine/core/ingestion/utils/type-parameters.js +209 -0
  568. package/dist/core/code/engine/core/ingestion/utils/verbose.js +6 -0
  569. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/c-cpp.js +133 -0
  570. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/csharp.js +66 -0
  571. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/dart.js +111 -0
  572. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/go.js +153 -0
  573. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/jvm.js +145 -0
  574. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/php.js +61 -0
  575. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/python.js +104 -0
  576. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/ruby.js +55 -0
  577. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/rust.js +79 -0
  578. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/swift.js +91 -0
  579. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/typescript-javascript.js +86 -0
  580. package/dist/core/code/engine/core/ingestion/variable-extractors/generic.js +111 -0
  581. package/dist/core/code/engine/core/ingestion/variable-types.js +3 -0
  582. package/dist/core/code/engine/core/ingestion/vue-sfc-extractor.js +544 -0
  583. package/dist/core/code/engine/core/ingestion/workers/callable-id.js +122 -0
  584. package/dist/core/code/engine/core/ingestion/workers/clone-safety.js +470 -0
  585. package/dist/core/code/engine/core/ingestion/workers/parse-worker.js +2456 -0
  586. package/dist/core/code/engine/core/ingestion/workers/post-result.js +90 -0
  587. package/dist/core/code/engine/core/ingestion/workers/quarantine.js +41 -0
  588. package/dist/core/code/engine/core/ingestion/workers/result-merge.js +59 -0
  589. package/dist/core/code/engine/core/ingestion/workers/worker-pool.js +1725 -0
  590. package/dist/core/code/engine/core/ingestion/workspace-config.js +139 -0
  591. package/dist/core/code/engine/core/lbug/conn-lock.js +72 -0
  592. package/dist/core/code/engine/core/lbug/csv-generator.js +710 -0
  593. package/dist/core/code/engine/core/lbug/cypher-escape.js +24 -0
  594. package/dist/core/code/engine/core/lbug/extension-load-error.js +339 -0
  595. package/dist/core/code/engine/core/lbug/extension-loader.js +261 -0
  596. package/dist/core/code/engine/core/lbug/graph-emit-sink.js +584 -0
  597. package/dist/core/code/engine/core/lbug/lbug-adapter.js +2703 -0
  598. package/dist/core/code/engine/core/lbug/lbug-config.js +1029 -0
  599. package/dist/core/code/engine/core/lbug/native-check.js +435 -0
  600. package/dist/core/code/engine/core/lbug/pool-adapter.js +973 -0
  601. package/dist/core/code/engine/core/lbug/query-params.js +25 -0
  602. package/dist/core/code/engine/core/lbug/query-result-utils.js +31 -0
  603. package/dist/core/code/engine/core/lbug/rel-pair-routing.js +373 -0
  604. package/dist/core/code/engine/core/lbug/schema.js +771 -0
  605. package/dist/core/code/engine/core/lbug/shutdown-helpers.js +40 -0
  606. package/dist/core/code/engine/core/lbug/sidecar-recovery.js +716 -0
  607. package/dist/core/code/engine/core/lbug/stdio-capture.js +49 -0
  608. package/dist/core/code/engine/core/lbug/sync-csv-writer.js +115 -0
  609. package/dist/core/code/engine/core/lbug/wal-checkpoint-driver.js +215 -0
  610. package/dist/core/code/engine/core/lbug/wal-driver-state.js +28 -0
  611. package/dist/core/code/engine/core/logger.js +339 -0
  612. package/dist/core/code/engine/core/platform/capabilities.js +91 -0
  613. package/dist/core/code/engine/core/run-analyze.js +1098 -0
  614. package/dist/core/code/engine/core/tree-sitter/parser-loader.js +281 -0
  615. package/dist/core/code/engine/core/tree-sitter/safe-parse.js +258 -0
  616. package/dist/core/code/engine/core/tree-sitter/vendored-grammars.js +64 -0
  617. package/dist/core/code/engine/lib/utils.js +121 -0
  618. package/dist/core/code/engine/mcp/core/lbug-adapter.js +27 -0
  619. package/dist/core/code/engine/mcp/local/aop-metadata.js +230 -0
  620. package/dist/core/code/engine/mcp/local/bean-metadata.js +49 -0
  621. package/dist/core/code/engine/mcp/local/limits.js +15 -0
  622. package/dist/core/code/engine/mcp/local/line-display.js +6 -0
  623. package/dist/core/code/engine/mcp/local/local-backend.js +4142 -0
  624. package/dist/core/code/engine/storage/branch-index.js +72 -0
  625. package/dist/core/code/engine/storage/file-hash.js +95 -0
  626. package/dist/core/code/engine/storage/fs-atomic.js +34 -0
  627. package/dist/core/code/engine/storage/git.js +555 -0
  628. package/dist/core/code/engine/storage/index-lock.js +664 -0
  629. package/dist/core/code/engine/storage/parse-cache.js +650 -0
  630. package/dist/core/code/engine/storage/parsedfile-store.js +620 -0
  631. package/dist/core/code/engine/storage/repo-manager.js +1061 -0
  632. package/dist/core/code/engine/storage/scope-index-store.js +247 -0
  633. package/dist/core/code/engine/types/pipeline.js +2 -0
  634. package/dist/core/code/scripts/install-duckdb-extension.mjs +125 -0
  635. package/dist/core/code/scripts/resolve-analyze-cmd.cjs +346 -0
  636. package/dist/core/code/shared/graph/types.js +8 -0
  637. package/dist/core/code/shared/index.js +105 -0
  638. package/dist/core/code/shared/integrations/circuit-breaker.js +242 -0
  639. package/dist/core/code/shared/integrations/resilient-fetch.js +224 -0
  640. package/dist/core/code/shared/integrations/retry.js +70 -0
  641. package/dist/core/code/shared/integrations/understand-quickly.js +145 -0
  642. package/dist/core/code/shared/language-detection.js +162 -0
  643. package/dist/core/code/shared/languages.js +27 -0
  644. package/dist/core/code/shared/lbug/schema-constants.js +98 -0
  645. package/dist/core/code/shared/mro-strategy.js +2 -0
  646. package/dist/core/code/shared/pipeline.js +5 -0
  647. package/dist/core/code/shared/scope-resolution/callable-flow-site.js +11 -0
  648. package/dist/core/code/shared/scope-resolution/def-index.js +53 -0
  649. package/dist/core/code/shared/scope-resolution/evidence-weights.js +87 -0
  650. package/dist/core/code/shared/scope-resolution/finalize-algorithm.js +807 -0
  651. package/dist/core/code/shared/scope-resolution/language-classification.js +46 -0
  652. package/dist/core/code/shared/scope-resolution/method-dispatch-index.js +100 -0
  653. package/dist/core/code/shared/scope-resolution/module-scope-index.js +59 -0
  654. package/dist/core/code/shared/scope-resolution/origin-priority.js +23 -0
  655. package/dist/core/code/shared/scope-resolution/parsed-file.js +54 -0
  656. package/dist/core/code/shared/scope-resolution/position-index.js +136 -0
  657. package/dist/core/code/shared/scope-resolution/qualified-name-index.js +77 -0
  658. package/dist/core/code/shared/scope-resolution/reference-site.js +24 -0
  659. package/dist/core/code/shared/scope-resolution/registries/class-registry.js +32 -0
  660. package/dist/core/code/shared/scope-resolution/registries/context.js +52 -0
  661. package/dist/core/code/shared/scope-resolution/registries/evidence.js +152 -0
  662. package/dist/core/code/shared/scope-resolution/registries/field-registry.js +33 -0
  663. package/dist/core/code/shared/scope-resolution/registries/lookup-core.js +392 -0
  664. package/dist/core/code/shared/scope-resolution/registries/lookup-qualified.js +58 -0
  665. package/dist/core/code/shared/scope-resolution/registries/macro-registry.js +34 -0
  666. package/dist/core/code/shared/scope-resolution/registries/method-registry.js +34 -0
  667. package/dist/core/code/shared/scope-resolution/registries/tie-breaks.js +63 -0
  668. package/dist/core/code/shared/scope-resolution/resolve-type-ref.js +128 -0
  669. package/dist/core/code/shared/scope-resolution/scope-id.js +49 -0
  670. package/dist/core/code/shared/scope-resolution/scope-tree.js +225 -0
  671. package/dist/core/code/shared/scope-resolution/symbol-definition.js +12 -0
  672. package/dist/core/code/shared/scope-resolution/types.js +25 -0
  673. package/dist/core/code/shared/test-helpers.js +17 -0
  674. package/dist/core/code/vendor/leiden/index.cjs +355 -0
  675. package/dist/core/code/vendor/leiden/utils.cjs +419 -0
  676. package/dist/core/features/scanner.d.ts +2 -0
  677. package/dist/core/features/scanner.d.ts.map +1 -1
  678. package/dist/core/features/scanner.js +27 -6
  679. package/dist/core/features/scanner.js.map +1 -1
  680. package/dist/core/timeline/cli.d.ts.map +1 -1
  681. package/dist/core/timeline/cli.js +13 -6
  682. package/dist/core/timeline/cli.js.map +1 -1
  683. package/dist/core/timeline/debris.d.ts +20 -0
  684. package/dist/core/timeline/debris.d.ts.map +1 -0
  685. package/dist/core/timeline/debris.js +124 -0
  686. package/dist/core/timeline/debris.js.map +1 -0
  687. package/dist/core/timeline/hook-runner.d.ts.map +1 -1
  688. package/dist/core/timeline/hook-runner.js +3 -1
  689. package/dist/core/timeline/hook-runner.js.map +1 -1
  690. package/dist/core/timeline/hooks.d.ts.map +1 -1
  691. package/dist/core/timeline/hooks.js +13 -5
  692. package/dist/core/timeline/hooks.js.map +1 -1
  693. package/dist/core/timeline/installer.d.ts +2 -0
  694. package/dist/core/timeline/installer.d.ts.map +1 -1
  695. package/dist/core/timeline/installer.js +12 -0
  696. package/dist/core/timeline/installer.js.map +1 -1
  697. package/dist/core/timeline/project-root.d.ts +21 -0
  698. package/dist/core/timeline/project-root.d.ts.map +1 -0
  699. package/dist/core/timeline/project-root.js +83 -0
  700. package/dist/core/timeline/project-root.js.map +1 -0
  701. package/package.json +1 -1
@@ -0,0 +1,1720 @@
1
+ "use strict";
2
+ /**
3
+ * Receiver-bound CALLS / ACCESSES emit pass — generic 8-case
4
+ * dispatcher consuming `ScopeResolver` for the language-specific bits
5
+ * (super recognizer, field-fallback toggle).
6
+ *
7
+ * **Contract Invariant I4 — case order is load-bearing.** The cases
8
+ * are evaluated in this order; the FIRST that emits an edge wins:
9
+ *
10
+ * 1. **super branch** — `provider.isSuperReceiver(receiverName)` →
11
+ * MRO walk skipping self
12
+ * 2. **Case 0 (compound)** — receiver has `.` or `(` → compound resolver.
13
+ * Also emits the interface-dispatch fan-out when the folded receiver type
14
+ * is an Interface (#2829) — see Case 4, which does the same.
15
+ * 3. **Case 0.5 (implicit `this` receiver)** — GATED: fires only when
16
+ * the language sets `resolveThisViaEnclosingClass === true` AND the
17
+ * receiver is literally `this` → enclosing-class + MRO chain walk
18
+ * with C++ member-name-hiding semantics. Languages that leave the
19
+ * toggle unset skip this case entirely; their `this` sites fall
20
+ * through to Case 4 via the synthesized `this` typeBinding (which
21
+ * emits the interface-dispatch fan-out that this case does not —
22
+ * as do Cases 0 since #2829 and 3b since #2832; Case 0.5 remains
23
+ * the only fold-or-walk case without it).
24
+ * 4. **Case 1 (namespace)** — receiver in `namespaceTargets` → exported def
25
+ * 5. **Case 2 (class-name / static receiver)** — receiver resolves to a
26
+ * class-like binding (Class/Interface/Struct/Record/Enum/Trait) → MRO
27
+ * walk on that class. Also handles static-style invocations
28
+ * (`ILogger.Warn(...)`) with kind-aware reason/confidence for
29
+ * read/write ACCESSES.
30
+ * 6. **Case 3 (dotted typeBinding for namespace prefix)** —
31
+ * `typeRef.rawName` like `models.User`
32
+ * 7. **Case 3b (chain-typebinding)** — `typeRef.rawName` has a dot
33
+ * but not a namespace prefix → compound resolver. Also emits the
34
+ * interface-dispatch fan-out when the folded receiver type is an
35
+ * Interface (#2832) — same call Cases 0 and 4 make.
36
+ * 8. **Case 4 (simple typeBinding)** — `typeRef.rawName` has no dot →
37
+ * MRO walk + `findOwnedMember`
38
+ * 9. **Case 5 (value-receiver bridge)** — receiver is a `Const`/`Variable`
39
+ * whose `nodeId` is referenced as an `ownerId` in `model.methods`
40
+ * (object-literal services). Last-resort fallback for lowercase
41
+ * receivers with no class-like or type-binding match. Mirrors
42
+ * the legacy DAG bridge in `call-processor.ts`.
43
+ * 10. **Case 6 (class-level member receiver)** — `Holder.repo.save(u)`,
44
+ * where the receiver's head is a CLASS and the one hop past it is a
45
+ * class-level (`isStatic`) field. Types the receiver from that field
46
+ * DEF's declared type rather than from a `typeBindings` entry, which
47
+ * is the thing a per-scope binding map cannot hold for a class that
48
+ * declares both a static and an instance member of one name. Gated on
49
+ * Case 0 having declined the same receiver, so it only ever adds an
50
+ * edge where there was none. Emits the interface-dispatch fan-out
51
+ * alongside Cases 0, 3b and 4.
52
+ *
53
+ * Reordering or merging cases changes resolution semantics.
54
+ *
55
+ * **Contract Invariant I5 — pre-seeding `seen` is forbidden.** The
56
+ * orchestrator runs this pass FIRST (before `emitReferencesViaLookup`)
57
+ * and consumes the populated `handledSites` set. Pre-seeding `seen`
58
+ * from the shared resolver's emissions (an old optimization) actively
59
+ * suppresses correct emissions for sites the shared resolver also
60
+ * resolved to a wrong target.
61
+ */
62
+ Object.defineProperty(exports, "__esModule", { value: true });
63
+ exports.OVERLOAD_AMBIGUOUS = exports.MAX_INTERFACE_DISPATCH_FANOUT = void 0;
64
+ exports.classifyReceiverOrigin = classifyReceiverOrigin;
65
+ exports.emitReceiverBoundCalls = emitReceiverBoundCalls;
66
+ const namespace_targets_js_1 = require("../scope/namespace-targets.js");
67
+ const walkers_js_1 = require("../scope/walkers.js");
68
+ const edges_js_1 = require("../graph-bridge/edges.js");
69
+ const compound_receiver_js_1 = require("../passes/compound-receiver.js");
70
+ const template_arguments_js_1 = require("../../utils/template-arguments.js");
71
+ const ids_js_1 = require("../graph-bridge/ids.js");
72
+ const overload_narrowing_js_1 = require("./overload-narrowing.js");
73
+ const resolution_outcome_js_1 = require("../resolution-outcome.js");
74
+ const receiver_chain_codec_js_1 = require("../../utils/receiver-chain-codec.js");
75
+ /** A bare, undecorated identifier and nothing else — see {@link isBareTypeName}. */
76
+ const BARE_TYPE_NAME_RE = /^[A-Za-z_$][\w$]*$/;
77
+ /**
78
+ * A type name a built-in test may be asked about: a bare, undecorated
79
+ * identifier and nothing else.
80
+ *
81
+ * `Promise<User>`, `[]Repo` and `Option<Repo>` all name a built-in CONTAINER
82
+ * whose ELEMENT is very often in-program, and an await/index/unwrap step is
83
+ * exactly how a receiver chain reaches that element. Answering "external"
84
+ * because the outer spelling matched a built-in would relabel a real in-program
85
+ * drop, which is the failure this whole function exists to stop. A decorated or
86
+ * dotted spelling is likewise not a built-in name, it merely contains one.
87
+ */
88
+ function isBareTypeName(rawName) {
89
+ return BARE_TYPE_NAME_RE.test(rawName);
90
+ }
91
+ /**
92
+ * Is this dropped receiver rooted inside the analyzed program?
93
+ *
94
+ * Asks of the receiver's BASE — the leftmost name the chain hangs off — what
95
+ * this index can DEMONSTRATE. Three answers, and the asymmetry between them is
96
+ * the whole point:
97
+ *
98
+ * - `in-program` — the base's declared type resolves here, or the base itself is
99
+ * a class, a qualified name, or a value this program declares. A real edge was
100
+ * lost; the hedge must fire.
101
+ * - `external` — POSITIVE evidence that the target is outside: the language
102
+ * itself names the base (or its bare declared type) a built-in. `console.log`,
103
+ * `fetch(...)`, `JSON.stringify` reach code no index contains, so there is no
104
+ * node an edge could have pointed at and nothing was lost.
105
+ * - `unknown` — everything else. An absence of evidence is NOT evidence of
106
+ * externality: an unannotated parameter (`function f(svc) { svc.a().b(); }`)
107
+ * is recorded nowhere in the scope model at all, and calling that "external"
108
+ * published `epistemic: 'exact'` over a genuinely missing in-program caller —
109
+ * strictly worse than hedging, because it is a confident wrong answer rather
110
+ * than an admitted gap. `unknown` counts WITH `in-program` in
111
+ * `summarizeUnresolvedReceivers`, which is the safe direction.
112
+ *
113
+ * Uses the AST-derived chain base when one was minted, and falls back to the
114
+ * head of the receiver text otherwise — never a regex over the source line.
115
+ *
116
+ * Exported for the unit tests that pin the three-way split; the pass is its only
117
+ * production caller.
118
+ */
119
+ function classifyReceiverOrigin(decoded, inScope, receiverName, scopes, options = {}) {
120
+ // The chain's base is authoritative. Without one, take the head of the
121
+ // receiver text up to the first member/call punctuation.
122
+ const base = decoded?.baseReceiverName ?? /^[A-Za-z_$][\w$]*/.exec(receiverName)?.[0];
123
+ if (base === undefined || base.length === 0)
124
+ return 'unknown';
125
+ const strip = options.stripTypePreservingDecoration;
126
+ const isBuiltIn = options.isBuiltInName;
127
+ // The base's declared TYPE, when it has one, is the strongest signal about
128
+ // where the member lives: `inputs.stream()` has an in-program base bound to
129
+ // `List<String>`, whose `stream` is in the JDK.
130
+ const binding = (0, walkers_js_1.findReceiverTypeBinding)(inScope, base, scopes);
131
+ if (binding !== undefined) {
132
+ // `resolveClassBindingForName`, not a bare lookup: it also strips template
133
+ // arguments, so an in-program generic base (`Box<String> b; b.open()`)
134
+ // resolves instead of being mislabelled and dropped from the hedge.
135
+ if ((0, walkers_js_1.resolveClassBindingForName)(binding.declaredAtScope, binding.rawName, scopes, strip) !==
136
+ undefined) {
137
+ return 'in-program';
138
+ }
139
+ // The declared type is not one this index contains. That is only proof of
140
+ // externality when the language itself names it — otherwise the type merely
141
+ // failed to resolve (an alias, an inferred callable, a generic parameter),
142
+ // and we fall through to ask what the index knows about the base itself.
143
+ if (isBareTypeName(binding.rawName) && isBuiltIn?.(binding.rawName) === true) {
144
+ return 'external';
145
+ }
146
+ }
147
+ // Anything else this index knows by that name (namespace, module, free fn).
148
+ // O(1), so it goes ahead of the scope-chain walks below: all three checks are
149
+ // arms of the same `in-program` disjunction and none has a side effect, so
150
+ // answering from the index first is free and changes no verdict.
151
+ if (scopes.qualifiedNames.has(base))
152
+ return 'in-program';
153
+ // A type the program declares, used as a static receiver.
154
+ if ((0, walkers_js_1.findClassBindingInScope)(inScope, base, scopes, strip) !== undefined)
155
+ return 'in-program';
156
+ // A VALUE the program declares — an object-literal service, a local whose
157
+ // initializer we could not type (`const loc = makeIt(); loc.getUser().save()`),
158
+ // a field. The type channel had nothing usable to say about these, but the
159
+ // program demonstrably declares the name, so the lost edge is in-program and
160
+ // failing to type it is a resolver defect. This is the channel Case 5 already
161
+ // dispatches on; consulting it here keeps the diagnostic honest about the
162
+ // same population.
163
+ if ((0, walkers_js_1.findValueBindingInScope)(inScope, base, scopes) !== undefined)
164
+ return 'in-program';
165
+ // Positive external evidence, and the only kind reachable from this pass.
166
+ if (isBuiltIn?.(base) === true)
167
+ return 'external';
168
+ return 'unknown';
169
+ }
170
+ /**
171
+ * Upper bound on how many implementors ONE interface member may fan out to at a
172
+ * single call site (#2829).
173
+ *
174
+ * Mirrors `MAX_PROPERTY_DISPATCH_FANOUT` in `property-dispatch.ts`, deliberately
175
+ * including its reporting half: a bare cap would silently discard valid dispatch
176
+ * targets, which is the same false-safe silence #2813 was filed about. The
177
+ * default matches that sibling's 32 — the fan-out is a per-call-site product, so
178
+ * an interface with hundreds of implementors (mock proliferation is the usual
179
+ * cause) multiplies the graph without adding information a reader can act on.
180
+ *
181
+ * Override with `CGRAPH_MAX_INTERFACE_DISPATCH_FANOUT` for a repo with
182
+ * legitimately high implementor counts.
183
+ */
184
+ exports.MAX_INTERFACE_DISPATCH_FANOUT = (() => {
185
+ const env = Number(process.env.CGRAPH_MAX_INTERFACE_DISPATCH_FANOUT);
186
+ return Number.isInteger(env) && env >= 1 ? env : 32;
187
+ })();
188
+ /** Bound on the sample of over-cap interface members kept for the warning. */
189
+ const MAX_REPORTED_SKIPPED_INTERFACES = 20;
190
+ function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, handledSites, provider, index, model, options = {}) {
191
+ let emitted = 0;
192
+ let dispatchFanoutSkipped = 0;
193
+ const dispatchFanoutSkippedNames = [];
194
+ // Per-pass dedup so the multiple cases don't double-emit if two of
195
+ // them resolve the same site to the same target. NEVER pre-seed
196
+ // from the reference index — see Contract Invariant I5.
197
+ const seen = new Set();
198
+ const fieldFallback = provider.fieldFallbackOnMethodLookup ?? true;
199
+ const collapse = provider.collapseMemberCallsByCallerTarget === true;
200
+ const hoistTypeBindingsToModule = provider.hoistTypeBindingsToModule === true;
201
+ const compoundOpts = {
202
+ fieldFallback,
203
+ elementTypeOf: provider.elementTypeOf,
204
+ hoistTypeBindingsToModule,
205
+ stripReceiverCastExpressions: provider.stripReceiverCastExpressions === true,
206
+ constructionSyntax: provider.constructionSyntax,
207
+ stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
208
+ resolveThisViaEnclosingClass: provider.resolveThisViaEnclosingClass,
209
+ };
210
+ // Loop-invariant: both hooks come off the pass arguments, so the options bag
211
+ // for `classifyReceiverOrigin` is built once here rather than per dropped site.
212
+ const receiverOriginOpts = {
213
+ stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
214
+ isBuiltInName: options.isBuiltInName,
215
+ };
216
+ // Build an interface → implementors map from IMPLEMENTS edges.
217
+ // Maps Interface graph-id → list of implementor class scope-def-ids.
218
+ // We translate graph-ids back to scope-resolution DefIds via
219
+ // `parsedFiles.localDefs` lookup so downstream `findOwnedMember`
220
+ // (which keys by DefId) can find the implementor's members.
221
+ const graphIdToClassDef = new Map();
222
+ for (const parsed of parsedFiles) {
223
+ for (const def of parsed.localDefs) {
224
+ if (def.type !== 'Class' && def.type !== 'Struct' && def.type !== 'Interface')
225
+ continue;
226
+ const graphId = (0, ids_js_1.resolveDefGraphId)(parsed.filePath, def, nodeLookup);
227
+ if (graphId !== undefined)
228
+ graphIdToClassDef.set(graphId, def);
229
+ }
230
+ }
231
+ // Direct subtypes of a type, keyed by the SUPERtype's def id.
232
+ //
233
+ // Built from IMPLEMENTS **and** EXTENDS (#2829). IMPLEMENTS alone is not the
234
+ // set of implementations: `preEmitInheritanceEdges` classifies heritage by the
235
+ // TARGET's kind, so `interface B extends A` is stored as `B IMPLEMENTS A` and
236
+ // an INTERFACE lands in A's list; and a concrete class reaches its interface
237
+ // through `class C extends AbstractBase` (EXTENDS) + `AbstractBase implements
238
+ // I` (IMPLEMENTS), so it is two hops away and invisible to a depth-1 walk.
239
+ // Both shapes previously ended the fan-out on a bodiless declaration while the
240
+ // only executable target got no edge at all.
241
+ const subtypesBySupertypeDefId = new Map();
242
+ const addSubtype = (superId, sub) => {
243
+ let list = subtypesBySupertypeDefId.get(superId);
244
+ if (list === undefined) {
245
+ list = [];
246
+ subtypesBySupertypeDefId.set(superId, list);
247
+ }
248
+ list.push(sub);
249
+ };
250
+ for (const relType of ['IMPLEMENTS', 'EXTENDS']) {
251
+ for (const rel of graph.iterRelationshipsByType(relType)) {
252
+ const superDef = graphIdToClassDef.get(rel.targetId);
253
+ const subDef = graphIdToClassDef.get(rel.sourceId);
254
+ if (superDef === undefined || subDef === undefined)
255
+ continue;
256
+ addSubtype(superDef.nodeId, subDef);
257
+ }
258
+ }
259
+ /**
260
+ * Is this member a bodiless DECLARATION rather than an implementation?
261
+ *
262
+ * An interface method, and an `abstract` method on an abstract base, are
263
+ * both declarations: dispatching to them names something with no body while
264
+ * the executable target sits further down the hierarchy. `isAbstract` lives
265
+ * on the graph NODE (the structure phase sets it), not on `SymbolDefinition`,
266
+ * so this resolves the def to its node. A def that cannot be resolved is
267
+ * treated as NOT abstract — the fail-open direction, matching how the rest of
268
+ * this pass treats an unresolvable lookup.
269
+ */
270
+ const isDeclarationOnly = (def) => {
271
+ const graphId = (0, ids_js_1.resolveDefGraphId)(def.filePath, def, nodeLookup);
272
+ if (graphId === undefined)
273
+ return false;
274
+ return graph.getNode(graphId)?.properties.isAbstract === true;
275
+ };
276
+ /**
277
+ * Can an INSTANCE-typed receiver reach this member? A static member cannot be,
278
+ * ever — `class C implements I { static save() {} }` does not satisfy `I`
279
+ * (TypeScript rejects it outright as TS2420, "Property 'save' is missing"), so
280
+ * an edge to it from an `I`-typed receiver names a target no dispatch can
281
+ * produce. Every comparable tool draws the same line: tsserver partitions
282
+ * static from instance results, clangd gates on `isVirtual()` (C++ forbids
283
+ * virtual statics), jdtls filters abstract-or-static, and class-hierarchy
284
+ * analysis expands only VIRTUAL call sites — a static call already has exactly
285
+ * one target and needs no fan-out.
286
+ *
287
+ * Two sources answer this, and the order matters:
288
+ *
289
+ * 1. `provider.isStaticOnly` when the language declares it. It is the
290
+ * precise answer, because a language that needs the distinction defines
291
+ * it exactly — Kotlin marks only COMPANION-promoted defs, so a Kotlin
292
+ * `object Impl : Iface { override fun handle() }` is correctly kept: an
293
+ * `object` is a singleton INSTANCE and its members really are reachable
294
+ * through an `Iface`-typed receiver.
295
+ * 2. Otherwise the graph node's `isStatic`. For every language that does not
296
+ * declare the hook, that flag comes from the member's own modifier (or,
297
+ * for Ruby, from `singleton_class` — `def self.foo`, which is likewise
298
+ * unreachable through an instance), so it means what we need here.
299
+ *
300
+ * Getting that order wrong is a live regression, not a hypothetical: the
301
+ * method extractor derives `isStatic` from the OWNER type as well as the
302
+ * member (`method-extractors/generic.ts`, `staticOwnerTypes`), and the JVM
303
+ * config lists `object_declaration`. Reading the flag first would delete
304
+ * Kotlin object implementations from the fan-out. A language that needs
305
+ * precision declares the hook; that is the upgrade path.
306
+ *
307
+ * Unresolvable defs fail open (treated as reachable), matching
308
+ * `isDeclarationOnly` and the rest of this pass.
309
+ */
310
+ const isUnreachableByInstanceDispatch = (def) => {
311
+ const staticOnly = provider.isStaticOnly;
312
+ if (staticOnly !== undefined)
313
+ return staticOnly(def) === true;
314
+ const graphId = (0, ids_js_1.resolveDefGraphId)(def.filePath, def, nodeLookup);
315
+ if (graphId === undefined)
316
+ return false;
317
+ return graph.getNode(graphId)?.properties.isStatic === true;
318
+ };
319
+ /**
320
+ * Emit secondary CALLS edges with reason='interface-dispatch' when the primary
321
+ * receiver-typed edge targeted an Interface's method.
322
+ *
323
+ * Walks the SUBTYPE CLOSURE of the interface rather than its direct
324
+ * implementors (#2829). Two shapes made the depth-1 walk both wrong and
325
+ * incomplete, each reproduced in plain Java:
326
+ *
327
+ * interface ReadCloser extends Reader { int read(String p); } // re-declares
328
+ * abstract class AbstractHandler implements Handler { public abstract void handle(String s); }
329
+ *
330
+ * In both, the depth-1 list contains a type whose `read`/`handle` is a bodiless
331
+ * declaration, so the fan-out emitted an edge to *that* — while the only class
332
+ * with a body (`FileRC`, `RealHandler`) is one hop further down and received
333
+ * nothing at all. Descending and skipping declarations fixes both directions
334
+ * at once: the wrong edge disappears and the real implementation gains one.
335
+ *
336
+ * Descent continues THROUGH a type that supplied a concrete member, because an
337
+ * override further down is an equally real runtime target — dispatch is an
338
+ * over-approximation by design, and stopping early would silently prefer the
339
+ * base.
340
+ */
341
+ const emitInterfaceDispatchFor = (ownerDef, memberName, primaryMemberDef, site, confidence, calleeCapture) => {
342
+ if (ownerDef.type !== 'Interface')
343
+ return 0;
344
+ if (subtypesBySupertypeDefId.get(ownerDef.nodeId) === undefined)
345
+ return 0;
346
+ // Collect concrete targets across the closure first, so the cap below counts
347
+ // real dispatch targets rather than types visited.
348
+ const targets = [];
349
+ const seenTypes = new Set([ownerDef.nodeId]);
350
+ const queue = [ownerDef.nodeId];
351
+ while (queue.length > 0) {
352
+ const superId = queue.shift();
353
+ for (const subDef of subtypesBySupertypeDefId.get(superId) ?? []) {
354
+ if (seenTypes.has(subDef.nodeId))
355
+ continue;
356
+ seenTypes.add(subDef.nodeId);
357
+ queue.push(subDef.nodeId);
358
+ const implMember = pickOverload(subDef.nodeId, memberName, site, model, provider);
359
+ if (implMember === undefined ||
360
+ implMember === exports.OVERLOAD_AMBIGUOUS ||
361
+ implMember.isDeleted === true) {
362
+ continue;
363
+ }
364
+ if (implMember.nodeId === primaryMemberDef.nodeId)
365
+ continue;
366
+ // A re-declared interface method or an `abstract` override is not an
367
+ // implementation — keep descending past it rather than emitting to it.
368
+ if (isDeclarationOnly(implMember))
369
+ continue;
370
+ // Nor is a static member: no instance-typed receiver can reach one, so
371
+ // an edge to it is a target dispatch cannot produce (#2842 review).
372
+ if (isUnreachableByInstanceDispatch(implMember))
373
+ continue;
374
+ targets.push(implMember);
375
+ }
376
+ }
377
+ // Bounded, and NEVER silently (#2829). An interface with a very large
378
+ // implementor set multiplies edges by every call site — Go, TypeScript and
379
+ // Kotlin do not set `collapseMemberCallsByCallerTarget`, so the product is
380
+ // per SITE. Truncating without saying so would recreate the false-safe
381
+ // silence this whole issue is about, which is why the sibling
382
+ // `MAX_PROPERTY_DISPATCH_FANOUT` reports its dropped keys too.
383
+ if (targets.length > exports.MAX_INTERFACE_DISPATCH_FANOUT) {
384
+ dispatchFanoutSkipped += targets.length - exports.MAX_INTERFACE_DISPATCH_FANOUT;
385
+ if (dispatchFanoutSkippedNames.length < MAX_REPORTED_SKIPPED_INTERFACES) {
386
+ dispatchFanoutSkippedNames.push(`${ownerDef.qualifiedName ?? ownerDef.nodeId}.${memberName} (${targets.length} targets)`);
387
+ }
388
+ targets.length = exports.MAX_INTERFACE_DISPATCH_FANOUT;
389
+ }
390
+ let n = 0;
391
+ for (const implMember of targets) {
392
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, implMember, 'interface-dispatch', seen, confidence, collapse, calleeCapture);
393
+ if (ok)
394
+ n++;
395
+ }
396
+ return n;
397
+ };
398
+ /**
399
+ * Declared type of the CLASS-LEVEL field named `fieldName` on `ownerId`, or
400
+ * `undefined` when the owner declares no such field, declares only an
401
+ * instance one, or declares one whose type was never captured.
402
+ *
403
+ * Both facts live on the graph NODE rather than on `SymbolDefinition` —
404
+ * `isStatic` is set by the structure phase and `declaredType` by the field
405
+ * extractor — which is the same place {@link isUnreachableByInstanceDispatch}
406
+ * reads `isStatic` from, so this introduces no new dependency.
407
+ *
408
+ * `isStatic === true` is required, not merely preferred. The receiver that
409
+ * asks this question resolved its head to the CLASS, so an instance field of
410
+ * that name is not reachable through it and answering with the instance
411
+ * field's type would type the receiver as something the source cannot
412
+ * denote. A def that resolves to no node, or a node with no captured type,
413
+ * answers `undefined` — the declining direction, matching how the rest of
414
+ * this pass treats an unresolvable lookup.
415
+ */
416
+ const declaredTypeOfClassLevelField = (ownerId, fieldName) => {
417
+ for (const candidate of model.fields.lookupAllByOwner(ownerId, fieldName)) {
418
+ const graphId = (0, ids_js_1.resolveDefGraphId)(candidate.filePath, candidate, nodeLookup);
419
+ if (graphId === undefined)
420
+ continue;
421
+ const properties = graph.getNode(graphId)?.properties;
422
+ if (properties?.isStatic !== true)
423
+ continue;
424
+ const declaredType = properties.declaredType;
425
+ if (typeof declaredType !== 'string')
426
+ continue;
427
+ const trimmed = declaredType.trim();
428
+ if (trimmed.length === 0)
429
+ continue;
430
+ return trimmed;
431
+ }
432
+ return undefined;
433
+ };
434
+ for (const parsed of parsedFiles) {
435
+ const namespaceTargets = (0, namespace_targets_js_1.collectNamespaceTargets)(parsed, scopes, {
436
+ receiverPaths: provider.namespaceReceiverPaths,
437
+ moduleFileExists: (filePath) => index.moduleScopeByFile.has(filePath),
438
+ });
439
+ const fileCompoundOpts = { ...compoundOpts, namespaceTargets };
440
+ // Per-file resolved-callee-id capture context (#2227 U2). Built once per
441
+ // file; `undefined` when the sink is absent (pdg off) so the `tryEmitEdge`
442
+ // capture is a no-op and emission stays byte-identical (R4).
443
+ const calleeCapture = options.calleeIdSink !== undefined
444
+ ? { sink: options.calleeIdSink, filePath: parsed.filePath }
445
+ : undefined;
446
+ for (const site of parsed.referenceSites) {
447
+ if (site.kind !== 'call' && site.kind !== 'read' && site.kind !== 'write')
448
+ continue;
449
+ if (site.explicitReceiver === undefined)
450
+ continue;
451
+ const receiverName = site.explicitReceiver.name;
452
+ const memberName = site.name;
453
+ const siteKey = `${parsed.filePath}:${site.atRange.startLine}:${site.atRange.startCol}`;
454
+ // ── owned-but-unbound receiver ───────────────────────────────
455
+ // The language declared this scope REBINDS the receiver and gave
456
+ // it no type — a JS/TS ordinary `function`, whose `this` comes
457
+ // from the call site (#2701). No enclosing type can be its type,
458
+ // so this is a definitive negative, not a miss: suppress the site
459
+ // instead of letting the receiver-blind lexical fallback in
460
+ // `lookupCore` match the enclosing class's member by name.
461
+ // No-op for every language that leaves `Scope.ownsReceivers` unset.
462
+ if ((0, walkers_js_1.isReceiverOwnedButUnbound)(site.inScope, receiverName, scopes)) {
463
+ options.recordResolutionOutcome?.({
464
+ kind: 'suppressed',
465
+ phase: 'receiver-bound-calls',
466
+ filePath: parsed.filePath,
467
+ name: site.name,
468
+ range: site.atRange,
469
+ reason: 'receiver-owned-but-unbound',
470
+ candidateIds: [],
471
+ });
472
+ handledSites.add(siteKey);
473
+ continue;
474
+ }
475
+ // ── super branch ─────────────────────────────────────────────
476
+ // Languages with caller-context-dependent super classification
477
+ // (C++) define `isSuperReceiverInContext`; we prefer it. Simple
478
+ // text-only languages (Python, Java, PHP) use the plain hook.
479
+ const isSuper = provider.isSuperReceiverInContext !== undefined
480
+ ? provider.isSuperReceiverInContext(receiverName, site.inScope, scopes)
481
+ : provider.isSuperReceiver(receiverName);
482
+ if (isSuper) {
483
+ const enclosingClass = (0, walkers_js_1.findEnclosingClassDef)(site.inScope, scopes);
484
+ if (enclosingClass !== undefined) {
485
+ // For super-receiver dispatch (`parent::`, `base.`, `super()`),
486
+ // walk the inheritance-only ancestor chain when the language
487
+ // exposes it. PHP's `parent::` semantically bypasses composed
488
+ // traits; other languages without mixin augmentation have no
489
+ // `extendsOnlyMroFor` and fall back to `mroFor`.
490
+ const extendsOnly = scopes.methodDispatch.extendsOnlyMroFor;
491
+ const ancestors = extendsOnly !== undefined
492
+ ? extendsOnly(enclosingClass.nodeId)
493
+ : scopes.methodDispatch.mroFor(enclosingClass.nodeId);
494
+ let memberDef;
495
+ let ambiguousOwnerId;
496
+ for (const ownerId of ancestors) {
497
+ const picked = site.kind === 'call'
498
+ ? pickOverload(ownerId, memberName, site, model, provider)
499
+ : (0, walkers_js_1.findOwnedMember)(ownerId, memberName, model);
500
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
501
+ ambiguousOwnerId = ownerId;
502
+ break;
503
+ }
504
+ if (picked !== undefined) {
505
+ memberDef = picked;
506
+ break;
507
+ }
508
+ }
509
+ if (ambiguousOwnerId !== undefined) {
510
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
511
+ handledSites.add(siteKey);
512
+ continue;
513
+ }
514
+ if (memberDef !== undefined) {
515
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
516
+ handledSites.add(siteKey);
517
+ continue;
518
+ }
519
+ // Super/base calls resolve through the MRO chain, not
520
+ // through imports — the ancestor method is found by
521
+ // walking `methodDispatch.mroFor(enclosingClass)`, which
522
+ // is independent of whether a `using` / `import` directive
523
+ // brought the ancestor into scope. We emit the canonical
524
+ // `'global'` tier (ARCHITECTURE.md § Scope-Resolution
525
+ // Pipeline — edge vocabulary).
526
+ //
527
+ // Known legacy-path asymmetry: the C# legacy DAG also
528
+ // classifies `base.Save()` as `'global'` (same-graph); the
529
+ // Python legacy DAG classifies `super().save()` as
530
+ // `'import-resolved'` because Python's ancestor lookup
531
+ // flows through `typeEnv.lookup(...)` which resolves the
532
+ // superclass via its `import`/`from … import …` binding.
533
+ // Closing that gap requires realigning the legacy tier
534
+ // classifier and is tracked separately.
535
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, 'global', seen, 0.85, collapse, calleeCapture);
536
+ if (ok)
537
+ emitted++;
538
+ // Always mark handled when the site was resolved, even
539
+ // if the edge was deduplicated (collapse mode), so
540
+ // `emitReferencesViaLookup` doesn't re-emit from the
541
+ // reference index.
542
+ handledSites.add(siteKey);
543
+ continue;
544
+ }
545
+ }
546
+ }
547
+ // ── Case 0: compound receiver ────────────────────────────────
548
+ // #2744: remember a compound receiver we could not type. Reported at
549
+ // the end of the site loop, not here — a later case may still resolve
550
+ // the site, and only a site that survives every case is a real drop.
551
+ let compoundReceiverUnresolved = false;
552
+ // The punctuation test is a C-family heuristic and it is the reason
553
+ // `repos[0].save()` is INVISIBLE in all 14 languages: a subscript receiver
554
+ // contains neither `.` nor `(`, so this case never fired, the fold was
555
+ // never consulted, and no drop was recorded either — the call vanished
556
+ // with the instrument blind to it. PHP `->` and `::` receivers are lost
557
+ // the same way.
558
+ //
559
+ // A minted receiver chain is the STRUCTURAL answer to the same question:
560
+ // the capture layer walked the real AST and found the receiver is an
561
+ // expression, whatever punctuation it happens to be spelled with. Trusting
562
+ // that instead of the text is the substitution this whole line of work
563
+ // exists to make.
564
+ if (receiverName.includes('.') ||
565
+ receiverName.includes('(') ||
566
+ site.receiverChain !== undefined) {
567
+ const currentClass = (0, compound_receiver_js_1.resolveCompoundReceiverClass)(receiverName, site.inScope, scopes, index,
568
+ // Group A: the receiver IS this site's expression, so the site's
569
+ // captured chain describes it and the structural fold applies.
570
+ { ...fileCompoundOpts, receiverChain: site.receiverChain });
571
+ compoundReceiverUnresolved = currentClass === undefined;
572
+ if (currentClass !== undefined) {
573
+ const chain = [currentClass.nodeId, ...scopes.methodDispatch.mroFor(currentClass.nodeId)];
574
+ let memberDef;
575
+ let ambiguousOwnerId;
576
+ // Static-only filter (#1756 / U3): same shape as Case 4's
577
+ // overload-aware chain walk (skip-and-walk-on). When
578
+ // an owner's resolved candidate is static-only (Kotlin
579
+ // companion-promoted), continue to the next ancestor in
580
+ // the MRO chain so a legitimate instance member can bind.
581
+ // If the entire chain is static-only, no edge is emitted —
582
+ // unlike Case 4, Case 0 does NOT mark the site handled in
583
+ // that situation because compound receivers (`a.b.c()`)
584
+ // are not pre-emitted by `emitReferencesViaLookup` (the
585
+ // reference index has no compound-receiver entry for
586
+ // shapes like `Logger.create("a")`), so there's no wrong
587
+ // target to suppress.
588
+ for (const ownerId of chain) {
589
+ const picked = site.kind === 'call'
590
+ ? pickFirstNonStaticOnly(ownerId, memberName, site, model, provider)
591
+ : (0, walkers_js_1.findOwnedMember)(ownerId, memberName, model);
592
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
593
+ ambiguousOwnerId = ownerId;
594
+ break;
595
+ }
596
+ if (picked === STATIC_ONLY_FILTERED || picked === undefined) {
597
+ continue;
598
+ }
599
+ memberDef = picked;
600
+ break;
601
+ }
602
+ if (ambiguousOwnerId !== undefined) {
603
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
604
+ handledSites.add(siteKey);
605
+ continue;
606
+ }
607
+ if (memberDef !== undefined) {
608
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
609
+ handledSites.add(siteKey);
610
+ continue;
611
+ }
612
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
613
+ if (ok)
614
+ emitted++;
615
+ // Interface dispatch, exactly as Case 4 does it (#2813). When the
616
+ // folded receiver type is an Interface, the primary edge above
617
+ // lands on the interface's own method DECLARATION; these secondary
618
+ // edges are what reach the implementations.
619
+ //
620
+ // Case 4 had this and Case 0 did not, which made the gap a property
621
+ // of receiver SYNTAX rather than of types: a struct-field receiver
622
+ // (`s.orderRepo`) contains a dot, so it always takes Case 0, while
623
+ // the same interface reached through a local or parameter is a bare
624
+ // name and reaches Case 4. Field-held interfaces — dependency
625
+ // injection, in other words — were the half that silently lost every
626
+ // implementation edge.
627
+ //
628
+ // `currentClass` is the receiver's own folded type, matching what
629
+ // Case 4 passes. `emitInterfaceDispatchFor` self-gates on
630
+ // `ownerDef.type !== 'Interface'`, so this is inert for every
631
+ // concrete receiver and needs no language check of its own — a
632
+ // member whose owner resolved to a Struct emits nothing extra.
633
+ //
634
+ // Confidence mirrors THIS case's own primary emit above — the 0.85
635
+ // literal — so a site's dispatch edges never claim more certainty
636
+ // than the edge they hang off.
637
+ //
638
+ // Case 4 passes a site.kind-dependent value instead (1.0 for
639
+ // read/write, `:1399-1405`) because ITS primary varies the same way.
640
+ // Case 0 does branch on `site.kind` when picking the member
641
+ // (`:713-716`), it simply does not vary reason/confidence with it,
642
+ // so there is no 1.0 arm here to mirror. That leaves a read/write
643
+ // ACCESSES through a compound receiver at 0.85 while the same access
644
+ // through a bare name is 1.0 — a PRE-EXISTING difference between the
645
+ // two cases' primaries, not something this fan-out introduces.
646
+ // Deliberately not "fixed" here: changing Case 0's primary
647
+ // confidence is a separate behavioural change affecting every
648
+ // language, and is out of scope for #2813.
649
+ emitted += emitInterfaceDispatchFor(currentClass, memberName, memberDef, site, 0.85, calleeCapture);
650
+ // Always mark handled when the site was resolved, even
651
+ // if the edge was deduplicated (collapse mode), so
652
+ // `emitReferencesViaLookup` doesn't re-emit from the
653
+ // reference index.
654
+ handledSites.add(siteKey);
655
+ continue;
656
+ }
657
+ }
658
+ }
659
+ // ── Case 0.5: implicit `this` receiver ───────────────────────
660
+ // C++ `this->member()` (and same-shape receivers in other OO
661
+ // languages) should resolve against the enclosing class + MRO
662
+ // even when there is no explicit `this` typeBinding in scope.
663
+ //
664
+ // **Static-only filter dependency (#1756 / U3):** this case does
665
+ // NOT currently consult `provider.isStaticOnly`. Today it fires
666
+ // only for C++ (the sole `resolveThisViaEnclosingClass === true`
667
+ // language), which has no static-only semantics. Kotlin — the
668
+ // current `isStaticOnly` consumer — leaves `resolveThisVia
669
+ // EnclosingClass` unset, so Case 0.5 is dead code for Kotlin
670
+ // crossover suppression and U3 leaves it untouched. If any
671
+ // future language enables BOTH `resolveThisViaEnclosingClass`
672
+ // AND `isStaticOnly`, the chain-walk below MUST adopt the
673
+ // skip-and-walk-on filter pattern used by Cases 0, 3b, and 4.
674
+ if (provider.resolveThisViaEnclosingClass === true && receiverName === 'this') {
675
+ const enclosingClass = (0, walkers_js_1.findEnclosingClassDef)(site.inScope, scopes);
676
+ if (enclosingClass !== undefined) {
677
+ const languageResolution = provider.resolveReceiverMember?.(enclosingClass, memberName, site, scopes, model);
678
+ if (languageResolution?.kind === 'ambiguous') {
679
+ options.recordResolutionOutcome?.({
680
+ kind: 'suppressed',
681
+ phase: 'receiver-bound-calls',
682
+ filePath: parsed.filePath,
683
+ name: site.name,
684
+ range: site.atRange,
685
+ reason: 'member-lookup-ambiguous',
686
+ candidateIds: languageResolution.candidateIds,
687
+ });
688
+ handledSites.add(siteKey);
689
+ continue;
690
+ }
691
+ if (languageResolution?.kind === 'resolved') {
692
+ const memberDef = languageResolution.definition;
693
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
694
+ handledSites.add(siteKey);
695
+ continue;
696
+ }
697
+ const reason = site.kind === 'write' || site.kind === 'read'
698
+ ? site.kind
699
+ : memberDef.filePath !== parsed.filePath
700
+ ? 'import-resolved'
701
+ : 'global';
702
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
703
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
704
+ if (ok)
705
+ emitted++;
706
+ handledSites.add(siteKey);
707
+ continue;
708
+ }
709
+ const chain = [
710
+ enclosingClass.nodeId,
711
+ ...scopes.methodDispatch.mroFor(enclosingClass.nodeId),
712
+ ];
713
+ let memberDef;
714
+ let ambiguous = false;
715
+ let hiddenByName = false;
716
+ for (const ownerId of chain) {
717
+ const methodOverloads = model.methods.lookupAllByOwner(ownerId, memberName);
718
+ if (methodOverloads.length > 0) {
719
+ const narrowed = (0, overload_narrowing_js_1.narrowOverloadCandidates)(methodOverloads, site.arity, site.argumentTypes, {
720
+ argumentTypeClasses: site.argumentTypeClasses,
721
+ conversionRankFn: provider.conversionRankFn,
722
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
723
+ constraintCompatibility: provider.constraintCompatibility,
724
+ });
725
+ if ((0, overload_narrowing_js_1.isOverloadAmbiguousAfterNormalization)(narrowed, site.arity)) {
726
+ ambiguous = true;
727
+ break;
728
+ }
729
+ if (narrowed.length === 0) {
730
+ // C++ name hiding: if the derived class declares `f`, base-class
731
+ // overloads named `f` are hidden for member lookup
732
+ // ([basic.lookup.classref]). A non-viable derived overload set
733
+ // therefore terminates lookup instead of falling through to base.
734
+ hiddenByName = true;
735
+ break;
736
+ }
737
+ // Multiple tied survivors with distinct param types (e.g.
738
+ // h(int,double) vs h(double,int) both scoring 2) → ambiguous.
739
+ if (narrowed.length > 1) {
740
+ ambiguous = true;
741
+ break;
742
+ }
743
+ memberDef = narrowed[0] ?? methodOverloads[0];
744
+ break;
745
+ }
746
+ // Field/property lookup intentionally runs only after the method
747
+ // lookup above: in C++ member-name lookup, functions with this
748
+ // name hide same-named base members; we therefore prefer method
749
+ // candidates first and only target a field when no methods with
750
+ // this name exist on the current owner.
751
+ memberDef = model.fields.lookupFieldByOwner(ownerId, memberName);
752
+ if (memberDef !== undefined) {
753
+ break;
754
+ }
755
+ }
756
+ if (ambiguous) {
757
+ handledSites.add(siteKey);
758
+ continue;
759
+ }
760
+ if (hiddenByName) {
761
+ handledSites.add(siteKey);
762
+ continue;
763
+ }
764
+ if (memberDef !== undefined) {
765
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
766
+ handledSites.add(siteKey);
767
+ continue;
768
+ }
769
+ const reason = site.kind === 'write' || site.kind === 'read'
770
+ ? site.kind
771
+ : memberDef.filePath !== parsed.filePath
772
+ ? 'import-resolved'
773
+ : 'global';
774
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
775
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
776
+ if (ok)
777
+ emitted++;
778
+ handledSites.add(siteKey);
779
+ continue;
780
+ }
781
+ }
782
+ }
783
+ // ── Case 1: namespace receiver ───────────────────────────────
784
+ // `namespaceTargets` is collected per FILE, so a local declaration that
785
+ // shadows the import must suppress it — `def f(pkg): pkg.db.query()`
786
+ // calls a method on the PARAMETER, and resolving it through the import
787
+ // emits a wrong edge, not a missing one. The compound-receiver
788
+ // construction path has applied this guard since #2770; Case 1 never did,
789
+ // for dotted and single-segment receivers alike.
790
+ // Map lookup FIRST: it is an O(1) miss for almost every site, and the
791
+ // guard is a scope-chain walk (a Set allocation plus a linear `ownedDefs`
792
+ // scan per level). Guarding before looking up would charge that walk to
793
+ // every explicit-receiver site in every language, for a candidate set
794
+ // that is usually empty. Mirrors the order the compound-receiver
795
+ // construction path already uses.
796
+ const namespaceCandidates = namespaceTargets.get(receiverName);
797
+ const targetFiles = namespaceCandidates !== undefined &&
798
+ !(0, walkers_js_1.isNamespaceNameShadowed)(receiverName, site.inScope, scopes)
799
+ ? namespaceCandidates
800
+ : undefined;
801
+ if (targetFiles !== undefined && provider.resolveQualifiedReceiverMember === undefined) {
802
+ let found = false;
803
+ for (const targetFile of targetFiles) {
804
+ const memberDef = (0, walkers_js_1.findExportedDef)(targetFile, memberName, index);
805
+ if (memberDef !== undefined) {
806
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
807
+ handledSites.add(siteKey);
808
+ found = true;
809
+ break;
810
+ }
811
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
812
+ if (ok)
813
+ emitted++;
814
+ handledSites.add(siteKey);
815
+ found = true;
816
+ break;
817
+ }
818
+ }
819
+ if (found)
820
+ continue;
821
+ }
822
+ // ── Case 1.5: qualified namespace-receiver (language-specific) ───
823
+ // Languages whose qualified-name semantics need workspace-wide
824
+ // namespace-scope walking (C++ `outer::foo()`, including inline-
825
+ // namespace transitive traversal) implement `resolveQualifiedReceiverMember`.
826
+ // Runs before Case 2 so namespace receivers don't accidentally match a
827
+ // class with the same simple name.
828
+ if (provider.resolveQualifiedReceiverMember !== undefined) {
829
+ const memberDef = provider.resolveQualifiedReceiverMember(receiverName, memberName, site.inScope, scopes, parsedFiles, site);
830
+ if (memberDef === 'ambiguous') {
831
+ // Same-name ambiguity across inline-namespace children (#1564):
832
+ // suppress edge emission, mark site handled.
833
+ options.recordResolutionOutcome?.({
834
+ kind: 'suppressed',
835
+ phase: 'receiver-bound-calls',
836
+ filePath: parsed.filePath,
837
+ name: site.name,
838
+ range: site.atRange,
839
+ reason: 'inline-ns-ambiguous',
840
+ candidateIds: [],
841
+ });
842
+ handledSites.add(siteKey);
843
+ continue;
844
+ }
845
+ if (memberDef !== undefined) {
846
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
847
+ handledSites.add(siteKey);
848
+ continue;
849
+ }
850
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
851
+ if (ok)
852
+ emitted++;
853
+ handledSites.add(siteKey);
854
+ continue;
855
+ }
856
+ }
857
+ // ── Case 2: class-name receiver ──────────────────────────────
858
+ const classDef = (0, walkers_js_1.findClassBindingInScope)(site.inScope, receiverName, scopes);
859
+ if (classDef !== undefined) {
860
+ const chain = [classDef.nodeId, ...scopes.methodDispatch.mroFor(classDef.nodeId)];
861
+ let memberDef;
862
+ let ambiguousOwnerId;
863
+ for (const ownerId of chain) {
864
+ const picked = site.kind === 'call'
865
+ ? pickOverload(ownerId, memberName, site, model, provider)
866
+ : (0, walkers_js_1.findOwnedMember)(ownerId, memberName, model);
867
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
868
+ ambiguousOwnerId = ownerId;
869
+ break;
870
+ }
871
+ if (picked !== undefined) {
872
+ memberDef = picked;
873
+ // The MRO chain is most-derived-first ([classDef, ...ancestors]).
874
+ // If the most-derived definition is arity-incompatible with the
875
+ // call site, PHP throws ArgumentCountError at runtime — it does
876
+ // NOT silently dispatch to an ancestor. Terminate the chain walk
877
+ // so no edge is emitted, rather than falling through to an
878
+ // arity-compatible ancestor (which would be a false positive).
879
+ if ((0, overload_narrowing_js_1.narrowOverloadCandidates)([memberDef], site.arity, site.argumentTypes).length === 0) {
880
+ memberDef = undefined;
881
+ break;
882
+ }
883
+ break;
884
+ }
885
+ }
886
+ if (ambiguousOwnerId !== undefined) {
887
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
888
+ handledSites.add(siteKey);
889
+ continue;
890
+ }
891
+ if (memberDef !== undefined) {
892
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
893
+ handledSites.add(siteKey);
894
+ continue;
895
+ }
896
+ const reason = site.kind === 'write' || site.kind === 'read'
897
+ ? site.kind
898
+ : memberDef.filePath !== parsed.filePath
899
+ ? 'import-resolved'
900
+ : 'global';
901
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
902
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
903
+ if (ok)
904
+ emitted++;
905
+ handledSites.add(siteKey);
906
+ continue;
907
+ }
908
+ }
909
+ // ── Case 3: dotted typeBinding (`u: models.User`) ────────────
910
+ const typeRef = (0, walkers_js_1.findReceiverTypeBinding)(site.inScope, receiverName, scopes);
911
+ if (typeRef !== undefined && typeRef.rawName.includes('.')) {
912
+ const [nsName, ...classNameParts] = typeRef.rawName.split('.');
913
+ const className = classNameParts.join('.');
914
+ const targetFiles3 = namespaceTargets.get(nsName);
915
+ if (targetFiles3 !== undefined && className.length > 0) {
916
+ let found3 = false;
917
+ for (const targetFile3 of targetFiles3) {
918
+ const classDef3 = (0, walkers_js_1.findExportedDef)(targetFile3, className, index);
919
+ if (classDef3 !== undefined) {
920
+ const picked = site.kind === 'call'
921
+ ? pickOverload(classDef3.nodeId, memberName, site, model, provider)
922
+ : (0, walkers_js_1.findOwnedMember)(classDef3.nodeId, memberName, model);
923
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
924
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, classDef3.nodeId, memberName, model, provider);
925
+ handledSites.add(siteKey);
926
+ found3 = true;
927
+ break;
928
+ }
929
+ if (picked !== undefined) {
930
+ const memberDef = picked;
931
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
932
+ handledSites.add(siteKey);
933
+ found3 = true;
934
+ break;
935
+ }
936
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen,
937
+ // Explicit defaults so the trailing capture ctx (#2227 U2) can
938
+ // be threaded without changing dedup/confidence behavior.
939
+ 0.85, false, calleeCapture);
940
+ if (ok) {
941
+ emitted++;
942
+ handledSites.add(siteKey);
943
+ }
944
+ found3 = true;
945
+ break;
946
+ }
947
+ }
948
+ }
949
+ if (found3)
950
+ continue;
951
+ }
952
+ }
953
+ // ── Case 3b: chain-typebinding (`city → user.get_city`) ──────
954
+ // Also handles compound member-call rawNames (`city → addr.get_city()`)
955
+ // where the rawName includes both `.` and `()` — Ruby's
956
+ // member-call-return captures produce this shape.
957
+ const chainHead = typeRef !== undefined && typeRef.rawName.includes('.')
958
+ ? (typeRef.rawName.split('.', 1)[0] ?? '')
959
+ : undefined;
960
+ if (typeRef !== undefined && chainHead !== undefined && !namespaceTargets.has(chainHead)) {
961
+ // Try the plain dotted-field walk first — covers property /
962
+ // collection-accessor shapes (`.Values`, Kotlin `.size`) and
963
+ // field chains. Fall back to call-form (`x()`) which treats
964
+ // the last segment as a method invocation. For rawNames that
965
+ // already contain `()` (Ruby member-call-return captures),
966
+ // pass through directly — the compound resolver handles the
967
+ // full expression including the call syntax.
968
+ let ownerDef = (0, compound_receiver_js_1.resolveCompoundReceiverClass)(typeRef.rawName, typeRef.declaredAtScope, scopes, index, fileCompoundOpts);
969
+ if (ownerDef === undefined && !typeRef.rawName.includes('(')) {
970
+ ownerDef = (0, compound_receiver_js_1.resolveCompoundReceiverClass)(typeRef.rawName + '()', typeRef.declaredAtScope, scopes, index, fileCompoundOpts);
971
+ }
972
+ if (ownerDef !== undefined) {
973
+ const chain = [ownerDef.nodeId, ...scopes.methodDispatch.mroFor(ownerDef.nodeId)];
974
+ let memberDef;
975
+ let ambiguousOwnerId;
976
+ // Static-only filter (#1756 / U3): mirrors Case 0's
977
+ // overload-aware chain walk. When
978
+ // a static-only candidate is found at an ancestor, walk on
979
+ // so a legitimate instance member can bind. If the entire
980
+ // chain is static-only, no edge is emitted (Case 3b is fed
981
+ // by chain-typebinding receivers, not pre-emitted by
982
+ // `emitReferencesViaLookup` for compound shapes, so no
983
+ // handled-site marker is needed for chain-only-static).
984
+ for (const ownerId of chain) {
985
+ const picked = site.kind === 'call'
986
+ ? pickFirstNonStaticOnly(ownerId, memberName, site, model, provider)
987
+ : (0, walkers_js_1.findOwnedMember)(ownerId, memberName, model);
988
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
989
+ ambiguousOwnerId = ownerId;
990
+ break;
991
+ }
992
+ if (picked === STATIC_ONLY_FILTERED || picked === undefined) {
993
+ continue;
994
+ }
995
+ memberDef = picked;
996
+ break;
997
+ }
998
+ if (ambiguousOwnerId !== undefined) {
999
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
1000
+ handledSites.add(siteKey);
1001
+ continue;
1002
+ }
1003
+ if (memberDef !== undefined) {
1004
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
1005
+ handledSites.add(siteKey);
1006
+ continue;
1007
+ }
1008
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse, calleeCapture);
1009
+ if (ok)
1010
+ emitted++;
1011
+ // Interface dispatch, exactly as Cases 0 and 4 do it (#2832). Case
1012
+ // 3b folds a chain to a receiver type through the SAME
1013
+ // `resolveCompoundReceiverClass` call and the same MRO walk Case 0
1014
+ // uses, so when that fold lands on an Interface the primary edge
1015
+ // above names the interface's own bodiless DECLARATION and nothing
1016
+ // reaches the implementations.
1017
+ //
1018
+ // Leaving 3b out made the fan-out a property of how the receiver
1019
+ // was SPELLED rather than of what it resolved to: `d.repo.save()`
1020
+ // took Case 0 and fanned out, while binding the identical field to
1021
+ // a local first (`const r = d.repo; r.save()`) took Case 3b and
1022
+ // did not. #2829 closed that gap for Case 0 and left this half of
1023
+ // it open (#2832).
1024
+ //
1025
+ // `ownerDef` is the receiver's own folded type — matching Case 0's
1026
+ // `currentClass` and Case 4's `ownerDef` — NOT the owner of the
1027
+ // member the MRO walk settled on. That distinction matters: a
1028
+ // receiver that folds to a concrete class merely INHERITING an
1029
+ // interface method must not fan out, because its runtime type is
1030
+ // that class. `emitInterfaceDispatchFor` self-gates on
1031
+ // `ownerDef.type !== 'Interface'`, so this is inert for every
1032
+ // concrete receiver and needs no language check of its own.
1033
+ //
1034
+ // That gate is deliberately narrower than "the primary landed on
1035
+ // something bodiless": a chain folding to an ABSTRACT class also
1036
+ // dead-ends on a declaration-only member and does NOT fan out
1037
+ // here. Widening it to `|| isDeclarationOnly(memberDef)` would
1038
+ // cover that, but it changes Cases 0 and 4 identically and for
1039
+ // every language, so it is not #2832's to make.
1040
+ //
1041
+ // Confidence mirrors THIS case's own primary emit above — the 0.85
1042
+ // literal — so a site's dispatch edges never claim more certainty
1043
+ // than the edge they hang off. Case 4 passes a site.kind-dependent
1044
+ // value instead because ITS primary varies that way; Case 3b's
1045
+ // primary, like Case 0's, does not, so there is no 1.0 arm here to
1046
+ // mirror.
1047
+ emitted += emitInterfaceDispatchFor(ownerDef, memberName, memberDef, site, 0.85, calleeCapture);
1048
+ // Always mark handled when the site was resolved, even
1049
+ // if the edge was deduplicated (collapse mode), so
1050
+ // `emitReferencesViaLookup` doesn't re-emit from the
1051
+ // reference index.
1052
+ handledSites.add(siteKey);
1053
+ continue;
1054
+ }
1055
+ }
1056
+ }
1057
+ // ── Case 4: simple typeBinding (`u: U`) ──────────────────────
1058
+ if (typeRef !== undefined && !typeRef.rawName.includes('.')) {
1059
+ // A `rawName` the capture layer reduced from a type application is
1060
+ // resolved through the application it was written as, so the erasure
1061
+ // takes the GROUNDED route rather than binding whatever the workspace
1062
+ // declares under that base name — see {@link erasedTypeApplication}.
1063
+ const typeApplication = (0, template_arguments_js_1.erasedTypeApplication)(typeRef);
1064
+ let ownerDef = (0, walkers_js_1.resolveClassBindingForName)(site.inScope, typeApplication ?? typeRef.rawName, scopes);
1065
+ // `findClassBindingInScope(..., typeRef.rawName)` only works when
1066
+ // rawName is itself a class symbol reachable through scope bindings.
1067
+ // For languages with namespace-style imports (Go), imported types
1068
+ // don't create bindings. Fall back to QualifiedNameIndex — single-
1069
+ // match wins; ambiguous/missing falls through.
1070
+ //
1071
+ // NOT for an erased base name. This fallback consults no scope, no
1072
+ // import and no module: it binds any name with exactly one workspace
1073
+ // definition. That is a defensible last resort for a name the source
1074
+ // WROTE — the file named it, so the only question is which declaration
1075
+ // it meant — and is not defensible for a name the capture layer
1076
+ // MANUFACTURED by erasing type arguments, where the file may never
1077
+ // have named it at all. The lookup above already answered that case on
1078
+ // grounds; re-asking it here without any would undo them.
1079
+ if (ownerDef === undefined && typeApplication === undefined) {
1080
+ const qnameIds = scopes.qualifiedNames.get(typeRef.rawName);
1081
+ if (qnameIds.length === 1) {
1082
+ const qdef = scopes.defs.get(qnameIds[0]);
1083
+ if (qdef !== undefined && (0, walkers_js_1.isClassLike)(qdef.type))
1084
+ ownerDef = qdef;
1085
+ }
1086
+ }
1087
+ // Map for-of tuple bindings (`__MAP_TUPLE_i__:mapId`), callable
1088
+ // aliases (`getUser` → User), and other compound-friendly shapes
1089
+ // need the compound resolver keyed by the receiver identifier.
1090
+ //
1091
+ // Not asked for a receiver whose declared type IS an erased type
1092
+ // application the grounded lookup just refused. Those shapes are
1093
+ // alternatives to a declared type, not readings of one: this receiver
1094
+ // HAS a declared type, the question "which class does its base name
1095
+ // denote here" was already put and answered "cannot tell", and the
1096
+ // compound resolver reaches the same base name through its own
1097
+ // scope-free routes (its bare-identifier step re-runs the lookup on
1098
+ // `rawName`; its callable-alias step retries the same name as a
1099
+ // construction). Asking again by a route that cannot see the grounds
1100
+ // would make the refusal decorative.
1101
+ if (ownerDef === undefined && typeApplication === undefined) {
1102
+ ownerDef = (0, compound_receiver_js_1.resolveCompoundReceiverClass)(receiverName, site.inScope, scopes, index,
1103
+ // Group A, same reasoning as Case 0 above.
1104
+ { ...fileCompoundOpts, receiverChain: site.receiverChain });
1105
+ }
1106
+ // The receiver has a declared type, that type is a type APPLICATION,
1107
+ // and its base name could not be connected to any declaration this
1108
+ // file can see. The site is DROPPED, and dropped deliberately, so it
1109
+ // must be marked handled: `emitReferencesViaLookup` would otherwise
1110
+ // re-emit the very target the grounds refused, because the pre-resolved
1111
+ // reference index answers a name with the single workspace definition
1112
+ // that carries it and knows nothing about erasure. That is exactly why
1113
+ // the static-only filter above marks handled too — a refusal this pass
1114
+ // makes is not a refusal until the fallback emitter is told.
1115
+ //
1116
+ // Recorded as `receiver-unresolved` rather than silently: the receiver's
1117
+ // TYPE could not be established, which is the reason's own definition,
1118
+ // and a consumer counting resolver gaps must see this drop rather than
1119
+ // read the absence as a resolved site. No `receiverOrigin` — the base
1120
+ // name resolving in the index is precisely the evidence just rejected,
1121
+ // so claiming `in-program` from it would relaunder the fabrication as a
1122
+ // diagnostic, and the absent field hedges (the safe direction).
1123
+ if (ownerDef === undefined && typeApplication !== undefined) {
1124
+ options.recordResolutionOutcome?.({
1125
+ kind: 'suppressed',
1126
+ reason: 'receiver-unresolved',
1127
+ candidateIds: [],
1128
+ phase: 'receiver-bound-calls',
1129
+ filePath: parsed.filePath,
1130
+ name: site.name,
1131
+ range: site.atRange,
1132
+ siteKind: site.kind,
1133
+ });
1134
+ handledSites.add(siteKey);
1135
+ continue;
1136
+ }
1137
+ if (ownerDef !== undefined) {
1138
+ const languageResolution = provider.resolveReceiverMember?.(ownerDef, memberName, site, scopes, model);
1139
+ if (languageResolution?.kind === 'ambiguous') {
1140
+ options.recordResolutionOutcome?.({
1141
+ kind: 'suppressed',
1142
+ phase: 'receiver-bound-calls',
1143
+ filePath: parsed.filePath,
1144
+ name: site.name,
1145
+ range: site.atRange,
1146
+ reason: 'member-lookup-ambiguous',
1147
+ candidateIds: languageResolution.candidateIds,
1148
+ });
1149
+ handledSites.add(siteKey);
1150
+ continue;
1151
+ }
1152
+ if (languageResolution?.kind === 'resolved') {
1153
+ const memberDef = languageResolution.definition;
1154
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
1155
+ handledSites.add(siteKey);
1156
+ continue;
1157
+ }
1158
+ const reason = site.kind === 'write' || site.kind === 'read'
1159
+ ? site.kind
1160
+ : memberDef.filePath !== parsed.filePath
1161
+ ? 'import-resolved'
1162
+ : 'global';
1163
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
1164
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
1165
+ if (ok)
1166
+ emitted++;
1167
+ handledSites.add(siteKey);
1168
+ continue;
1169
+ }
1170
+ const chain = [ownerDef.nodeId, ...scopes.methodDispatch.mroFor(ownerDef.nodeId)];
1171
+ let memberDef;
1172
+ let ambiguous = false;
1173
+ let ambiguousOwnerId;
1174
+ // Track whether the chain walk filtered out any static-only
1175
+ // candidates. When it did and the chain ended with no
1176
+ // legitimate instance member, we mark the site as handled so
1177
+ // `emitReferencesViaLookup` doesn't re-emit a wrong target
1178
+ // from the pre-resolved reference index (which has no
1179
+ // static-only awareness).
1180
+ let allFilteredStaticOnly = false;
1181
+ // Static-only filter (#1756 / U2): the filter must run INSIDE
1182
+ // the chain walk and BEFORE arity narrowing.
1183
+ //
1184
+ // INSIDE: when a derived owner's only candidates are static-
1185
+ // only (Kotlin companion-promoted), `pickFirstNonStaticOnly`
1186
+ // returns `undefined` and the loop `continue`s to the next
1187
+ // ancestor in the MRO chain — giving a legitimate ancestor
1188
+ // instance method a chance to bind. The earlier after-chain
1189
+ // filter aborted the entire site instead, producing a false
1190
+ // negative whenever the most-derived owner shadowed an
1191
+ // ancestor's instance method with a static-only companion
1192
+ // member.
1193
+ //
1194
+ // BEFORE narrowing: filtering survivors of `lookupAllByOwner`
1195
+ // (rather than survivors of `narrowOverloadCandidates`) means
1196
+ // a same-arity static + instance pair on one owner doesn't
1197
+ // collapse to `OVERLOAD_AMBIGUOUS`. Kotlin compile-resolves
1198
+ // such a pair unambiguously to the instance method because
1199
+ // companion members are not legal instance-dispatch
1200
+ // candidates.
1201
+ for (const ownerId of chain) {
1202
+ const picked = pickFirstNonStaticOnly(ownerId, memberName, site, model, provider);
1203
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
1204
+ ambiguous = true;
1205
+ ambiguousOwnerId = ownerId;
1206
+ break;
1207
+ }
1208
+ if (picked === STATIC_ONLY_FILTERED) {
1209
+ // At least one static-only candidate was filtered out at
1210
+ // this owner; remember so we can mark handled if the
1211
+ // chain ends with no legitimate match.
1212
+ allFilteredStaticOnly = true;
1213
+ continue;
1214
+ }
1215
+ if (picked !== undefined) {
1216
+ memberDef = picked;
1217
+ break;
1218
+ }
1219
+ // `picked === undefined` means this owner had no member of
1220
+ // this name at all. Walk on to the next ancestor in the
1221
+ // MRO chain.
1222
+ }
1223
+ if (ambiguous) {
1224
+ // Suppress and mark handled so `emitReferencesViaLookup`
1225
+ // doesn't re-emit the pre-resolved reference. See
1226
+ // OVERLOAD_AMBIGUOUS docstring for the upstream cause.
1227
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId ?? ownerDef.nodeId, memberName, model, provider);
1228
+ handledSites.add(siteKey);
1229
+ continue;
1230
+ }
1231
+ if (memberDef === undefined && allFilteredStaticOnly) {
1232
+ // The chain ended with no candidates because every viable
1233
+ // owner had only static-only members. Mark handled so
1234
+ // `emitReferencesViaLookup` doesn't re-emit a wrong target
1235
+ // from the pre-resolved reference index. Parallels the old
1236
+ // after-chain `isStaticOnly` suppression block.
1237
+ handledSites.add(siteKey);
1238
+ continue;
1239
+ }
1240
+ if (memberDef !== undefined) {
1241
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
1242
+ handledSites.add(siteKey);
1243
+ continue;
1244
+ }
1245
+ // For read/write ACCESSES, mirror the legacy DAG's reason
1246
+ // convention so consumers asserting `reason === 'write'`
1247
+ // keep working.
1248
+ const reason = site.kind === 'write' || site.kind === 'read'
1249
+ ? site.kind
1250
+ : memberDef.filePath !== parsed.filePath
1251
+ ? 'import-resolved'
1252
+ : 'global';
1253
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
1254
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
1255
+ if (ok)
1256
+ emitted++;
1257
+ // Interface dispatch: when the primary owner is an
1258
+ // Interface, emit secondary CALLS edges to every
1259
+ // implementing class's same-named method.
1260
+ emitted += emitInterfaceDispatchFor(ownerDef, memberName, memberDef, site, confidence, calleeCapture);
1261
+ // Always mark handled when the site was resolved, even
1262
+ // if the edge was deduplicated (collapse mode), so
1263
+ // `emitReferencesViaLookup` doesn't re-emit from the
1264
+ // reference index.
1265
+ handledSites.add(siteKey);
1266
+ continue;
1267
+ }
1268
+ }
1269
+ }
1270
+ // ── Case 5: value-receiver bridge (object-literal services) ──
1271
+ // When prior cases couldn't resolve the receiver as a class or
1272
+ // type binding, fall back to value-binding resolution. Covers:
1273
+ //
1274
+ // export const fooService = { getUser(id) {...} };
1275
+ // import { fooService } from './service';
1276
+ // fooService.getUser(id); // ← resolve here
1277
+ //
1278
+ // `fooService` is a `Const`/`Variable` (not class-like, no typeBinding
1279
+ // for unannotated literals), so Cases 2-4 skip it. Scope-resolution
1280
+ // defs for non-class values carry a synthetic id, so we translate to
1281
+ // the canonical graph node ID via `resolveDefGraphId` before owner-
1282
+ // indexed lookup — the parser writes the graph node ID as `ownerId`
1283
+ // on the method symbol-table entry to match.
1284
+ //
1285
+ // Object-literal methods do not carry a `qualifiedName` (no class
1286
+ // owner to seed it), so the picked def cannot round-trip through
1287
+ // `tryEmitEdge` → `resolveDefGraphId`. We use
1288
+ // `tryEmitEdgeWithExplicitTargetId` instead, passing `picked.nodeId`
1289
+ // directly — same dedup-key shape, collapse-flag honoring, and
1290
+ // caller resolution as `tryEmitEdge`.
1291
+ const valueDef = (0, walkers_js_1.findValueBindingInScope)(site.inScope, receiverName, scopes);
1292
+ if (valueDef !== undefined) {
1293
+ const ownerGraphId = (0, ids_js_1.resolveDefGraphId)(valueDef.filePath, valueDef, nodeLookup) ?? valueDef.nodeId;
1294
+ const picked = pickOverload(ownerGraphId, memberName, site, model, provider);
1295
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
1296
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ownerGraphId, memberName, model, provider);
1297
+ handledSites.add(siteKey);
1298
+ continue;
1299
+ }
1300
+ if (picked !== undefined) {
1301
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, picked)) {
1302
+ handledSites.add(siteKey);
1303
+ continue;
1304
+ }
1305
+ // Static-only filter (#1756 / U3): unlike Case 4 there's no
1306
+ // MRO chain to walk here — Case 5 dispatches on a single
1307
+ // owner via `pickOverload`. When the picked candidate is
1308
+ // static-only (Kotlin companion-promoted), suppress the
1309
+ // edge entirely and mark the site handled so
1310
+ // `emitReferencesViaLookup` doesn't re-emit a wrong target
1311
+ // from the pre-resolved reference index. Matches the after-
1312
+ // chain handled-marker semantic used by Case 4's
1313
+ // all-filtered fall-through.
1314
+ if (provider.isStaticOnly?.(picked) === true) {
1315
+ handledSites.add(siteKey);
1316
+ continue;
1317
+ }
1318
+ const reason = site.kind === 'write' || site.kind === 'read'
1319
+ ? site.kind
1320
+ : picked.filePath !== parsed.filePath
1321
+ ? 'import-resolved'
1322
+ : 'global';
1323
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
1324
+ const ok = (0, edges_js_1.tryEmitEdgeWithExplicitTargetId)(graph, scopes, nodeLookup, site, picked.nodeId, reason, seen, confidence, collapse, calleeCapture);
1325
+ if (ok)
1326
+ emitted++;
1327
+ handledSites.add(siteKey);
1328
+ continue;
1329
+ }
1330
+ }
1331
+ // ── Case 6: class-level (static) member receiver ─────────────
1332
+ // `Holder.repo.save(u)` — the receiver `Holder.repo` reaches a value
1333
+ // through a CLASS-LEVEL member. Both routes that type a compound
1334
+ // receiver (the structural fold and the text cascade) read the same
1335
+ // place for the `repo` hop: the owning class scope's `typeBindings`.
1336
+ // A scope has ONE `typeBindings` map with no static/instance split, so
1337
+ // a language that declares both `p` and `static p` cannot record both
1338
+ // — and at least two resolve that collision by not recording the
1339
+ // static one at all, leaving `Holder.repo` with nothing to type
1340
+ // against. A language that nests its class-level members in a scope of
1341
+ // their own (a companion/singleton body) lands in the same place from
1342
+ // the other direction: the binding exists, but not in the scope keyed
1343
+ // by the class the receiver names. Both were MEASURED as emitting no
1344
+ // edge at all, generic field and non-generic control alike.
1345
+ //
1346
+ // The definition side does not have that ambiguity: a class-level
1347
+ // member and an instance member of one name are two distinct defs, and
1348
+ // the graph node carries both `isStatic` and the member's declared
1349
+ // type. So this case types the receiver off the DEF rather than off a
1350
+ // typeBinding, and needs no scope-tree change to do it.
1351
+ //
1352
+ // ── WHY THIS CANNOT MINT A STATIC-TARGETED EDGE ────────────────────
1353
+ //
1354
+ // `Holder.repo` is a static FIELD whose TYPE is `Repo`; the value it
1355
+ // holds is an INSTANCE. So "reached through a class-level member" says
1356
+ // nothing about the target: `save` is looked up with the ordinary
1357
+ // `pickFirstNonStaticOnly` instance walk that Cases 0/3b/4 use, and a
1358
+ // static-only `save` is skipped exactly as it is there. A genuine
1359
+ // static CALL (`Repo.create()`) never arrives here — its receiver is a
1360
+ // bare class name with no dot, which Case 2 owns and this case's
1361
+ // two-part receiver requirement excludes.
1362
+ //
1363
+ // The `isStatic === true` requirement on the FIELD is the load-bearing
1364
+ // guard in the other direction: the head resolved to the class itself,
1365
+ // so only a class-level member is reachable through it, and an
1366
+ // instance field of the same name must not be substituted. That is a
1367
+ // POSITIVE selection among the defs that exist, never a filter that
1368
+ // deletes otherwise-valid targets — the distinction that matters for a
1369
+ // language whose singleton/companion members all carry `isStatic` from
1370
+ // their OWNER type, where the flag being set is precisely what makes
1371
+ // reaching them through the type name correct.
1372
+ //
1373
+ // Runs LAST, and only for a receiver Case 0 already declined
1374
+ // (`compoundReceiverUnresolved`): a site any earlier case resolved
1375
+ // keeps that answer, so this can only turn a missing edge into an edge
1376
+ // and never retarget an existing one. Contract Invariant I4 holds —
1377
+ // nothing above moved.
1378
+ if (compoundReceiverUnresolved) {
1379
+ const staticMemberReceiver = splitClassLevelMemberReceiver(receiverName, site.receiverChain);
1380
+ const headClass = staticMemberReceiver === undefined
1381
+ ? undefined
1382
+ : (0, walkers_js_1.findClassBindingInScope)(site.inScope, staticMemberReceiver.headName, scopes);
1383
+ // The head must be the CLASS ITSELF, not a value that happens to
1384
+ // share its name — the same `currentIsClassConstant` test the text
1385
+ // cascade makes before it treats a head as a class constant. A head
1386
+ // with a type binding is an instance and its members are typed by
1387
+ // the routes above.
1388
+ if (staticMemberReceiver !== undefined &&
1389
+ headClass !== undefined &&
1390
+ (0, walkers_js_1.findReceiverTypeBinding)(site.inScope, staticMemberReceiver.headName, scopes) === undefined) {
1391
+ // MRO walk, so a class-level member declared on an ancestor is
1392
+ // reachable through a subclass name where the language allows it.
1393
+ // First owner that declares one wins, matching every other walk in
1394
+ // this pass.
1395
+ let fieldOwnerId;
1396
+ let fieldDeclaredType;
1397
+ for (const ownerId of [
1398
+ headClass.nodeId,
1399
+ ...scopes.methodDispatch.mroFor(headClass.nodeId),
1400
+ ]) {
1401
+ const declared = declaredTypeOfClassLevelField(ownerId, staticMemberReceiver.memberName);
1402
+ if (declared === undefined)
1403
+ continue;
1404
+ fieldOwnerId = ownerId;
1405
+ fieldDeclaredType = declared;
1406
+ break;
1407
+ }
1408
+ // Resolve the declared type from where it was WRITTEN — the
1409
+ // declaring class's own scope — not from the call site. A caller
1410
+ // in another file need not have the field's type in scope at all,
1411
+ // and resolving `Repo` against the caller's bindings would either
1412
+ // miss or, worse, find an unrelated same-named class.
1413
+ const declaringScope = fieldOwnerId === undefined ? undefined : index.classScopeByDefId.get(fieldOwnerId)?.id;
1414
+ const receiverClass = declaringScope === undefined || fieldDeclaredType === undefined
1415
+ ? undefined
1416
+ : (0, walkers_js_1.resolveClassBindingForName)(declaringScope, fieldDeclaredType, scopes, provider.stripTypePreservingDecoration);
1417
+ if (receiverClass !== undefined) {
1418
+ const chain = [
1419
+ receiverClass.nodeId,
1420
+ ...scopes.methodDispatch.mroFor(receiverClass.nodeId),
1421
+ ];
1422
+ let memberDef;
1423
+ let ambiguousOwnerId;
1424
+ for (const ownerId of chain) {
1425
+ const picked = pickFirstNonStaticOnly(ownerId, memberName, site, model, provider);
1426
+ if (picked === exports.OVERLOAD_AMBIGUOUS) {
1427
+ ambiguousOwnerId = ownerId;
1428
+ break;
1429
+ }
1430
+ // Same skip-and-walk-on as Case 4: a static-only candidate at
1431
+ // this owner must not block an ancestor's instance member.
1432
+ if (picked === STATIC_ONLY_FILTERED || picked === undefined)
1433
+ continue;
1434
+ memberDef = picked;
1435
+ break;
1436
+ }
1437
+ if (ambiguousOwnerId !== undefined) {
1438
+ recordReceiverOverloadSuppression(options.recordResolutionOutcome, parsed.filePath, site, ambiguousOwnerId, memberName, model, provider);
1439
+ handledSites.add(siteKey);
1440
+ continue;
1441
+ }
1442
+ if (memberDef !== undefined) {
1443
+ if (suppressDeletedCallTarget(options.recordResolutionOutcome, parsed.filePath, site, memberDef)) {
1444
+ handledSites.add(siteKey);
1445
+ continue;
1446
+ }
1447
+ const reason = site.kind === 'write' || site.kind === 'read'
1448
+ ? site.kind
1449
+ : memberDef.filePath !== parsed.filePath
1450
+ ? 'import-resolved'
1451
+ : 'global';
1452
+ const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
1453
+ const ok = (0, edges_js_1.tryEmitEdge)(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse, calleeCapture);
1454
+ if (ok)
1455
+ emitted++;
1456
+ // The receiver's declared type can be an Interface exactly as
1457
+ // in Cases 0/3b/4 — an interface-typed static field is the
1458
+ // canonical service-locator shape — so it fans out the same
1459
+ // way. Omitting it would make the static spelling emit fewer
1460
+ // targets than the identical instance field, which is the very
1461
+ // spelling-dependence #2829/#2842 closed elsewhere.
1462
+ emitted += emitInterfaceDispatchFor(receiverClass, memberName, memberDef, site, confidence, calleeCapture);
1463
+ handledSites.add(siteKey);
1464
+ continue;
1465
+ }
1466
+ }
1467
+ }
1468
+ }
1469
+ // #2744: the site survived every case with a compound receiver we could
1470
+ // not type, so the call is dropped with no candidate. Record it here —
1471
+ // after the cases, so a site a later case resolved is never reported —
1472
+ // keyed by the MEMBER name, which is the only thing still known about a
1473
+ // dropped site (its callee is unknown by definition, so the drop cannot
1474
+ // be attributed to any target symbol).
1475
+ if (compoundReceiverUnresolved && !handledSites.has(siteKey)) {
1476
+ // Decoded once: both the shape census and the origin classifier read the
1477
+ // same chain, and this is inside the drop guard so a resolved site pays
1478
+ // nothing.
1479
+ const decodedChain = (0, receiver_chain_codec_js_1.decodeReceiverChain)(site.receiverChain);
1480
+ options.recordResolutionOutcome?.({
1481
+ kind: 'suppressed',
1482
+ reason: 'receiver-unresolved',
1483
+ candidateIds: [],
1484
+ phase: 'receiver-bound-calls',
1485
+ filePath: parsed.filePath,
1486
+ name: site.name,
1487
+ range: site.atRange,
1488
+ // The gate above tests the receiver's punctuation, not the site's
1489
+ // kind, so property reads and writes with a compound receiver are
1490
+ // recorded here too. Carry the kind so a consumer can separate a
1491
+ // dropped CALL from a dropped property access.
1492
+ siteKind: site.kind,
1493
+ // Structural, from the AST-derived chain the emitter minted — never
1494
+ // re-derived from the source line.
1495
+ // `decodeReceiverChain` opens with a non-string guard, so the
1496
+ // undefined case needs no ternary here.
1497
+ receiverShape: (0, resolution_outcome_js_1.classifyReceiverShape)(decodedChain),
1498
+ // Whether anything was actually lost. An external target has no node
1499
+ // to point at, so its absence is completeness, not uncertainty — but
1500
+ // ONLY a positive built-in match may say so. Everything the index
1501
+ // cannot demonstrate stays `unknown` and keeps hedging.
1502
+ receiverOrigin: classifyReceiverOrigin(decodedChain, site.inScope, receiverName, scopes, receiverOriginOpts),
1503
+ });
1504
+ }
1505
+ }
1506
+ }
1507
+ return { emitted, dispatchFanoutSkipped, dispatchFanoutSkippedNames };
1508
+ }
1509
+ /**
1510
+ * Split a receiver into `Head` + one member hop, or decline.
1511
+ *
1512
+ * The STRUCTURE decides when the capture layer minted a chain: exactly one
1513
+ * step, and that step a FIELD. A `call` step is a different shape entirely
1514
+ * (`Holder.make().save()` — the value comes from a return type, which the
1515
+ * routes above already own), and an `await`/`index` step transforms the value
1516
+ * in a way a field's declared type does not describe.
1517
+ *
1518
+ * Without a chain the receiver TEXT answers, and only in the one spelling that
1519
+ * cannot be read two ways: two bare identifiers around a single dot. Anything
1520
+ * carrying a call, a subscript, a second dot or a decoration declines rather
1521
+ * than being parsed here — re-deriving structure from text is what the chain
1522
+ * exists to replace, and a second, looser text parser beside the cascade's own
1523
+ * would drift from it.
1524
+ */
1525
+ function splitClassLevelMemberReceiver(receiverText, receiverChain) {
1526
+ const decoded = (0, receiver_chain_codec_js_1.decodeReceiverChain)(receiverChain);
1527
+ if (decoded !== undefined) {
1528
+ if (decoded.truncated || decoded.steps.length !== 1)
1529
+ return undefined;
1530
+ const step = decoded.steps[0];
1531
+ if (step === undefined || step.kind !== 'field')
1532
+ return undefined;
1533
+ return { headName: decoded.baseReceiverName, memberName: step.name };
1534
+ }
1535
+ const match = TWO_PART_RECEIVER_RE.exec(receiverText);
1536
+ if (match === null)
1537
+ return undefined;
1538
+ const [, headName, memberName] = match;
1539
+ if (headName === undefined || memberName === undefined)
1540
+ return undefined;
1541
+ return { headName, memberName };
1542
+ }
1543
+ /** `Holder.repo` and nothing looser — see {@link splitClassLevelMemberReceiver}. */
1544
+ const TWO_PART_RECEIVER_RE = /^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/;
1545
+ /** Resolve a member by name on a class def, narrowing by argument
1546
+ * types when multiple overloads share the name. Falls back to the
1547
+ * first-seen def (legacy `findOwnedMember` semantics) when there's
1548
+ * no narrowing signal or when `argumentTypes` is unavailable. */
1549
+ function pickOverload(ownerId, memberName, site, model, provider) {
1550
+ const overloads = model.methods.lookupAllByOwner(ownerId, memberName);
1551
+ if (overloads.length === 0) {
1552
+ // Non-callable member (field / property / variable) — ACCESSES
1553
+ // write/read sites target these too. Fall back to the field
1554
+ // registry so owner-scoped attribute access resolves.
1555
+ return model.fields.lookupFieldByOwner(ownerId, memberName);
1556
+ }
1557
+ if (overloads.length === 1)
1558
+ return overloads[0];
1559
+ const candidates = (0, overload_narrowing_js_1.narrowOverloadCandidates)(overloads, site.arity, site.argumentTypes, {
1560
+ argumentTypeClasses: site.argumentTypeClasses,
1561
+ conversionRankFn: provider.conversionRankFn,
1562
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
1563
+ constraintCompatibility: provider.constraintCompatibility,
1564
+ });
1565
+ // When narrowing leaves >1 candidate that share identical normalized
1566
+ // parameter-types (e.g., C++ `f(int)` vs `f(long)` both collapsed to
1567
+ // `['int']` by `normalizeCppParamType`), suppress the edge entirely.
1568
+ // The graph schema has no ambiguous-target edge model, so emitting one
1569
+ // would arbitrarily pick a candidate and lie about the call's target.
1570
+ // PR #1520 review follow-up plan U2 / Claude review Finding 5.
1571
+ if ((0, overload_narrowing_js_1.isOverloadAmbiguousAfterNormalization)(candidates, site.arity))
1572
+ return exports.OVERLOAD_AMBIGUOUS;
1573
+ // When conversion-rank scoring leaves >1 tied candidate with distinct
1574
+ // parameter types (e.g. h(int,double) vs h(double,int) both scoring 2),
1575
+ // suppress rather than picking arbitrarily — C++ would call this
1576
+ // ambiguous. Mirrors ADL merged-candidate suppression behavior.
1577
+ if (candidates.length > 1)
1578
+ return exports.OVERLOAD_AMBIGUOUS;
1579
+ return candidates[0] ?? overloads[0];
1580
+ }
1581
+ /**
1582
+ * Sentinel returned by `pickOverload` when narrowing leaves >1 candidate
1583
+ * sharing identical normalized parameter-types. Callers should suppress
1584
+ * the CALLS edge AND mark the site as handled so `emitReferencesViaLookup`
1585
+ * does not re-emit from the pre-resolved reference index. See
1586
+ * `pickOverload` JSDoc for the upstream cause (per-language normalizer
1587
+ * collapses distinct types in arity-metadata).
1588
+ */
1589
+ exports.OVERLOAD_AMBIGUOUS = Symbol('overload-ambiguous');
1590
+ /**
1591
+ * Sentinel returned by `pickFirstNonStaticOnly` when the only candidates
1592
+ * at the queried owner were filtered out by `provider.isStaticOnly`. Lets
1593
+ * the Case 4 chain walk distinguish "owner had no member of this name"
1594
+ * (return `undefined`, continue silently) from "owner had only static-
1595
+ * only members" (return this sentinel, continue and remember so the
1596
+ * post-chain handled-marker logic can suppress wrong-target re-emission
1597
+ * from `emitReferencesViaLookup`). See #1756 / remediation plan U2.
1598
+ */
1599
+ const STATIC_ONLY_FILTERED = Symbol('static-only-filtered');
1600
+ /**
1601
+ * Receiver-bound member lookup that filters static-only candidates BEFORE
1602
+ * arity narrowing. Wraps the raw `lookupAllByOwner` → `narrowOverloadCandidates`
1603
+ * pipeline so:
1604
+ *
1605
+ * 1. Candidates flagged by `provider.isStaticOnly` (Kotlin companion-
1606
+ * promoted methods today) never enter the narrowing stage. A same-
1607
+ * name same-arity static + instance pair on one owner therefore does
1608
+ * NOT collapse to `OVERLOAD_AMBIGUOUS` — the instance member wins
1609
+ * unambiguously, matching Kotlin's compile-time resolution.
1610
+ * 2. The chain walk in `emitReceiverBoundCalls` Case 4 can fall through
1611
+ * to ancestors when only static-only candidates exist at the
1612
+ * most-derived owner (returns `STATIC_ONLY_FILTERED`), rather than
1613
+ * aborting the site as the previous after-chain filter did.
1614
+ *
1615
+ * Returns:
1616
+ * - `undefined` — no member with this name on this owner; chain walk
1617
+ * continues silently.
1618
+ * - `STATIC_ONLY_FILTERED` — at least one candidate existed but every
1619
+ * one was static-only; chain walk continues and remembers so the
1620
+ * post-chain handled-marker can fire if no ancestor binds.
1621
+ * - `OVERLOAD_AMBIGUOUS` — narrowing on the surviving non-static
1622
+ * candidates left >1 ambiguous match; chain walk aborts and the
1623
+ * site is marked handled (existing sentinel handling preserved).
1624
+ * - `SymbolDefinition` — single survivor (the chosen target).
1625
+ *
1626
+ * See remediation plan `docs/plans/2026-05-22-002-fix-lang-kotlin-1782-
1627
+ * remediation-plan.md` § U2 for the full rationale.
1628
+ */
1629
+ function pickFirstNonStaticOnly(ownerId, memberName, site, model, provider) {
1630
+ const rawOverloads = model.methods.lookupAllByOwner(ownerId, memberName);
1631
+ if (rawOverloads.length === 0) {
1632
+ // Non-callable member (field / property / variable) — ACCESSES
1633
+ // write/read sites target these too. Static-only filtering doesn't
1634
+ // apply to fields, so delegate straight to `lookupFieldByOwner`.
1635
+ return model.fields.lookupFieldByOwner(ownerId, memberName);
1636
+ }
1637
+ const isStaticOnly = provider.isStaticOnly;
1638
+ let overloads = rawOverloads;
1639
+ let filteredAny = false;
1640
+ if (isStaticOnly !== undefined) {
1641
+ const survivors = [];
1642
+ for (const candidate of rawOverloads) {
1643
+ if (isStaticOnly(candidate) === true) {
1644
+ filteredAny = true;
1645
+ continue;
1646
+ }
1647
+ survivors.push(candidate);
1648
+ }
1649
+ overloads = survivors;
1650
+ }
1651
+ if (overloads.length === 0) {
1652
+ // Every candidate was static-only; the caller (Case 4 chain walk)
1653
+ // should walk on to the next owner AND remember that filtering
1654
+ // happened so it can mark the site handled if the whole chain
1655
+ // ends with no legitimate match.
1656
+ return filteredAny ? STATIC_ONLY_FILTERED : undefined;
1657
+ }
1658
+ if (overloads.length === 1)
1659
+ return overloads[0];
1660
+ const candidates = (0, overload_narrowing_js_1.narrowOverloadCandidates)(overloads, site.arity, site.argumentTypes, {
1661
+ argumentTypeClasses: site.argumentTypeClasses,
1662
+ conversionRankFn: provider.conversionRankFn,
1663
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
1664
+ constraintCompatibility: provider.constraintCompatibility,
1665
+ });
1666
+ // Same ambiguity handling as `pickOverload`: when normalization
1667
+ // collapses the surviving overloads into a single bucket (e.g., C++
1668
+ // `f(int)`/`f(long)` normalized to `['int']`), suppress rather than
1669
+ // arbitrarily picking. When narrowing leaves >1 distinct candidate
1670
+ // with no tie-breaker, suppress for the same reason.
1671
+ if ((0, overload_narrowing_js_1.isOverloadAmbiguousAfterNormalization)(candidates, site.arity))
1672
+ return exports.OVERLOAD_AMBIGUOUS;
1673
+ if (candidates.length > 1)
1674
+ return exports.OVERLOAD_AMBIGUOUS;
1675
+ return candidates[0] ?? overloads[0];
1676
+ }
1677
+ function suppressDeletedCallTarget(record, filePath, site, target) {
1678
+ if (site.kind !== 'call' || target.isDeleted !== true)
1679
+ return false;
1680
+ record?.({
1681
+ kind: 'suppressed',
1682
+ phase: 'receiver-bound-calls',
1683
+ filePath,
1684
+ name: site.name,
1685
+ range: site.atRange,
1686
+ reason: 'selected-callable-deleted',
1687
+ candidateIds: [target.nodeId],
1688
+ });
1689
+ return true;
1690
+ }
1691
+ function recordReceiverOverloadSuppression(record, filePath, site, ownerId, memberName, model, provider) {
1692
+ if (record === undefined)
1693
+ return;
1694
+ const overloads = model.methods.lookupAllByOwner(ownerId, memberName);
1695
+ const candidates = (0, overload_narrowing_js_1.narrowOverloadCandidates)(overloads, site.arity, site.argumentTypes, {
1696
+ argumentTypeClasses: site.argumentTypeClasses,
1697
+ conversionRankFn: provider.conversionRankFn,
1698
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
1699
+ constraintCompatibility: provider.constraintCompatibility,
1700
+ });
1701
+ const reason = (0, overload_narrowing_js_1.isOverloadAmbiguousAfterNormalization)(candidates, site.arity)
1702
+ ? 'overload-ambiguous-normalization'
1703
+ : hasConversionRankingSignal(site, provider)
1704
+ ? 'conversion-rank-tied'
1705
+ : 'overload-ambiguous';
1706
+ record({
1707
+ kind: 'suppressed',
1708
+ phase: 'receiver-bound-calls',
1709
+ filePath,
1710
+ name: site.name,
1711
+ range: site.atRange,
1712
+ reason,
1713
+ candidateIds: candidates.map((d) => d.nodeId),
1714
+ });
1715
+ }
1716
+ function hasConversionRankingSignal(site, provider) {
1717
+ return (provider.conversionRankFn !== undefined &&
1718
+ site.argumentTypes !== undefined &&
1719
+ site.argumentTypes.length > 0);
1720
+ }