rigortype 0.1.16 → 0.1.18

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +18 -1
  4. data/lib/rigor/analysis/check_rules/rule_walk.rb +67 -0
  5. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +100 -0
  6. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +226 -0
  7. data/lib/rigor/analysis/check_rules.rb +180 -73
  8. data/lib/rigor/analysis/dependency_recorder.rb +122 -0
  9. data/lib/rigor/analysis/diagnostic.rb +18 -0
  10. data/lib/rigor/analysis/incremental.rb +162 -0
  11. data/lib/rigor/analysis/incremental_session.rb +337 -0
  12. data/lib/rigor/analysis/rule_catalog.rb +48 -0
  13. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +580 -0
  14. data/lib/rigor/analysis/runner/pool_coordinator.rb +569 -0
  15. data/lib/rigor/analysis/runner/project_pre_passes.rb +318 -0
  16. data/lib/rigor/analysis/runner/run_snapshots.rb +46 -0
  17. data/lib/rigor/analysis/runner.rb +477 -1110
  18. data/lib/rigor/analysis/self_call_resolution_recorder.rb +121 -0
  19. data/lib/rigor/analysis/worker_session.rb +47 -8
  20. data/lib/rigor/builtins/static_return_refinements.rb +7 -1
  21. data/lib/rigor/cache/descriptor.rb +50 -49
  22. data/lib/rigor/cache/incremental_snapshot.rb +153 -0
  23. data/lib/rigor/cache/rbs_cache_producer.rb +34 -0
  24. data/lib/rigor/cache/rbs_class_ancestor_table.rb +2 -8
  25. data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -8
  26. data/lib/rigor/cache/rbs_constant_table.rb +2 -8
  27. data/lib/rigor/cache/rbs_environment.rb +2 -8
  28. data/lib/rigor/cache/rbs_known_class_names.rb +2 -8
  29. data/lib/rigor/cache/store.rb +145 -14
  30. data/lib/rigor/cli/annotate_command.rb +2 -7
  31. data/lib/rigor/cli/baseline_command.rb +2 -7
  32. data/lib/rigor/cli/check_command.rb +705 -0
  33. data/lib/rigor/cli/ci_detector.rb +94 -0
  34. data/lib/rigor/cli/command.rb +47 -0
  35. data/lib/rigor/cli/coverage_command.rb +3 -23
  36. data/lib/rigor/cli/coverage_renderer.rb +3 -8
  37. data/lib/rigor/cli/diagnostic_formats.rb +345 -0
  38. data/lib/rigor/cli/diff_command.rb +3 -7
  39. data/lib/rigor/cli/explain_command.rb +2 -7
  40. data/lib/rigor/cli/lsp_command.rb +3 -7
  41. data/lib/rigor/cli/mcp_command.rb +3 -7
  42. data/lib/rigor/cli/options.rb +57 -0
  43. data/lib/rigor/cli/plugin_command.rb +3 -7
  44. data/lib/rigor/cli/plugins_command.rb +2 -7
  45. data/lib/rigor/cli/prism_colorizer.rb +10 -3
  46. data/lib/rigor/cli/renderable.rb +26 -0
  47. data/lib/rigor/cli/sig_gen_command.rb +2 -7
  48. data/lib/rigor/cli/skill_command.rb +3 -7
  49. data/lib/rigor/cli/trace_command.rb +143 -0
  50. data/lib/rigor/cli/trace_renderer.rb +310 -0
  51. data/lib/rigor/cli/triage_command.rb +2 -7
  52. data/lib/rigor/cli/type_of_command.rb +5 -38
  53. data/lib/rigor/cli/type_of_renderer.rb +4 -9
  54. data/lib/rigor/cli/type_scan_command.rb +3 -23
  55. data/lib/rigor/cli/type_scan_renderer.rb +4 -9
  56. data/lib/rigor/cli.rb +15 -532
  57. data/lib/rigor/configuration/dependencies.rb +18 -1
  58. data/lib/rigor/configuration/severity_profile.rb +22 -3
  59. data/lib/rigor/configuration.rb +16 -3
  60. data/lib/rigor/environment/rbs_loader.rb +129 -71
  61. data/lib/rigor/environment.rb +1 -1
  62. data/lib/rigor/inference/acceptance.rb +10 -0
  63. data/lib/rigor/inference/block_parameter_binder.rb +1 -2
  64. data/lib/rigor/inference/builtins/array_catalog.rb +2 -5
  65. data/lib/rigor/inference/builtins/comparable_catalog.rb +2 -5
  66. data/lib/rigor/inference/builtins/complex_catalog.rb +2 -5
  67. data/lib/rigor/inference/builtins/date_catalog.rb +2 -5
  68. data/lib/rigor/inference/builtins/encoding_catalog.rb +2 -5
  69. data/lib/rigor/inference/builtins/enumerable_catalog.rb +2 -5
  70. data/lib/rigor/inference/builtins/exception_catalog.rb +2 -5
  71. data/lib/rigor/inference/builtins/hash_catalog.rb +2 -5
  72. data/lib/rigor/inference/builtins/method_catalog.rb +15 -0
  73. data/lib/rigor/inference/builtins/numeric_catalog.rb +21 -93
  74. data/lib/rigor/inference/builtins/pathname_catalog.rb +2 -5
  75. data/lib/rigor/inference/builtins/proc_catalog.rb +2 -5
  76. data/lib/rigor/inference/builtins/random_catalog.rb +2 -5
  77. data/lib/rigor/inference/builtins/range_catalog.rb +2 -5
  78. data/lib/rigor/inference/builtins/rational_catalog.rb +2 -5
  79. data/lib/rigor/inference/builtins/re_catalog.rb +2 -5
  80. data/lib/rigor/inference/builtins/set_catalog.rb +2 -5
  81. data/lib/rigor/inference/builtins/string_catalog.rb +2 -5
  82. data/lib/rigor/inference/builtins/struct_catalog.rb +2 -5
  83. data/lib/rigor/inference/builtins/time_catalog.rb +2 -5
  84. data/lib/rigor/inference/expression_typer.rb +149 -63
  85. data/lib/rigor/inference/flow_tracer.rb +180 -0
  86. data/lib/rigor/inference/macro_block_self_type.rb +10 -11
  87. data/lib/rigor/inference/method_dispatcher/block_folding.rb +5 -1
  88. data/lib/rigor/inference/method_dispatcher/call_context.rb +65 -0
  89. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +11 -10
  90. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +12 -6
  91. data/lib/rigor/inference/method_dispatcher/data_folding.rb +246 -0
  92. data/lib/rigor/inference/method_dispatcher/file_folding.rb +6 -2
  93. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
  94. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +4 -1
  95. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +4 -1
  96. data/lib/rigor/inference/method_dispatcher/math_folding.rb +6 -6
  97. data/lib/rigor/inference/method_dispatcher/method_folding.rb +12 -7
  98. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +33 -1
  99. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +23 -13
  100. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +9 -9
  101. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -6
  102. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +120 -9
  103. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +12 -12
  104. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +49 -0
  105. data/lib/rigor/inference/method_dispatcher/time_folding.rb +6 -6
  106. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -9
  107. data/lib/rigor/inference/method_dispatcher.rb +185 -84
  108. data/lib/rigor/inference/narrowing.rb +262 -5
  109. data/lib/rigor/inference/scope_indexer.rb +208 -21
  110. data/lib/rigor/inference/statement_evaluator.rb +110 -48
  111. data/lib/rigor/language_server/buffer_resolution.rb +33 -0
  112. data/lib/rigor/language_server/completion_provider.rb +4 -4
  113. data/lib/rigor/language_server/document_symbol_provider.rb +4 -4
  114. data/lib/rigor/language_server/folding_range_provider.rb +4 -4
  115. data/lib/rigor/language_server/hover_provider.rb +4 -4
  116. data/lib/rigor/language_server/selection_range_provider.rb +4 -4
  117. data/lib/rigor/language_server/signature_help_provider.rb +4 -4
  118. data/lib/rigor/plugin/additional_initializer.rb +61 -38
  119. data/lib/rigor/plugin/base.rb +302 -45
  120. data/lib/rigor/plugin/node_rule_walk.rb +147 -0
  121. data/lib/rigor/plugin/registry.rb +281 -15
  122. data/lib/rigor/plugin.rb +1 -0
  123. data/lib/rigor/rbs_extended/conformance_checker.rb +293 -0
  124. data/lib/rigor/rbs_extended.rb +39 -0
  125. data/lib/rigor/scope/discovery_index.rb +58 -0
  126. data/lib/rigor/scope.rb +150 -167
  127. data/lib/rigor/sig_gen/observation_collector.rb +6 -6
  128. data/lib/rigor/source/literals.rb +14 -0
  129. data/lib/rigor/type/acceptance_router.rb +19 -0
  130. data/lib/rigor/type/accepts_result.rb +3 -10
  131. data/lib/rigor/type/app.rb +3 -7
  132. data/lib/rigor/type/bot.rb +2 -3
  133. data/lib/rigor/type/bound_method.rb +5 -12
  134. data/lib/rigor/type/combinator.rb +22 -0
  135. data/lib/rigor/type/constant.rb +2 -3
  136. data/lib/rigor/type/data_class.rb +80 -0
  137. data/lib/rigor/type/data_instance.rb +100 -0
  138. data/lib/rigor/type/difference.rb +5 -10
  139. data/lib/rigor/type/dynamic.rb +5 -10
  140. data/lib/rigor/type/hash_shape.rb +5 -15
  141. data/lib/rigor/type/integer_range.rb +5 -10
  142. data/lib/rigor/type/intersection.rb +5 -10
  143. data/lib/rigor/type/nominal.rb +5 -10
  144. data/lib/rigor/type/refined.rb +5 -10
  145. data/lib/rigor/type/singleton.rb +5 -10
  146. data/lib/rigor/type/top.rb +2 -3
  147. data/lib/rigor/type/tuple.rb +5 -10
  148. data/lib/rigor/type/union.rb +5 -10
  149. data/lib/rigor/type.rb +2 -0
  150. data/lib/rigor/value_semantics.rb +77 -0
  151. data/lib/rigor/version.rb +1 -1
  152. data/lib/rigor.rb +1 -1
  153. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -2
  154. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +2 -4
  155. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +70 -32
  156. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +3 -3
  157. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +15 -21
  158. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +1 -1
  159. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -2
  160. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +2 -2
  161. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +12 -2
  162. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +12 -2
  163. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
  164. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +35 -18
  165. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +8 -29
  166. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +17 -1
  167. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +2 -2
  168. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +83 -36
  169. data/sig/rigor/cache.rbs +19 -0
  170. data/sig/rigor/environment.rbs +0 -2
  171. data/sig/rigor/inference.rbs +27 -0
  172. data/sig/rigor/plugin/base.rbs +1 -2
  173. data/sig/rigor/rbs_extended.rbs +2 -0
  174. data/sig/rigor/scope.rbs +42 -25
  175. data/sig/rigor/source.rbs +1 -0
  176. data/sig/rigor/type.rbs +58 -1
  177. data/sig/rigor.rbs +6 -1
  178. data/skills/rigor-ci-setup/SKILL.md +319 -0
  179. metadata +36 -2
  180. data/lib/rigor/cache/rbs_instance_definitions.rb +0 -79
