rigortype 0.4.3 → 0.4.5
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 +5 -5
- data/data/core_overlay/ostruct.rbs +40 -0
- data/docs/handbook/11-sig-gen.md +104 -15
- data/docs/manual/02-cli-reference.md +43 -12
- data/docs/manual/03-configuration.md +20 -7
- data/docs/manual/04-diagnostics.md +56 -3
- data/docs/manual/05-inspecting-types.md +2 -2
- data/docs/manual/06-baseline.md +1 -1
- data/docs/manual/07-plugins.md +3 -2
- data/docs/manual/08-skills.md +7 -0
- data/docs/manual/10-mcp-server.md +40 -4
- data/docs/manual/18-removing-dead-code.md +23 -2
- data/docs/manual/plugins/rigor-rails-routes.md +2 -2
- data/docs/manual/plugins/rigor-rspec.md +101 -1
- data/docs/manual/plugins/rigor-shoulda-matchers.md +4 -1
- data/exe/rigor +12 -17
- data/lib/rigor/analysis/check_rules/clause_coverage.rb +134 -0
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +111 -7
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +190 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +60 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +32 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +13 -4
- data/lib/rigor/analysis/check_rules.rb +274 -51
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +61 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +36 -18
- data/lib/rigor/analysis/incremental_session.rb +270 -28
- data/lib/rigor/analysis/path_expansion.rb +3 -1
- data/lib/rigor/analysis/reachability/graph.rb +111 -14
- data/lib/rigor/analysis/reachability/scan.rb +305 -23
- data/lib/rigor/analysis/rule_catalog.rb +22 -4
- data/lib/rigor/analysis/run_cache_key.rb +31 -7
- data/lib/rigor/analysis/run_cache_probe.rb +5 -3
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +48 -12
- data/lib/rigor/analysis/runner/pool_coordinator.rb +179 -31
- data/lib/rigor/analysis/runner/project_pre_passes.rb +29 -4
- data/lib/rigor/analysis/runner.rb +102 -72
- data/lib/rigor/analysis/severity_stamp.rb +45 -1
- data/lib/rigor/analysis/worker_session.rb +69 -2
- data/lib/rigor/cache/descriptor.rb +79 -12
- data/lib/rigor/cache/engine_source.rb +3 -2
- data/lib/rigor/cache/incremental_snapshot.rb +39 -5
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +4 -3
- data/lib/rigor/cli/command.rb +3 -1
- data/lib/rigor/cli/docs_command.rb +3 -2
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +3 -2
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/plugin_command.rb +2 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/sig_gen_command.rb +32 -11
- data/lib/rigor/cli/skill_command.rb +2 -1
- data/lib/rigor/cli/skill_describe.rb +3 -2
- data/lib/rigor/cli/unused_command.rb +10 -7
- data/lib/rigor/cli.rb +3 -2
- data/lib/rigor/config_audit.rb +163 -22
- data/lib/rigor/configuration/dependencies.rb +19 -11
- data/lib/rigor/configuration/severity_profile.rb +20 -2
- data/lib/rigor/configuration.rb +29 -3
- data/lib/rigor/effects/signature_sources.rb +3 -1
- data/lib/rigor/environment/bundle_sig_discovery.rb +3 -2
- data/lib/rigor/environment/gated_signature_guard.rb +2 -1
- data/lib/rigor/environment/gated_signature_plan.rb +2 -1
- data/lib/rigor/environment/installed_gem_set.rb +2 -1
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -3
- data/lib/rigor/environment/rbs_loader.rb +67 -11
- data/lib/rigor/inference/block_call_timing.rb +12 -1
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/captured_locals.rb +67 -13
- data/lib/rigor/inference/clause_widening.rb +90 -0
- data/lib/rigor/inference/definer_resolution.rb +101 -25
- data/lib/rigor/inference/expression_typer.rb +94 -9
- data/lib/rigor/inference/guard_rebinding.rb +7 -2
- data/lib/rigor/inference/intervening_ivar_reset.rb +303 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +1 -1
- data/lib/rigor/inference/macro_block_self_type.rb +20 -6
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +170 -35
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +50 -2
- data/lib/rigor/inference/method_dispatcher.rb +67 -3
- data/lib/rigor/inference/module_function_state.rb +213 -51
- data/lib/rigor/inference/narrowing.rb +235 -75
- data/lib/rigor/inference/parameter_inference_collector.rb +4 -26
- data/lib/rigor/inference/project_patched_methods.rb +168 -4
- data/lib/rigor/inference/project_patched_mixins.rb +162 -0
- data/lib/rigor/inference/project_patched_scanner.rb +51 -12
- data/lib/rigor/inference/project_patched_visibility.rb +214 -0
- data/lib/rigor/inference/project_seed_tables.rb +120 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +113 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +41 -12
- data/lib/rigor/inference/reflective_ivar_write.rb +116 -0
- data/lib/rigor/inference/repeated_or_writes.rb +414 -1
- data/lib/rigor/inference/return_barrier.rb +16 -0
- data/lib/rigor/inference/scope_indexer.rb +1061 -122
- data/lib/rigor/inference/self_call_ivar_writes.rb +346 -0
- data/lib/rigor/inference/singleton_external_ahead.rb +64 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +7 -0
- data/lib/rigor/inference/statement_evaluator.rb +512 -150
- data/lib/rigor/inference/unthreaded_rebinds.rb +3 -1
- data/lib/rigor/lens/anchor.rb +3 -3
- data/lib/rigor/lens/contract_reader.rb +60 -2
- data/lib/rigor/lens/document.rb +4 -3
- data/lib/rigor/lens/file_reader.rb +452 -73
- data/lib/rigor/lens/members.rb +81 -17
- data/lib/rigor/lens/run.rb +73 -4
- data/lib/rigor/lens.rb +2 -1
- data/lib/rigor/mcp/server.rb +63 -22
- data/lib/rigor/plugin/base.rb +3 -2
- data/lib/rigor/plugin/box_probe.rb +154 -7
- data/lib/rigor/plugin/io_boundary.rb +42 -6
- data/lib/rigor/plugin/isolation.rb +4 -3
- data/lib/rigor/project_environment.rb +6 -3
- data/lib/rigor/protection/discovery_seed.rb +9 -36
- data/lib/rigor/protection/mutation_cache.rb +8 -2
- data/lib/rigor/rooted_glob.rb +27 -0
- data/lib/rigor/scope/discovery_index.rb +5 -0
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -0
- data/lib/rigor/scope/resolution_chain.rb +40 -5
- data/lib/rigor/scope.rb +56 -8
- data/lib/rigor/sig_gen/alias_index.rb +2 -1
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/generator.rb +167 -22
- data/lib/rigor/sig_gen/layout_index.rb +40 -1
- data/lib/rigor/sig_gen/method_candidate.rb +8 -0
- data/lib/rigor/sig_gen/observation_collector.rb +137 -11
- data/lib/rigor/sig_gen/path_mapper.rb +18 -2
- data/lib/rigor/sig_gen/renderer.rb +13 -155
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +11 -0
- data/lib/rigor/sig_gen/write_reporter.rb +203 -0
- data/lib/rigor/sig_gen/write_result.rb +3 -1
- data/lib/rigor/sig_gen/writer.rb +50 -35
- data/lib/rigor/signature_path_audit.rb +4 -2
- data/lib/rigor/type/constant.rb +10 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +6 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +4 -3
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +1 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +1 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -1
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +5 -1
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +57 -6
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +1 -1
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +5 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +1 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +1 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +7 -2
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -5
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +18 -17
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +155 -12
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +10 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +1 -1
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +4 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +2 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +2 -2
- data/sig/rigor/plugin/io_boundary.rbs +5 -2
- data/sig/rigor/rooted_glob.rbs +7 -0
- data/sig/rigor/scope.rbs +4 -3
- data/skills/rigor-doctor/references/01-checks.md +23 -11
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +2 -1
- metadata +16 -1
|
@@ -18,7 +18,8 @@ module Rigor
|
|
|
18
18
|
# Nominal[T] uniformly, so the distinction with `be_a` is observed at the carrier level but not the
|
|
19
19
|
# runtime).
|
|
20
20
|
# - `be_nil` — narrows `x` to `Constant<nil>`.
|
|
21
|
-
# - `eq(LITERAL)` for a literal-value argument —
|
|
21
|
+
# - `eq(LITERAL)` / `eql(LITERAL)` for a literal-value argument — meets `x` with `Constant<literal>`
|
|
22
|
+
# (see "Equality is the local's own method" below).
|
|
22
23
|
#
|
|
23
24
|
# The matchers below this floor (`be_truthy` / `be_falsey` / `be_within` / `be > / < / >=` /
|
|
24
25
|
# `include` / `start_with` / `match(regex)` / `raise_error` / receive-style mocks) require either
|
|
@@ -35,16 +36,47 @@ module Rigor
|
|
|
35
36
|
# fall through.
|
|
36
37
|
# 3. The matcher is one of the recognised forms above (`be_a` / `be_kind_of` / `be_instance_of` /
|
|
37
38
|
# `be_an_instance_of` / `be_nil` / `eq(literal)` / `eql(literal)` / `match(/regex/)`).
|
|
39
|
+
#
|
|
40
|
+
# ## Equality is the local's own method
|
|
41
|
+
#
|
|
42
|
+
# `expect(x).to eq(lit)` passes when `x == lit` and `eql(lit)` when `x.eql?(lit)`: the local is the
|
|
43
|
+
# receiver, so its own `==` / `eql?` decides, and a class with a custom `==` can equal even a `nil`,
|
|
44
|
+
# boolean or Symbol literal. A positive equality fact therefore never replaces the local's type (issue
|
|
45
|
+
# #1807). It is a meet with the local's current type, member by member:
|
|
46
|
+
#
|
|
47
|
+
# - a member of the literal's own core class (`Integer`, `Float`, `String`, `Symbol`, `NilClass`,
|
|
48
|
+
# `TrueClass`, `FalseClass`) narrows to the literal, a refinement of that class (`non-empty-string`,
|
|
49
|
+
# `decimal-int-string`, `non-zero-int`) included; a `Constant` member is kept when it equals the
|
|
50
|
+
# literal and dropped otherwise; a `Float` member meeting `0.0` (which `-0.0` also equals) is kept;
|
|
51
|
+
# - a core numeric member of another class (`Integer`, `Float`, `Rational`, `Complex`) is kept under
|
|
52
|
+
# `eq` (`1.0 == 1`) and dropped under `eql` (`1.0.eql?(1)` is false);
|
|
53
|
+
# - any other core member (`nil` against `9`, a `String` against `:a`) is dropped: built-in equality
|
|
54
|
+
# across those classes is false;
|
|
55
|
+
# - a member of a core class is kept unnarrowed when the project's source defines the operator on that
|
|
56
|
+
# class or on a core ancestor up to the one that owns the operator at runtime (`class Symbol; def
|
|
57
|
+
# ==`, `class Numeric; def eql?` for an `Integer`, `class Object; def ==` for `nil`): its own method
|
|
58
|
+
# decides.
|
|
59
|
+
#
|
|
60
|
+
# When any member is `Dynamic` or of any other class (a user class, `Object`, `Numeric`, `BigDecimal`),
|
|
61
|
+
# the analyzer emits no fact and the local keeps its type. It also emits none when the project's source
|
|
62
|
+
# defines the operator on the literal's class or those ancestors of it — a core `==` calls back into the
|
|
63
|
+
# literal's (`Integer#==` runs `other == self` for a non-numeric argument, `String#==` for one that
|
|
64
|
+
# responds to `to_str`), so a custom one there can make any member equal — and for an unbound local,
|
|
65
|
+
# when no member survives, and without a scope. A reopening that defines other methods only
|
|
66
|
+
# (`class String; def shout`) does not count.
|
|
67
|
+
#
|
|
68
|
+
# The negative forms (`not_to` / `to_not`) still emit a negative `Constant` fact, which the engine's fact
|
|
69
|
+
# narrowing does not act on, so the local keeps its type there too.
|
|
38
70
|
module MatcherAnalyzer
|
|
39
71
|
module_function
|
|
40
72
|
|
|
41
73
|
# @param call_node — the call whose contribution we're computing. Returns nil when
|
|
42
74
|
# the call shape does not match `expect(local).to matcher`.
|
|
43
|
-
# @param
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
def contribution_for(call_node,
|
|
75
|
+
# @param scope — the scope at the call, or nil. Its environment resolves a matcher's class-name
|
|
76
|
+
# argument to a `Type::Nominal` (without one, a bare `Nominal[<name>]` carrier — sound, the receiver
|
|
77
|
+
# constant may be a user class not in RBS); the local's current type in it is what a positive
|
|
78
|
+
# `eq` / `eql` fact meets (without one, no such fact).
|
|
79
|
+
def contribution_for(call_node, scope:)
|
|
48
80
|
verb = assertion_verb(call_node)
|
|
49
81
|
return nil if verb.nil?
|
|
50
82
|
return nil unless call_node.receiver.is_a?(Prism::CallNode)
|
|
@@ -58,14 +90,15 @@ module Rigor
|
|
|
58
90
|
matcher = matcher_call(call_node)
|
|
59
91
|
return nil if matcher.nil?
|
|
60
92
|
|
|
61
|
-
|
|
93
|
+
negative = verb == :negative
|
|
94
|
+
narrowed_type = narrowed_type_for(matcher, target_local, negative: negative, scope: scope)
|
|
62
95
|
return nil if narrowed_type.nil?
|
|
63
96
|
|
|
64
97
|
fact = Rigor::FlowContribution::Fact.new(
|
|
65
98
|
target_kind: :local,
|
|
66
99
|
target_name: target_local,
|
|
67
100
|
type: narrowed_type,
|
|
68
|
-
negative:
|
|
101
|
+
negative: negative
|
|
69
102
|
)
|
|
70
103
|
Rigor::FlowContribution.new(post_return_facts: [fact])
|
|
71
104
|
end
|
|
@@ -105,7 +138,8 @@ module Rigor
|
|
|
105
138
|
# narrowed type. Returns nil when the matcher is
|
|
106
139
|
# unrecognised or its argument shape does not match the
|
|
107
140
|
# supported envelope.
|
|
108
|
-
def narrowed_type_for(matcher,
|
|
141
|
+
def narrowed_type_for(matcher, target_local, negative:, scope:)
|
|
142
|
+
environment = scope&.environment
|
|
109
143
|
return nil unless matcher.is_a?(Prism::CallNode) && matcher.receiver.nil?
|
|
110
144
|
|
|
111
145
|
case matcher.name
|
|
@@ -116,7 +150,7 @@ module Rigor
|
|
|
116
150
|
|
|
117
151
|
Rigor::Type::Combinator.constant_of(nil)
|
|
118
152
|
when :eq, :eql
|
|
119
|
-
|
|
153
|
+
equality_type_for_literal_arg(matcher, target_local, negative: negative, scope: scope)
|
|
120
154
|
when :match
|
|
121
155
|
# `match(/regex/)` narrows x to String. `match("...")` or `match(arbitrary_object)` falls
|
|
122
156
|
# through — the broader matcher dispatch needs the receiver to be a String, but we can only
|
|
@@ -140,14 +174,123 @@ module Rigor
|
|
|
140
174
|
end
|
|
141
175
|
end
|
|
142
176
|
|
|
143
|
-
def
|
|
177
|
+
def equality_type_for_literal_arg(matcher, target_local, negative:, scope:)
|
|
144
178
|
args = matcher.arguments&.arguments || []
|
|
145
179
|
return nil unless args.size == 1
|
|
146
180
|
|
|
147
181
|
literal_value = literal_value_for(args.first)
|
|
148
182
|
return nil if literal_value.equal?(NO_LITERAL)
|
|
183
|
+
return Rigor::Type::Combinator.constant_of(literal_value) if negative
|
|
184
|
+
return nil if scope.nil?
|
|
185
|
+
|
|
186
|
+
operator = matcher.name == :eql ? :eql? : :==
|
|
187
|
+
equality_meet(scope.local(target_local), literal_value, operator, scope)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# --- equality meet (`eq` / `eql`; see "Equality is the local's own method") ---
|
|
191
|
+
|
|
192
|
+
# Core classes whose `==` / `eql?` Rigor can evaluate against a literal: across any two of them the
|
|
193
|
+
# answer is built in, unless the project defines the operator on one of them.
|
|
194
|
+
EQUALITY_CORE_CLASSES = [Integer, Float, Rational, Complex, String, Symbol, NilClass, TrueClass,
|
|
195
|
+
FalseClass].freeze
|
|
196
|
+
Ractor.make_shareable(EQUALITY_CORE_CLASSES)
|
|
197
|
+
private_constant :EQUALITY_CORE_CLASSES
|
|
198
|
+
|
|
199
|
+
NUMERIC_CLASS_NAMES = %w[Integer Float Rational Complex].freeze
|
|
200
|
+
Ractor.make_shareable(NUMERIC_CLASS_NAMES)
|
|
201
|
+
private_constant :NUMERIC_CLASS_NAMES
|
|
202
|
+
|
|
203
|
+
# For each core class and operator, the class and its ancestors up to and including the one that owns
|
|
204
|
+
# the operator at runtime (`Integer#eql?` is `Numeric`'s, `nil == x` is `BasicObject`'s). A project
|
|
205
|
+
# definition on any of them is the method the member runs; one above the owner is shadowed by it.
|
|
206
|
+
OPERATOR_OWNER_CHAINS = EQUALITY_CORE_CLASSES.each_with_object({}) do |klass, chains|
|
|
207
|
+
%i[== eql?].each do |operator|
|
|
208
|
+
ancestors = klass.ancestors
|
|
209
|
+
owner_index = ancestors.index(klass.instance_method(operator).owner)
|
|
210
|
+
chains[[klass.name, operator]] = ancestors[0..owner_index].map(&:name).freeze
|
|
211
|
+
end
|
|
212
|
+
end.freeze
|
|
213
|
+
Ractor.make_shareable(OPERATOR_OWNER_CHAINS)
|
|
214
|
+
private_constant :OPERATOR_OWNER_CHAINS
|
|
215
|
+
|
|
216
|
+
# Marks a member whose equality with the literal cannot be decided, so the whole meet gives up.
|
|
217
|
+
UNDECIDED = Object.new.freeze
|
|
218
|
+
private_constant :UNDECIDED
|
|
219
|
+
|
|
220
|
+
# The members of `current` that `x <operator> literal` admits, narrowed where the member's class is
|
|
221
|
+
# the literal's, or nil when any member is undecided or none survives. An unbound local (nil) is one
|
|
222
|
+
# undecided member.
|
|
223
|
+
def equality_meet(current, literal, operator, scope)
|
|
224
|
+
return nil if project_defines?(literal.class.name, operator, scope)
|
|
225
|
+
|
|
226
|
+
members = current.is_a?(Rigor::Type::Union) ? current.members : [current]
|
|
227
|
+
kept = []
|
|
228
|
+
members.each do |member|
|
|
229
|
+
met = meet_member(member, literal, operator, scope)
|
|
230
|
+
return nil if met.equal?(UNDECIDED)
|
|
149
231
|
|
|
150
|
-
|
|
232
|
+
kept << met unless met.nil?
|
|
233
|
+
end
|
|
234
|
+
return nil if kept.empty?
|
|
235
|
+
|
|
236
|
+
Rigor::Type::Combinator.union(*kept)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# One member's part of the meet: the member itself or its narrowing, nil when no value of it equals
|
|
240
|
+
# the literal, or UNDECIDED.
|
|
241
|
+
def meet_member(member, literal, operator, scope)
|
|
242
|
+
class_name = member_class_name(member)
|
|
243
|
+
return UNDECIDED if class_name.nil?
|
|
244
|
+
return member if project_defines?(class_name, operator, scope)
|
|
245
|
+
|
|
246
|
+
case member
|
|
247
|
+
when Rigor::Type::Constant then member.value.public_send(operator, literal) ? member : nil
|
|
248
|
+
when Rigor::Type::IntegerRange
|
|
249
|
+
literal.is_a?(Integer) && !member.covers?(literal) ? nil : meet_class(member, class_name, literal, operator)
|
|
250
|
+
else meet_class(member, class_name, literal, operator)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# The core class a member's values belong to, or nil for a member that is not wholly of one. A
|
|
255
|
+
# refinement (`Difference`, `Refined`) belongs to its base's class, an `Intersection` to the class all
|
|
256
|
+
# its members share.
|
|
257
|
+
def member_class_name(member)
|
|
258
|
+
case member
|
|
259
|
+
when Rigor::Type::Difference, Rigor::Type::Refined then member_class_name(member.base)
|
|
260
|
+
when Rigor::Type::Intersection
|
|
261
|
+
names = member.members.map { |part| member_class_name(part) }.uniq
|
|
262
|
+
names.size == 1 ? names.first : nil
|
|
263
|
+
when Rigor::Type::FloatRange then "Float"
|
|
264
|
+
when Rigor::Type::Constant
|
|
265
|
+
klass = EQUALITY_CORE_CLASSES.find { |core| member.value.instance_of?(core) }
|
|
266
|
+
klass&.name
|
|
267
|
+
when Rigor::Type::IntegerRange then "Integer"
|
|
268
|
+
when Rigor::Type::Nominal
|
|
269
|
+
name = member.class_name
|
|
270
|
+
member.type_args.empty? && EQUALITY_CORE_CLASSES.any? { |core| core.name == name } ? name : nil
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def meet_class(member, class_name, literal, operator)
|
|
275
|
+
literal_class = literal.class.name
|
|
276
|
+
if class_name == literal_class
|
|
277
|
+
literal.is_a?(Float) && literal.zero? ? member : Rigor::Type::Combinator.constant_of(literal)
|
|
278
|
+
elsif NUMERIC_CLASS_NAMES.include?(class_name) && NUMERIC_CLASS_NAMES.include?(literal_class)
|
|
279
|
+
operator == :== ? member : nil
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Whether the project's source defines `operator` on the core class `class_name` or on a core ancestor
|
|
284
|
+
# up to the operator's runtime owner (OPERATOR_OWNER_CHAINS): a reopening's `def`, an included or
|
|
285
|
+
# prepended project module, a `define_method`. The def-node walk sees other files' `def`s and records
|
|
286
|
+
# the dependency on them; the discovery table adds `define_method`. An RBS declaration is not
|
|
287
|
+
# consulted: once the project reopens `String` for anything, `String#==`'s declaring owner is a
|
|
288
|
+
# project class, which says nothing about who wrote `==`.
|
|
289
|
+
def project_defines?(class_name, operator, scope)
|
|
290
|
+
OPERATOR_OWNER_CHAINS.fetch([class_name, operator]).any? do |name|
|
|
291
|
+
!scope.user_def_through_ancestors(name, operator).first.nil? ||
|
|
292
|
+
scope.discovered_method_through_ancestors?(name, operator, :instance)
|
|
293
|
+
end
|
|
151
294
|
end
|
|
152
295
|
|
|
153
296
|
def string_type_for_regex_arg(matcher)
|
|
@@ -86,7 +86,7 @@ module Rigor
|
|
|
86
86
|
# ADR-37 slice 2 — matcher narrowing (`expect(x).to be_a(T)` → `post_return_facts` on `x`),
|
|
87
87
|
# method-gated by the engine on the expectation verbs.
|
|
88
88
|
narrowing_facts methods: %i[to not_to to_not] do |call_node, scope|
|
|
89
|
-
MatcherAnalyzer.contribution_for(call_node,
|
|
89
|
+
MatcherAnalyzer.contribution_for(call_node, scope: scope)&.post_return_facts
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# ADR-52 slice 5a — binds local reads in `it` / spec bodies to their `let(:name) { ... }` block's
|
|
@@ -98,13 +98,15 @@ module Rigor
|
|
|
98
98
|
let_binding_return_type(call_node, scope)
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
# ADR-88 WD1 — both contributions are per-file: the matcher narrowing facts come from the call's own AST
|
|
102
|
-
# and
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
101
|
+
# ADR-88 WD1 — both contributions are per-file: the matcher narrowing facts come from the call's own AST
|
|
102
|
+
# and, for `eq` / `eql`, from the local's current type and the scope's project discovery (whether the
|
|
103
|
+
# project defines `==` / `eql?` on a core class); the `let`-binding return types come from each spec
|
|
104
|
+
# file's OWN `describe`/`let` structure (`let` is file-scoped). A spec file's edit changes its own
|
|
105
|
+
# content (re-analysed already). The one cross-file input — the optional factorybot `:factory_index`
|
|
106
|
+
# fact this plugin consumes — is itself an ADR-9 publication captured in the incremental fact-surface
|
|
107
|
+
# digest via factorybot's own channel, so it need not appear here. A stable sentinel declares "no OWN
|
|
108
|
+
# cross-file fact surface", keeping the plugin incremental-capable; `--verify-incremental` backstops
|
|
109
|
+
# the claim.
|
|
108
110
|
def incremental_state_fingerprint
|
|
109
111
|
"per-file-lets"
|
|
110
112
|
end
|
|
@@ -92,7 +92,7 @@ module Rigor
|
|
|
92
92
|
# ADR-45 WD1b (#613) — boundary-probed: a root that appears later invalidates the warm run.
|
|
93
93
|
next [] unless @io_boundary.directory?(absolute)
|
|
94
94
|
|
|
95
|
-
Dir.glob(File.join(absolute,
|
|
95
|
+
Dir.glob("**/*.rb", base: absolute).map { |path| File.join(absolute, path) }
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -29,7 +29,9 @@ module Rigor
|
|
|
29
29
|
# ## Reach
|
|
30
30
|
#
|
|
31
31
|
# All nine class-level HTTP verb methods Sinatra exposes: `get`, `post`, `put`, `delete`, `head`,
|
|
32
|
-
# `options`, `patch`, `link`, `unlink` (`lib/sinatra/base.rb:1531-1553`)
|
|
32
|
+
# `options`, `patch`, `link`, `unlink` (`lib/sinatra/base.rb:1531-1553`), plus the `before` / `after`
|
|
33
|
+
# filters (`add_filter`) and the `error` / `not_found` handlers, whose blocks `compile!` turns into
|
|
34
|
+
# instance methods through the same `generate_method` (issue #1768). Both modular-style subclasses
|
|
33
35
|
# of `Sinatra::Base` and `Sinatra::Application` (classic top-level style, when used via `class App <
|
|
34
36
|
# Sinatra::Application`) match because the receiver constraint accepts every subclass.
|
|
35
37
|
#
|
|
@@ -57,7 +59,7 @@ module Rigor
|
|
|
57
59
|
block_as_methods: [
|
|
58
60
|
Rigor::Plugin::Macro::BlockAsMethod.new(
|
|
59
61
|
receiver_constraint: "Sinatra::Base",
|
|
60
|
-
method_names: %i[get post put delete head options patch link unlink]
|
|
62
|
+
method_names: %i[get post put delete head options patch link unlink before after error not_found]
|
|
61
63
|
)
|
|
62
64
|
]
|
|
63
65
|
)
|
|
@@ -504,8 +504,8 @@ module Rigor
|
|
|
504
504
|
# must not vary by machine / run. `Dir.glob` sorts its results by default on Ruby 3.0+, so the fold
|
|
505
505
|
# order is already stable (the slice-1 comment's "filesystem order" caveat predates that default);
|
|
506
506
|
# this walk relies on it rather than re-sorting.
|
|
507
|
-
Dir.glob(
|
|
508
|
-
harvest_file(canonicalize(
|
|
507
|
+
Dir.glob("**/*#{ext}", base: absolute).each do |relative|
|
|
508
|
+
harvest_file(canonicalize(File.join(absolute, relative)), catalog, sigil_by_path, parse_errors_by_path)
|
|
509
509
|
end
|
|
510
510
|
end
|
|
511
511
|
elsif io_boundary.file?(absolute) && extensions.any? { |ext| absolute.end_with?(ext) }
|
|
@@ -63,7 +63,7 @@ module Rigor
|
|
|
63
63
|
@project_paths.flat_map do |entry|
|
|
64
64
|
absolute = File.expand_path(entry)
|
|
65
65
|
if @io_boundary.directory?(absolute)
|
|
66
|
-
Dir.glob(File.join(absolute,
|
|
66
|
+
Dir.glob("**/*.rb", base: absolute).map { |path| File.join(absolute, path) }
|
|
67
67
|
elsif absolute.end_with?(".rb") && @io_boundary.file?(absolute)
|
|
68
68
|
[absolute]
|
|
69
69
|
else
|
|
@@ -78,7 +78,7 @@ module Rigor
|
|
|
78
78
|
# ADR-45 WD1b (#613) — boundary-probed: a root that appears later invalidates the warm run.
|
|
79
79
|
next [] unless @io_boundary.directory?(absolute)
|
|
80
80
|
|
|
81
|
-
Dir.glob(File.join(absolute,
|
|
81
|
+
Dir.glob("**/*.rb", base: absolute).map { |path| File.join(absolute, path) }
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
end
|
|
@@ -4,11 +4,14 @@ class Rigor::Plugin::IoBoundary
|
|
|
4
4
|
def file?: (untyped) -> bool
|
|
5
5
|
def directory?: (untyped) -> bool
|
|
6
6
|
def list_directory: (untyped) -> Array[String]
|
|
7
|
+
def list_directory_kinds: (untyped) -> Hash[String, untyped]
|
|
7
8
|
# Records a `:names` glob row (membership only); a caller needing a match's content `read_file`s it. A `..`
|
|
8
9
|
# segment, a brace or a backslash in `pattern` raises `AccessDeniedError`.
|
|
9
10
|
def glob: (untyped root, untyped pattern) -> Array[String]
|
|
10
|
-
# sig-gen gap: #
|
|
11
|
-
#
|
|
11
|
+
# sig-gen gap: #1154 — the proposal leaves both string fields untyped. `nearest_root` comes from `@policy`, an
|
|
12
|
+
# ivar assigned from an `initialize` parameter (the #1154 shape); `first_path` comes from `@first_refused_path`,
|
|
13
|
+
# written from `record_refusal(path)`'s parameter outside `initialize`, a case #1154 as titled does not yet cover.
|
|
14
|
+
# The record's fields are the running count and the first refused path, nil when nothing was refused.
|
|
12
15
|
def refusal_summary: () -> { count: Integer, first_path: String?, nearest_root: String? }?
|
|
13
16
|
def open_url: (untyped url) -> String
|
|
14
17
|
# Returns a frozen `Rigor::Cache::Descriptor` (no RBS yet -> untyped).
|
data/sig/rigor/scope.rbs
CHANGED
|
@@ -61,7 +61,7 @@ module Rigor
|
|
|
61
61
|
def discovered_singleton_def_nodes: () -> Hash[String, Hash[Symbol, untyped]]
|
|
62
62
|
def discovered_def_sources: () -> Hash[String, Hash[Symbol, String]]
|
|
63
63
|
def discovered_singleton_def_sources: () -> Hash[String, Hash[Symbol, String]]
|
|
64
|
-
def discovered_method_visibilities: () -> Hash[String, Hash[Symbol, Symbol]]
|
|
64
|
+
def discovered_method_visibilities: () -> Hash[String, Hash[Symbol | [:singleton, Symbol], Symbol]]
|
|
65
65
|
# sig-gen gap: #1148 — sig-gen skips an endless-def reader (untyped return); the row is hand-written.
|
|
66
66
|
def discovered_parameter_envelopes: () -> Hash[String, Hash[untyped, untyped]]
|
|
67
67
|
# sig-gen gap: #1149 — sig-gen skips the `||` fallback reader (untyped return); the row is hand-written.
|
|
@@ -128,7 +128,7 @@ module Rigor
|
|
|
128
128
|
attr_reader discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]]
|
|
129
129
|
attr_reader discovered_def_sources: Hash[String, Hash[Symbol, String]]
|
|
130
130
|
attr_reader discovered_singleton_def_sources: Hash[String, Hash[Symbol, String]]
|
|
131
|
-
attr_reader discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]]
|
|
131
|
+
attr_reader discovered_method_visibilities: Hash[String, Hash[Symbol | [:singleton, Symbol], Symbol]]
|
|
132
132
|
# sig-gen gap: #1150 — `Data.define` members carry no type, as for every other row in this class.
|
|
133
133
|
attr_reader discovered_parameter_envelopes: Hash[String, Hash[untyped, untyped]]
|
|
134
134
|
attr_reader discovered_superclasses: Hash[String, String]
|
|
@@ -201,7 +201,7 @@ module Rigor
|
|
|
201
201
|
# authored: ADR-119 WD1 sibling pairing; no inferred signature exists for it (#1150).
|
|
202
202
|
def sibling_tables: () -> Hash[Symbol, untyped]
|
|
203
203
|
|
|
204
|
-
def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?program_global_seeds: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_nestings: Hash[untyped, Array[String]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_singleton_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol, Symbol]], ?discovered_parameter_envelopes: Hash[String, Hash[untyped, untyped]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_prepends: Hash[String, Array[String]], ?discovered_extends: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?constant_sources: Hash[String, Set[String]], ?constant_writers: Hash[String, Array[String]], ?constant_shadowers: Hash[String, Array[String]], ?published_constant_names: Set[String], ?local_constant_names: Set[String], ?published_constant_alias_names: Set[String], ?published_constant_ivars: Hash[String, Set[Symbol]], ?data_member_layouts: Hash[String, Array[Symbol]], ?struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }], ?param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]], ?discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?discovered_refinements: Hash[String, Hash[Symbol | String, Array[String]]], ?discovered_global_write_census: Set[Array[untyped]], ?run_generation: Object?, ?patched_line_readers: Set[Symbol], ?clears_last_status: bool, ?defines_case_equality: bool, ?implicit_self_evidence: untyped, ?in_effect_refinements: untyped, ?possible_discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?possible_discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?contested_discovered_def_nodes: Set[Array[untyped]], ?contested_discovered_singleton_def_nodes: Set[Array[untyped]], ?contested_discovered_method_visibilities: Set[Array[untyped]], ?contested_discovered_parameter_envelopes: Set[Array[untyped]]) -> DiscoveryIndex
|
|
204
|
+
def with: (?declared_types: Hash[untyped, Type::t], ?class_ivars: Hash[String, Hash[Symbol, Type::t]], ?class_cvars: Hash[String, Hash[Symbol, Type::t]], ?program_globals: Hash[Symbol, Type::t], ?program_global_seeds: Hash[Symbol, Type::t], ?discovered_classes: Hash[String, Type::Singleton], ?in_source_constants: Hash[String, Type::t], ?discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?discovered_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_nestings: Hash[untyped, Array[String]], ?discovered_singleton_def_nodes: Hash[String, Hash[Symbol, untyped]], ?discovered_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_singleton_def_sources: Hash[String, Hash[Symbol, String]], ?discovered_method_visibilities: Hash[String, Hash[Symbol | [:singleton, Symbol], Symbol]], ?discovered_parameter_envelopes: Hash[String, Hash[untyped, untyped]], ?discovered_superclasses: Hash[String, String], ?discovered_includes: Hash[String, Array[String]], ?discovered_prepends: Hash[String, Array[String]], ?discovered_extends: Hash[String, Array[String]], ?discovered_class_sources: Hash[String, Set[String]], ?constant_sources: Hash[String, Set[String]], ?constant_writers: Hash[String, Array[String]], ?constant_shadowers: Hash[String, Array[String]], ?published_constant_names: Set[String], ?local_constant_names: Set[String], ?published_constant_alias_names: Set[String], ?published_constant_ivars: Hash[String, Set[Symbol]], ?data_member_layouts: Hash[String, Array[Symbol]], ?struct_member_layouts: Hash[String, { members: Array[Symbol], keyword_init: bool }], ?param_inferred_types: Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]], ?discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?discovered_refinements: Hash[String, Hash[Symbol | String, Array[String]]], ?discovered_global_write_census: Set[Array[untyped]], ?run_generation: Object?, ?patched_line_readers: Set[Symbol], ?clears_last_status: bool, ?defines_case_equality: bool, ?implicit_self_evidence: untyped, ?in_effect_refinements: untyped, ?possible_discovered_methods: Hash[String, Hash[Symbol, Symbol]], ?possible_discovered_deferred_ranges: Hash[String, Array[[Integer, Integer, Symbol?, Symbol?, String?]]], ?contested_discovered_def_nodes: Set[Array[untyped]], ?contested_discovered_singleton_def_nodes: Set[Array[untyped]], ?contested_discovered_method_visibilities: Set[Array[untyped]], ?contested_discovered_parameter_envelopes: Set[Array[untyped]]) -> DiscoveryIndex
|
|
205
205
|
end
|
|
206
206
|
|
|
207
207
|
class IndexedKey
|
|
@@ -338,6 +338,7 @@ module Rigor
|
|
|
338
338
|
# Issue #530 — public so the external-gem ancestry probe asks the same question the walk does.
|
|
339
339
|
def known_user_class?: (String | Symbol name) -> bool
|
|
340
340
|
def singleton_def_for: (String | Symbol class_name, String | Symbol method_name) -> ::Prism::DefNode?
|
|
341
|
+
def module_function_def?: (untyped, untyped) -> (false | true)
|
|
341
342
|
def singleton_def_through_ancestors: (String | Symbol class_name, String | Symbol method_name, ?name_memo: Hash[untyped, untyped]) -> ([::Prism::DefNode, String] | [nil, nil])
|
|
342
343
|
def user_def_site_for: (String | Symbol class_name, String | Symbol method_name) -> String?
|
|
343
344
|
def user_singleton_def_site_for: (String | Symbol class_name, String | Symbol method_name) -> String?
|
|
@@ -78,17 +78,24 @@ Make sure a single `rigortype` is on the load path.
|
|
|
78
78
|
- `warn` — the baseline file failed to load. Check the `baseline:` path
|
|
79
79
|
in the config.
|
|
80
80
|
|
|
81
|
-
### `plugin_gap` — the stack has a plugin that is not
|
|
81
|
+
### `plugin_gap` — the stack has a plugin that is not listed
|
|
82
82
|
|
|
83
|
-
Read from the `DEPENDENCIES` section of `Gemfile.lock
|
|
83
|
+
Read from the `DEPENDENCIES` section of `Gemfile.lock`, plus the Rails
|
|
84
|
+
components a direct `rails` stands for. A `plugins:` entry counts as
|
|
85
|
+
listing its plugin even with `enabled: false`. Skipped when no
|
|
86
|
+
`.rigor.yml` or `.rigor.dist.yml` is discovered in the current directory.
|
|
84
87
|
|
|
85
88
|
- `fail` — the project depends on gems that bundled plugins model, and
|
|
86
|
-
**none** of
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
`plugins:` lists **none** of the bundled plugins that model gems (those
|
|
90
|
+
declaring `target_gems:`; `rigor-rbs-inline` does not count): framework
|
|
91
|
+
calls will not resolve. Add the plugins for the stack to `plugins:` (the
|
|
92
|
+
`rigor-plugin-tune` skill does this). Once any such plugin is listed,
|
|
93
|
+
the remaining gaps are reported as the per-plugin warnings below.
|
|
89
94
|
- `warn` — one per plugin that models a direct dependency but is not
|
|
90
|
-
|
|
91
|
-
a
|
|
95
|
+
listed. Add it, or decline it deliberately — declining is a legitimate
|
|
96
|
+
choice, and the way to record it is a `plugins:` entry with
|
|
97
|
+
`enabled: false`. Do not enable an unrelated plugin only to silence
|
|
98
|
+
this check.
|
|
92
99
|
|
|
93
100
|
### `gemfile_install` — Rigor is a project dependency
|
|
94
101
|
|
|
@@ -98,10 +105,15 @@ Read from the `DEPENDENCIES` section of `Gemfile.lock`.
|
|
|
98
105
|
|
|
99
106
|
### `bundle_layout` — gem-shipped signatures are not discovered
|
|
100
107
|
|
|
101
|
-
`warn` when a `Gemfile.lock` exists
|
|
102
|
-
bundle
|
|
103
|
-
ship their own `sig/` are then
|
|
104
|
-
|
|
108
|
+
`warn` when a `Gemfile.lock` exists in the current directory but Rigor
|
|
109
|
+
cannot locate the installed bundle — typically the gems live in the
|
|
110
|
+
active Ruby's default gem home. Gems that ship their own `sig/` are then
|
|
111
|
+
not loaded. Rigor looks only where the project records the bundle: a
|
|
112
|
+
`bundler.bundle_path:` in `.rigor.yml` is used alone and must exist;
|
|
113
|
+
without one, and unless `bundler.auto_detect: false`, it reads
|
|
114
|
+
`.bundle/config`'s `BUNDLE_PATH`, then an in-tree `vendor/bundle`, then
|
|
115
|
+
the global Bundler config. Point Rigor at the install root with
|
|
116
|
+
`bundler.bundle_path:`, install into `vendor/bundle`, or supply
|
|
105
117
|
signatures with `rbs collection install` instead.
|
|
106
118
|
|
|
107
119
|
## Not covered by `rigor doctor`: is the analysis seeing your code?
|
|
@@ -212,7 +212,8 @@ rigor explain [<rule>]
|
|
|
212
212
|
| `--format=text\|json` | Default `text`. |
|
|
213
213
|
|
|
214
214
|
With no argument it lists every rule. With a rule id, a legacy alias, or
|
|
215
|
-
a family prefix (`call`, `flow`, `assert`, `dump`, `
|
|
215
|
+
a family prefix (`call`, `flow`, `def`, `assert`, `dump`, `global`,
|
|
216
|
+
`suppression`, `static`, `effect`) it prints the
|
|
216
217
|
rule's firing conditions, the severity per profile, the evidence tier,
|
|
217
218
|
and how to suppress it.
|
|
218
219
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rigortype
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rigor contributors
|
|
@@ -321,6 +321,7 @@ files:
|
|
|
321
321
|
- data/core_overlay/module.rbs
|
|
322
322
|
- data/core_overlay/numeric.rbs
|
|
323
323
|
- data/core_overlay/object_space.rbs
|
|
324
|
+
- data/core_overlay/ostruct.rbs
|
|
324
325
|
- data/core_overlay/pathname.rbs
|
|
325
326
|
- data/core_overlay/proc.rbs
|
|
326
327
|
- data/core_overlay/process.rbs
|
|
@@ -445,6 +446,7 @@ files:
|
|
|
445
446
|
- lib/rigor/analysis/buffer_binding.rb
|
|
446
447
|
- lib/rigor/analysis/check_rules.rb
|
|
447
448
|
- lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb
|
|
449
|
+
- lib/rigor/analysis/check_rules/clause_coverage.rb
|
|
448
450
|
- lib/rigor/analysis/check_rules/dead_assignment_collector.rb
|
|
449
451
|
- lib/rigor/analysis/check_rules/dead_version_guard_arms.rb
|
|
450
452
|
- lib/rigor/analysis/check_rules/declaration_sourced_guard.rb
|
|
@@ -454,6 +456,7 @@ files:
|
|
|
454
456
|
- lib/rigor/analysis/check_rules/lexical_method_sites.rb
|
|
455
457
|
- lib/rigor/analysis/check_rules/main_pass_collector.rb
|
|
456
458
|
- lib/rigor/analysis/check_rules/published_constant_guard.rb
|
|
459
|
+
- lib/rigor/analysis/check_rules/rbs_receiver_surface.rb
|
|
457
460
|
- lib/rigor/analysis/check_rules/return_in_ensure_collector.rb
|
|
458
461
|
- lib/rigor/analysis/check_rules/ruby_deprecations.rb
|
|
459
462
|
- lib/rigor/analysis/check_rules/rule_ids.rb
|
|
@@ -704,6 +707,7 @@ files:
|
|
|
704
707
|
- lib/rigor/inference/builtins/struct_catalog.rb
|
|
705
708
|
- lib/rigor/inference/builtins/time_catalog.rb
|
|
706
709
|
- lib/rigor/inference/captured_locals.rb
|
|
710
|
+
- lib/rigor/inference/clause_widening.rb
|
|
707
711
|
- lib/rigor/inference/closure_escape_analyzer.rb
|
|
708
712
|
- lib/rigor/inference/content_join.rb
|
|
709
713
|
- lib/rigor/inference/coverage_scanner.rb
|
|
@@ -742,6 +746,7 @@ files:
|
|
|
742
746
|
- lib/rigor/inference/in_effect_refinements/walk.rb
|
|
743
747
|
- lib/rigor/inference/index_write_widening.rb
|
|
744
748
|
- lib/rigor/inference/indexed_narrowing.rb
|
|
749
|
+
- lib/rigor/inference/intervening_ivar_reset.rb
|
|
745
750
|
- lib/rigor/inference/jump_targets.rb
|
|
746
751
|
- lib/rigor/inference/key_presence_guard.rb
|
|
747
752
|
- lib/rigor/inference/key_presence_guard/scan.rb
|
|
@@ -818,7 +823,10 @@ files:
|
|
|
818
823
|
- lib/rigor/inference/project_method_ownership.rb
|
|
819
824
|
- lib/rigor/inference/project_patched_definedness_guard.rb
|
|
820
825
|
- lib/rigor/inference/project_patched_methods.rb
|
|
826
|
+
- lib/rigor/inference/project_patched_mixins.rb
|
|
821
827
|
- lib/rigor/inference/project_patched_scanner.rb
|
|
828
|
+
- lib/rigor/inference/project_patched_visibility.rb
|
|
829
|
+
- lib/rigor/inference/project_seed_tables.rb
|
|
822
830
|
- lib/rigor/inference/protection_scanner.rb
|
|
823
831
|
- lib/rigor/inference/range_constant.rb
|
|
824
832
|
- lib/rigor/inference/rbs_type_translator.rb
|
|
@@ -828,8 +836,10 @@ files:
|
|
|
828
836
|
- lib/rigor/inference/refine_self.rb
|
|
829
837
|
- lib/rigor/inference/refined_dispatch.rb
|
|
830
838
|
- lib/rigor/inference/refined_dispatch/class_object.rb
|
|
839
|
+
- lib/rigor/inference/refined_dispatch/constructed_class.rb
|
|
831
840
|
- lib/rigor/inference/refined_dispatch/own_method.rb
|
|
832
841
|
- lib/rigor/inference/refinement_mutation.rb
|
|
842
|
+
- lib/rigor/inference/reflective_ivar_write.rb
|
|
833
843
|
- lib/rigor/inference/repeated_or_writes.rb
|
|
834
844
|
- lib/rigor/inference/return_barrier.rb
|
|
835
845
|
- lib/rigor/inference/rewrite_mutation.rb
|
|
@@ -841,6 +851,8 @@ files:
|
|
|
841
851
|
- lib/rigor/inference/scope_indexer/member_layouts_collector.rb
|
|
842
852
|
- lib/rigor/inference/scope_indexer/mixin_accumulator.rb
|
|
843
853
|
- lib/rigor/inference/scope_indexer/superclasses_collector.rb
|
|
854
|
+
- lib/rigor/inference/self_call_ivar_writes.rb
|
|
855
|
+
- lib/rigor/inference/singleton_external_ahead.rb
|
|
844
856
|
- lib/rigor/inference/singleton_hook_decline.rb
|
|
845
857
|
- lib/rigor/inference/singleton_object_constant.rb
|
|
846
858
|
- lib/rigor/inference/statement_evaluator.rb
|
|
@@ -943,6 +955,7 @@ files:
|
|
|
943
955
|
- lib/rigor/reflection.rb
|
|
944
956
|
- lib/rigor/reflection/constant_ancestors.rb
|
|
945
957
|
- lib/rigor/reflection/constant_path.rb
|
|
958
|
+
- lib/rigor/rooted_glob.rb
|
|
946
959
|
- lib/rigor/runtime/jit.rb
|
|
947
960
|
- lib/rigor/scope.rb
|
|
948
961
|
- lib/rigor/scope/discovery_index.rb
|
|
@@ -966,6 +979,7 @@ files:
|
|
|
966
979
|
- lib/rigor/sig_gen/skip_reason_catalog.rb
|
|
967
980
|
- lib/rigor/sig_gen/superclass_spelling.rb
|
|
968
981
|
- lib/rigor/sig_gen/type_elaborator.rb
|
|
982
|
+
- lib/rigor/sig_gen/write_reporter.rb
|
|
969
983
|
- lib/rigor/sig_gen/write_result.rb
|
|
970
984
|
- lib/rigor/sig_gen/writer.rb
|
|
971
985
|
- lib/rigor/signature_path_audit.rb
|
|
@@ -1287,6 +1301,7 @@ files:
|
|
|
1287
1301
|
- sig/rigor/plugin/type_node_resolver.rbs
|
|
1288
1302
|
- sig/rigor/rbs_extended.rbs
|
|
1289
1303
|
- sig/rigor/reflection.rbs
|
|
1304
|
+
- sig/rigor/rooted_glob.rbs
|
|
1290
1305
|
- sig/rigor/scope.rbs
|
|
1291
1306
|
- sig/rigor/sig_gen/skip_reason_catalog.rbs
|
|
1292
1307
|
- sig/rigor/source.rbs
|