rigortype 0.3.3 → 0.3.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 +1 -1
- data/data/builtins/ruby_core/array.yml +11 -24
- data/data/builtins/ruby_core/enumerable.yml +4 -8
- data/data/builtins/ruby_core/exception.yml +6 -9
- data/data/builtins/ruby_core/hash.yml +13 -20
- data/data/builtins/ruby_core/io.yml +6 -9
- data/data/builtins/ruby_core/numeric.yml +2 -3
- data/data/builtins/ruby_core/proc.yml +4 -8
- data/data/builtins/ruby_core/re.yml +6 -9
- data/data/builtins/ruby_core/set.yml +2 -3
- data/data/builtins/ruby_core/string.yml +4 -7
- data/data/builtins/ruby_core/struct.yml +0 -6
- data/data/builtins/ruby_core/time.yml +3 -6
- data/data/effects/core.yml +860 -0
- data/data/effects/registry.yml +95 -0
- data/docs/handbook/07-rbs-and-extended.md +106 -5
- data/docs/manual/02-cli-reference.md +359 -2
- data/docs/manual/03-configuration.md +101 -1
- data/docs/manual/04-diagnostics.md +8 -3
- data/docs/manual/11-ci.md +37 -0
- data/docs/manual/12-caching.md +39 -0
- data/docs/manual/16-rbs-extended-annotations.md +90 -0
- data/docs/manual/18-removing-dead-code.md +326 -0
- data/docs/manual/19-effect-labels.md +671 -0
- data/docs/manual/README.md +10 -0
- data/docs/manual/ci-templates/README.md +9 -0
- data/docs/manual/plugins/rigor-actionmailer.md +5 -0
- data/docs/manual/plugins/rigor-activejob.md +47 -0
- data/docs/manual/plugins/rigor-factorybot.md +16 -0
- data/docs/manual/plugins/rigor-pundit.md +26 -0
- data/docs/manual/plugins/rigor-rails-routes.md +41 -2
- data/docs/manual/plugins/rigor-rspec-rails.md +5 -0
- data/docs/manual/plugins/rigor-rspec.md +8 -0
- data/docs/manual/plugins/rigor-sidekiq.md +54 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +28 -2
- data/lib/rigor/analysis/incremental_session.rb +140 -6
- data/lib/rigor/analysis/reachability/graph.rb +244 -0
- data/lib/rigor/analysis/reachability/plugin_roots.rb +164 -0
- data/lib/rigor/analysis/reachability/project_files.rb +58 -0
- data/lib/rigor/analysis/reachability/scan.rb +241 -0
- data/lib/rigor/analysis/reachability/signature_scan.rb +134 -0
- data/lib/rigor/analysis/rule_catalog.rb +168 -3
- data/lib/rigor/analysis/run_cache_key.rb +16 -0
- data/lib/rigor/analysis/run_cache_probe.rb +69 -1
- data/lib/rigor/analysis/runner/declaration_position.rb +38 -0
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +108 -0
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +358 -0
- data/lib/rigor/analysis/runner/envelope_messages.rb +61 -0
- data/lib/rigor/analysis/runner/pool_coordinator.rb +93 -10
- data/lib/rigor/analysis/runner/run_snapshots.rb +7 -4
- data/lib/rigor/analysis/runner.rb +429 -10
- data/lib/rigor/analysis/worker_session.rb +60 -2
- data/lib/rigor/bleeding_edge.rb +22 -0
- data/lib/rigor/cache/incremental_snapshot.rb +24 -5
- data/lib/rigor/cli/check_command.rb +13 -1
- data/lib/rigor/cli/check_runner_factory.rb +4 -1
- data/lib/rigor/cli/effects_command.rb +245 -0
- data/lib/rigor/cli/effects_diff_renderer.rb +127 -0
- data/lib/rigor/cli/effects_explain_renderer.rb +68 -0
- data/lib/rigor/cli/effects_renderer.rb +92 -0
- data/lib/rigor/cli/effects_report.rb +163 -0
- data/lib/rigor/cli/effects_snapshot_command.rb +275 -0
- data/lib/rigor/cli/unused_command.rb +288 -0
- data/lib/rigor/cli.rb +28 -1
- data/lib/rigor/configuration/severity_profile.rb +23 -0
- data/lib/rigor/configuration.rb +322 -28
- data/lib/rigor/configuration_error.rb +20 -0
- data/lib/rigor/effects/attribution.rb +76 -0
- data/lib/rigor/effects/catalog.rb +275 -0
- data/lib/rigor/effects/collector.rb +219 -0
- data/lib/rigor/effects/config_envelopes.rb +185 -0
- data/lib/rigor/effects/discharge.rb +69 -0
- data/lib/rigor/effects/effect_table.rb +92 -0
- data/lib/rigor/effects/entry_points.rb +139 -0
- data/lib/rigor/effects/envelope.rb +86 -0
- data/lib/rigor/effects/envelope_check.rb +172 -0
- data/lib/rigor/effects/envelope_index.rb +157 -0
- data/lib/rigor/effects/file_collection.rb +174 -0
- data/lib/rigor/effects/framework_units.rb +222 -0
- data/lib/rigor/effects/identity.rb +104 -0
- data/lib/rigor/effects/inline_anchor.rb +134 -0
- data/lib/rigor/effects/label.rb +77 -0
- data/lib/rigor/effects/label_intent.rb +73 -0
- data/lib/rigor/effects/label_set.rb +136 -0
- data/lib/rigor/effects/liskov_check.rb +167 -0
- data/lib/rigor/effects/local_ownership.rb +132 -0
- data/lib/rigor/effects/method_key.rb +40 -0
- data/lib/rigor/effects/mutation_classifier.rb +92 -0
- data/lib/rigor/effects/narrowing.rb +202 -0
- data/lib/rigor/effects/origin.rb +66 -0
- data/lib/rigor/effects/path_finder.rb +89 -0
- data/lib/rigor/effects/plugin_facts.rb +384 -0
- data/lib/rigor/effects/propagator.rb +335 -0
- data/lib/rigor/effects/registry.rb +200 -0
- data/lib/rigor/effects/scanner.rb +302 -0
- data/lib/rigor/effects/signature_sources.rb +90 -0
- data/lib/rigor/effects/snapshot.rb +396 -0
- data/lib/rigor/effects/snapshot_diff.rb +265 -0
- data/lib/rigor/effects/summary.rb +154 -0
- data/lib/rigor/effects/taint_cause.rb +39 -0
- data/lib/rigor/effects/unit_scan.rb +647 -0
- data/lib/rigor/effects/unknown_label_check.rb +86 -0
- data/lib/rigor/effects/unknown_label_report.rb +59 -0
- data/lib/rigor/effects.rb +47 -0
- data/lib/rigor/environment/rbs_loader.rb +34 -0
- data/lib/rigor/environment.rb +8 -1
- data/lib/rigor/flow_contribution/element.rb +1 -0
- data/lib/rigor/flow_contribution/merge_result.rb +5 -3
- data/lib/rigor/flow_contribution/merger.rb +16 -1
- data/lib/rigor/flow_contribution.rb +20 -4
- data/lib/rigor/inference/expression_typer.rb +18 -4
- data/lib/rigor/inference/pre_eval_constants.rb +189 -0
- data/lib/rigor/inference/scope_indexer.rb +15 -3
- data/lib/rigor/plugin/base.rb +28 -0
- data/lib/rigor/plugin/box.rb +18 -2
- data/lib/rigor/plugin/effect_ancestry.rb +80 -0
- data/lib/rigor/plugin/effect_attribution.rb +208 -0
- data/lib/rigor/plugin/effect_edge.rb +101 -0
- data/lib/rigor/plugin/effect_entry_points.rb +51 -0
- data/lib/rigor/plugin/first_party.rb +57 -0
- data/lib/rigor/plugin/isolation.rb +4 -1
- data/lib/rigor/plugin/manifest.rb +127 -3
- data/lib/rigor/plugin/registry.rb +55 -0
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/rbs_extended/envelope_scanner.rb +160 -0
- data/lib/rigor/rbs_extended.rb +188 -0
- data/lib/rigor/reflection.rb +131 -30
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +90 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +7 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/effects.rb +85 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +8 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +152 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +9 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +156 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +113 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +68 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +186 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +12 -1
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +145 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/effects.rb +77 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +6 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +143 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -1
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +401 -29
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +27 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +151 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +46 -3
- data/plugins/rigor-rails/lib/rigor-rails.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/effects.rb +47 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +7 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +81 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +13 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +202 -15
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +43 -3
- data/plugins/rigor-railties/lib/rigor/plugin/railties/effects.rb +171 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +62 -0
- data/plugins/rigor-railties/lib/rigor-railties.rb +3 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +56 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +75 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +122 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +68 -3
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/inference.rbs +2 -0
- data/sig/rigor/rbs_extended.rbs +6 -0
- data/sig/rigor.rbs +17 -1
- data/skills/rigor-unused-adjudicate/SKILL.md +90 -0
- metadata +84 -1
|
@@ -6,6 +6,7 @@ require_relative "../../environment"
|
|
|
6
6
|
require_relative "../diagnostic"
|
|
7
7
|
require_relative "../worker_session"
|
|
8
8
|
require_relative "../run_stats"
|
|
9
|
+
require_relative "../../effects/signature_sources"
|
|
9
10
|
require_relative "../../rbs_extended/conformance_checker"
|
|
10
11
|
require_relative "../../runtime/jit"
|
|
11
12
|
|
|
@@ -61,6 +62,11 @@ module Rigor
|
|
|
61
62
|
# slice's cross-file reads, marshalled back into `#collected_dependencies` for the runner's graph.
|
|
62
63
|
@record_dependencies = record_dependencies
|
|
63
64
|
@collected_dependencies = {}
|
|
65
|
+
# ADR-103 WD13 — effect collection, derived from the configuration exactly as `Runner` and
|
|
66
|
+
# `WorkerSession` derive it. A worker's per-file collections marshal back into
|
|
67
|
+
# `#collected_effects`, so a pooled run's effect graph is the sequential run's graph.
|
|
68
|
+
@record_effects = configuration.effects_enabled?
|
|
69
|
+
@collected_effects = {}
|
|
64
70
|
@collect_stats = collect_stats
|
|
65
71
|
@buffer = buffer
|
|
66
72
|
@environment_override = environment_override
|
|
@@ -81,6 +87,11 @@ module Rigor
|
|
|
81
87
|
# so the incremental session's dependency graph is refreshed whether analysis ran sequential or pooled.
|
|
82
88
|
attr_reader :collected_dependencies
|
|
83
89
|
|
|
90
|
+
# ADR-103 WD12 — the per-file {Effects::FileCollection}s the fork pool captured this run (empty
|
|
91
|
+
# unless the configuration carries an `effects:` block and a pool run occurred). The runner merges
|
|
92
|
+
# these with its own sequential records before the post-pool fixpoint.
|
|
93
|
+
attr_reader :collected_effects
|
|
94
|
+
|
|
84
95
|
# ADR-15 Phase 4b — pool mode is enabled when `@workers > 0`. Editor mode (`buffer:` non-nil)
|
|
85
96
|
# silently overrides pool mode to sequential: per design § "Ractor pool mode", the pool's warm-up
|
|
86
97
|
# cost dominates one-file wall time, so the pool gains nothing on a per-buffer invocation. The
|
|
@@ -113,6 +124,7 @@ module Rigor
|
|
|
113
124
|
|
|
114
125
|
def analyze_files_sequentially(files, environment)
|
|
115
126
|
snapshot_project_signature_state(environment)
|
|
127
|
+
snapshot_effect_annotation_carrier(environment&.rbs_loader)
|
|
116
128
|
result = files.flat_map { |path| @analyze_file.call(path, environment) }
|
|
117
129
|
if @collect_stats
|
|
118
130
|
loader = environment.rbs_loader
|
|
@@ -147,6 +159,27 @@ module Rigor
|
|
|
147
159
|
@snapshots.conformance_results = RbsExtended::ConformanceChecker.scan(loader)
|
|
148
160
|
end
|
|
149
161
|
|
|
162
|
+
# #441 — the inline stratum of `effect.annotations-unchecked`, carried out of the analysis path as
|
|
163
|
+
# small plain data, for the same reason the block above is: the environment stays a LOCAL so it goes
|
|
164
|
+
# GC-eligible when the path returns, and the residual pass runs after it.
|
|
165
|
+
#
|
|
166
|
+
# {Runner#effect_annotation_residual_diagnostics} used to read the loader off `@run_environment`,
|
|
167
|
+
# which only the ADR-45 result-cacheable path ever assigns — so a `--no-cache`, `--workers N` or
|
|
168
|
+
# `--incremental` run reported a `.rbs` annotation and stayed silent about the identical one written
|
|
169
|
+
# as an rbs-inline comment, while a default run reported both. The environment was there either way;
|
|
170
|
+
# nothing was carrying it. {Effects::SignatureSources.annotated_carrier} reduces it to at most ONE
|
|
171
|
+
# synthesized buffer, which is all a one-`:info`-per-run pass can spend.
|
|
172
|
+
#
|
|
173
|
+
# Skipped when collection is on — then {Runner::EffectEnvelopePass} reads the loader directly and
|
|
174
|
+
# this pass is gated off — so a collecting run pays nothing, and a project with no synthesizing
|
|
175
|
+
# plugin answers with an empty array and no regex at all.
|
|
176
|
+
def snapshot_effect_annotation_carrier(loader)
|
|
177
|
+
virtual = @record_effects ? nil : loader&.virtual_rbs
|
|
178
|
+
@snapshots.effect_annotation_carrier = Effects::SignatureSources.annotated_carrier(virtual)
|
|
179
|
+
rescue StandardError
|
|
180
|
+
@snapshots.effect_annotation_carrier = [].freeze
|
|
181
|
+
end
|
|
182
|
+
|
|
150
183
|
# Sequential-mode environment resolver. Returns the supplied `environment:` override (with the
|
|
151
184
|
# runner's fresh per-run reporter pair attached so dispatcher events route to THIS runner's
|
|
152
185
|
# diagnostics) when present; otherwise builds a fresh Environment per-call via
|
|
@@ -179,8 +212,12 @@ module Rigor
|
|
|
179
212
|
# per-worker dependency records back, and the Ractor path additionally lacks the cross-file
|
|
180
213
|
# `project_scope_seed` its worker would need to record complete edges. Without `fork` (Windows) a
|
|
181
214
|
# recording run degrades to sequential, which records correctly through `@analyze_file`.
|
|
215
|
+
#
|
|
216
|
+
# An effects run (ADR-103 WD13) is pinned for exactly the same reason — the Ractor messages carry
|
|
217
|
+
# no side-table channel — and degrades the same way. The degrade is sound rather than merely safe:
|
|
218
|
+
# the sequential fallback still collects, so the effect graph is complete either way.
|
|
182
219
|
def dispatch_pool(files)
|
|
183
|
-
if @record_dependencies
|
|
220
|
+
if @record_dependencies || @record_effects
|
|
184
221
|
return analyze_files_in_fork_pool(files) if Process.respond_to?(:fork)
|
|
185
222
|
|
|
186
223
|
return analyze_files_sequentially_fallback(
|
|
@@ -250,6 +287,14 @@ module Rigor
|
|
|
250
287
|
# replayed into the runner-side accumulators via their `record_*` APIs, which dedupe on the same
|
|
251
288
|
# keys as a single-session run would. Net result: reporter state is identical to the sequential
|
|
252
289
|
# path.
|
|
290
|
+
#
|
|
291
|
+
# **This backend cannot analyse a file under rbs 4.x, and the blocker is upstream** (#414).
|
|
292
|
+
# `RBS::Namespace.[]` interns every namespace through a process-wide flyweight cache held in
|
|
293
|
+
# module ivars (`@intern_trie_absolute` / `@intern_trie_relative`, mutable by design), and reading
|
|
294
|
+
# an unshareable module ivar from a non-main Ractor is `Ractor::IsolationError` — so every file a
|
|
295
|
+
# worker touches comes back as an internal analyzer error. What the code below fixes is the
|
|
296
|
+
# failure MODE, not the backend: the run used to hang forever instead of saying anything. Reviving
|
|
297
|
+
# the backend needs an upstream change, which is why `pool_backend` keeps `fork` as the default.
|
|
253
298
|
def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
254
299
|
# Pre-warm class-level lazy memos on the MAIN Ractor. `Environment::ClassRegistry.default` is the
|
|
255
300
|
# default kwarg threaded through `Environment.new` inside each worker session; lazy-initialising
|
|
@@ -303,15 +348,30 @@ module Rigor
|
|
|
303
348
|
end
|
|
304
349
|
end
|
|
305
350
|
|
|
351
|
+
# #414 — every worker is monitored BEFORE any file is dispatched, so a worker that dies at
|
|
352
|
+
# construction is still observed. `Ractor#monitor` posts `:exited` / `:aborted` to this
|
|
353
|
+
# Ractor's default port, which is the same mailbox the workers push their results to.
|
|
354
|
+
pool.each { |worker| worker.monitor(Ractor.current.default_port) }
|
|
355
|
+
|
|
306
356
|
files.each_with_index { |path, index| pool[index % pool.size].send(path) }
|
|
307
357
|
pool.each { |worker| worker.send(nil) }
|
|
308
358
|
|
|
309
359
|
prepare_diagnostics = nil
|
|
310
360
|
results_by_path = {}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
361
|
+
terminated = 0
|
|
362
|
+
|
|
363
|
+
# Bounded by TERMINATION, not by `:done`. A worker that dies never says `:done`, and the loop
|
|
364
|
+
# that counted `:done` blocked on `Ractor.receive` for as long as the process lived — the whole
|
|
365
|
+
# backend hung that way once `Environment.for_project` started raising `Ractor::IsolationError`
|
|
366
|
+
# inside `WorkerSession#initialize` (#414). Monitor notices are bare Symbols; worker messages
|
|
367
|
+
# are Arrays, so the two never collide.
|
|
368
|
+
while terminated < pool.size
|
|
314
369
|
message = Ractor.receive
|
|
370
|
+
if message.is_a?(Symbol)
|
|
371
|
+
terminated += 1
|
|
372
|
+
next
|
|
373
|
+
end
|
|
374
|
+
|
|
315
375
|
case message.first
|
|
316
376
|
when :prepare
|
|
317
377
|
prepare_diagnostics ||= message.last
|
|
@@ -319,13 +379,27 @@ module Rigor
|
|
|
319
379
|
results_by_path[message[1]] = message[2]
|
|
320
380
|
when :done
|
|
321
381
|
merge_worker_reporters(message.last)
|
|
322
|
-
done_count += 1
|
|
323
382
|
end
|
|
324
383
|
end
|
|
325
384
|
|
|
326
|
-
|
|
385
|
+
# `join` re-raises an abnormal worker's exception as `Ractor::RemoteError`; the degrade below is
|
|
386
|
+
# this path's answer to that, so the raise carries no information the coordinator acts on.
|
|
387
|
+
pool.each do |worker|
|
|
388
|
+
worker.join
|
|
389
|
+
rescue Ractor::Error
|
|
390
|
+
nil
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# The files no worker reported — every file of a worker that died, and any file in flight when
|
|
394
|
+
# it did. Re-analysed in process, exactly as the fork backend re-analyses a dead child's slice.
|
|
395
|
+
degraded = files.reject { |path| results_by_path.key?(path) }
|
|
396
|
+
unless degraded.empty?
|
|
397
|
+
environment = build_runner_environment(source_files: files)
|
|
398
|
+
degraded.each { |path| results_by_path[path] = @analyze_file.call(path, environment) }
|
|
399
|
+
end
|
|
327
400
|
|
|
328
|
-
Array(prepare_diagnostics) + files.flat_map { |path| results_by_path.fetch(path, []) }
|
|
401
|
+
diagnostics = Array(prepare_diagnostics) + files.flat_map { |path| results_by_path.fetch(path, []) }
|
|
402
|
+
degraded.empty? ? diagnostics : diagnostics.unshift(pool_degraded_diagnostic(degraded.size, "ractor"))
|
|
329
403
|
end
|
|
330
404
|
|
|
331
405
|
# ADR-15 Amendment (2026-05-20) — fork-based worker pool, the active backend for `workers > 0`.
|
|
@@ -357,6 +431,7 @@ module Rigor
|
|
|
357
431
|
# Force the full RBS load on the parent so children copy-on-write inherit a warm Environment
|
|
358
432
|
# rather than each rebuilding it after the fork.
|
|
359
433
|
session.environment.rbs_loader&.prewarm
|
|
434
|
+
snapshot_effect_annotation_carrier(session.environment.rbs_loader)
|
|
360
435
|
snapshot_fork_pool_stats(session) if @collect_stats
|
|
361
436
|
|
|
362
437
|
worker_count = [@workers, files.size].min
|
|
@@ -378,11 +453,12 @@ module Rigor
|
|
|
378
453
|
# The degraded slice was re-analysed on the parent session, so its dependency records live there,
|
|
379
454
|
# not in a child payload — fold them in alongside the successful children's.
|
|
380
455
|
@collected_dependencies.merge!(session.drain_dependencies) if @record_dependencies
|
|
456
|
+
@collected_effects.merge!(session.drain_effects) if @record_effects
|
|
381
457
|
end
|
|
382
458
|
|
|
383
459
|
diagnostics = Array(session.prepare_diagnostics) +
|
|
384
460
|
files.flat_map { |path| results_by_path.fetch(path, []) }
|
|
385
|
-
degraded.empty? ? diagnostics : diagnostics.unshift(
|
|
461
|
+
degraded.empty? ? diagnostics : diagnostics.unshift(pool_degraded_diagnostic(degraded.size, "fork"))
|
|
386
462
|
end
|
|
387
463
|
|
|
388
464
|
# Child-process body for {#analyze_files_in_fork_pool}. Analyses the slice with the
|
|
@@ -399,6 +475,9 @@ module Rigor
|
|
|
399
475
|
results = slice.to_h { |path| [path, session.analyze(path)] }
|
|
400
476
|
payload = { results: results, reporters: session.drain_reporters,
|
|
401
477
|
dependencies: session.drain_dependencies }
|
|
478
|
+
# ADR-103 WD13 — the effects slot exists only on a collecting run, so a normal `--workers N` run
|
|
479
|
+
# marshals exactly the payload it marshalled before the feature existed.
|
|
480
|
+
payload[:effects] = session.drain_effects if @record_effects
|
|
402
481
|
File.binwrite(out_path, Marshal.dump(payload))
|
|
403
482
|
exit!(0)
|
|
404
483
|
rescue StandardError
|
|
@@ -430,6 +509,7 @@ module Rigor
|
|
|
430
509
|
results_by_path.merge!(payload.fetch(:results))
|
|
431
510
|
merge_worker_reporters(payload.fetch(:reporters))
|
|
432
511
|
@collected_dependencies.merge!(payload.fetch(:dependencies, {})) if @record_dependencies
|
|
512
|
+
@collected_effects.merge!(payload.fetch(:effects, {})) if @record_effects
|
|
433
513
|
else
|
|
434
514
|
degraded.concat(child[:slice])
|
|
435
515
|
end
|
|
@@ -448,10 +528,12 @@ module Rigor
|
|
|
448
528
|
nil
|
|
449
529
|
end
|
|
450
530
|
|
|
451
|
-
|
|
531
|
+
# Both pool backends degrade the same way — the files a dead worker owed are re-analysed in
|
|
532
|
+
# process — so they say so the same way, naming which backend it was (#414).
|
|
533
|
+
def pool_degraded_diagnostic(count, backend)
|
|
452
534
|
Diagnostic.new(
|
|
453
535
|
path: ".rigor.yml", line: 1, column: 1,
|
|
454
|
-
message: "
|
|
536
|
+
message: "#{backend} pool degraded: #{count} file(s) re-analysed in-process " \
|
|
455
537
|
"after a worker exited abnormally",
|
|
456
538
|
severity: :warning, rule: "pool-degraded", source_family: :builtin
|
|
457
539
|
)
|
|
@@ -482,6 +564,7 @@ module Rigor
|
|
|
482
564
|
# per-file analysis runs on the coordinator, identical to the default sequential path.
|
|
483
565
|
def analyze_files_sequentially_fallback(files, reason:)
|
|
484
566
|
environment = build_runner_environment
|
|
567
|
+
snapshot_effect_annotation_carrier(environment.rbs_loader)
|
|
485
568
|
diagnostics = files.flat_map { |path| @analyze_file.call(path, environment) }
|
|
486
569
|
loader = environment.rbs_loader
|
|
487
570
|
@snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Analysis
|
|
5
5
|
class Runner
|
|
6
|
-
# Mutable per-run holder for the
|
|
6
|
+
# Mutable per-run holder for the end-of-pass snapshots that the analysis paths compute as a side
|
|
7
7
|
# effect and the rest of the run reads back: the RBS `class_decl_paths` / `signature_paths` tables
|
|
8
|
-
# (consumed by {RunStats}), the synthesized-namespace name list,
|
|
9
|
-
# (consumed by the diagnostic aggregator)
|
|
8
|
+
# (consumed by {RunStats}), the synthesized-namespace name list, the `conforms-to` scan results
|
|
9
|
+
# (consumed by the diagnostic aggregator), and the effect-annotation carrier (#441 — consumed by
|
|
10
|
+
# {EffectAnnotationResidualPass} on the runs that never store the environment).
|
|
10
11
|
#
|
|
11
12
|
# The snapshots are written by whichever analysis path ran ({PoolCoordinator} sequential / fork-pool /
|
|
12
13
|
# fallback) and read by the {Runner} and {DiagnosticAggregator}. A shared mutable holder keeps the
|
|
@@ -16,7 +17,7 @@ module Rigor
|
|
|
16
17
|
class RunSnapshots
|
|
17
18
|
attr_accessor :class_decl_paths, :signature_paths,
|
|
18
19
|
:synthesized_namespaces, :quarantined_signatures, :conformance_results,
|
|
19
|
-
:env_build_failure
|
|
20
|
+
:env_build_failure, :effect_annotation_carrier
|
|
20
21
|
|
|
21
22
|
# Constructor defaults match the {Runner} constructor: the pre-seed values `build_run_stats` /
|
|
22
23
|
# `pre_file_diagnostics` read before the first analysis path runs are frozen empties. The
|
|
@@ -29,6 +30,7 @@ module Rigor
|
|
|
29
30
|
@quarantined_signatures = [].freeze
|
|
30
31
|
@conformance_results = [].freeze
|
|
31
32
|
@env_build_failure = nil
|
|
33
|
+
@effect_annotation_carrier = [].freeze
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
# Per-`#run` reset. Mirrors the original `#run` body, which reset these to NON-frozen empties (distinct
|
|
@@ -40,6 +42,7 @@ module Rigor
|
|
|
40
42
|
@quarantined_signatures = []
|
|
41
43
|
@conformance_results = []
|
|
42
44
|
@env_build_failure = nil
|
|
45
|
+
@effect_annotation_carrier = [].freeze
|
|
43
46
|
end
|
|
44
47
|
end
|
|
45
48
|
end
|