@@ -7,6 +7,7 @@ require_relative "../analysis/runner"
7
7
  require_relative "../cache/store"
8
8
  require_relative "../triage"
9
9
  require_relative "triage_renderer"
10
+ require_relative "command"
10
11
 
11
12
  module Rigor
12
13
  class CLI
@@ -18,16 +19,10 @@ module Rigor
18
19
  # Read-only and advisory (WD4): never edits config, never
19
20
  # writes a baseline. Always exits 0 — it is an inspection
20
21
  # command, not a gate (`rigor check` remains the gate).
21
- class TriageCommand
22
+ class TriageCommand < Command
22
23
  USAGE = "Usage: rigor triage [options] [paths]"
23
24
  DEFAULT_SECTIONS = %i[distribution hotspots hints].freeze
24
25
 
25
- def initialize(argv:, out:, err:)
26
- @argv = argv
27
- @out = out
28
- @err = err
29
- end
30
-
31
26
  # @return [Integer] CLI exit status (always 0).
32
27
  def run
33
28
  options = parse_options
@@ -11,6 +11,8 @@ require_relative "../source/node_locator"
11
11
  require_relative "../inference/fallback_tracer"
12
12
  require_relative "../inference/scope_indexer"
13
13
  require_relative "type_of_renderer"
14
+ require_relative "command"
15
+ require_relative "options"
14
16
 
