rigortype 0.2.7 → 0.2.8

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 (414) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/docs/manual/04-diagnostics.md +7 -4
  4. data/docs/manual/06-baseline.md +5 -2
  5. data/docs/manual/15-type-protection-coverage.md +6 -4
  6. data/lib/rigor/analysis/baseline.rb +56 -96
  7. data/lib/rigor/analysis/buffer_binding.rb +13 -20
  8. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
  9. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
  10. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
  11. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
  12. data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
  13. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
  14. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
  15. data/lib/rigor/analysis/check_rules.rb +174 -274
  16. data/lib/rigor/analysis/dependency_recorder.rb +26 -38
  17. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
  18. data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
  19. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
  20. data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
  21. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
  22. data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
  23. data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
  24. data/lib/rigor/analysis/diagnostic.rb +48 -75
  25. data/lib/rigor/analysis/erb_template_detector.rb +13 -18
  26. data/lib/rigor/analysis/fact_store.rb +12 -22
  27. data/lib/rigor/analysis/incremental.rb +47 -63
  28. data/lib/rigor/analysis/incremental_session.rb +74 -100
  29. data/lib/rigor/analysis/project_scan.rb +12 -23
  30. data/lib/rigor/analysis/result.rb +3 -5
  31. data/lib/rigor/analysis/rule_catalog.rb +67 -95
  32. data/lib/rigor/analysis/run_stats.rb +38 -61
  33. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
  34. data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
  35. data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
  36. data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
  37. data/lib/rigor/analysis/runner.rb +220 -333
  38. data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
  39. data/lib/rigor/analysis/worker_session.rb +64 -102
  40. data/lib/rigor/ast/type_node.rb +6 -8
  41. data/lib/rigor/ast.rb +6 -10
  42. data/lib/rigor/bleeding_edge.rb +27 -35
  43. data/lib/rigor/builtins/hkt_builtins.rb +7 -14
  44. data/lib/rigor/builtins/imported_refinements.rb +106 -149
  45. data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
  46. data/lib/rigor/builtins/regex_refinement.rb +32 -43
  47. data/lib/rigor/builtins/static_return_refinements.rb +57 -81
  48. data/lib/rigor/cache/descriptor.rb +58 -94
  49. data/lib/rigor/cache/incremental_snapshot.rb +32 -48
  50. data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
  51. data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
  52. data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
  53. data/lib/rigor/cache/rbs_constant_table.rb +8 -13
  54. data/lib/rigor/cache/rbs_descriptor.rb +8 -13
  55. data/lib/rigor/cache/rbs_environment.rb +11 -19
  56. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
  57. data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
  58. data/lib/rigor/cache/store.rb +96 -151
  59. data/lib/rigor/cli/annotate_command.rb +51 -88
  60. data/lib/rigor/cli/baseline_command.rb +10 -17
  61. data/lib/rigor/cli/check_command.rb +121 -199
  62. data/lib/rigor/cli/check_runner_factory.rb +8 -14
  63. data/lib/rigor/cli/ci_detector.rb +9 -14
  64. data/lib/rigor/cli/command.rb +8 -14
  65. data/lib/rigor/cli/coverage_command.rb +19 -26
  66. data/lib/rigor/cli/coverage_mutation.rb +14 -19
  67. data/lib/rigor/cli/coverage_report.rb +0 -2
  68. data/lib/rigor/cli/coverage_scan.rb +7 -11
  69. data/lib/rigor/cli/diagnostic_formats.rb +43 -62
  70. data/lib/rigor/cli/diff_command.rb +10 -20
  71. data/lib/rigor/cli/docs_command.rb +26 -40
  72. data/lib/rigor/cli/doctor_command.rb +8 -9
  73. data/lib/rigor/cli/explain_command.rb +4 -7
  74. data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
  75. data/lib/rigor/cli/fused_protection_report.rb +6 -8
  76. data/lib/rigor/cli/lsp_command.rb +11 -19
  77. data/lib/rigor/cli/mcp_command.rb +4 -6
  78. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
  79. data/lib/rigor/cli/mutation_protection_report.rb +6 -9
  80. data/lib/rigor/cli/options.rb +11 -19
  81. data/lib/rigor/cli/plugin_command.rb +18 -30
  82. data/lib/rigor/cli/plugins_command.rb +29 -51
  83. data/lib/rigor/cli/plugins_renderer.rb +12 -20
  84. data/lib/rigor/cli/prism_colorizer.rb +13 -19
  85. data/lib/rigor/cli/protection_renderer.rb +5 -7
  86. data/lib/rigor/cli/protection_report.rb +27 -17
  87. data/lib/rigor/cli/renderable.rb +4 -6
  88. data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
  89. data/lib/rigor/cli/sig_gen_command.rb +14 -26
  90. data/lib/rigor/cli/skill_command.rb +30 -47
  91. data/lib/rigor/cli/skill_describe.rb +40 -64
  92. data/lib/rigor/cli/trace_command.rb +9 -16
  93. data/lib/rigor/cli/trace_renderer.rb +35 -51
  94. data/lib/rigor/cli/triage_command.rb +6 -10
  95. data/lib/rigor/cli/triage_renderer.rb +1 -2
  96. data/lib/rigor/cli/type_of_command.rb +14 -23
  97. data/lib/rigor/cli/type_of_renderer.rb +3 -5
  98. data/lib/rigor/cli/type_scan_command.rb +6 -10
  99. data/lib/rigor/cli/type_scan_renderer.rb +3 -5
  100. data/lib/rigor/cli/type_scan_report.rb +2 -3
  101. data/lib/rigor/cli/upgrade_command.rb +2 -3
  102. data/lib/rigor/cli.rb +16 -28
  103. data/lib/rigor/config_audit.rb +35 -44
  104. data/lib/rigor/configuration/dependencies.rb +41 -70
  105. data/lib/rigor/configuration/severity_profile.rb +28 -42
  106. data/lib/rigor/configuration.rb +150 -241
  107. data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
  108. data/lib/rigor/environment/class_registry.rb +19 -26
  109. data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
  110. data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
  111. data/lib/rigor/environment/lockfile_resolver.rb +31 -47
  112. data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
  113. data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
  114. data/lib/rigor/environment/rbs_loader.rb +420 -518
  115. data/lib/rigor/environment/reflection.rb +28 -53
  116. data/lib/rigor/environment/reporters.rb +13 -24
  117. data/lib/rigor/environment.rb +176 -291
  118. data/lib/rigor/flow_contribution/conflict.rb +16 -27
  119. data/lib/rigor/flow_contribution/element.rb +7 -12
  120. data/lib/rigor/flow_contribution/fact.rb +33 -57
  121. data/lib/rigor/flow_contribution/merge_result.rb +6 -9
  122. data/lib/rigor/flow_contribution/merger.rb +32 -47
  123. data/lib/rigor/flow_contribution.rb +37 -55
  124. data/lib/rigor/inference/acceptance.rb +133 -219
  125. data/lib/rigor/inference/block_parameter_binder.rb +52 -82
  126. data/lib/rigor/inference/body_fixpoint.rb +22 -30
  127. data/lib/rigor/inference/budget_trace.rb +43 -63
  128. data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
  129. data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
  130. data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
  131. data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
  132. data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
  133. data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
  134. data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
  135. data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
  136. data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
  137. data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
  138. data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
  139. data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
  140. data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
  141. data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
  142. data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
  143. data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
  144. data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
  145. data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
  146. data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
  147. data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
  148. data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
  149. data/lib/rigor/inference/coverage_scanner.rb +13 -18
  150. data/lib/rigor/inference/def_return_typer.rb +8 -14
  151. data/lib/rigor/inference/dynamic_origin.rb +23 -20
  152. data/lib/rigor/inference/expression_typer.rb +774 -1152
  153. data/lib/rigor/inference/fallback.rb +8 -12
  154. data/lib/rigor/inference/fallback_tracer.rb +4 -10
  155. data/lib/rigor/inference/flow_tracer.rb +25 -36
  156. data/lib/rigor/inference/hkt_body.rb +45 -68
  157. data/lib/rigor/inference/hkt_body_parser.rb +33 -52
  158. data/lib/rigor/inference/hkt_reducer.rb +38 -59
  159. data/lib/rigor/inference/hkt_registry.rb +50 -76
  160. data/lib/rigor/inference/indexed_narrowing.rb +55 -81
  161. data/lib/rigor/inference/macro_block_self_type.rb +21 -34
  162. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
  163. data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
  164. data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
  165. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
  166. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
  167. data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
  168. data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
  169. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
  170. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
  171. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
  172. data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
  173. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
  174. data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
  175. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
  176. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
  177. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
  178. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
  179. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
  180. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
  181. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
  182. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
  183. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
  184. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
  185. data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
  186. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
  187. data/lib/rigor/inference/method_dispatcher.rb +378 -524
  188. data/lib/rigor/inference/method_parameter_binder.rb +81 -114
  189. data/lib/rigor/inference/multi_target_binder.rb +51 -68
  190. data/lib/rigor/inference/mutation_widening.rb +115 -158
  191. data/lib/rigor/inference/narrowing.rb +509 -727
  192. data/lib/rigor/inference/origin_lookup.rb +38 -0
  193. data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
  194. data/lib/rigor/inference/precision_scanner.rb +26 -35
  195. data/lib/rigor/inference/project_patched_methods.rb +20 -32
  196. data/lib/rigor/inference/project_patched_scanner.rb +23 -37
  197. data/lib/rigor/inference/protection_scanner.rb +16 -18
  198. data/lib/rigor/inference/rbs_type_translator.rb +49 -66
  199. data/lib/rigor/inference/scope_indexer.rb +473 -817
  200. data/lib/rigor/inference/statement_evaluator.rb +706 -1111
  201. data/lib/rigor/inference/struct_fold_safety.rb +34 -48
  202. data/lib/rigor/inference/synthetic_method.rb +9 -16
  203. data/lib/rigor/inference/synthetic_method_index.rb +20 -35
  204. data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
  205. data/lib/rigor/language_server/buffer_resolution.rb +6 -9
  206. data/lib/rigor/language_server/buffer_table.rb +11 -18
  207. data/lib/rigor/language_server/completion_provider.rb +69 -116
  208. data/lib/rigor/language_server/debouncer.rb +16 -25
  209. data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
  210. data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
  211. data/lib/rigor/language_server/folding_range_provider.rb +11 -19
  212. data/lib/rigor/language_server/hover_provider.rb +8 -11
  213. data/lib/rigor/language_server/hover_renderer.rb +56 -93
  214. data/lib/rigor/language_server/loop.rb +14 -19
  215. data/lib/rigor/language_server/project_context.rb +46 -74
  216. data/lib/rigor/language_server/selection_range_provider.rb +9 -12
  217. data/lib/rigor/language_server/server.rb +55 -83
  218. data/lib/rigor/language_server/signature_help_provider.rb +29 -46
  219. data/lib/rigor/language_server/synchronized_writer.rb +4 -7
  220. data/lib/rigor/language_server/uri.rb +8 -13
  221. data/lib/rigor/language_server.rb +4 -6
  222. data/lib/rigor/mcp/loop.rb +2 -3
  223. data/lib/rigor/mcp/server.rb +4 -7
  224. data/lib/rigor/mcp.rb +3 -6
  225. data/lib/rigor/plugin/access_denied_error.rb +5 -8
  226. data/lib/rigor/plugin/additional_initializer.rb +21 -31
  227. data/lib/rigor/plugin/base.rb +335 -518
  228. data/lib/rigor/plugin/blueprint.rb +14 -23
  229. data/lib/rigor/plugin/box.rb +18 -29
  230. data/lib/rigor/plugin/fact_store.rb +16 -26
  231. data/lib/rigor/plugin/inflector.rb +37 -53
  232. data/lib/rigor/plugin/io_boundary.rb +33 -56
  233. data/lib/rigor/plugin/isolation.rb +42 -55
  234. data/lib/rigor/plugin/load_error.rb +10 -15
  235. data/lib/rigor/plugin/loader.rb +30 -49
  236. data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
  237. data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
  238. data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
  239. data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
  240. data/lib/rigor/plugin/macro.rb +10 -15
  241. data/lib/rigor/plugin/manifest.rb +85 -144
  242. data/lib/rigor/plugin/node_context.rb +14 -22
  243. data/lib/rigor/plugin/node_rule_walk.rb +49 -74
  244. data/lib/rigor/plugin/protocol_contract.rb +25 -39
  245. data/lib/rigor/plugin/registry.rb +132 -205
  246. data/lib/rigor/plugin/services.rb +21 -33
  247. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
  248. data/lib/rigor/plugin/trust_policy.rb +24 -38
  249. data/lib/rigor/plugin/type_node_resolver.rb +15 -24
  250. data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
  251. data/lib/rigor/protection/mutation_scanner.rb +27 -35
  252. data/lib/rigor/protection/mutator.rb +50 -70
  253. data/lib/rigor/protection/test_suite_oracle.rb +20 -27
  254. data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
  255. data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
  256. data/lib/rigor/rbs_extended/reporter.rb +24 -40
  257. data/lib/rigor/rbs_extended.rb +107 -197
  258. data/lib/rigor/reflection.rb +68 -86
  259. data/lib/rigor/scope/discovery_index.rb +14 -19
  260. data/lib/rigor/scope.rb +255 -310
  261. data/lib/rigor/sig_gen/classification.rb +6 -10
  262. data/lib/rigor/sig_gen/generator.rb +197 -323
  263. data/lib/rigor/sig_gen/layout_index.rb +12 -20
  264. data/lib/rigor/sig_gen/method_candidate.rb +12 -17
  265. data/lib/rigor/sig_gen/observation_collector.rb +38 -70
  266. data/lib/rigor/sig_gen/observed_call.rb +13 -23
  267. data/lib/rigor/sig_gen/path_mapper.rb +17 -29
  268. data/lib/rigor/sig_gen/renderer.rb +7 -13
  269. data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
  270. data/lib/rigor/sig_gen/write_result.rb +8 -16
  271. data/lib/rigor/sig_gen/writer.rb +95 -174
  272. data/lib/rigor/sig_gen.rb +3 -6
  273. data/lib/rigor/signature_path_audit.rb +24 -30
  274. data/lib/rigor/source/constant_path.rb +10 -14
  275. data/lib/rigor/source/literals.rb +31 -45
  276. data/lib/rigor/source/node_locator.rb +9 -11
  277. data/lib/rigor/source/node_walker.rb +9 -13
  278. data/lib/rigor/source.rb +3 -4
  279. data/lib/rigor/testing.rb +16 -20
  280. data/lib/rigor/triage/catalogue.rb +38 -62
  281. data/lib/rigor/triage.rb +31 -52
  282. data/lib/rigor/trinary.rb +9 -13
  283. data/lib/rigor/type/acceptance_router.rb +4 -6
  284. data/lib/rigor/type/accepts_result.rb +10 -14
  285. data/lib/rigor/type/app.rb +19 -27
  286. data/lib/rigor/type/bot.rb +4 -6
  287. data/lib/rigor/type/bound_method.rb +10 -15
  288. data/lib/rigor/type/combinator.rb +165 -257
  289. data/lib/rigor/type/constant.rb +23 -34
  290. data/lib/rigor/type/data_class.rb +10 -15
  291. data/lib/rigor/type/data_instance.rb +14 -20
  292. data/lib/rigor/type/difference.rb +21 -32
  293. data/lib/rigor/type/dynamic.rb +3 -5
  294. data/lib/rigor/type/hash_shape.rb +32 -18
  295. data/lib/rigor/type/integer_range.rb +11 -16
  296. data/lib/rigor/type/intersection.rb +27 -42
  297. data/lib/rigor/type/nominal.rb +10 -15
  298. data/lib/rigor/type/plain_lattice.rb +9 -13
  299. data/lib/rigor/type/refined.rb +67 -114
  300. data/lib/rigor/type/singleton.rb +4 -6
  301. data/lib/rigor/type/struct_class.rb +11 -16
  302. data/lib/rigor/type/struct_instance.rb +15 -21
  303. data/lib/rigor/type/tuple.rb +14 -19
  304. data/lib/rigor/type/union.rb +30 -42
  305. data/lib/rigor/type_node/generic.rb +14 -26
  306. data/lib/rigor/type_node/identifier.rb +12 -19
  307. data/lib/rigor/type_node.rb +3 -12
  308. data/lib/rigor/value_semantics.rb +16 -21
  309. data/lib/rigor/version.rb +1 -1
  310. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
  311. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
  312. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
  313. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
  314. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
  315. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
  316. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
  317. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
  318. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
  319. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
  320. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
  321. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
  322. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
  323. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
  324. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
  325. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
  326. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
  327. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
  328. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
  329. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
  330. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
  331. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
  332. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
  333. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
  334. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
  335. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
  336. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
  337. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
  338. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
  339. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
  340. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
  341. data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
  342. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
  343. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
  344. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
  345. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
  346. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
  347. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
  348. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
  349. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
  350. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
  351. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
  352. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
  353. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
  354. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
  355. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
  356. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
  357. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
  358. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
  359. data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
  360. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
  361. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
  362. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
  363. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
  364. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
  365. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
  366. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
  367. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
  368. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
  369. data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
  370. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
  371. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
  372. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
  373. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
  374. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
  375. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
  376. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
  377. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
  378. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
  379. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
  380. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
  381. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
  382. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
  383. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
  384. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
  385. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
  386. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
  387. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
  388. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
  389. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
  390. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
  391. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
  392. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
  393. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
  394. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
  395. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
  396. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
  397. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
  398. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
  399. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
  400. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
  401. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
  402. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
  403. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
  404. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
  405. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
  406. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
  407. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
  408. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
  409. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
  410. data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
  411. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
  412. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
  413. data/sig/rigor/scope.rbs +6 -0
  414. metadata +2 -1
