rigortype 0.4.0 → 0.4.2

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 (237) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/data/builtins/ruby_core/io.yml +1 -0
  4. data/data/builtins/ruby_core/proc.yml +4 -0
  5. data/data/builtins/ruby_core/random.yml +4 -0
  6. data/data/builtins/ruby_core/struct.yml +3 -0
  7. data/data/core_overlay/env.rbs +34 -0
  8. data/data/core_overlay/gc.rbs +50 -0
  9. data/data/core_overlay/hash.rbs +45 -0
  10. data/data/core_overlay/integer.rbs +31 -0
  11. data/data/core_overlay/io_buffer.rbs +27 -0
  12. data/data/core_overlay/kernel.rbs +40 -0
  13. data/data/core_overlay/match_data.rbs +28 -0
  14. data/data/core_overlay/module.rbs +51 -0
  15. data/data/core_overlay/object_space.rbs +29 -0
  16. data/data/core_overlay/proc.rbs +45 -0
  17. data/data/core_overlay/range.rbs +40 -0
  18. data/data/core_overlay/source_range.rbs +78 -0
  19. data/data/core_overlay/string.rbs +86 -0
  20. data/data/vendored_gem_sigs/prime/integer-extension.rbs +41 -0
  21. data/data/vendored_gem_sigs/prime/prime.rbs +372 -0
  22. data/docs/handbook/01-getting-started.md +3 -3
  23. data/docs/handbook/06-classes.md +3 -1
  24. data/docs/handbook/08-understanding-errors.md +3 -2
  25. data/docs/handbook/11-sig-gen.md +6 -0
  26. data/docs/handbook/appendix-liskov.md +5 -0
  27. data/docs/install.md +87 -15
  28. data/docs/manual/02-cli-reference.md +2 -2
  29. data/docs/manual/03-configuration.md +6 -1
  30. data/docs/manual/04-diagnostics.md +2 -1
  31. data/docs/manual/06-baseline.md +2 -0
  32. data/docs/manual/07-plugins.md +1 -1
  33. data/docs/manual/08-skills.md +4 -3
  34. data/docs/manual/12-caching.md +43 -4
  35. data/docs/manual/14-rails-quickstart.md +19 -11
  36. data/docs/manual/18-removing-dead-code.md +32 -2
  37. data/docs/manual/plugins/README.md +6 -1
  38. data/docs/manual/plugins/rigor-activerecord.md +21 -0
  39. data/docs/manual/plugins/rigor-alba.md +60 -0
  40. data/docs/manual/plugins/rigor-minitest.md +22 -4
  41. data/docs/manual/plugins/rigor-typelizer.md +71 -0
  42. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +27 -3
  43. data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +21 -92
  44. data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +275 -0
  45. data/lib/rigor/analysis/check_rules/rule_ids.rb +4 -0
  46. data/lib/rigor/analysis/check_rules/source_arity.rb +184 -61
  47. data/lib/rigor/analysis/check_rules.rb +407 -144
  48. data/lib/rigor/analysis/dependency_recorder.rb +215 -18
  49. data/lib/rigor/analysis/dependency_source_inference/builder.rb +8 -1
  50. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +21 -0
  51. data/lib/rigor/analysis/dependency_source_inference/index.rb +36 -11
  52. data/lib/rigor/analysis/dependency_source_inference/walker.rb +196 -27
  53. data/lib/rigor/analysis/erb_template_detector.rb +2 -1
  54. data/lib/rigor/analysis/incremental.rb +29 -9
  55. data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +291 -0
  56. data/lib/rigor/analysis/incremental_run_slot.rb +173 -0
  57. data/lib/rigor/analysis/incremental_session.rb +287 -50
  58. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
  59. data/lib/rigor/analysis/reachability/graph.rb +123 -23
  60. data/lib/rigor/analysis/reachability/scan.rb +290 -36
  61. data/lib/rigor/analysis/reachability/scan_cache.rb +2 -1
  62. data/lib/rigor/analysis/rule_catalog.rb +43 -0
  63. data/lib/rigor/analysis/run_cache_key.rb +43 -9
  64. data/lib/rigor/analysis/run_stats.rb +2 -2
  65. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +88 -6
  66. data/lib/rigor/analysis/runner/pool_coordinator.rb +52 -13
  67. data/lib/rigor/analysis/runner/project_pre_passes.rb +21 -13
  68. data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
  69. data/lib/rigor/analysis/runner.rb +371 -49
  70. data/lib/rigor/analysis/shadow_harness.rb +27 -0
  71. data/lib/rigor/analysis/source_rbs_gate.rb +157 -0
  72. data/lib/rigor/analysis/template_unit_paths.rb +6 -4
  73. data/lib/rigor/analysis/template_units.rb +15 -5
  74. data/lib/rigor/analysis/worker_session.rb +11 -7
  75. data/lib/rigor/cache/descriptor.rb +40 -1
  76. data/lib/rigor/cache/file_digest.rb +28 -0
  77. data/lib/rigor/cache/incremental_snapshot.rb +92 -8
  78. data/lib/rigor/cache/store.rb +63 -3
  79. data/lib/rigor/cache/value_digest.rb +325 -0
  80. data/lib/rigor/cli/annotate_command.rb +5 -0
  81. data/lib/rigor/cli/baseline_command.rb +7 -18
  82. data/lib/rigor/cli/check_command.rb +85 -14
  83. data/lib/rigor/cli/doctor_command.rb +1 -1
  84. data/lib/rigor/cli/effects_report.rb +2 -2
  85. data/lib/rigor/cli/trace_command.rb +5 -0
  86. data/lib/rigor/cli/type_of_command.rb +5 -3
  87. data/lib/rigor/cli/unused_command.rb +16 -10
  88. data/lib/rigor/cli.rb +11 -3
  89. data/lib/rigor/config_audit.rb +3 -2
  90. data/lib/rigor/config_path.rb +29 -0
  91. data/lib/rigor/configuration/severity_profile.rb +11 -0
  92. data/lib/rigor/configuration.rb +52 -7
  93. data/lib/rigor/effects/plugin_facts.rb +6 -6
  94. data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
  95. data/lib/rigor/environment/gated_signature_guard.rb +43 -0
  96. data/lib/rigor/environment/gated_signature_plan.rb +339 -0
  97. data/lib/rigor/environment/lockfile_resolver.rb +10 -1
  98. data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
  99. data/lib/rigor/environment/rbs_coverage_report.rb +1 -1
  100. data/lib/rigor/environment/rbs_loader.rb +284 -15
  101. data/lib/rigor/environment/required_features.rb +206 -0
  102. data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
  103. data/lib/rigor/environment.rb +34 -73
  104. data/lib/rigor/inference/acceptance.rb +28 -3
  105. data/lib/rigor/inference/block_parameter_binder.rb +29 -13
  106. data/lib/rigor/inference/builtins/cruby_definers.rb +61 -0
  107. data/lib/rigor/inference/builtins/method_catalog.rb +3 -0
  108. data/lib/rigor/inference/captured_locals.rb +7 -1
  109. data/lib/rigor/inference/declaration_walk/context.rb +195 -0
  110. data/lib/rigor/inference/declaration_walk/errors.rb +18 -0
  111. data/lib/rigor/inference/declaration_walk/shadow.rb +147 -0
  112. data/lib/rigor/inference/declaration_walk/traversal.rb +441 -0
  113. data/lib/rigor/inference/declaration_walk.rb +7 -0
  114. data/lib/rigor/inference/def_node_resolver.rb +26 -3
  115. data/lib/rigor/inference/definer_resolution.rb +266 -0
  116. data/lib/rigor/inference/expression_typer.rb +351 -61
  117. data/lib/rigor/inference/external_ancestor_resolution.rb +13 -16
  118. data/lib/rigor/inference/global_write_census.rb +7 -4
  119. data/lib/rigor/inference/guard_rebinding.rb +54 -13
  120. data/lib/rigor/inference/in_effect_refinements/proc_literals.rb +83 -0
  121. data/lib/rigor/inference/in_effect_refinements/refine_defs.rb +54 -0
  122. data/lib/rigor/inference/in_effect_refinements/scope_reads.rb +282 -0
  123. data/lib/rigor/inference/in_effect_refinements/walk.rb +276 -0
  124. data/lib/rigor/inference/in_effect_refinements.rb +256 -0
  125. data/lib/rigor/inference/key_presence_guard/scan.rb +281 -0
  126. data/lib/rigor/inference/key_presence_guard.rb +303 -0
  127. data/lib/rigor/inference/macro_block_self_type.rb +73 -14
  128. data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
  129. data/lib/rigor/inference/method_dispatcher/arithmetic_sequence_elements.rb +73 -0
  130. data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +68 -0
  131. data/lib/rigor/inference/method_dispatcher/integer_step_block_params.rb +81 -0
  132. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -0
  133. data/lib/rigor/inference/method_dispatcher/keyword_arguments.rb +267 -0
  134. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -1
  135. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +122 -105
  136. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +305 -54
  137. data/lib/rigor/inference/method_dispatcher/splat_arity.rb +71 -0
  138. data/lib/rigor/inference/method_dispatcher.rb +44 -11
  139. data/lib/rigor/inference/module_function_state.rb +214 -0
  140. data/lib/rigor/inference/multi_target_binder.rb +21 -16
  141. data/lib/rigor/inference/narrowing.rb +166 -22
  142. data/lib/rigor/inference/object_mixins.rb +180 -0
  143. data/lib/rigor/inference/parameter_inference_collector.rb +10 -9
  144. data/lib/rigor/inference/project_patched_methods.rb +10 -5
  145. data/lib/rigor/inference/project_patched_scanner.rb +71 -3
  146. data/lib/rigor/inference/refine_census.rb +239 -0
  147. data/lib/rigor/inference/refine_self.rb +317 -0
  148. data/lib/rigor/inference/refined_dispatch/own_method.rb +403 -0
  149. data/lib/rigor/inference/refined_dispatch.rb +272 -0
  150. data/lib/rigor/inference/scope_indexer/certainty.rb +176 -0
  151. data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +35 -0
  152. data/lib/rigor/inference/scope_indexer/def_nestings_collector.rb +47 -0
  153. data/lib/rigor/inference/scope_indexer/layered_def_nestings.rb +36 -0
  154. data/lib/rigor/inference/scope_indexer/member_layouts_collector.rb +61 -0
  155. data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +143 -0
  156. data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
  157. data/lib/rigor/inference/scope_indexer.rb +2129 -354
  158. data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
  159. data/lib/rigor/inference/statement_evaluator.rb +149 -32
  160. data/lib/rigor/inference/string_mutation.rb +9 -3
  161. data/lib/rigor/inference/synthetic_method_scanner.rb +2 -1
  162. data/lib/rigor/inference/version_guard.rb +19 -10
  163. data/lib/rigor/language_server/project_context.rb +31 -0
  164. data/lib/rigor/language_server/server.rb +18 -0
  165. data/lib/rigor/plugin/base.rb +28 -8
  166. data/lib/rigor/plugin/inflector.rb +1 -1
  167. data/lib/rigor/plugin/io_boundary.rb +124 -7
  168. data/lib/rigor/plugin/isolation.rb +1 -1
  169. data/lib/rigor/plugin/macro/block_as_method.rb +51 -8
  170. data/lib/rigor/plugin/trust_policy.rb +3 -3
  171. data/lib/rigor/project_environment.rb +29 -6
  172. data/lib/rigor/protection/discovery_seed.rb +18 -9
  173. data/lib/rigor/protection/mutation_cache.rb +4 -4
  174. data/lib/rigor/protection/mutator.rb +1 -1
  175. data/lib/rigor/reflection/constant_ancestors.rb +211 -46
  176. data/lib/rigor/reflection/constant_path.rb +33 -7
  177. data/lib/rigor/reflection.rb +41 -10
  178. data/lib/rigor/scope/discovery_index.rb +258 -3
  179. data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
  180. data/lib/rigor/scope/resolution_chain.rb +1032 -0
  181. data/lib/rigor/scope.rb +480 -328
  182. data/lib/rigor/sig_gen/alias_index.rb +1 -1
  183. data/lib/rigor/sig_gen/classification.rb +4 -1
  184. data/lib/rigor/sig_gen/effect_annotation.rb +2 -2
  185. data/lib/rigor/sig_gen/generator.rb +77 -21
  186. data/lib/rigor/sig_gen/method_candidate.rb +2 -2
  187. data/lib/rigor/sig_gen/skip_reason_catalog.rb +12 -0
  188. data/lib/rigor/source/alias_names.rb +52 -0
  189. data/lib/rigor/source/literals.rb +3 -2
  190. data/lib/rigor/source/symbol_name.rb +20 -0
  191. data/lib/rigor/type/combinator.rb +59 -3
  192. data/lib/rigor/type/float_range.rb +4 -1
  193. data/lib/rigor/type/nominal.rb +6 -1
  194. data/lib/rigor/version.rb +1 -1
  195. data/plugins/rigor-ac-library-rb/lib/rigor/plugin/ac_library_rb.rb +28 -0
  196. data/plugins/rigor-ac-library-rb/lib/rigor-ac-library-rb.rb +3 -0
  197. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/convolution.rbs +7 -0
  198. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/data_structures.rbs +160 -0
  199. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/graph.rbs +94 -0
  200. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/math.rbs +42 -0
  201. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/modint.rbs +71 -0
  202. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/object.rbs +37 -0
  203. data/plugins/rigor-ac-library-rb/sig/ac_library_rb/segtree.rbs +83 -0
  204. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +2 -1
  205. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +100 -0
  206. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +94 -10
  207. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +43 -2
  208. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +3 -1
  209. data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +149 -0
  210. data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +74 -0
  211. data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +104 -0
  212. data/plugins/rigor-alba/lib/rigor/plugin/alba.rb +85 -0
  213. data/plugins/rigor-alba/lib/rigor-alba.rb +3 -0
  214. data/plugins/rigor-alba/sig/alba.rbs +4 -0
  215. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +2 -2
  216. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +29 -12
  217. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +13 -2
  218. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +130 -21
  219. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +6 -4
  220. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +4 -4
  221. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +1 -1
  222. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +1 -1
  223. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +31 -0
  224. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +102 -0
  225. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +87 -0
  226. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +76 -0
  227. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +73 -0
  228. data/plugins/rigor-typelizer/lib/rigor-typelizer.rb +3 -0
  229. data/sig/rigor/analysis/dependency_source_inference/index.rbs +1 -1
  230. data/sig/rigor/environment.rbs +2 -0
  231. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  232. data/sig/rigor/scope.rbs +69 -4
  233. data/sig/rigor/source.rbs +4 -0
  234. data/sig/rigor.rbs +3 -1
  235. data/skills/rigor-project-init/SKILL.md +37 -11
  236. data/skills/rigor-project-init/references/02-configure.md +7 -2
  237. metadata +90 -1