15
17
  module Rigor
16
18
  class CLI
@@ -25,21 +27,15 @@ module Rigor
25
27
  # dispatching and lets us evolve the type-of UX (extra flags, watch mode,
26
28
  # streaming output) without bloating the CLI shell. Output formatting is
27
29
  # delegated to {TypeOfRenderer}.
28
- class TypeOfCommand
30
+ class TypeOfCommand < Command
29
31
  USAGE = "Usage: rigor type-of [options] FILE:LINE:COL"
30
32
 
31
33
  Result = Data.define(:file, :line, :column, :node, :type, :tracer)
32
34
 
33
- def initialize(argv:, out:, err:)
34
- @argv = argv
35
- @out = out
36
- @err = err
37
- end
38
-
39
35
  # @return [Integer] CLI exit status.
40
36
  def run
41
37
  options = parse_options
42
- buffer = resolve_buffer_binding(options)
38
+ buffer = Options.resolve_buffer_binding(options, err: @err)
43
39
  return CLI::EXIT_USAGE if buffer == :usage_error
44
40
 
45
41
  target = parse_position_argument(@argv)
@@ -58,42 +54,13 @@ module Rigor
58
54
  opts.on("--format=FORMAT", "Output format: text or json") { |value| options[:format] = value }
59
55
  opts.on("--trace", "Record fail-soft fallbacks via FallbackTracer") { options[:trace] = true }