@@ -5,14 +5,11 @@ require_relative "buffer_table"
5
5
 
6
6
  module Rigor
7
7
  module LanguageServer
8
- # LSP server lifecycle state machine + JSON-RPC method dispatcher.
9
- # State machine: `:uninitialized` → `:initialized` → `:shutdown`
10
- # `:exited`. {#dispatch} routes (method, params) to the matching
11
- # handler and returns the response payload (`nil` for notifications);
12
- # out-of-state requests return `InvalidRequest` (-32002) /
13
- # `MethodNotFound` (-32601). Full v1 capability surface (document
14
- # sync, publishDiagnostics, hover, completion, sig-help, folding,
15
- # selection, and watched-file invalidation) is implemented.
8
+ # LSP server lifecycle state machine + JSON-RPC method dispatcher. State machine: `:uninitialized` →
9
+ # `:initialized` → `:shutdown` → `:exited`. {#dispatch} routes (method, params) to the matching handler and
10
+ # returns the response payload (`nil` for notifications); out-of-state requests return `InvalidRequest`
11
+ # (-32002) / `MethodNotFound` (-32601). Full v1 capability surface (document sync, publishDiagnostics,
12
+ # hover, completion, sig-help, folding, selection, and watched-file invalidation) is implemented.
16
13
  class Server # rubocop:disable Metrics/ClassLength
