rigortype 0.1.17 → 0.1.19
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.
- checksums.yaml +4 -4
- data/README.md +159 -222
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +24 -1
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +25 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +29 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +54 -0
- data/lib/rigor/analysis/check_rules/rule_walk.rb +213 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +24 -1
- data/lib/rigor/analysis/check_rules.rb +275 -44
- data/lib/rigor/analysis/diagnostic.rb +8 -0
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +581 -0
- data/lib/rigor/analysis/runner/pool_coordinator.rb +569 -0
- data/lib/rigor/analysis/runner/project_pre_passes.rb +321 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +46 -0
- data/lib/rigor/analysis/runner.rb +207 -1200
- data/lib/rigor/analysis/worker_session.rb +60 -11
- data/lib/rigor/bleeding_edge.rb +123 -0
- data/lib/rigor/cache/descriptor.rb +86 -8
- data/lib/rigor/cache/incremental_snapshot.rb +10 -4
- data/lib/rigor/cache/rbs_cache_producer.rb +5 -1
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +46 -13
- data/lib/rigor/cli/annotate_command.rb +100 -15
- data/lib/rigor/cli/check_command.rb +708 -0
- data/lib/rigor/cli/ci_detector.rb +94 -0
- data/lib/rigor/cli/diagnostic_formats.rb +345 -0
- data/lib/rigor/cli/plugins_command.rb +2 -4
- data/lib/rigor/cli/plugins_renderer.rb +0 -2
- data/lib/rigor/cli/prism_colorizer.rb +10 -3
- data/lib/rigor/cli/show_bleedingedge_command.rb +114 -0
- data/lib/rigor/cli/trace_command.rb +143 -0
- data/lib/rigor/cli/trace_renderer.rb +310 -0
- data/lib/rigor/cli/triage_command.rb +6 -3
- data/lib/rigor/cli/triage_renderer.rb +15 -1
- data/lib/rigor/cli.rb +21 -612
- data/lib/rigor/configuration/severity_profile.rb +13 -1
- data/lib/rigor/configuration.rb +66 -7
- data/lib/rigor/environment/rbs_loader.rb +78 -68
- data/lib/rigor/environment.rb +1 -1
- data/lib/rigor/inference/acceptance.rb +10 -0
- data/lib/rigor/inference/body_fixpoint.rb +89 -0
- data/lib/rigor/inference/budget_trace.rb +29 -2
- data/lib/rigor/inference/expression_typer.rb +1080 -105
- data/lib/rigor/inference/flow_tracer.rb +180 -0
- data/lib/rigor/inference/macro_block_self_type.rb +11 -12
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +60 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +54 -14
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +33 -1
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +281 -0
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +71 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +148 -10
- data/lib/rigor/inference/method_dispatcher.rb +187 -55
- data/lib/rigor/inference/method_parameter_binder.rb +56 -2
- data/lib/rigor/inference/multi_target_binder.rb +46 -3
- data/lib/rigor/inference/mutation_widening.rb +142 -0
- data/lib/rigor/inference/narrowing.rb +330 -37
- data/lib/rigor/inference/scope_indexer.rb +770 -39
- data/lib/rigor/inference/statement_evaluator.rb +998 -68
- data/lib/rigor/inference/synthetic_method_scanner.rb +1 -1
- data/lib/rigor/plugin/additional_initializer.rb +61 -38
- data/lib/rigor/plugin/base.rb +517 -120
- data/lib/rigor/plugin/macro/block_as_method.rb +22 -21
- data/lib/rigor/plugin/macro/nested_class_template.rb +9 -7
- data/lib/rigor/plugin/macro.rb +2 -3
- data/lib/rigor/plugin/manifest.rb +4 -24
- data/lib/rigor/plugin/node_rule_walk.rb +192 -0
- data/lib/rigor/plugin/registry.rb +264 -35
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/rbs_extended/conformance_checker.rb +86 -1
- data/lib/rigor/scope/discovery_index.rb +60 -0
- data/lib/rigor/scope.rb +199 -204
- data/lib/rigor/sig_gen/generator.rb +8 -0
- data/lib/rigor/sig_gen/observation_collector.rb +6 -6
- data/lib/rigor/source/literals.rb +14 -0
- data/lib/rigor/triage/catalogue.rb +4 -19
- data/lib/rigor/triage.rb +69 -1
- data/lib/rigor/type/combinator.rb +34 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +13 -29
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -32
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -2
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +27 -90
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +13 -30
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +2 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +90 -51
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +3 -3
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -29
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -2
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +11 -40
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +2 -2
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +1 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +10 -21
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +21 -34
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +11 -18
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +0 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +12 -2
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +37 -31
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +3 -23
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +8 -21
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +8 -29
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +17 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +108 -36
- data/sig/rigor/analysis/fact_store.rbs +3 -0
- data/sig/rigor/environment.rbs +0 -2
- data/sig/rigor/inference/builtins/method_catalog.rbs +1 -1
- data/sig/rigor/inference.rbs +5 -0
- data/sig/rigor/plugin/base.rbs +6 -4
- data/sig/rigor/plugin/manifest.rbs +1 -2
- data/sig/rigor/scope.rbs +50 -29
- data/sig/rigor/source.rbs +1 -0
- data/sig/rigor/type.rbs +1 -0
- data/sig/rigor.rbs +1 -1
- data/skills/rigor-baseline-reduce/references/01-classify.md +27 -0
- data/skills/rigor-ci-setup/SKILL.md +319 -0
- data/skills/rigor-plugin-author/SKILL.md +6 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +22 -17
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +18 -1
- metadata +21 -3
- data/lib/rigor/cache/rbs_instance_definitions.rb +0 -66
- data/lib/rigor/plugin/macro/external_file.rb +0 -143
|
@@ -228,7 +228,7 @@ module Rigor
|
|
|
228
228
|
return unless call.is_a?(Prism::CallNode) && call.receiver.nil? && call.name == template.variant_method
|
|
229
229
|
|
|
230
230
|
args = call.arguments&.arguments || []
|
|
231
|
-
variant_const = const_name_string(args[template.
|
|
231
|
+
variant_const = const_name_string(args[template.symbol_arg_position])
|
|
232
232
|
return if variant_const.nil?
|
|
233
233
|
|
|
234
234
|
yield variant_const, args[template.inner_arg_position]
|
|
@@ -3,32 +3,40 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
# ADR-38 declaration: "on `receiver_constraint` (and its
|
|
6
|
-
# subclasses), every method named in `methods`
|
|
7
|
-
#
|
|
8
|
-
# read-before-write nil
|
|
6
|
+
# subclasses), every method named in `methods` (def-form) or
|
|
7
|
+
# `block_methods` (block-form) also establishes instance-variable
|
|
8
|
+
# state — treat it like `initialize` for the read-before-write nil
|
|
9
|
+
# soundness gate."
|
|
10
|
+
#
|
|
11
|
+
# **Def-form** (`methods:`) — applies when the ivar write lives in a
|
|
12
|
+
# named `def` body. Example: Minitest `def setup; @conn = …; end`.
|
|
13
|
+
#
|
|
14
|
+
# **Block-form** (`block_methods:`) — applies when the ivar write
|
|
15
|
+
# lives in a block passed to a method call. Example: RSpec
|
|
16
|
+
# `before { @user = create(:user) }` / `let(:x) { @y = … }`.
|
|
17
|
+
# `ScopeIndexer` descends the block body of any `CallNode` whose
|
|
18
|
+
# method name is in `block_methods`, collecting ivar writes exactly
|
|
19
|
+
# as it would for a def-form initializer.
|
|
20
|
+
#
|
|
21
|
+
# At least one of `methods:` or `block_methods:` must be non-empty.
|
|
9
22
|
#
|
|
10
23
|
# Authored on a plugin manifest:
|
|
11
24
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
25
|
+
# # def-form (Minitest):
|
|
26
|
+
# AdditionalInitializer.new(
|
|
27
|
+
# receiver_constraint: "Minitest::Test",
|
|
28
|
+
# methods: [:setup]
|
|
29
|
+
# )
|
|
30
|
+
#
|
|
31
|
+
# # block-form (RSpec):
|
|
32
|
+
# AdditionalInitializer.new(
|
|
33
|
+
# receiver_constraint: "RSpec::ExampleGroup",
|
|
34
|
+
# block_methods: [:before, :let, :subject]
|
|
21
35
|
# )
|
|
22
36
|
#
|
|
23
37
|
# The Ruby analogue of PHPStan's `AdditionalConstructorsExtension`.
|
|
24
38
|
# `Rigor::Inference::ScopeIndexer` consults the aggregated set at
|
|
25
|
-
# its
|
|
26
|
-
# `methods` on a class that equals or inherits from
|
|
27
|
-
# `receiver_constraint` (matched via `Environment#class_ordering`,
|
|
28
|
-
# the same mechanism ADR-16 Tier A uses), the method's ivar writes
|
|
29
|
-
# are folded into the class's `init_writes` set, so a sibling
|
|
30
|
-
# method reading those ivars no longer gets a `Constant[nil]`
|
|
31
|
-
# widening.
|
|
39
|
+
# its read-before-write gate.
|
|
32
40
|
#
|
|
33
41
|
# The contribution can only ever *suppress* a nil widening — it
|
|
34
42
|
# never makes the analyzer stricter — so a missed or over-broad
|
|
@@ -39,38 +47,47 @@ module Rigor
|
|
|
39
47
|
#
|
|
40
48
|
# - `receiver_constraint` — fully-qualified class name (String).
|
|
41
49
|
# The entry applies to that class and its subclasses.
|
|
42
|
-
# - `methods` — Array of Symbol method names
|
|
43
|
-
#
|
|
50
|
+
# - `methods` — Array of Symbol `def`-form method names (may be
|
|
51
|
+
# empty when only block_methods is used).
|
|
52
|
+
# - `block_methods` — Array of Symbol call-with-block method names
|
|
53
|
+
# (may be empty when only methods is used).
|
|
44
54
|
#
|
|
45
55
|
# ## Ractor-shareability
|
|
46
56
|
#
|
|
47
|
-
#
|
|
48
|
-
# `Ractor.shareable?` returns true after `#initialize
|
|
49
|
-
# value object survives `Plugin::Registry.materialize` into a
|
|
50
|
-
# worker Ractor.
|
|
57
|
+
# All fields are frozen at construction (ADR-15 Phase 1);
|
|
58
|
+
# `Ractor.shareable?` returns true after `#initialize`.
|
|
51
59
|
class AdditionalInitializer
|
|
52
|
-
attr_reader :receiver_constraint, :methods
|
|
60
|
+
attr_reader :receiver_constraint, :methods, :block_methods
|
|
53
61
|
|
|
54
|
-
def initialize(receiver_constraint:, methods:)
|
|
62
|
+
def initialize(receiver_constraint:, methods: [], block_methods: [])
|
|
55
63
|
validate_receiver_constraint!(receiver_constraint)
|
|
56
|
-
|
|
64
|
+
validate_method_list!(methods, :methods)
|
|
65
|
+
validate_method_list!(block_methods, :block_methods)
|
|
66
|
+
validate_at_least_one!(methods, block_methods)
|
|
57
67
|
|
|
58
68
|
@receiver_constraint = receiver_constraint.dup.freeze
|
|
59
69
|
@methods = methods.map(&:to_sym).freeze
|
|
70
|
+
@block_methods = block_methods.map(&:to_sym).freeze
|
|
60
71
|
freeze
|
|
61
72
|
end
|
|
62
73
|
|
|
63
|
-
# True when `method_name` (a Symbol) is declared
|
|
64
|
-
# by this entry.
|
|
65
|
-
# responsibility (it needs the environment's class graph).
|
|
74
|
+
# True when `method_name` (a Symbol) is declared a def-form
|
|
75
|
+
# initializer by this entry.
|
|
66
76
|
def covers_method?(method_name)
|
|
67
77
|
methods.include?(method_name)
|
|
68
78
|
end
|
|
69
79
|
|
|
80
|
+
# True when `method_name` (a Symbol) is declared a block-form
|
|
81
|
+
# initializer by this entry.
|
|
82
|
+
def covers_block_method?(method_name)
|
|
83
|
+
block_methods.include?(method_name)
|
|
84
|
+
end
|
|
85
|
+
|
|
70
86
|
def to_h
|
|
71
87
|
{
|
|
72
88
|
"receiver_constraint" => receiver_constraint,
|
|
73
|
-
"methods" => methods.map(&:to_s)
|
|
89
|
+
"methods" => methods.map(&:to_s),
|
|
90
|
+
"block_methods" => block_methods.map(&:to_s)
|
|
74
91
|
}
|
|
75
92
|
end
|
|
76
93
|
|
|
@@ -93,16 +110,22 @@ module Rigor
|
|
|
93
110
|
"got #{value.inspect}"
|
|
94
111
|
end
|
|
95
112
|
|
|
96
|
-
def
|
|
97
|
-
if value.is_a?(Array) &&
|
|
98
|
-
|
|
99
|
-
return
|
|
100
|
-
end
|
|
113
|
+
def validate_method_list!(value, field)
|
|
114
|
+
return if value.is_a?(Array) &&
|
|
115
|
+
value.all? { |m| m.is_a?(Symbol) || (m.is_a?(String) && !m.empty?) }
|
|
101
116
|
|
|
102
117
|
raise ArgumentError,
|
|
103
|
-
"Plugin::AdditionalInitializer
|
|
118
|
+
"Plugin::AdditionalInitializer##{field} must be an Array of " \
|
|
104
119
|
"Symbol/non-empty String, got #{value.inspect}"
|
|
105
120
|
end
|
|
121
|
+
|
|
122
|
+
def validate_at_least_one!(methods, block_methods)
|
|
123
|
+
return unless methods.empty? && block_methods.empty?
|
|
124
|
+
|
|
125
|
+
raise ArgumentError,
|
|
126
|
+
"Plugin::AdditionalInitializer requires at least one of methods: or block_methods: " \
|
|
127
|
+
"to be non-empty"
|
|
128
|
+
end
|
|
106
129
|
end
|
|
107
130
|
end
|
|
108
131
|
end
|