@@ -0,0 +1,160 @@
1
+ module AcLibraryRb
2
+ class DSU
3
+ attr_reader parent_or_size: Array[Integer]
4
+ attr_reader n: Integer
5
+
6
+ def initialize: (?Integer n) -> void
7
+
8
+ # The leader of the merged component.
9
+ def merge: (Integer a, Integer b) -> Integer
10
+ alias unite merge
11
+
12
+ def same?: (Integer a, Integer b) -> bool
13
+ alias same same?
14
+
15
+ def leader: (Integer a) -> Integer
16
+ alias root leader
17
+ alias find leader
18
+
19
+ # Like `leader`, growing the set to hold `a` when it is out of range.
20
+ def []: (Integer a) -> Integer
21
+
22
+ def size: (Integer a) -> Integer
23
+
24
+ def groups: () -> Array[Array[Integer]]
25
+
26
+ def to_s: () -> String
27
+ end
28
+
29
+ class UnionFind = DSU
30
+
31
+ # Element values are whatever the caller adds: the tree starts from `0` and adds with `+`, so an
32
+ # `Integer`, a `Float` and a `ModInt` all work.
33
+ class FenwickTree
34
+ attr_reader data: Array[untyped]
35
+ attr_reader size: Integer
36
+
37
+ def initialize: (Array[untyped] | Integer arg) -> void
38
+
39
+ def add: (Integer i, untyped x) -> void
40
+
41
+ def sum: (Integer l, Integer r) -> untyped
42
+ | (Integer r) -> untyped
43
+ | (Range[Integer] range) -> untyped
44
+
45
+ def _sum: (Integer i) -> untyped
46
+ alias left_sum _sum
47
+
48
+ def to_s: () -> String
49
+ end
50
+
51
+ # A binary heap that pops the highest-priority element first: the largest by default, or the first
52
+ # argument of the block when it returns truthy.
53
+ class PriorityQueue[T]
54
+ # The factories answer `PriorityQueue[untyped]`: bound from a literal array, `T` would be the literals it
55
+ # starts with, and a later `pop` would read as one of them.
56
+ def self.max: (Array[untyped] array) -> PriorityQueue[untyped]
57
+
58
+ def self.min: (Array[untyped] array) -> PriorityQueue[untyped]
59
+
60
+ def self.[]: (*untyped array) ?{ (untyped, untyped) -> boolish } -> PriorityQueue[untyped]
61
+
62
+ def initialize: (?Array[T] array) ?{ (T, T) -> boolish } -> void
63
+
64
+ attr_reader heap: Array[T]
65
+ alias to_a heap
66
+
67
+ def push: (T item) -> self
68
+ alias << push
69
+ alias append push
70
+
71
+ def pop: () -> T?
72
+
73
+ def get: () -> T?
74
+ alias top get
75
+ alias first get
76
+
77
+ def empty?: () -> bool
78
+
79
+ def size: () -> Integer
80
+
81
+ def to_s: () -> String
82
+ end
83
+
84
+ class HeapQueue = PriorityQueue
85
+
86
+ class Deque[T]
87
+ include Enumerable[T]
88
+
89
+ def self.[]: (*untyped args) -> Deque[untyped]
90
+
91
+ def initialize: (?Array[T] arg, ?untyped value, ?initial_capacity: Integer) -> void
92
+ | (Integer size, ?T value, ?initial_capacity: Integer) -> void
93
+
94
+ def empty?: () -> bool
95
+
96
+ def size: () -> Integer
97
+ alias length size
98
+
99
+ def <<: (T x) -> self
100
+
101
+ def push: (*T args) -> self
102
+ alias append push
103
+
104
+ def unshift: (*T args) -> self
105
+ alias prepend unshift
106
+
107
+ def pop: () -> T?
108
+
109
+ def shift: () -> T?
110
+
111
+ def last: () -> T?
112
+
113
+ def slice: (Integer idx) -> T?
114
+
115
+ def []: (Integer idx) -> T?
116
+ | (Integer start, Integer length) -> Deque[T]?
117
+ | (Range[Integer] range) -> Deque[T]?
118
+
119
+ def at: (Integer idx) -> T?
120
+
121
+ def []=: (Integer idx, T value) -> T
122
+
123
+ def ==: (untyped other) -> bool
124
+
125
+ def hash: () -> Integer
126
+
127
+ def reverse: () -> Deque[T]
128
+
129
+ def reverse!: () -> self
130
+
131
+ def reversed?: () -> bool
132
+
133
+ def dig: (int idx, *untyped) -> untyped
134
+
135
+ def each: () { (T) -> void } -> Array[T]
136
+ | () -> Enumerator[T, Array[T]]
137
+
138
+ def clear: () -> self
139
+
140
+ def join: (?String? sep) -> String
141
+
142
+ def rotate!: (?Integer cnt) -> self
143
+
144
+ def rotate: (?Integer cnt) -> Deque[T]
145
+
146
+ def sample: () -> T?
147
+
148
+ def shuffle: () -> Deque[T]
149
+
150
+ def replace: (_ToA[T] other) -> self
151
+
152
+ def swap: (Integer i, Integer j) -> self
153
+
154
+ def to_a: () -> Array[T]
155
+
156
+ def to_s: () -> String
157
+
158
+ def inspect: () -> String
159
+ end
160
+ end
@@ -0,0 +1,94 @@
1
+ module AcLibraryRb
2
+ class MaxFlow
3
+ def initialize: (Integer n) -> void
4
+
5
+ # The index of the added edge.
6
+ def add_edge: (Integer from, Integer to, Integer cap) -> Integer
7
+
8
+ def add_edges: (_Each[[Integer, Integer, Integer]] edges) -> self
9
+
10
+ def add: (Integer from, Integer to, Integer cap) -> Integer
11
+ | (_Each[[Integer, Integer, Integer]] edges) -> self
12
+
13
+ # `[from, to, cap]`, as `gets.split.map(&:to_i)` reads it.
14
+ def push: (Array[Integer] edge) -> Integer
15
+ alias << push
16
+
17
+ # `[from, to, cap, flow]` of the `i`-th edge.
18
+ def []: (Integer i) -> [Integer, Integer, Integer, Integer]
19
+ alias get_edge []
20
+ alias edge []
21
+
22
+ def edges: () -> Array[[Integer, Integer, Integer, Integer]]
23
+
24
+ def change_edge: (Integer i, Integer new_cap, Integer new_flow) -> void
25
+
26
+ # A `Float` limit the capacities do not bound comes back as the flow.
27
+ def flow: (Integer s, Integer t, ?Integer flow_limit) -> Integer
28
+ | (Integer s, Integer t, (Integer | Float) flow_limit) -> (Integer | Float)
29
+ alias max_flow flow
30
+
31
+ # Whether each vertex is reachable from `s` in the residual graph.
32
+ def min_cut: (Integer s) -> Array[bool]
33
+ end
34
+
35
+ class MinCostFlow
36
+ def initialize: (Integer n) -> void
37
+
38
+ # The index of the added edge.
39
+ def add_edge: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
40
+
41
+ def add_edges: (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
42
+
43
+ def add: (Integer from, Integer to, Integer cap, Integer cost) -> Integer
44
+ | (_Each[[Integer, Integer, Integer, Integer]] edges) -> self
45
+
46
+ # `[from, to, cap, flow, cost]` of the `i`-th edge.
47
+ def get_edge: (Integer i) -> [Integer, Integer, Integer, Integer, Integer]
48
+ alias edge get_edge
49
+ alias [] get_edge
50
+
51
+ def edges: () -> Array[[Integer, Integer, Integer, Integer, Integer]]
52
+
53
+ # `[flow, cost]`.
54
+ # The default limit is `Float::MAX`, which the capacities always bound; a smaller `Float` limit may not.
55
+ def flow: (Integer s, Integer t, ?Integer flow_limit) -> [Integer, Integer]
56
+ | (Integer s, Integer t, (Integer | Float) flow_limit) -> [Integer | Float, Integer | Float]
57
+ alias min_cost_max_flow flow
58
+
59
+ def dual_ref: (Integer s, Integer t) -> bool
60
+
61
+ # The `[flow, cost]` breakpoints of the cost curve.
62
+ def slope: (Integer s, Integer t, ?Integer flow_limit) -> Array[[Integer, Integer]]
63
+ | (Integer s, Integer t, (Integer | Float) flow_limit) -> Array[[Integer | Float, Integer | Float]]
64
+ alias min_cost_slop slope
65
+ end
66
+
67
+ class SCC
68
+ def initialize: (Integer n) -> void
69
+
70
+ def add_edge: (Integer from, Integer to) -> self
71
+
72
+ def add_edges: (_Each[[Integer, Integer]] edges) -> self
73
+
74
+ def add: (Integer from, Integer to) -> self
75
+ | (_Each[[Integer, Integer]] edges) -> self
76
+
77
+ # The strongly connected components in topological order.
78
+ def scc: () -> Array[Array[Integer]]
79
+ end
80
+
81
+ class TwoSAT
82
+ def initialize: (Integer n) -> void
83
+
84
+ # One assignment per variable once `satisfiable?` has answered true; `nil` before that.
85
+ attr_reader answer: Array[bool?]
86
+
87
+ def add_clause: (Integer i, boolish f, Integer j, boolish g) -> nil
88
+
89
+ def satisfiable?: () -> bool
90
+ alias satisfiable satisfiable?
91
+ end
92
+
93
+ class TwoSat = TwoSAT
94
+ end
@@ -0,0 +1,42 @@
1
+ # ac-library-rb's math and string algorithms, instance methods of `AcLibraryRb` that a caller reaches by
2
+ # including the module.
3
+ module AcLibraryRb
4
+ # A callable taking two arguments: a `Proc`, a lambda or a `Method`.
5
+ interface _Call2[A, B, R]
6
+ def call: (A, B) -> R
7
+ end
8
+
9
+ # An object `Deque#replace` can read elements from.
10
+ interface _ToA[T]
11
+ def to_a: () -> Array[T]
12
+ end
13
+
14
+ def convolution: (Array[Integer] a, Array[Integer] b, ?mod: Integer, ?k: Integer, ?z: Integer) -> Array[Integer]
15
+
16
+ # `[remainder, modulus]`, or `[0, 0]` when there is no solution.
17
+ def crt: (Array[Integer] r, Array[Integer] m) -> [Integer, Integer]
18
+
19
+ def inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
20
+
21
+ def floor_sum: (Integer n, Integer m, Integer a, Integer b) -> Integer
22
+
23
+ def floor_sum_unsigned: (Integer n, Integer m, Integer a, Integer b) -> Integer
24
+
25
+ def inv_mod: (Integer x, Integer m) -> Integer
26
+
27
+ def _inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
28
+
29
+ def pow_mod: (Integer x, Integer n, Integer m) -> Integer
30
+
31
+ def suffix_array: (String s) -> Array[Integer]
32
+ | (Array[untyped] a, ?Integer? upper) -> Array[Integer]
33
+
34
+ def sa_is: (Array[Integer] s, Integer upper) -> Array[Integer]
35
+
36
+ def sa_is_induce: (Array[Integer] s, Array[bool] ls, Array[Integer] sum_l, Array[Integer] sum_s,
37
+ Array[Integer] lms) -> Array[Integer]
38
+
39
+ def lcp_array: (String | Array[untyped] s, Array[Integer] sa) -> Array[Integer]
40
+
41
+ def z_algorithm: (String | Array[untyped] s) -> Array[Integer]
42
+ end
@@ -0,0 +1,71 @@
1
+ module AcLibraryRb
2
+ # An integer modulo the global modulus set by `ModInt.set_mod`.
3
+ class ModInt < ::Numeric
4
+ def self.set_mod: (Integer mod) -> bool
5
+
6
+ def self.mod=: (Integer mod) -> bool
7
+
8
+ def self.mod: () -> Integer
9
+
10
+ def self.raw: (_ToI val) -> ModInt
11
+
12
+ def self.prime?: (Integer n) -> bool
13
+
14
+ def self.inv_gcd: (Integer a, Integer b) -> [Integer, Integer]
15
+
16
+ attr_accessor val: Integer
17
+ alias to_i val
18
+
19
+ def initialize: (?_ToI val) -> void
20
+
21
+ def inc!: () -> self
22
+
23
+ def dec!: () -> self
24
+
25
+ def add!: (_ToI other) -> self
26
+
27
+ def sub!: (_ToI other) -> self
28
+
29
+ def mul!: (_ToI other) -> self
30
+
31
+ def div!: (_ToI other) -> self
32
+
33
+ def +@: () -> self
34
+
35
+ def -@: () -> ModInt
36
+
37
+ # Answers the Integer `0` when the modulus is 1. Declared `ModInt` all the same: a union return reached
38
+ # `1 + m ** 2` as an argument, where overload selection reads a union whole (#1356), typed the sum `Integer`
39
+ # and reported `call.undefined-method` for `.val` on correct code.
40
+ def **: (Integer other) -> ModInt
41
+ alias pow **
42
+
43
+ def inv: () -> ModInt
44
+
45
+ def coerce: (_ToI other) -> [ModInt, ModInt]
46
+
47
+ def +: (_ToI other) -> ModInt
48
+
49
+ def -: (_ToI other) -> ModInt
50
+
51
+ def *: (_ToI other) -> ModInt
52
+
53
+ def /: (_ToI other) -> ModInt
54
+
55
+ def ==: (untyped other) -> bool
56
+
57
+ def pred: () -> ModInt
58
+
59
+ def succ: () -> ModInt
60
+
61
+ def zero?: () -> bool
62
+
63
+ def dup: () -> ModInt
64
+
65
+ def to_int: () -> Integer
66
+
67
+ def to_s: () -> String
68
+
69
+ def inspect: () -> String
70
+ end
71
+ end
@@ -0,0 +1,37 @@
1
+ # The core extensions under `ac-library-rb/core_ext/`. `ac-library-rb/modint` loads the `ModInt` conversions;
2
+ # `Integer#divisors` and the `Array` conversions need `ac-library-rb/core_ext/all` (or `integer`).
3
+ class Object
4
+ private
5
+
6
+ def ModInt: (_ToI val) -> AcLibraryRb::ModInt
7
+ end
8
+
9
+ class Array[unchecked out Elem]
10
+ def to_fenwick_tree: () -> AcLibraryRb::FenwickTree
11
+ alias to_fetree to_fenwick_tree
12
+
13
+ # The element type is not carried over: a literal array would pin it to the literals it starts with.
14
+ def to_priority_queue: () -> AcLibraryRb::PriorityQueue[untyped]
15
+ alias to_pq to_priority_queue
16
+ end
17
+
18
+ class Integer
19
+ # `ModInt#coerce` makes an Integer on the left answer a `ModInt`.
20
+ def +: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
21
+ def -: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
22
+ def *: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
23
+ def /: (AcLibraryRb::ModInt) -> AcLibraryRb::ModInt | ...
24
+
25
+ def divisors: () -> Array[Integer]
26
+
27
+ def each_divisor: () { (Integer) -> void } -> Array[Integer]
28
+ | () -> Enumerator[Integer, Array[Integer]]
29
+
30
+ def to_modint: () -> AcLibraryRb::ModInt
31
+ alias to_m to_modint
32
+ end
33
+
34
+ class String
35
+ def to_modint: () -> AcLibraryRb::ModInt
36
+ alias to_m to_modint
37
+ end
@@ -0,0 +1,83 @@
1
+ module AcLibraryRb
2
+ # A segment tree over the monoid `(S, op, e)`.
3
+ class Segtree[S]
4
+ attr_reader d: Array[S]
5
+ attr_reader op: _Call2[S, S, S]
6
+ attr_reader n: Integer
7
+ attr_reader leaf_size: Integer
8
+ attr_reader log: Integer
9
+
10
+ def initialize: (Array[S] | Integer v, S e) { (S, S) -> S } -> void
11
+ | (Array[S] | Integer v, _Call2[S, S, S] op, S e) -> void
12
+
13
+ def set: (Integer pos, S x) -> void
14
+ alias []= set
15
+
16
+ def get: (Integer pos) -> S
17
+ alias [] get
18
+
19
+ def prod: (Integer l, Integer r) -> S
20
+ | (Range[Integer] range) -> S
21
+
22
+ def all_prod: () -> S
23
+
24
+ def max_right: (Integer l) { (S) -> boolish } -> Integer
25
+
26
+ def min_left: (Integer r) { (S) -> boolish } -> Integer
27
+
28
+ def update: (Integer k) -> S
29
+ end
30
+
31
+ class SegTree = Segtree
32
+
33
+ # A lazy segment tree over the monoid `(S, op, e)` acted on by the maps `(F, composition, id)`, where
34
+ # `mapping.call(f, x)` applies `f` to `x` and `composition.call(f, g)` is `f` after `g`.
35
+ class LazySegtree[S, F]
36
+ attr_reader d: Array[S]
37
+ attr_reader lz: Array[F]
38
+ attr_reader e: S
39
+ attr_reader id: F
40
+ attr_accessor op: _Call2[S, S, S]
41
+ attr_accessor mapping: _Call2[F, S, S]?
42
+ attr_accessor composition: _Call2[F, F, F]?
43
+
44
+ # The first form is chosen when the second argument is a `Proc`.
45
+ def initialize: (Array[S] | Integer v, ^(S, S) -> S op, S e, _Call2[F, S, S] mapping,
46
+ _Call2[F, F, F] composition, F id) -> void
47
+ | (Array[S] | Integer v, S e, F id, ?_Call2[S, S, S]? op, ?_Call2[F, S, S]? mapping,
48
+ ?_Call2[F, F, F]? composition) ?{ (S, S) -> S } -> void
49
+
50
+ def set_mapping: () { (F, S) -> S } -> Proc
51
+
52
+ def set_composition: () { (F, F) -> F } -> Proc
53
+
54
+ def set: (Integer pos, S x) -> void
55
+ alias []= set
56
+
57
+ def get: (Integer pos) -> S
58
+ alias [] get
59
+
60
+ def prod: (Integer l, Integer r) -> S
61
+ | (Range[Integer] range) -> S
62
+
63
+ def all_prod: () -> S
64
+
65
+ def apply: (Integer pos, F f) -> void
66
+ | (Integer l, Integer r, F f) -> void
67
+ | (Range[Integer] range, F f) -> void
68
+
69
+ def range_apply: (Integer l, Integer r, F f) -> void
70
+
71
+ def max_right: (Integer l) { (S) -> boolish } -> Integer
72
+
73
+ def min_left: (Integer r) { (S) -> boolish } -> Integer
74
+
75
+ def update: (Integer k) -> S
76
+
77
+ def all_apply: (Integer k, F f) -> void
78
+
79
+ def push: (Integer k) -> void
80
+ end
81
+
82
+ class LazySegTree = LazySegtree
83
+ end
@@ -309,8 +309,9 @@ module Rigor
309
309
  args
310
310
  end
311
311
 
312
+ # The name is interned later (`filter_name.to_sym`), so a name no Symbol can hold reads as nil.
312
313
  def literal_symbol_or_string(node)
313
- Rigor::Source::Literals.symbol_or_string_name(node)
314
+ Rigor::Source::Literals.symbol_or_string(node)&.to_s
314
315
  end
315
316
 
316
317
  def filter_lookup_violation(call_node, arg_node, filter_name, methods, spell_checker, ambiguous_filters:)
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rigor
4
+ module Plugin
5
+ class Activerecord < Rigor::Plugin::Base
6
+ # The model classes ActiveRecord loads BY NAME from an association (`belongs_to :user` → `User`), for
7
+ # `rigor unused` (ADR-102 WD3). The name is derived at runtime and never written in source, so a
8
+ # reference index sees a model reached only this way as unreferenced.
9
+ #
10
+ # The rows come from the {ModelIndex}'s association list, which {ModelDiscoverer} already extracts
11
+ # (class-body declarations and `with_options` groups only — not `class << self`, a `def` or another
12
+ # block). This module only resolves them, mirroring ActiveRecord:
13
+ #
14
+ # - `class_name:` (String or Symbol) wins; `"::Foo"` is rooted.
15
+ # - otherwise `has_many` / `has_and_belongs_to_many` → `name.singularize.camelize`, and
16
+ # `belongs_to` / `has_one` → `name.camelize` (`Reflection#derive_class_name`).
17
+ # - the name is tried as nested in the owner itself, then in each enclosing namespace innermost first,
18
+ # then at top level (`ActiveRecord::Inheritance#compute_type`).
19
+ # - a root is published only when the project declares a model of that name.
20
+ #
21
+ # Declined — no root, never a guess: a polymorphic association (no single target), a non-literal
22
+ # `class_name:` / `**opts`, `anonymous_class:`, a `with_options` group with non-literal options, and a
23
+ # `through:` association without a literal `class_name:` / `source_type:`. Without them a `through:` target is the SOURCE association's class on the through model, and
24
+ # that association (declared there, hence in this same index) roots it itself.
25
+ #
26
+ # A computed name equal to the owner's own demodulized name declines too (Rails 7.2+ tries `::Name`
27
+ # first; the target is then the owner itself or a top-level class).
28
+ #
29
+ # ActiveRecord takes the first candidate that is a defined constant. The index knows only models, so the
30
+ # walk stops (declines) at a candidate that is not a model but is a namespace of one: Rails would pick
31
+ # that module and fail, never the next candidate. A non-model class at an earlier candidate is invisible
32
+ # here.
33
+ #
34
+ # The roots are flat: an association on a model `rigor unused` itself reports as dead still roots its
35
+ # target, exactly as the other plugins' roots do.
36
+ module AssociationRoots
37
+ COLLECTION_MACROS = %i[has_many has_and_belongs_to_many].freeze
38
+ ROOTED_MACROS = (COLLECTION_MACROS + %i[belongs_to has_one]).freeze
39
+ VALID_NAME = /\A(?:::)?[A-Z][A-Za-z0-9_]*(?:::[A-Z][A-Za-z0-9_]*)*\z/
40
+ private_constant :VALID_NAME
41
+
42
+ module_function
43
+
44
+ # Sorted, unique model class names. Raises {Rigor::Plugin::Inflector::Unavailable} when a name had to
45
+ # be inflected and could not be.
46
+ def call(model_index)
47
+ namespaces = model_index.class_names.flat_map { |name| prefixes(name) }.to_set
48
+ roots = model_index.entries.each_value.flat_map do |entry|
49
+ entry.associations.filter_map { |row| resolve(entry.class_name, row, model_index, namespaces) }
50
+ end
51
+ roots.uniq.sort
52
+ end
53
+
54
+ def prefixes(name)
55
+ segments = name.split("::")
56
+ (1...segments.length).map { |n| segments.first(n).join("::") }
57
+ end
58
+
59
+ def resolve(owner, row, model_index, namespaces)
60
+ return nil unless ROOTED_MACROS.include?(row[:macro])
61
+ return nil if row[:polymorphic] || row[:roots_declined]
62
+
63
+ type_name = type_name(row)
64
+ return nil if type_name.nil? || !VALID_NAME.match?(type_name)
65
+ # Rails 7.2+ (`MacroReflection#_klass`) tries `::Name` first when the computed name is the owner's
66
+ # own demodulized name, so the target may be the owner or a top-level class: decline.
67
+ return nil if type_name == owner.split("::").last
68
+
69
+ candidates(owner, type_name).each do |candidate|
70
+ return candidate if model_index.model?(candidate)
71
+ return nil if namespaces.include?(candidate)
72
+ end
73
+ nil
74
+ end
75
+
76
+ def type_name(row)
77
+ option = row[:class_name_option]
78
+ option = row[:source_type_option] if option.nil? && row[:through]
79
+ return nil if option == :dynamic
80
+ return option unless option.nil?
81
+ return nil if row[:through]
82
+
83
+ name = row[:name].to_s
84
+ name = Rigor::Plugin::Inflector.singularize(name) if COLLECTION_MACROS.include?(row[:macro])
85
+ Rigor::Plugin::Inflector.camelize(name)
86
+ end
87
+
88
+ # `compute_type`: a rooted name is looked up as is; otherwise the owner ITSELF first (`Post has_many
89
+ # :comments` tries `Post::Comment`), then its enclosing namespaces innermost first, then top level.
90
+ def candidates(owner, type_name)
91
+ return [type_name.delete_prefix("::")] if type_name.start_with?("::")
92
+
93
+ segments = owner.split("::")
94
+ nested = segments.length.downto(1).map { |n| "#{segments.first(n).join('::')}::#{type_name}" }
95
+ nested + [type_name]
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end