17
14
  # JSON-RPC error codes per LSP spec § "Response Message".
18
15
  ERROR_PARSE_ERROR = -32_700
@@ -24,16 +21,13 @@ module Rigor
24
21
  ERROR_SERVER_NOT_INITIALIZED = -32_002
25
22
  ERROR_INVALID_REQUEST_AFTER_SHUTDOWN = -32_600
26
23
 
27
- # `TextDocumentSyncKind::Full = 1`. Slice 10 (deferred)
28
- # promotes to `Incremental = 2`.
24
+ # `TextDocumentSyncKind::Full = 1`. Slice 10 (deferred) promotes to `Incremental = 2`.
29
25
  TEXT_DOCUMENT_SYNC_FULL = 1
30
26
 
31
- # Methods callable BEFORE `initialize`. Per LSP spec § 3 only
32
- # `initialize` and `exit` are allowed pre-initialization; every
33
- # other request returns `ServerNotInitialized`. We also accept
34
- # `shutdown` so a sequence like `initialize → shutdown → exit`
35
- # (the conformance harness) round-trips even when the client
36
- # skips real work.
27
+ # Methods callable BEFORE `initialize`. Per LSP spec § 3 only `initialize` and `exit` are allowed
28
+ # pre-initialization; every other request returns `ServerNotInitialized`. We also accept `shutdown` so a
29
+ # sequence like `initialize → shutdown → exit` (the conformance harness) round-trips even when the
30
+ # client skips real work.
37
31
  PRE_INITIALIZE_METHODS = %w[initialize shutdown exit].freeze
