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
|
@@ -23,7 +23,9 @@ module Rigor
|
|
|
23
23
|
# - a statement, and the body of `(…)`, `begin` / `rescue` / `else` / `ensure`;
|
|
24
24
|
# - an assignment's value — every variable-write form, and an index `||=` / `&&=` / `op=`, but not its
|
|
25
25
|
# receiver or index arguments;
|
|
26
|
-
# - an `if` / `unless` / `case` predicate and every branch, but not a `when` condition or an `in` guard
|
|
26
|
+
# - an `if` / `unless` / `case` predicate and every branch, but not a `when` condition or an `in` guard (since
|
|
27
|
+
# issue #1963 the evaluator threads a `when` test that runs code in a `case` with a subject; the scan does
|
|
28
|
+
# not admit it yet, which floors a name needlessly rather than letting a pin through);
|
|
27
29
|
# - both operands of `&&` / `||`;
|
|
28
30
|
# - a `while` / `until` predicate and body, a `for` index, collection and body;
|
|
29
31
|
# - a multi-assign value and its local and instance-variable targets, and the LOCAL a `rescue => e`
|
data/lib/rigor/lens/anchor.rb
CHANGED
|
@@ -32,9 +32,9 @@ module Rigor
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# The anchor of the declaration spanning bytes `start_offset...end_offset` and lines `start_line..end_line`.
|
|
35
|
-
def for_span(start_offset, end_offset, start_line, end_line)
|
|
36
|
-
leading = leading_contract_comments(start_line)
|
|
37
|
-
trailing = trailing_contract_comment(end_line, end_offset)
|
|
35
|
+
def for_span(start_offset, end_offset, start_line, end_line, leading: true, trailing: true)
|
|
36
|
+
leading = leading ? leading_contract_comments(start_line) : []
|
|
37
|
+
trailing = trailing ? trailing_contract_comment(end_line, end_offset) : nil
|
|
38
38
|
material = +"".b
|
|
39
39
|
leading.each { |comment| material << line_text_from(comment.location.start_offset) << "\n" }
|
|
40
40
|
material << @source.byteslice(start_offset, end_offset - start_offset)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "slot"
|
|
4
|
+
require_relative "parameters"
|
|
4
5
|
require_relative "../reflection"
|
|
5
6
|
|
|
6
7
|
module Rigor
|
|
@@ -34,6 +35,41 @@ module Rigor
|
|
|
34
35
|
unreadable("definition_build_failed", [])
|
|
35
36
|
end
|
|
36
37
|
|
|
38
|
+
# The block an otherwise defaulted inline declaration (`rigor:v1:inferred-signature`) declares, as a
|
|
39
|
+
# `{required, type}` slot, or nil. The rbs-inline plugin defaults an unannotated `&block` to `?{ (?) ->
|
|
40
|
+
# untyped }`, so any other block came from a `# @rbs &block:` annotation, and `check` binds the block's
|
|
41
|
+
# parameters from it. A block spelled like the default carries nothing either way.
|
|
42
|
+
def read_defaulted_block(owner, scope, name, lookup_scope)
|
|
43
|
+
method = lookup(owner, scope, name, lookup_scope)
|
|
44
|
+
defs = method ? method.defs.select { |definition| definition.defined_in.to_s.delete_prefix("::") == owner } : []
|
|
45
|
+
return nil unless defs.size == 1 && annotations_of(method, defs).include?(INFERRED_SIGNATURE)
|
|
46
|
+
|
|
47
|
+
block = defs.first.type.block
|
|
48
|
+
return nil if block.nil? || default_block?(block)
|
|
49
|
+
|
|
50
|
+
provenance, path = @provenance.classify(buffer_name(defs.first))
|
|
51
|
+
return nil if provenance.nil?
|
|
52
|
+
|
|
53
|
+
{ "required" => block.required, "type" => Slot.from_rbs(block_type(block), provenance, path) }
|
|
54
|
+
rescue StandardError
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The declared type of the constant `name` (qualified), as a slot with its declaration's provenance, or nil
|
|
59
|
+
# when no RBS or inline declaration names it.
|
|
60
|
+
def read_constant(name, environment)
|
|
61
|
+
declaration = environment&.rbs_loader&.constant_declaration(name)
|
|
62
|
+
return nil if declaration.nil?
|
|
63
|
+
|
|
64
|
+
type, buffer = declaration
|
|
65
|
+
provenance, path = @provenance.classify(buffer)
|
|
66
|
+
return Slot.unavailable("not_computed") if provenance.nil?
|
|
67
|
+
|
|
68
|
+
Slot.from_rbs(type, provenance, path)
|
|
69
|
+
rescue StandardError
|
|
70
|
+
Slot.unavailable("not_computed")
|
|
71
|
+
end
|
|
72
|
+
|
|
37
73
|
private
|
|
38
74
|
|
|
39
75
|
def contract(defs, annotations)
|
|
@@ -87,14 +123,36 @@ module Rigor
|
|
|
87
123
|
def overload(method_type, provenance, path, return_inferred, annotations)
|
|
88
124
|
function = method_type.type
|
|
89
125
|
params = function.respond_to?(:required_positionals) ? params_of(function, provenance, path) : nil
|
|
90
|
-
|
|
91
|
-
|
|
126
|
+
partly_defaulted = return_inferred && provenance == "inline"
|
|
127
|
+
block = method_type.block && block_slot(method_type.block, provenance, path, partly_defaulted)
|
|
92
128
|
prefix = annotations.map { |string| "%a{#{string}} " }.join
|
|
93
129
|
return_slot = return_inferred ? nil : Slot.from_rbs(function.return_type.to_s, provenance, path)
|
|
94
130
|
{ "rbs" => "#{prefix}#{method_type}", "params" => params, "block" => block, "return" => return_slot,
|
|
95
131
|
"return_rbs" => function.return_type.to_s }
|
|
96
132
|
end
|
|
97
133
|
|
|
134
|
+
# A block's function type as `RBS::MethodType#to_s` spells it inside the braces (`(Integer) -> void`, with a
|
|
135
|
+
# `[self: T]` binding when declared). Neither `RBS::Types::Function` nor `UntypedFunction` has a `to_s`.
|
|
136
|
+
def block_type(block)
|
|
137
|
+
self_binding = ::RBS::Types::SelfTypeBindingHelper.self_type_binding_to_s(block.self_type)
|
|
138
|
+
"(#{block.type.param_to_s}) #{self_binding}-> #{block.type.return_to_s}"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Under an inline declaration the rbs-inline plugin defaulted in part (`partly_defaulted`), a block shaped
|
|
142
|
+
# like its default was not written: it reads as an undeclared block does.
|
|
143
|
+
def block_slot(block, provenance, path, partly_defaulted)
|
|
144
|
+
if partly_defaulted && default_block?(block)
|
|
145
|
+
return { "required" => false, "type" => Slot.dynamic("inferred", Parameters::UNDECLARED) }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
{ "required" => block.required, "type" => Slot.from_rbs(block_type(block), provenance, path) }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def default_block?(block)
|
|
152
|
+
!block.required && block.type.is_a?(::RBS::Types::UntypedFunction) && block.self_type.nil? &&
|
|
153
|
+
block.type.return_type.is_a?(::RBS::Types::Bases::Any)
|
|
154
|
+
end
|
|
155
|
+
|
|
98
156
|
def params_of(function, provenance, path)
|
|
99
157
|
(positional_params(function) + keyword_params(function)).map do |kind, name, param|
|
|
100
158
|
{ "name" => name&.to_s, "kind" => kind, "type" => Slot.from_rbs(param.type.to_s, provenance, path) }
|
data/lib/rigor/lens/document.rb
CHANGED
|
@@ -5,13 +5,14 @@ require "json"
|
|
|
5
5
|
require_relative "../version"
|
|
6
6
|
require_relative "../cache/engine_source"
|
|
7
7
|
require_relative "../analysis/run_cache_key"
|
|
8
|
+
require_relative "../rooted_glob"
|
|
8
9
|
|
|
9
10
|
module Rigor
|
|
10
11
|
module Lens
|
|
11
12
|
# Assembles the `lens/v0` document (docs/internal-spec/lens.md § Document) from a {Run::Outcome}.
|
|
12
13
|
class Document
|
|
13
|
-
SITE_FIELDS = %w[key kind name owner scope attribute members ordinal span contract_span
|
|
14
|
-
contract params block body_return].freeze
|
|
14
|
+
SITE_FIELDS = %w[key kind name owner scope attribute members module_function builder ordinal span contract_span
|
|
15
|
+
anchor visibility contract params block body_return value alias_of].freeze
|
|
15
16
|
|
|
16
17
|
def initialize(outcome:, configuration:, root:, config_path:)
|
|
17
18
|
@outcome = outcome
|
|
@@ -60,7 +61,7 @@ module Rigor
|
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
def signature_digest
|
|
63
|
-
listing = signature_roots.flat_map { |root|
|
|
64
|
+
listing = signature_roots.flat_map { |root| RootedGlob.glob(root, "**/*.rbs") }.sort.map do |path|
|
|
64
65
|
"#{relative(path)}\t#{Lens.digest(File.binread(path))}\n"
|
|
65
66
|
end
|
|
66
67
|
Lens.digest(listing.join)
|