rigortype 0.1.18 → 0.2.0
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 -224
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +9 -3
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +25 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +32 -23
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +54 -0
- data/lib/rigor/analysis/check_rules/rule_walk.rb +151 -23
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +24 -15
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +9 -3
- data/lib/rigor/analysis/check_rules.rb +756 -132
- data/lib/rigor/analysis/dependency_source_inference/index.rb +4 -7
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -18
- data/lib/rigor/analysis/dependency_source_inference.rb +3 -12
- data/lib/rigor/analysis/diagnostic.rb +8 -0
- data/lib/rigor/analysis/fact_store.rb +5 -4
- data/lib/rigor/analysis/rule_catalog.rb +153 -6
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +19 -18
- data/lib/rigor/analysis/runner/project_pre_passes.rb +13 -9
- data/lib/rigor/analysis/runner.rb +75 -27
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +3 -4
- data/lib/rigor/analysis/worker_session.rb +31 -25
- data/lib/rigor/bleeding_edge.rb +123 -0
- data/lib/rigor/builtins/predefined_constant_refinements.rb +151 -0
- data/lib/rigor/cache/descriptor.rb +86 -8
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +5 -3
- data/lib/rigor/cli/annotate_command.rb +122 -16
- data/lib/rigor/cli/baseline_command.rb +4 -3
- data/lib/rigor/cli/check_command.rb +118 -16
- data/lib/rigor/cli/coverage_command.rb +148 -16
- data/lib/rigor/cli/coverage_scan.rb +57 -0
- data/lib/rigor/cli/explain_command.rb +2 -0
- data/lib/rigor/cli/lsp_command.rb +3 -7
- data/lib/rigor/cli/mutation_protection_renderer.rb +63 -0
- data/lib/rigor/cli/mutation_protection_report.rb +73 -0
- data/lib/rigor/cli/options.rb +9 -0
- data/lib/rigor/cli/plugins_command.rb +4 -5
- data/lib/rigor/cli/plugins_renderer.rb +0 -2
- data/lib/rigor/cli/protection_renderer.rb +63 -0
- data/lib/rigor/cli/protection_report.rb +68 -0
- data/lib/rigor/cli/show_bleedingedge_command.rb +114 -0
- data/lib/rigor/cli/sig_gen_command.rb +2 -1
- data/lib/rigor/cli/trace_command.rb +2 -1
- data/lib/rigor/cli/triage_command.rb +8 -4
- data/lib/rigor/cli/triage_renderer.rb +15 -1
- data/lib/rigor/cli/type_of_command.rb +1 -1
- data/lib/rigor/cli/type_scan_command.rb +2 -1
- data/lib/rigor/cli.rb +12 -3
- data/lib/rigor/configuration/dependencies.rb +2 -4
- data/lib/rigor/configuration/severity_profile.rb +13 -1
- data/lib/rigor/configuration.rb +100 -6
- data/lib/rigor/environment/bundle_sig_discovery.rb +61 -13
- data/lib/rigor/environment/class_registry.rb +4 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +43 -0
- data/lib/rigor/environment/lockfile_resolver.rb +1 -1
- data/lib/rigor/environment/rbs_collection_discovery.rb +1 -2
- data/lib/rigor/environment/rbs_coverage_report.rb +2 -1
- data/lib/rigor/environment/rbs_loader.rb +74 -5
- data/lib/rigor/environment.rb +17 -7
- data/lib/rigor/flow_contribution/fact.rb +1 -1
- data/lib/rigor/flow_contribution.rb +3 -5
- data/lib/rigor/inference/acceptance.rb +17 -9
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +89 -0
- data/lib/rigor/inference/budget_trace.rb +29 -2
- data/lib/rigor/inference/builtins/comparable_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/method_catalog.rb +19 -0
- data/lib/rigor/inference/builtins/string_catalog.rb +9 -1
- data/lib/rigor/inference/expression_typer.rb +1072 -71
- data/lib/rigor/inference/hkt_body.rb +8 -11
- data/lib/rigor/inference/hkt_body_parser.rb +10 -12
- data/lib/rigor/inference/hkt_registry.rb +10 -11
- data/lib/rigor/inference/macro_block_self_type.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +60 -0
- data/lib/rigor/inference/method_dispatcher/call_context.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +210 -35
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +9 -73
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +6 -7
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +10 -16
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +25 -13
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +93 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +1 -3
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +24 -22
- 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 +237 -24
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +303 -0
- data/lib/rigor/inference/method_dispatcher.rb +112 -49
- 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 +147 -11
- data/lib/rigor/inference/narrowing.rb +284 -53
- data/lib/rigor/inference/parameter_inference_collector.rb +367 -0
- data/lib/rigor/inference/project_patched_methods.rb +4 -7
- data/lib/rigor/inference/project_patched_scanner.rb +2 -13
- data/lib/rigor/inference/protection_scanner.rb +86 -0
- data/lib/rigor/inference/scope_indexer.rb +821 -76
- data/lib/rigor/inference/statement_evaluator.rb +1179 -102
- data/lib/rigor/inference/struct_fold_safety.rb +181 -0
- data/lib/rigor/inference/synthetic_method.rb +7 -7
- data/lib/rigor/inference/synthetic_method_scanner.rb +1 -1
- data/lib/rigor/language_server/completion_provider.rb +6 -12
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +3 -3
- data/lib/rigor/language_server/hover_provider.rb +2 -3
- data/lib/rigor/language_server/hover_renderer.rb +2 -11
- data/lib/rigor/language_server/server.rb +9 -17
- data/lib/rigor/language_server.rb +4 -5
- data/lib/rigor/plugin/base.rb +245 -87
- data/lib/rigor/plugin/macro/block_as_method.rb +25 -25
- data/lib/rigor/plugin/macro/heredoc_template.rb +4 -7
- data/lib/rigor/plugin/macro/nested_class_template.rb +9 -7
- data/lib/rigor/plugin/macro/trait_registry.rb +3 -6
- data/lib/rigor/plugin/macro.rb +6 -8
- data/lib/rigor/plugin/manifest.rb +49 -90
- data/lib/rigor/plugin/node_rule_walk.rb +59 -14
- data/lib/rigor/plugin/registry.rb +18 -18
- data/lib/rigor/plugin/type_node_resolver.rb +6 -8
- data/lib/rigor/protection/mutation_scanner.rb +120 -0
- data/lib/rigor/protection/mutator.rb +246 -0
- data/lib/rigor/rbs_extended.rb +24 -36
- data/lib/rigor/reflection.rb +4 -7
- data/lib/rigor/scope/discovery_index.rb +16 -2
- data/lib/rigor/scope.rb +185 -16
- data/lib/rigor/sig_gen/generator.rb +8 -0
- data/lib/rigor/sig_gen/observed_call.rb +3 -3
- data/lib/rigor/sig_gen/writer.rb +40 -2
- data/lib/rigor/source/constant_path.rb +62 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +4 -19
- data/lib/rigor/triage.rb +69 -1
- data/lib/rigor/type/bound_method.rb +2 -11
- data/lib/rigor/type/combinator.rb +45 -3
- data/lib/rigor/type/constant.rb +2 -11
- data/lib/rigor/type/data_class.rb +2 -11
- data/lib/rigor/type/data_instance.rb +2 -11
- data/lib/rigor/type/hash_shape.rb +2 -11
- data/lib/rigor/type/integer_range.rb +2 -11
- data/lib/rigor/type/intersection.rb +2 -11
- data/lib/rigor/type/nominal.rb +2 -11
- data/lib/rigor/type/plain_lattice.rb +37 -0
- data/lib/rigor/type/refined.rb +72 -13
- data/lib/rigor/type/singleton.rb +2 -11
- data/lib/rigor/type/struct_class.rb +75 -0
- data/lib/rigor/type/struct_instance.rb +93 -0
- data/lib/rigor/type/tuple.rb +5 -15
- data/lib/rigor/type.rb +2 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +3 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +16 -32
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +5 -13
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -32
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +11 -17
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +34 -100
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +3 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +13 -30
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +4 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +26 -27
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +5 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +9 -8
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +9 -11
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +8 -9
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +13 -12
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +3 -4
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +8 -8
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +9 -11
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +7 -8
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +18 -49
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +12 -13
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +15 -23
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +4 -4
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +3 -3
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +10 -21
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +2 -4
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +27 -11
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +22 -35
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +4 -6
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +12 -18
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +16 -23
- 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 +3 -4
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +21 -27
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +0 -1
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +3 -23
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +5 -4
- 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/assertion_recognizer.rb +2 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +7 -11
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +6 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +5 -15
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +52 -40
- data/sig/rigor/analysis/fact_store.rbs +3 -0
- data/sig/rigor/inference/builtins/method_catalog.rbs +1 -1
- data/sig/rigor/plugin/base.rbs +5 -2
- data/sig/rigor/plugin/manifest.rbs +1 -2
- data/sig/rigor/scope.rbs +18 -1
- data/sig/rigor/type.rbs +37 -1
- data/sig/rigor.rbs +1 -1
- data/skills/rigor-baseline-reduce/references/01-classify.md +27 -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 +25 -2
- data/lib/rigor/plugin/macro/external_file.rb +0 -143
|
@@ -6,14 +6,11 @@ module Rigor
|
|
|
6
6
|
module Analysis
|
|
7
7
|
module DependencySourceInference
|
|
8
8
|
# Per-run collection of gem-source-inference state. Holds
|
|
9
|
-
# the resolved gems the walker
|
|
10
|
-
#
|
|
9
|
+
# the resolved gems the walker visits plus the unresolvable
|
|
10
|
+
# entries the runner surfaces as
|
|
11
11
|
# `dynamic.dependency-source.gem-not-found` diagnostics.
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# tier consults {#contribution_for} but the lookup always
|
|
15
|
-
# answers `nil` until slice 2b populates the method table
|
|
16
|
-
# by walking the resolved gems' `roots:`.
|
|
12
|
+
# The method table is fully populated by {Walker} at build
|
|
13
|
+
# time; {#contribution_for} returns live entries.
|
|
17
14
|
class Index
|
|
18
15
|
attr_reader :resolved_gems, :unresolvable, :method_catalog, :budget_exceeded,
|
|
19
16
|
:class_to_gem, :budget_overrun_strategy, :gem_modes
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
5
|
require_relative "return_type_heuristic"
|
|
6
|
+
require_relative "../../source/constant_path"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module Analysis
|
|
@@ -166,7 +167,7 @@ module Rigor
|
|
|
166
167
|
# children under the same prefix so any inner class
|
|
167
168
|
# definitions are still recorded under their own name.
|
|
168
169
|
def descend_class_or_module(node, qualified_prefix, in_singleton_class, accumulator, budget)
|
|
169
|
-
name =
|
|
170
|
+
name = Source::ConstantPath.qualified_name_or_nil(node.constant_path)
|
|
170
171
|
if name && node.body
|
|
171
172
|
walk_node(node.body, qualified_prefix + [name], in_singleton_class, accumulator, budget)
|
|
172
173
|
else
|
|
@@ -197,23 +198,6 @@ module Rigor
|
|
|
197
198
|
return_type = ReturnTypeHeuristic.extract(node)
|
|
198
199
|
accumulator[key] = CatalogEntry.new(kind: kind, return_type: return_type)
|
|
199
200
|
end
|
|
200
|
-
|
|
201
|
-
# Resolves a `Prism::ConstantPathNode` /
|
|
202
|
-
# `Prism::ConstantReadNode` chain to its dot-separated
|
|
203
|
-
# name (e.g. `"Foo::Bar"`). Returns nil for the rare
|
|
204
|
-
# dynamic-prefix shape (`module ::Foo`-rooted variants
|
|
205
|
-
# whose left side is a runtime expression) so the
|
|
206
|
-
# walker treats those as opaque rather than guessing.
|
|
207
|
-
def qualified_name_for(node)
|
|
208
|
-
case node
|
|
209
|
-
when Prism::ConstantReadNode then node.name.to_s
|
|
210
|
-
when Prism::ConstantPathNode
|
|
211
|
-
parent = node.parent.nil? ? nil : qualified_name_for(node.parent)
|
|
212
|
-
return nil if !node.parent.nil? && parent.nil?
|
|
213
|
-
|
|
214
|
-
parent.nil? ? node.name.to_s : "#{parent}::#{node.name}"
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
201
|
end
|
|
218
202
|
end
|
|
219
203
|
end
|
|
@@ -20,18 +20,9 @@ module Rigor
|
|
|
20
20
|
# - {Builder.build} folds a `Configuration::Dependencies`
|
|
21
21
|
# into a frozen {Index} carrying the partitioned outcomes.
|
|
22
22
|
# - {Index} holds the per-run state the dispatcher tier
|
|
23
|
-
# consults via `#contribution_for
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# Per the ADR's "Implementation slicing" section, slice 2 is
|
|
28
|
-
# split internally:
|
|
29
|
-
#
|
|
30
|
-
# - Slice 2a (this commit): gem resolution, index plumbing,
|
|
31
|
-
# `Analysis::Runner` wiring, `dynamic.dependency-source.gem-not-found`
|
|
32
|
-
# diagnostic for unresolvable entries.
|
|
33
|
-
# - Slice 2b (next commit): walker, dispatcher tier
|
|
34
|
-
# integration, `Type::Dynamic`-wrapped returns.
|
|
23
|
+
# consults via `#contribution_for`; the method table is
|
|
24
|
+
# fully populated by {Walker} walking each resolved gem's
|
|
25
|
+
# `roots:`.
|
|
35
26
|
module DependencySourceInference
|
|
36
27
|
end
|
|
37
28
|
end
|
|
@@ -132,6 +132,12 @@ module Rigor
|
|
|
132
132
|
"#{source_family}.#{rule}"
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
+
# `--format json` serialisation. The structured `receiver_type`
|
|
136
|
+
# / `method_name` / `project_definition_site` fields are emitted
|
|
137
|
+
# only when populated, so a consumer (`jq`, `rigor triage`, an AI
|
|
138
|
+
# agent) can group a `rigor check --format json` stream by the
|
|
139
|
+
# called class / method without parsing the human-readable
|
|
140
|
+
# `message` — the message wording is presentation, not contract.
|
|
135
141
|
def to_h
|
|
136
142
|
base = {
|
|
137
143
|
"path" => path,
|
|
@@ -142,6 +148,8 @@ module Rigor
|
|
|
142
148
|
"source_family" => source_family.to_s,
|
|
143
149
|
"message" => message
|
|
144
150
|
}
|
|
151
|
+
base["receiver_type"] = receiver_type if receiver_type
|
|
152
|
+
base["method_name"] = method_name if method_name
|
|
145
153
|
base["project_definition_site"] = project_definition_site if project_definition_site
|
|
146
154
|
base
|
|
147
155
|
end
|
|
@@ -4,10 +4,11 @@ module Rigor
|
|
|
4
4
|
module Analysis
|
|
5
5
|
# Immutable storage for flow-sensitive facts attached to a Scope snapshot.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# facts that mention a target,
|
|
10
|
-
# retaining only facts that both
|
|
7
|
+
# Six buckets (see BUCKETS): local_binding, captured_local,
|
|
8
|
+
# object_content, global_storage, dynamic_origin, relational.
|
|
9
|
+
# Callers can record facts, invalidate all facts that mention a target,
|
|
10
|
+
# and conservatively join two stores by retaining only facts that both
|
|
11
|
+
# incoming edges share.
|
|
11
12
|
class FactStore
|
|
12
13
|
BUCKETS = %i[
|
|
13
14
|
local_binding
|
|
@@ -29,19 +29,48 @@ module Rigor
|
|
|
29
29
|
# - `severity_by_profile` — Hash of `:lenient` / `:balanced`
|
|
30
30
|
# / `:strict` to the configured severity per profile, taken
|
|
31
31
|
# from `Configuration::SeverityProfile::PROFILES`.
|
|
32
|
+
# - `evidence_tier` — `:high` / `:medium` / `:low` (or `nil`
|
|
33
|
+
# for informational helpers), Rigor's own confidence that a
|
|
34
|
+
# firing is a true positive, derived from the rule's firing
|
|
35
|
+
# gates. `:high` rules fire only on a concrete, statically-
|
|
36
|
+
# known type with no metaprogramming escape (Rigor's false-
|
|
37
|
+
# positive discipline has already filtered the uncertain
|
|
38
|
+
# cases); `:medium` rules rest on flow / inference proofs
|
|
39
|
+
# that inherit a documented FP envelope (loop / mutation /
|
|
40
|
+
# RBS-strictness modelling gaps); `:low` rules are
|
|
41
|
+
# resolution- or coverage-gap signals where a firing often
|
|
42
|
+
# reflects missing context rather than a definite bug. The
|
|
43
|
+
# tier routes a consumer's attention (and lets a downstream
|
|
44
|
+
# classifier promote a `:high` firing without cross-tool
|
|
45
|
+
# corroboration); it never feeds severity — that stays the
|
|
46
|
+
# `severity_profile:` decision.
|
|
32
47
|
# - `since` — first version the rule shipped in.
|
|
33
48
|
module RuleCatalog # rubocop:disable Metrics/ModuleLength
|
|
49
|
+
# Stable documentation home for a built-in rule. `documentation_url`
|
|
50
|
+
# appends a per-rule fragment that resolves to the rule's anchor in
|
|
51
|
+
# the published diagnostics catalogue; the page itself points at
|
|
52
|
+
# `rigor explain <rule>` as the authoritative per-rule reference.
|
|
53
|
+
# Mirrors the gemspec `documentation_uri` URL scheme (`…/tree/main`).
|
|
54
|
+
DOCUMENTATION_BASE = "https://github.com/rigortype/rigor/blob/main/docs/manual/04-diagnostics.md"
|
|
55
|
+
|
|
34
56
|
class Entry < Data.define(:id, :summary, :fires_when, :does_not_fire_when,
|
|
35
|
-
:suppression, :severity_authored, :severity_by_profile,
|
|
57
|
+
:suppression, :severity_authored, :severity_by_profile,
|
|
58
|
+
:evidence_tier, :since)
|
|
36
59
|
def aliases
|
|
37
60
|
CheckRules::LEGACY_RULE_ALIASES.select { |_legacy, canonical| canonical == id }.keys
|
|
38
61
|
end
|
|
39
62
|
|
|
63
|
+
# Stable per-rule documentation URL (see {RuleCatalog.documentation_url}).
|
|
64
|
+
def documentation_url
|
|
65
|
+
RuleCatalog.documentation_url(id)
|
|
66
|
+
end
|
|
67
|
+
|
|
40
68
|
# Hash-shaped form for `--format=json` consumers. Keys are
|
|
41
69
|
# Strings so the payload is JSON-stable without a transform
|
|
42
|
-
# pass.
|
|
70
|
+
# pass. `evidence_tier` is omitted when nil (informational
|
|
71
|
+
# helpers carry no confidence tier).
|
|
43
72
|
def to_h
|
|
44
|
-
{
|
|
73
|
+
base = {
|
|
45
74
|
"id" => id,
|
|
46
75
|
"aliases" => aliases,
|
|
47
76
|
"summary" => summary,
|
|
@@ -50,8 +79,11 @@ module Rigor
|
|
|
50
79
|
"suppression" => suppression,
|
|
51
80
|
"severity_authored" => severity_authored.to_s,
|
|
52
81
|
"severity_by_profile" => severity_by_profile.transform_keys(&:to_s).transform_values(&:to_s),
|
|
82
|
+
"documentation_url" => documentation_url,
|
|
53
83
|
"since" => since
|
|
54
84
|
}
|
|
85
|
+
base["evidence_tier"] = evidence_tier.to_s if evidence_tier
|
|
86
|
+
base
|
|
55
87
|
end
|
|
56
88
|
end
|
|
57
89
|
|
|
@@ -75,6 +107,7 @@ module Rigor
|
|
|
75
107
|
"or `disable: [\"call.undefined-method\"]` in `.rigor.yml`.",
|
|
76
108
|
severity_authored: :error,
|
|
77
109
|
severity_by_profile: { lenient: :error, balanced: :error, strict: :error },
|
|
110
|
+
evidence_tier: :high,
|
|
78
111
|
since: "0.0.1"
|
|
79
112
|
),
|
|
80
113
|
|
|
@@ -98,9 +131,43 @@ module Rigor
|
|
|
98
131
|
"`severity_overrides: { call.self-undefined-method: warning }` in `.rigor.yml`.",
|
|
99
132
|
severity_authored: :warning,
|
|
100
133
|
severity_by_profile: { lenient: :off, balanced: :off, strict: :off },
|
|
134
|
+
# Off by default and metaprogramming-prone — a firing on a
|
|
135
|
+
# class whose real surface the per-class scan cannot enumerate
|
|
136
|
+
# (C-extension, `class << self`, dynamic accessors) is the
|
|
137
|
+
# known FP mode, so a firing is a candidate to review, not a
|
|
138
|
+
# high-confidence bug.
|
|
139
|
+
evidence_tier: :low,
|
|
101
140
|
since: "0.1.17"
|
|
102
141
|
),
|
|
103
142
|
|
|
143
|
+
CheckRules::RULE_UNRESOLVED_TOPLEVEL => Entry.new(
|
|
144
|
+
id: CheckRules::RULE_UNRESOLVED_TOPLEVEL,
|
|
145
|
+
summary: "Top-level implicit-self call resolves against no def, pre_eval: patch, or Kernel method.",
|
|
146
|
+
fires_when: [
|
|
147
|
+
"The call is an implicit-self call (no receiver) at top level (outside any class / module body).",
|
|
148
|
+
"Its name resolves against no same-file top-level `def`.",
|
|
149
|
+
"No ADR-17 `pre_eval:` monkey-patch on `Object` / `Kernel` declares it.",
|
|
150
|
+
"It is not a standard `Kernel` / `Object` private method (`puts`, `require`, `loop`, …)."
|
|
151
|
+
],
|
|
152
|
+
does_not_fire_when: [
|
|
153
|
+
"The call has an explicit receiver, or sits inside a `def` / `class` / `module` body (ADR-24 WD3 " \
|
|
154
|
+
"stays lenient there).",
|
|
155
|
+
"A project file defines the name via a top-level `def` or an Object/Kernel monkey-patch listed in " \
|
|
156
|
+
"`.rigor.yml`'s `pre_eval:` (ADR-17).",
|
|
157
|
+
"The name is a Kernel/Object method visible in the loaded RBS environment."
|
|
158
|
+
],
|
|
159
|
+
suppression: "`# rigor:disable call.unresolved-toplevel` on the call line, or list the defining " \
|
|
160
|
+
"file in `.rigor.yml`'s `pre_eval:` so the analyzer sees the top-level `def` / patch.",
|
|
161
|
+
severity_authored: :warning,
|
|
162
|
+
severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
|
|
163
|
+
# A firing is frequently a resolution gap — the defining file
|
|
164
|
+
# is not in the analyzed set or injects the method via a
|
|
165
|
+
# metaprogramming patch the analyzer does not see — rather than
|
|
166
|
+
# a definite typo, so it routes to the `pre_eval:` review path.
|
|
167
|
+
evidence_tier: :low,
|
|
168
|
+
since: "0.1.14"
|
|
169
|
+
),
|
|
170
|
+
|
|
104
171
|
CheckRules::RULE_WRONG_ARITY => Entry.new(
|
|
105
172
|
id: CheckRules::RULE_WRONG_ARITY,
|
|
106
173
|
summary: "Call's positional argument count is outside the declared overloads' envelope.",
|
|
@@ -117,6 +184,7 @@ module Rigor
|
|
|
117
184
|
suppression: "`# rigor:disable call.wrong-arity`.",
|
|
118
185
|
severity_authored: :error,
|
|
119
186
|
severity_by_profile: { lenient: :error, balanced: :error, strict: :error },
|
|
187
|
+
evidence_tier: :high,
|
|
120
188
|
since: "0.0.1"
|
|
121
189
|
),
|
|
122
190
|
|
|
@@ -125,17 +193,22 @@ module Rigor
|
|
|
125
193
|
summary: "Call passes an argument whose type the parameter cannot accept.",
|
|
126
194
|
fires_when: [
|
|
127
195
|
"The parameter type rejects the argument under `accepts(arg, mode: :gradual)`.",
|
|
128
|
-
"
|
|
196
|
+
"Single-overload: no overload accepts the arg class (ADR-64 non-nil channel).",
|
|
197
|
+
"Multi-overload: every overload rejects a pure-`nil` arg (ADR-64 nil channel) " \
|
|
198
|
+
"or every overload rejects a single concrete non-nil arg class (non-nil channel).",
|
|
129
199
|
"Both sides have a non-Dynamic concrete type."
|
|
130
200
|
],
|
|
131
201
|
does_not_fire_when: [
|
|
132
202
|
"Either the parameter or the argument is `Dynamic[T]`.",
|
|
133
|
-
"
|
|
134
|
-
"
|
|
203
|
+
"The call is a coerce-dispatch operator (`+`, `-`, `*`, `/`, `<`, `>`, …) — " \
|
|
204
|
+
"excluded because the `coerce` protocol makes acceptance undecidable.",
|
|
205
|
+
"Method has `*rest_positionals`, required keywords, or trailing positionals.",
|
|
206
|
+
"The argument type is a union (not a single concrete class)."
|
|
135
207
|
],
|
|
136
208
|
suppression: "`# rigor:disable call.argument-type-mismatch`.",
|
|
137
209
|
severity_authored: :error,
|
|
138
210
|
severity_by_profile: { lenient: :warning, balanced: :error, strict: :error },
|
|
211
|
+
evidence_tier: :high,
|
|
139
212
|
since: "0.0.2"
|
|
140
213
|
),
|
|
141
214
|
|
|
@@ -155,6 +228,7 @@ module Rigor
|
|
|
155
228
|
suppression: "`# rigor:disable call.possible-nil-receiver`.",
|
|
156
229
|
severity_authored: :error,
|
|
157
230
|
severity_by_profile: { lenient: :warning, balanced: :error, strict: :error },
|
|
231
|
+
evidence_tier: :high,
|
|
158
232
|
since: "0.0.2"
|
|
159
233
|
),
|
|
160
234
|
|
|
@@ -171,6 +245,9 @@ module Rigor
|
|
|
171
245
|
suppression: "Remove the `dump_type` call (it's a debug helper, not a real diagnostic).",
|
|
172
246
|
severity_authored: :info,
|
|
173
247
|
severity_by_profile: { lenient: :info, balanced: :info, strict: :error },
|
|
248
|
+
# Informational helper, not a correctness finding — no
|
|
249
|
+
# confidence tier applies.
|
|
250
|
+
evidence_tier: nil,
|
|
174
251
|
since: "0.0.1"
|
|
175
252
|
),
|
|
176
253
|
|
|
@@ -187,6 +264,7 @@ module Rigor
|
|
|
187
264
|
suppression: "Update the assertion to the actual inferred type, or correct the source.",
|
|
188
265
|
severity_authored: :error,
|
|
189
266
|
severity_by_profile: { lenient: :error, balanced: :error, strict: :error },
|
|
267
|
+
evidence_tier: :high,
|
|
190
268
|
since: "0.0.1"
|
|
191
269
|
),
|
|
192
270
|
|
|
@@ -205,6 +283,7 @@ module Rigor
|
|
|
205
283
|
suppression: "`# rigor:disable flow.always-raises`.",
|
|
206
284
|
severity_authored: :error,
|
|
207
285
|
severity_by_profile: { lenient: :warning, balanced: :error, strict: :error },
|
|
286
|
+
evidence_tier: :high,
|
|
208
287
|
since: "0.0.3"
|
|
209
288
|
),
|
|
210
289
|
|
|
@@ -224,6 +303,9 @@ module Rigor
|
|
|
224
303
|
"points at the dead branch, not the predicate, so the suppression goes there).",
|
|
225
304
|
severity_authored: :warning,
|
|
226
305
|
severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
|
|
306
|
+
# The literal-only firing envelope makes the deadness provable
|
|
307
|
+
# from syntax alone — no inference uncertainty.
|
|
308
|
+
evidence_tier: :high,
|
|
227
309
|
since: "0.1.2"
|
|
228
310
|
),
|
|
229
311
|
|
|
@@ -246,6 +328,11 @@ module Rigor
|
|
|
246
328
|
suppression: "`# rigor:disable always-truthy-condition` on the predicate line.",
|
|
247
329
|
severity_authored: :warning,
|
|
248
330
|
severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
|
|
331
|
+
# Rests on inferred-constant folding, which inherits the
|
|
332
|
+
# loop / mutation FP envelope the `does_not_fire_when` guards
|
|
333
|
+
# narrow — true positive in the common case, but not literal-
|
|
334
|
+
# provable like `unreachable-branch`.
|
|
335
|
+
evidence_tier: :medium,
|
|
249
336
|
since: "0.1.2"
|
|
250
337
|
),
|
|
251
338
|
|
|
@@ -271,6 +358,9 @@ module Rigor
|
|
|
271
358
|
# ADR-47 WD4: balanced stays :info (one notch below its `flow.*`
|
|
272
359
|
# siblings' :warning) until the regression-corpus FP gate is green.
|
|
273
360
|
severity_by_profile: { lenient: :info, balanced: :info, strict: :warning },
|
|
361
|
+
# Narrowing-driven proof that inherits the `always-truthy`
|
|
362
|
+
# FP envelope; balanced keeps it `:info` pending the corpus gate.
|
|
363
|
+
evidence_tier: :medium,
|
|
274
364
|
since: "0.1.17"
|
|
275
365
|
),
|
|
276
366
|
|
|
@@ -292,6 +382,11 @@ module Rigor
|
|
|
292
382
|
suppression: "`# rigor:disable dead-assignment` on the offending line, or rename the local to `_<name>`.",
|
|
293
383
|
severity_authored: :warning,
|
|
294
384
|
severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
|
|
385
|
+
# The unread-write proof is reliable, but it flags a code
|
|
386
|
+
# smell rather than a runtime fault, and the syntactic write
|
|
387
|
+
# classification has narrow corners (the `does_not_fire_when`
|
|
388
|
+
# exclusions).
|
|
389
|
+
evidence_tier: :medium,
|
|
295
390
|
since: "0.1.2"
|
|
296
391
|
),
|
|
297
392
|
|
|
@@ -313,6 +408,10 @@ module Rigor
|
|
|
313
408
|
suppression: "`# rigor:disable def.return-type-mismatch`.",
|
|
314
409
|
severity_authored: :warning,
|
|
315
410
|
severity_by_profile: { lenient: :warning, balanced: :warning, strict: :error },
|
|
411
|
+
# Depends on re-typing the body against an authored RBS return;
|
|
412
|
+
# RBS strict-on-returns plus incomplete body inference makes a
|
|
413
|
+
# firing usually-right but not concrete-call certain.
|
|
414
|
+
evidence_tier: :medium,
|
|
316
415
|
since: "0.1.0"
|
|
317
416
|
),
|
|
318
417
|
|
|
@@ -333,6 +432,7 @@ module Rigor
|
|
|
333
432
|
suppression: "`# rigor:disable method-visibility-mismatch`.",
|
|
334
433
|
severity_authored: :error,
|
|
335
434
|
severity_by_profile: { lenient: :warning, balanced: :error, strict: :error },
|
|
435
|
+
evidence_tier: :high,
|
|
336
436
|
since: "0.1.2"
|
|
337
437
|
),
|
|
338
438
|
|
|
@@ -356,6 +456,10 @@ module Rigor
|
|
|
356
456
|
suppression: "`# rigor:disable def.override-visibility-reduced` on the override.",
|
|
357
457
|
severity_authored: :warning,
|
|
358
458
|
severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
|
|
459
|
+
# Both the override and the shadowed ancestor visibility are
|
|
460
|
+
# statically observed from project source — the substitutability
|
|
461
|
+
# violation is concrete.
|
|
462
|
+
evidence_tier: :high,
|
|
359
463
|
since: "0.1.15"
|
|
360
464
|
),
|
|
361
465
|
|
|
@@ -383,6 +487,9 @@ module Rigor
|
|
|
383
487
|
suppression: "`# rigor:disable def.override-return-widened` on the override.",
|
|
384
488
|
severity_authored: :warning,
|
|
385
489
|
severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
|
|
490
|
+
# Gated on both-sides-authored RBS and a resolvable subtype
|
|
491
|
+
# relationship, so a firing is a concrete covariance violation.
|
|
492
|
+
evidence_tier: :high,
|
|
386
493
|
since: "0.1.15"
|
|
387
494
|
),
|
|
388
495
|
|
|
@@ -413,6 +520,9 @@ module Rigor
|
|
|
413
520
|
suppression: "`# rigor:disable def.override-param-narrowed` on the override.",
|
|
414
521
|
severity_authored: :warning,
|
|
415
522
|
severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
|
|
523
|
+
# Gated on both-sides-authored RBS and a resolvable subtype
|
|
524
|
+
# relationship, so a firing is a concrete contravariance violation.
|
|
525
|
+
evidence_tier: :high,
|
|
416
526
|
since: "0.1.15"
|
|
417
527
|
),
|
|
418
528
|
|
|
@@ -434,6 +544,9 @@ module Rigor
|
|
|
434
544
|
suppression: "`# rigor:disable ivar-write-mismatch` on the offending write.",
|
|
435
545
|
severity_authored: :error,
|
|
436
546
|
severity_by_profile: { lenient: :warning, balanced: :warning, strict: :error },
|
|
547
|
+
# Both writes resolve to concrete classes before firing; the
|
|
548
|
+
# union / Dynamic / clear-idiom escapes are excluded.
|
|
549
|
+
evidence_tier: :high,
|
|
437
550
|
since: "0.1.2"
|
|
438
551
|
)
|
|
439
552
|
}.freeze
|
|
@@ -466,6 +579,40 @@ module Rigor
|
|
|
466
579
|
def all
|
|
467
580
|
ENTRIES.values.sort_by(&:id)
|
|
468
581
|
end
|
|
582
|
+
|
|
583
|
+
# Rigor's confidence tier (`:high` / `:medium` / `:low`) that a
|
|
584
|
+
# firing of `token` is a true positive, or nil for an
|
|
585
|
+
# informational rule (`dump.type`) or an unknown / non-built-in
|
|
586
|
+
# token (plugin and `rbs_extended.*` rules carry no built-in
|
|
587
|
+
# tier). Resolves legacy aliases. See {Entry}'s `evidence_tier`
|
|
588
|
+
# documentation for the tier semantics.
|
|
589
|
+
def evidence_tier(token)
|
|
590
|
+
entries = resolve(token)
|
|
591
|
+
return nil unless entries.size == 1
|
|
592
|
+
|
|
593
|
+
entries.first.evidence_tier
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
# Stable documentation URL for `token`, or nil for an unknown /
|
|
597
|
+
# non-built-in token. The URL is the published diagnostics
|
|
598
|
+
# catalogue page anchored at the rule's per-rule anchor
|
|
599
|
+
# (`#rule-<id-with-dots-as-dashes>`); the page itself names
|
|
600
|
+
# `rigor explain <rule>` as the authoritative per-rule reference.
|
|
601
|
+
# Resolves legacy aliases to the canonical id.
|
|
602
|
+
def documentation_url(token)
|
|
603
|
+
entries = resolve(token)
|
|
604
|
+
return nil unless entries.size == 1
|
|
605
|
+
|
|
606
|
+
"#{DOCUMENTATION_BASE}##{doc_anchor(entries.first.id)}"
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# The per-rule fragment a `documentation_url` points at:
|
|
610
|
+
# `call.undefined-method` → `rule-call-undefined-method`. The
|
|
611
|
+
# `04-diagnostics.md` catalogue carries the matching `<a id>`
|
|
612
|
+
# anchors.
|
|
613
|
+
def doc_anchor(rule_id)
|
|
614
|
+
"rule-#{rule_id.tr('.', '-')}"
|
|
615
|
+
end
|
|
469
616
|
end
|
|
470
617
|
end
|
|
471
618
|
end
|
|
@@ -423,23 +423,6 @@ module Rigor
|
|
|
423
423
|
unresolved + lossy
|
|
424
424
|
end
|
|
425
425
|
|
|
426
|
-
# ADR-10 slice 5c — drains the per-run
|
|
427
|
-
# {DependencySourceInference::BoundaryCrossReporter} into
|
|
428
|
-
# `dynamic.dependency-source.boundary-cross` `:info`
|
|
429
|
-
# diagnostics. Each event flags a call site where RBS
|
|
430
|
-
# dispatch produced a concrete answer AND a `mode: :full`
|
|
431
|
-
# opt-in gem's source catalog ALSO contains an entry for
|
|
432
|
-
# the same `(class_name, method_name)` — i.e., both
|
|
433
|
-
# contracts have an opinion. RBS still wins on the
|
|
434
|
-
# dispatch result; the diagnostic is purely advisory so
|
|
435
|
-
# the user can verify the two contracts haven't drifted.
|
|
436
|
-
#
|
|
437
|
-
# Severity profile re-stamps the rule per project taste.
|
|
438
|
-
# The diagnostic carries no `path` / `line` / `column`
|
|
439
|
-
# because the crossing is per-method-per-gem, not
|
|
440
|
-
# per-call-site — the diagnostic anchors at `.rigor.yml`
|
|
441
|
-
# like the other `dependency-source.*` diagnostics that
|
|
442
|
-
# report on opt-in configuration.
|
|
443
426
|
# ADR-32 WD6 — drains the per-run
|
|
444
427
|
# {Plugin::SourceRbsSynthesisReporter} into
|
|
445
428
|
# `source-rbs-synthesis-failed` `:info` diagnostics. Each
|
|
@@ -469,6 +452,23 @@ module Rigor
|
|
|
469
452
|
end
|
|
470
453
|
end
|
|
471
454
|
|
|
455
|
+
# ADR-10 slice 5c — drains the per-run
|
|
456
|
+
# {DependencySourceInference::BoundaryCrossReporter} into
|
|
457
|
+
# `dynamic.dependency-source.boundary-cross` `:info`
|
|
458
|
+
# diagnostics. Each event flags a call site where RBS
|
|
459
|
+
# dispatch produced a concrete answer AND a `mode: :full`
|
|
460
|
+
# opt-in gem's source catalog ALSO contains an entry for
|
|
461
|
+
# the same `(class_name, method_name)` — i.e., both
|
|
462
|
+
# contracts have an opinion. RBS still wins on the
|
|
463
|
+
# dispatch result; the diagnostic is purely advisory so
|
|
464
|
+
# the user can verify the two contracts haven't drifted.
|
|
465
|
+
#
|
|
466
|
+
# Severity profile re-stamps the rule per project taste.
|
|
467
|
+
# The diagnostic carries no `path` / `line` / `column`
|
|
468
|
+
# because the crossing is per-method-per-gem, not
|
|
469
|
+
# per-call-site — the diagnostic anchors at `.rigor.yml`
|
|
470
|
+
# like the other `dependency-source.*` diagnostics that
|
|
471
|
+
# report on opt-in configuration.
|
|
472
472
|
def boundary_cross_diagnostics
|
|
473
473
|
return [] if @boundary_cross_reporter.empty?
|
|
474
474
|
|
|
@@ -529,7 +529,8 @@ module Rigor
|
|
|
529
529
|
rule: diagnostic.rule,
|
|
530
530
|
authored_severity: diagnostic.severity,
|
|
531
531
|
profile: @configuration.severity_profile,
|
|
532
|
-
overrides: @configuration.severity_overrides
|
|
532
|
+
overrides: @configuration.severity_overrides,
|
|
533
|
+
bleeding_edge_overrides: @configuration.bleeding_edge_severity_overrides
|
|
533
534
|
)
|
|
534
535
|
return nil if resolved == :off
|
|
535
536
|
return diagnostic if resolved == diagnostic.severity
|
|
@@ -38,13 +38,15 @@ module Rigor
|
|
|
38
38
|
:pre_eval_diagnostics_from_scanner,
|
|
39
39
|
:discovered_classes,
|
|
40
40
|
:discovered_def_nodes,
|
|
41
|
+
:discovered_singleton_def_nodes,
|
|
41
42
|
:discovered_def_sources,
|
|
42
43
|
:discovered_superclasses,
|
|
43
44
|
:discovered_includes,
|
|
44
45
|
:discovered_class_sources,
|
|
45
46
|
:discovered_method_visibilities,
|
|
46
47
|
:discovered_methods,
|
|
47
|
-
:data_member_layouts
|
|
48
|
+
:data_member_layouts,
|
|
49
|
+
:struct_member_layouts
|
|
48
50
|
)
|
|
49
51
|
|
|
50
52
|
# @param configuration [Rigor::Configuration]
|
|
@@ -64,7 +66,7 @@ module Rigor
|
|
|
64
66
|
# results bundled in {Result} in the order the downstream `#run`
|
|
65
67
|
# body expects. Extracted so `#prepare_project_scan` and the
|
|
66
68
|
# prebuilt-less `#run` path share one implementation.
|
|
67
|
-
def run(expansion:) # rubocop:disable Metrics/MethodLength
|
|
69
|
+
def run(expansion:) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
68
70
|
plugin_registry = load_plugins
|
|
69
71
|
dependency_source_index = DependencySourceInference::Builder.build(@configuration.dependencies)
|
|
70
72
|
# ADR-18 slice 3 — plugin prepare MUST run before the
|
|
@@ -131,13 +133,15 @@ module Rigor
|
|
|
131
133
|
pre_eval_diagnostics_from_scanner: pre_eval_diagnostics_from_scanner,
|
|
132
134
|
discovered_classes: discovered_classes,
|
|
133
135
|
discovered_def_nodes: def_index.fetch(:def_nodes),
|
|
136
|
+
discovered_singleton_def_nodes: def_index.fetch(:singleton_def_nodes),
|
|
134
137
|
discovered_def_sources: def_index.fetch(:def_sources),
|
|
135
138
|
discovered_superclasses: def_index.fetch(:superclasses),
|
|
136
139
|
discovered_includes: def_index.fetch(:includes),
|
|
137
140
|
discovered_class_sources: def_index.fetch(:class_sources),
|
|
138
141
|
discovered_method_visibilities: def_index.fetch(:method_visibilities),
|
|
139
142
|
discovered_methods: def_index.fetch(:methods),
|
|
140
|
-
data_member_layouts: def_index.fetch(:data_member_layouts)
|
|
143
|
+
data_member_layouts: def_index.fetch(:data_member_layouts),
|
|
144
|
+
struct_member_layouts: def_index.fetch(:struct_member_layouts)
|
|
141
145
|
)
|
|
142
146
|
end
|
|
143
147
|
|
|
@@ -173,13 +177,15 @@ module Rigor
|
|
|
173
177
|
pre_eval_diagnostics_from_scanner: scan.pre_eval_diagnostics,
|
|
174
178
|
discovered_classes: nil,
|
|
175
179
|
discovered_def_nodes: nil,
|
|
180
|
+
discovered_singleton_def_nodes: nil,
|
|
176
181
|
discovered_def_sources: nil,
|
|
177
182
|
discovered_superclasses: nil,
|
|
178
183
|
discovered_includes: nil,
|
|
179
184
|
discovered_class_sources: nil,
|
|
180
185
|
discovered_method_visibilities: nil,
|
|
181
186
|
discovered_methods: nil,
|
|
182
|
-
data_member_layouts: nil
|
|
187
|
+
data_member_layouts: nil,
|
|
188
|
+
struct_member_layouts: nil
|
|
183
189
|
)
|
|
184
190
|
end
|
|
185
191
|
|
|
@@ -275,11 +281,9 @@ module Rigor
|
|
|
275
281
|
# `#diagnostics_for_file` raise envelope in
|
|
276
282
|
# `plugin_runtime_error_diagnostic`.
|
|
277
283
|
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
# `Configuration#plugins` order MUST be producer-first if
|
|
282
|
-
# cross-plugin dependencies exist.
|
|
284
|
+
# `Plugin::Loader` returns plugins in topological order by
|
|
285
|
+
# `manifest(consumes:)` (ADR-9 slice 5), so producers
|
|
286
|
+
# always run before consumers.
|
|
283
287
|
def plugin_prepare_diagnostics(plugin_registry)
|
|
284
288
|
return [] if plugin_registry.empty?
|
|
285
289
|
|