38
32
 
39
33
  attr_reader :state, :exit_code, :buffer_table, :publisher,
@@ -45,13 +39,11 @@ module Rigor
45
39
  # resolves `textDocument/completion`. Nil → `MethodNotFound`.
46
40
  # @param signature_help_provider [Rigor::LanguageServer::SignatureHelpProvider, nil]
47
41
  # resolves `textDocument/signatureHelp`. Nil → `MethodNotFound`.
48
- # @param project_context [Rigor::LanguageServer::ProjectContext, nil]
49
- # the per-session cache of `Environment` + `Cache::Store`
50
- # the providers read on every request. When present,
51
- # `workspace/didChangeWatchedFiles` and
52
- # `workspace/didChangeConfiguration` invalidate the cache;
53
- # nil means "no project context": each request rebuilds env
54
- # from scratch (mainly for specs and backward compatibility).
42
+ # @param project_context [Rigor::LanguageServer::ProjectContext, nil] the per-session cache of
43
+ # `Environment` + `Cache::Store` the providers read on every request. When present,
44
+ # `workspace/didChangeWatchedFiles` and `workspace/didChangeConfiguration` invalidate the cache; nil
45
+ # means "no project context": each request rebuilds env from scratch (mainly for specs and backward
46
+ # compatibility).
55
47
  def initialize(buffer_table: BufferTable.new, publisher: nil, # rubocop:disable Metrics/ParameterLists
56
48
  hover_provider: nil, document_symbol_provider: nil,
57
49
  completion_provider: nil, signature_help_provider: nil,
@@ -143,10 +135,9 @@ module Rigor
143
135
  end
144
136
  end
145
137
 
146
- # Per LSP spec § "Server lifecycle / initialize": the server
147
- # responds with its capabilities. Each later slice extends
148
- # `advertised_capabilities` with the handler it wires;
149
- # clients asking for unadvertised methods get `MethodNotFound`.
138
+ # Per LSP spec § "Server lifecycle / initialize": the server responds with its capabilities. Each later
139
+ # slice extends `advertised_capabilities` with the handler it wires; clients asking for unadvertised
140
+ # methods get `MethodNotFound`.
150
141
  def handle_initialize(_params)
151
142
  @state = :initialized
152
143
  {
@@ -169,20 +160,17 @@ module Rigor
169
160
  caps[:documentSymbolProvider] = true if @document_symbol_provider
170
161
  if @completion_provider
171
162
  caps[:completionProvider] = {
172
- # `.` for method completion; `:` for constant-path
173
- # completion (slice 6). The server detects which form
174
- # by looking one character back when `:` triggers.
163
+ # `.` for method completion; `:` for constant-path completion (slice 6). The server detects which
164
+ # form by looking one character back when `:` triggers.
175
165
  triggerCharacters: [".", ":"],
176
- # v1 eager — full payload returned on first request.
177
- # Resolve becomes relevant if large enumerations
178
- # (Object descendants) become noticeable.
166
+ # v1 eager — full payload returned on first request. Resolve becomes relevant if large
167
+ # enumerations (Object descendants) become noticeable.
179
168
  resolveProvider: false
180
169
  }
181
170
  end
182
171
  if @signature_help_provider
183
172
  caps[:signatureHelpProvider] = {
184
- # `(` opens the argument list; `,` advances to the
185
- # next argument. Editors retrigger on both.
173
+ # `(` opens the argument list; `,` advances to the next argument. Editors retrigger on both.
186
174
  triggerCharacters: ["(", ","]
187
175
  }
188
176
  end
@@ -191,17 +179,15 @@ module Rigor
191
179
  caps
192
180
  end
193
181
 
194
- # `initialized` is a notification — no response body. Slice 7
195
- # will hook this to register `workspace/didChangeWatchedFiles`
196
- # if the client advertised the capability.
182
+ # `initialized` is a notification — no response body. Slice 7 will hook this to register
183
+ # `workspace/didChangeWatchedFiles` if the client advertised the capability.
197
184
  def handle_initialized
198
185
  nil
199
186
  end
200
187
 
201
188
  def handle_shutdown
202
189
  @state = :shutdown
203
- # Drop any in-flight debounced publishes so they don't
204
- # fire after the client has stopped listening.
190
+ # Drop any in-flight debounced publishes so they don't fire after the client has stopped listening.
205
191
  @publisher&.cancel_pending
206
192
  nil
207
193
  end
@@ -212,10 +198,9 @@ module Rigor
212
198
  nil
213
199
  end
214
200
 
215
- # textDocument/didOpen notification. Per LSP spec § the
216
- # `textDocument` payload carries `uri`, `languageId`,
217
- # `version`, and the full initial `text`. Triggers a
218
- # `publishDiagnostics` push when a publisher is wired.
201
+ # textDocument/didOpen notification. Per LSP spec § the `textDocument` payload carries `uri`,
202
+ # `languageId`, `version`, and the full initial `text`. Triggers a `publishDiagnostics` push when a
203
+ # publisher is wired.
219
204
  def handle_did_open(params)
220
205
  doc = params.fetch(:textDocument)
221
206
  uri = doc.fetch(:uri)
@@ -228,12 +213,10 @@ module Rigor
228
213
  nil
229
214
  end
230
215
 
231
- # textDocument/didChange under FULL sync. Each `contentChanges`
232
- # entry carries only `{ text: }`; the LAST entry is the new
233
- # full document text. Per LSP spec § "FULL sync" the array
234
- # MUST be exactly one entry in practice — we still take
235
- # `.last` defensively for clients that pad. Triggers
236
- # `publishDiagnostics` afterwards.
216
+ # textDocument/didChange under FULL sync. Each `contentChanges` entry carries only `{ text: }`; the LAST
217
+ # entry is the new full document text. Per LSP spec § "FULL sync" the array MUST be exactly one entry in
218
+ # practice we still take `.last` defensively for clients that pad. Triggers `publishDiagnostics`
219
+ # afterwards.
237
220
  def handle_did_change(params)
238
221
  doc = params.fetch(:textDocument)
239
222
  changes = params.fetch(:contentChanges)
@@ -249,13 +232,10 @@ module Rigor
249
232
  nil
250
233
  end
251
234
 
252
- # textDocument/hover REQUEST. Slice 5 returns either a
253
- # `Hover` payload (markdown contents wrapping type +
254
- # erased-RBS info) or nil when no expression is at the
255
- # queried position. Nil maps to `result: null` per LSP
256
- # spec; clients suppress the popup. Returns
257
- # `MethodNotFound` when no hover_provider is wired (slice
258
- # 1-4 behaviour).
235
+ # textDocument/hover REQUEST. Slice 5 returns either a `Hover` payload (markdown contents wrapping type
236
+ # + erased-RBS info) or nil when no expression is at the queried position. Nil maps to `result: null`
237
+ # per LSP spec; clients suppress the popup. Returns `MethodNotFound` when no hover_provider is wired
238
+ # (slice 1-4 behaviour).
259
239
  def handle_hover(params)
260
240
  return method_not_found("textDocument/hover") unless @hover_provider
261
241
 
@@ -268,29 +248,25 @@ module Rigor
268
248
  )
269
249
  end
270
250
 
271
- # workspace/didChangeWatchedFiles NOTIFICATION. Invalidates
272
- # the ProjectContext so cached pre-pass / Environment is
273
- # rebuilt on the next request. Slice 7's floor: any watched
274
- # file change triggers a full context rebuild. Per-file
275
- # surgical invalidation (per design doc § "Project context
276
- # refresh") is a follow-up; this is the LSP-correct floor.
251
+ # workspace/didChangeWatchedFiles NOTIFICATION. Invalidates the ProjectContext so cached pre-pass /
252
+ # Environment is rebuilt on the next request. Slice 7's floor: any watched file change triggers a full
253
+ # context rebuild. Per-file surgical invalidation (per design doc § "Project context refresh") is a
254
+ # follow-up; this is the LSP-correct floor.
277
255
  def handle_did_change_watched_files(_params)
278
256
  @project_context&.invalidate!
279
257
  nil
280
258
  end
281
259
 
282
- # workspace/didChangeConfiguration NOTIFICATION. The payload
283
- # shape is client-specific; v1 ignores the payload and
284
- # invalidates the context so the next read picks up any
285
- # external config changes (.rigor.yml / Gemfile.lock / etc).
260
+ # workspace/didChangeConfiguration NOTIFICATION. The payload shape is client-specific; v1 ignores the
261
+ # payload and invalidates the context so the next read picks up any external config changes
262
+ # (.rigor.yml / Gemfile.lock / etc).
286
263
  def handle_did_change_configuration(_params)
287
264
  @project_context&.invalidate!
288
265
  nil
289
266
  end
290
267
 
291
- # textDocument/selectionRange REQUEST. Routes to the
292
- # selection-range provider when wired; `MethodNotFound`
293
- # otherwise.
268
+ # textDocument/selectionRange REQUEST. Routes to the selection-range provider when wired;
269
+ # `MethodNotFound` otherwise.
294
270
  def handle_selection_range(params)
295
271
  return method_not_found("textDocument/selectionRange") unless @selection_range_provider
296
272
 
@@ -299,8 +275,7 @@ module Rigor
299
275
  @selection_range_provider.provide(doc.fetch(:uri), positions)
300
276
  end
301
277
 
302
- # textDocument/foldingRange REQUEST. Routes to the
303
- # folding-range provider when wired; `MethodNotFound`
278
+ # textDocument/foldingRange REQUEST. Routes to the folding-range provider when wired; `MethodNotFound`
304
279
  # otherwise.
305
280
  def handle_folding_range(params)
306
281
  return method_not_found("textDocument/foldingRange") unless @folding_range_provider
@@ -309,8 +284,7 @@ module Rigor
309
284
  @folding_range_provider.provide(doc.fetch(:uri))
310
285
  end
311
286
 
312
- # textDocument/signatureHelp REQUEST. Routes to the
313
- # signature-help provider when wired; `MethodNotFound`
287
+ # textDocument/signatureHelp REQUEST. Routes to the signature-help provider when wired; `MethodNotFound`
314
288
  # otherwise.
315
289
  def handle_signature_help(params)
316
290
  return method_not_found("textDocument/signatureHelp") unless @signature_help_provider
@@ -326,8 +300,8 @@ module Rigor
326
300
  )