60
56
  opts.on("--config=PATH", "Path to the Rigor configuration file") { |value| options[:config] = value }
61
- opts.on("--tmp-file=PATH",
62
- "Editor mode: read source bytes from PATH instead of --instead-of (paired)") do |value|
63
- options[:tmp_file] = value
64
- end
65
- opts.on("--instead-of=PATH",
66
- "Editor mode: the logical project path the buffer represents (paired with --tmp-file)") do |value|
67
- options[:instead_of] = value
68
- end
57
+ Options.add_editor_mode(opts, options)
69
58
  end
70
59
  parser.parse!(@argv)
71
60
 
72
61
  options
73
62
  end
74
63
 
75
- # Mirrors `Rigor::CLI#resolve_buffer_binding` (the `check`
76
- # path). Returns nil / BufferBinding / :usage_error. The
77
- # symbol return path lets the caller translate to
78
- # `CLI::EXIT_USAGE` without raising.
79
- def resolve_buffer_binding(options)
80
- tmp = options[:tmp_file]
81
- instead = options[:instead_of]
82
- return nil if tmp.nil? && instead.nil?
83
-
84
- if tmp.nil? || instead.nil?
85
- @err.puts("--tmp-file and --instead-of must appear together")
86
- return :usage_error
87
- end
88
-
89
- unless File.file?(tmp)
90
- @err.puts("--tmp-file #{tmp.inspect}: no such file or not readable")
91
- return :usage_error
92
- end
93
-
94
- Rigor::Analysis::BufferBinding.new(logical_path: instead, physical_path: tmp)
95
- end
96
-
97
64
  def execute(target:, options:, buffer: nil)
98
65
  file, line, column = target