327
301
  end
328
302
 
329
- # textDocument/completion REQUEST. Routes to the completion
330
- # provider when wired; `MethodNotFound` otherwise.
303
+ # textDocument/completion REQUEST. Routes to the completion provider when wired; `MethodNotFound`
304
+ # otherwise.
331
305
  def handle_completion(params)
332
306
  return method_not_found("textDocument/completion") unless @completion_provider
333
307
 
@@ -342,9 +316,8 @@ module Rigor
342
316
  )
343
317
  end
344
318
 
345
- # textDocument/documentSymbol REQUEST. Returns the
346
- # `DocumentSymbol[]` outline for the buffer at the requested
347
- # URI. Returns `MethodNotFound` when no provider is wired.
319
+ # textDocument/documentSymbol REQUEST. Returns the `DocumentSymbol[]` outline for the buffer at the
320
+ # requested URI. Returns `MethodNotFound` when no provider is wired.
348
321
  def handle_document_symbol(params)
349
322
  return method_not_found("textDocument/documentSymbol") unless @document_symbol_provider
350
323
 
@@ -352,10 +325,9 @@ module Rigor
352
325
  @document_symbol_provider.provide(doc.fetch(:uri))
353
326
  end
354
327
 
355
- # textDocument/didClose. Drops the buffer table entry AND
356
- # publishes an empty diagnostic set so clients clear inline
357
- # markers per LSP spec § "publishDiagnostics" the standard
358
- # way to indicate "no diagnostics remain for this URI".
328
+ # textDocument/didClose. Drops the buffer table entry AND publishes an empty diagnostic set so clients
329
+ # clear inline markers per LSP spec § "publishDiagnostics" the standard way to indicate "no
330
+ # diagnostics remain for this URI".
359
331
  def handle_did_close(params)
360
332
  doc = params.fetch(:textDocument)
361
333
  uri = doc.fetch(:uri)
@@ -19,22 +19,19 @@ require_relative "../type/hash_shape"
19
19
 
20
20
  module Rigor
21
21
  module LanguageServer
22
- # Answers `textDocument/signatureHelp` requests. When the user
23
- # types `(` inside a method call (`obj.foo(|`) editors fire
24
- # `signatureHelp` to show the method's parameter signature
25
- # inline. The provider parses the buffer, locates the enclosing
26
- # `CallNode`, infers the receiver's type, and returns the
22
+ # Answers `textDocument/signatureHelp` requests. When the user types `(` inside a method call
23
+ # (`obj.foo(|`) editors fire `signatureHelp` to show the method's parameter signature inline. The provider
24
+ # parses the buffer, locates the enclosing `CallNode`, infers the receiver's type, and returns the
27
25
  # method's first overload as a `SignatureInformation`.
28
26
  #
29
27
  # Slice C1 (this commit) ships:
30
- # - Sentinel patching for `obj.foo(|` so Prism's parse
31
- # succeeds (mirrors `CompletionProvider`'s slice B4 pattern).
28
+ # - Sentinel patching for `obj.foo(|` so Prism's parse succeeds (mirrors `CompletionProvider`'s slice B4
29
+ # pattern).
32
30
  # - First-overload signature only.
33
31
  # - Active parameter = comma count before cursor.
34
32
  #
35
- # Multi-overload presentation + `documentation` field +
36
- # active-parameter override per overload land in follow-up
37
- # slices (queued in the design doc § "Out of scope for v2").
33
+ # Multi-overload presentation + `documentation` field + active-parameter override per overload land in
34
+ # follow-up slices (queued in the design doc § "Out of scope for v2").
38
35
  class SignatureHelpProvider
39
36
  include BufferResolution
40
37
 
@@ -75,12 +72,10 @@ module Rigor
75
72
  patch_with_arg_sentinel(original_bytes, line, character)
76
73
  end
77
74
 
78
- # Mid-edit buffer at `obj.foo(|` or `obj.foo(1,|`: truncate
79
- # everything from the cursor onwards and append `SENTINEL)`
80
- # so the call is syntactically complete. The truncation is
81
- # aggressive — signatureHelp only cares about the enclosing
82
- # call's signature; downstream content (closing parens,
83
- # subsequent statements) is irrelevant.
75
+ # Mid-edit buffer at `obj.foo(|` or `obj.foo(1,|`: truncate everything from the cursor onwards and append
76
+ # `SENTINEL)` so the call is syntactically complete. The truncation is aggressive — signatureHelp only
77
+ # cares about the enclosing call's signature; downstream content (closing parens, subsequent statements)
78
+ # is irrelevant.
84
79
  def patch_with_arg_sentinel(original_bytes, line, character)
85
80
  prefix_offset = byte_offset_for(original_bytes, line, character)
86
81
  return [original_bytes, [line, character]] if prefix_offset.nil?
@@ -93,11 +88,9 @@ module Rigor
93
88
  [patched, [line, character]]
94
89
  end
95
90
 
96
- # Walks the AST for the smallest CallNode whose `arguments`
97
- # location encloses the cursor offset. Prism doesn't expose
98
- # parent pointers, so NodeLocator's leaf-returning shape
99
- # isn't enough; we re-walk. For LSP usage this is cheap —
100
- # the buffer is parsed once per request.
91
+ # Walks the AST for the smallest CallNode whose `arguments` location encloses the cursor offset. Prism
92
+ # doesn't expose parent pointers, so NodeLocator's leaf-returning shape isn't enough; we re-walk. For
93
+ # LSP usage this is cheap — the buffer is parsed once per request.
101
94
  def enclosing_call_for_offset(root, cursor_offset)
102
95
  result = nil
103
96
  walk = lambda do |n|
@@ -137,23 +130,18 @@ module Rigor
137
130
  end