99
66
  # Under editor mode the logical `file` may not exist on disk
@@ -3,6 +3,8 @@
3
3
  require "json"
4
4
  require "optionparser"
5
5
 
6
+ require_relative "renderable"
7
+
6
8
  module Rigor
7
9
  class CLI
8
10
  # Renders a `TypeOfCommand::Result` as either human-readable text or a
@@ -12,19 +14,12 @@ module Rigor
12
14
  # output formats (sexp, lsp-style hover payloads, color decoration) can
13
15
  # plug in without disturbing argument parsing or the inference call site.
14
16
  class TypeOfRenderer
17
+ include Renderable
18
+
15
19
  def initialize(out:)
16
20
  @out = out
17
21
  end
18
22
 
19
- def render(result, format:)
20
- case format
21
- when "text" then render_text(result)
22
- when "json" then render_json(result)
23
- else
24
- raise OptionParser::InvalidArgument, "unsupported format: #{format}"
25
- end
26
- end
27
-
28
23
  private
29
24
 
30
25
  def render_text(result)
@@ -9,6 +9,7 @@ require_relative "../inference/coverage_scanner"
9
9
  require_relative "../scope"
10
10
  require_relative "type_scan_renderer"
11
11
  require_relative "type_scan_report"
12
+ require_relative "command"
12
13
 
13
14
  module Rigor
14
15
  class CLI
@@ -19,21 +20,15 @@ module Rigor
19
20
  # the inference engine's directly recognized classes. It is the project's
20
21
  # primary CI gate for tracking how much of an input source the engine can
21
22
  # name without falling back to `Dynamic[Top]`.
22
- class TypeScanCommand
23
+ class TypeScanCommand < Command
23
24
  USAGE = "Usage: rigor type-scan [options] PATH..."
24
25
 
25
26
  LocatedEvent = Data.define(:file, :event)
26
27
 
27
- def initialize(argv:, out:, err:)
28
- @argv = argv
29
- @out = out
30
- @err = err
31
- end
32
-
33
28
  # @return [Integer] CLI exit status.
34
29
  def run
35
30
  options = parse_options
36
- paths = collect_paths(@argv)
31
+ paths = collect_paths(@argv, command_name: "type-scan")
37
32
  return CLI::EXIT_USAGE if paths.nil?
38
33
  return usage_error if paths.empty?
39
34
 
@@ -67,21 +62,6 @@ module Rigor
67
62
  options
68
63
  end
69
64
 
70
- def collect_paths(args)
71
- paths = []
72
- args.each do |arg|
73
- if File.directory?(arg)
74
- paths.concat(Dir.glob(File.join(arg, "**/*.rb")))
75
- elsif File.file?(arg)
76
- paths << arg
77
- else
78
- @err.puts("type-scan: not a file or directory: #{arg}")
79
- return nil
80
- end
81
- end
82
- paths.uniq
83
- end
84
-
85
65
  def usage_error
86
66
  @err.puts("type-scan: at least one path is required")
87
67
  @err.puts(USAGE)
@@ -3,6 +3,8 @@
3
3
  require "json"
4
4
  require "optionparser"
5
5
 
6
+ require_relative "renderable"
7
+
6
8
  module Rigor
7
9
  class CLI
8
10
  # Renders a `TypeScanCommand::Report` as either a terminal-friendly text
@@ -11,19 +13,12 @@ module Rigor
11
13
  # the two formats stay in lockstep; that pairing is why this class is a
12
14
  # bit longer than the default class-length budget.
13
15
  class TypeScanRenderer
16
+ include Renderable
17
+
14
18
  def initialize(out:)
15
19
  @out = out
16
20
  end
17
21
 
18
- def render(report, format:)
19
- case format
20
- when "text" then render_text(report)
21
- when "json" then render_json(report)
22
- else
23
- raise OptionParser::InvalidArgument, "unsupported format: #{format}"
24
- end
25
- end
26
-
27
22
  private
28
23
 
29
24
  def render_text(report)