138
131
  {
139
132
  signatures: signatures,
140
- # `activeSignature` is the index editors highlight by
141
- # default. Slice C2 picks the first overload uniformly;
142
- # a future slice could choose the overload that best
143
- # matches the current argument shape.
133
+ # `activeSignature` is the index editors highlight by default. Slice C2 picks the first overload
134
+ # uniformly; a future slice could choose the overload that best matches the current argument shape.
144
135
  activeSignature: 0,
145
136
  activeParameter: active_param
146
137
  }
147
138
  end
148
139
 
149
- # Builds the LSP `ParameterInformation[]` for a method type's
150
- # parameter list. Each entry's `label` is a STRING form
151
- # (e.g. `"::int width"`, `"?::string pad_string"`); LSP's
152
- # offset-tuple form (`[start, end]`) for in-signature
153
- # highlighting is queued. Order matches `activeParameter`'s
154
- # index expectation: required positionals, then optionals,
155
- # then rest, then trailing, then required keywords, then
156
- # optional keywords, then rest keywords.
140
+ # Builds the LSP `ParameterInformation[]` for a method type's parameter list. Each entry's `label` is a
141
+ # STRING form (e.g. `"::int width"`, `"?::string pad_string"`); LSP's offset-tuple form
142
+ # (`[start, end]`) for in-signature highlighting is queued. Order matches `activeParameter`'s index
143
+ # expectation: required positionals, then optionals, then rest, then trailing, then required keywords,
144
+ # then optional keywords, then rest keywords.
157
145
  def parameter_information(method_type) # rubocop:disable Metrics/AbcSize
158
146
  func = method_type.type
159
147
  return [] unless func.respond_to?(:required_positionals)
@@ -172,12 +160,9 @@ module Rigor
172
160
  param.name ? "#{param.type} #{param.name}" : param.type.to_s
173
161
  end
174
162
 
175
- # Identical contract to HoverRenderer#rbs_documentation —
176
- # surfaces the method's RBS comment text or nil. Kept inline
177
- # rather than extracted to a shared mixin because the two
178
- # call sites are small and the shape may diverge (signatureHelp
179
- # might want per-parameter docs split out; hover wants the
180
- # full paragraph).
163
+ # Identical contract to HoverRenderer#rbs_documentation — surfaces the method's RBS comment text or nil.
164
+ # Kept inline rather than extracted to a shared mixin because the two call sites are small and the shape
165
+ # may diverge (signatureHelp might want per-parameter docs split out; hover wants the full paragraph).
181
166
  def rbs_documentation(definition)
182
167
  comments = definition.respond_to?(:comments) ? definition.comments : nil
183
168
  return nil if comments.nil? || comments.empty?
@@ -200,9 +185,8 @@ module Rigor
200
185
  end
201
186
  end
202
187
 
203
- # Mirrors CompletionProvider's receiver-type mapping. Tuple →
204
- # Array, HashShape Hash, Refined / Difference unwrap to
205
- # their base (handled in `lookup_method` above for clarity).
188
+ # Mirrors CompletionProvider's receiver-type mapping. Tuple → Array, HashShape → Hash, Refined /
189
+ # Difference unwrap to their base (handled in `lookup_method` above for clarity).
206
190
  def nominal_class_name(type)
207
191
  case type
208
192
  when Type::Nominal then type.class_name
@@ -217,10 +201,9 @@ module Rigor
217
201
  Inference::ScopeIndexer.index(root, default_scope: scope)
218
202
  end
219
203
 
220
- # Counts commas in the buffer between the call's opening `(`
221
- # and the cursor position. Cursor on the first argument 0;
222
- # after one comma 1; etc. Bounded by the call's arguments
223
- # location so commas in nested expressions don't bleed in.
204
+ # Counts commas in the buffer between the call's opening `(` and the cursor position. Cursor on the
205
+ # first argument 0; after one comma → 1; etc. Bounded by the call's arguments location so commas in
206
+ # nested expressions don't bleed in.
224
207
  def active_parameter_index(call_node, bytes, line, character)
225
208
  return 0 if call_node.arguments.nil?
226
209
 
@@ -2,14 +2,11 @@
2
2
 
3
3
  module Rigor
4
4
  module LanguageServer
5
- # Wraps the LSP gem's `Io::Writer` with a Mutex so concurrent
6
- # writes (the dispatch loop's response writes + the Debouncer's
7
- # async `publishDiagnostics` writes) don't interleave on the
8
- # shared STDOUT.
5
+ # Wraps the LSP gem's `Io::Writer` with a Mutex so concurrent writes (the dispatch loop's response writes +
6
+ # the Debouncer's async `publishDiagnostics` writes) don't interleave on the shared STDOUT.
9
7
  #
10
- # Pass-through proxy: `#write(message)` is the only call site
11
- # the rest of the LSP uses; `#close` is forwarded for
12
- # completeness.
8
+ # Pass-through proxy: `#write(message)` is the only call site the rest of the LSP uses; `#close` is
9
+ # forwarded for completeness.
13
10
  class SynchronizedWriter
14
11
  def initialize(inner)
15
12
  @inner = inner
@@ -2,15 +2,12 @@
2
2
 
3
3
  module Rigor
4
4
  module LanguageServer
5
- # LSP DocumentUri ↔ filesystem path conversions. v1 supports
6
- # only `file://` URIs; other schemes (e.g. `untitled:`) return
7
- # nil from `#to_path` so the caller can short-circuit.
5
+ # LSP DocumentUri ↔ filesystem path conversions. v1 supports only `file://` URIs; other schemes (e.g.
6
+ # `untitled:`) return nil from `#to_path` so the caller can short-circuit.
8
7
  #
9
- # Windows drive-letter handling: `file:///C:/path` → `C:/path`.
10
- # The leading slash after the scheme is dropped on Windows; on
11
- # POSIX it stays. v1 ships POSIX behaviour; Windows specifics
12
- # land when Windows CI is wired (see design doc § "Open
13
- # questions").
8
+ # Windows drive-letter handling: `file:///C:/path` → `C:/path`. The leading slash after the scheme is
9
+ # dropped on Windows; on POSIX it stays. v1 ships POSIX behaviour; Windows specifics land when Windows CI is
10
+ # wired (see design doc § "Open questions").
14
11
  module Uri
15
12
  module_function
16
13
 
@@ -22,11 +19,9 @@ module Rigor
22
19
  def to_path(uri)
23
20
  return nil unless uri.is_a?(String) && uri.start_with?(FILE_SCHEME)
24
21
 
25
- # Percent-decode at the BYTE level so multi-byte UTF-8
26
- # escapes (`%E6%97%A5` `日`) reassemble correctly. Each
27
- # `%xx` decodes to one raw byte; the result is a byte string
28
- # we re-interpret as UTF-8. `delete_prefix` always returns
29
- # a String (vs `byteslice` whose RBS return is `String?`).
22
+ # Percent-decode at the BYTE level so multi-byte UTF-8 escapes (`%E6%97%A5` → `日`) reassemble
23
+ # correctly. Each `%xx` decodes to one raw byte; the result is a byte string we re-interpret as UTF-8.
24
+ # `delete_prefix` always returns a String (vs `byteslice` whose RBS return is `String?`).
30
25
  uri.delete_prefix(FILE_SCHEME).b
31
26
  .gsub(/%([0-9A-Fa-f]{2})/) { ::Regexp.last_match(1).hex.chr }
32
27
  .force_encoding(Encoding::UTF_8)
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rigor
4
- # The Language Server subsystem. See
5
- # `docs/design/20260517-language-server.md` for the design.
6
- # The full v1 capability surface (document sync, publishDiagnostics,
7
- # hover, completion, sig-help, folding, selection, and watched-file
8
- # invalidation) is implemented. This module is the namespace and
9
- # require entry point for the subsystem.
4
+ # The Language Server subsystem. See `docs/design/20260517-language-server.md` for the design. The full v1
5
+ # capability surface (document sync, publishDiagnostics, hover, completion, sig-help, folding, selection, and
6
+ # watched-file invalidation) is implemented. This module is the namespace and require entry point for the
7
+ # subsystem.
10
8
  module LanguageServer
11
9
  end
12
10
  end
@@ -4,9 +4,8 @@ require "json"
4
4
 
5
5
  module Rigor
6
6
  module MCP
7
- # Reads newline-delimited JSON-RPC 2.0 messages from `input`,
8
- # dispatches each to `server`, and writes responses to `output`.
9
- # Runs until input reaches EOF (the client closes the connection).
7
+ # Reads newline-delimited JSON-RPC 2.0 messages from `input`, dispatches each to `server`, and writes responses to
8
+ # `output`. Runs until input reaches EOF (the client closes the connection).
10
9
  class Loop
11
10
  def initialize(input:, output:, server:)
12
11
  @input = input
@@ -7,11 +7,9 @@ module Rigor
7
7
  module MCP
8
8
  # JSON-RPC 2.0 dispatcher for the MCP server.
9
9
  #
10
- # Each public `handle` call takes a parsed request hash and returns
11
- # a response hash (or nil for notifications that require no reply).
12
- # Tool implementations delegate to `CLI.new(argv, out:, err:).run`
13
- # with StringIO capture — every tool stays in sync with its CLI
14
- # counterpart automatically (ADR-33 WD4).
10
+ # Each public `handle` call takes a parsed request hash and returns a response hash (or nil for notifications that
11
+ # require no reply). Tool implementations delegate to `CLI.new(argv, out:, err:).run` with StringIO capture every
12
+ # tool stays in sync with its CLI counterpart automatically (ADR-33 WD4).
15
13
  class Server # rubocop:disable Metrics/ClassLength
16
14
  PROTOCOL_VERSION = "2024-11-05"
17
15
 
@@ -142,8 +140,7 @@ module Rigor
142
140
  @err = err
143
141
  end
144
142
 
145
- # Dispatches a parsed JSON-RPC request hash.
146
- # Returns nil for notifications (requests without an `id`).
143
+ # Dispatches a parsed JSON-RPC request hash. Returns nil for notifications (requests without an `id`).
147
144
  def handle(request)
148
145
  id = request["id"]
149
146
  method_name = request["method"]
data/lib/rigor/mcp.rb CHANGED
@@ -1,13 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rigor
4
- # The MCP (Model Context Protocol) server subsystem.
5
- # See `docs/adr/33-mcp-server.md` for the design.
4
+ # The MCP (Model Context Protocol) server subsystem. See `docs/adr/33-mcp-server.md` for the design.
6
5
  #
7
- # Entry point: `rigor mcp --transport stdio`.
8
- # The server exposes Rigor's analysis tools (check, type-of, triage,
9
- # annotate, sig-gen, explain, coverage) as MCP tool calls over a
10
- # newline-delimited JSON-RPC 2.0 stdio stream.
6
+ # Entry point: `rigor mcp --transport stdio`. The server exposes Rigor's analysis tools (check, type-of, triage,
7
+ # annotate, sig-gen, explain, coverage) as MCP tool calls over a newline-delimited JSON-RPC 2.0 stdio stream.
11
8
  module MCP
12
9
  end
13
10
  end
@@ -2,15 +2,12 @@
2
2
 
3
3
  module Rigor
4
4
  module Plugin
5
- # Raised when a plugin's I/O attempt fails the active
6
- # {TrustPolicy}. Surfaced through {IoBoundary} so the analyzer
7
- # can convert the exception into a `:plugin_loader` diagnostic
8
- # without crashing `rigor check`.
5
+ # Raised when a plugin's I/O attempt fails the active {TrustPolicy}. Surfaced through {IoBoundary} so the
6
+ # analyzer can convert the exception into a `:plugin_loader` diagnostic without crashing `rigor check`.
9
7
  #
10
- # The policy is documented in [ADR-2 § "Plugin Trust and I/O
11
- # Policy"](../../../docs/adr/2-extension-api.md). Slice 2's
12
- # surface lists `:read_outside_scope` and `:network_disabled`
13
- # as the two reason codes; future slices may extend the set.
8
+ # The policy is documented in [ADR-2 § "Plugin Trust and I/O Policy"](../../../docs/adr/2-extension-api.md).
9
+ # Slice 2's surface lists `:read_outside_scope` and `:network_disabled` as the two reason codes; future slices
10
+ # may extend the set.
14
11
  class AccessDeniedError < StandardError
15
12
  attr_reader :reason, :resource
16
13