rigortype 0.3.8 → 0.4.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 +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -9,6 +9,7 @@ require_relative "../scope"
|
|
|
9
9
|
require_relative "../cache/store"
|
|
10
10
|
require_relative "../cache/rbs_descriptor"
|
|
11
11
|
require_relative "../cache/file_digest"
|
|
12
|
+
require_relative "../cache/incremental_snapshot"
|
|
12
13
|
require_relative "run_cache_key"
|
|
13
14
|
require_relative "path_expansion"
|
|
14
15
|
require_relative "../plugin"
|
|
@@ -47,6 +48,7 @@ require_relative "runner/run_snapshots"
|
|
|
47
48
|
require_relative "runner/project_pre_passes"
|
|
48
49
|
require_relative "runner/pool_coordinator"
|
|
49
50
|
require_relative "runner/diagnostic_aggregator"
|
|
51
|
+
require_relative "template_units"
|
|
50
52
|
require_relative "runner/effect_envelope_pass"
|
|
51
53
|
require_relative "runner/effect_annotation_residual_pass"
|
|
52
54
|
require_relative "runner/buffer_pool_dispatcher"
|
|
@@ -74,6 +76,18 @@ module Rigor
|
|
|
74
76
|
# file-positioned ones (`effect.annotations-unchecked`, `source-rbs-*`).
|
|
75
77
|
:per_file_diagnostics
|
|
76
78
|
|
|
79
|
+
# Issues #796 / #794 — the two run-level rows a NARROWED run cannot re-derive from the files it
|
|
80
|
+
# analyses: the `definition-build-failed` set (whose producer is the analysis's own demand, and #696
|
|
81
|
+
# forbids Rigor demanding in its place) and the HKT-scan outcome (whose producer is an environment a
|
|
82
|
+
# nothing-changed recheck otherwise has no reason to build). {IncrementalSession} persists what a full
|
|
83
|
+
# run answers here and hands it back to the next narrowed run.
|
|
84
|
+
def run_level_rows
|
|
85
|
+
Cache::IncrementalSnapshot::RunLevelRows.new(
|
|
86
|
+
definition_build_failures: @snapshots.definition_build_failures,
|
|
87
|
+
hkt_scan_failure: @snapshots.hkt_scan_failure
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
77
91
|
# ADR-46 — the per-file cross-file read records this run captured (empty unless
|
|
78
92
|
# `record_dependencies: true`). Sequential analysis records into `@file_dependencies` via
|
|
79
93
|
# {#analyze_file}; the fork pool records per-worker and marshals the records into the coordinator, so a
|
|
@@ -94,6 +108,32 @@ module Rigor
|
|
|
94
108
|
@effect_table || Effects::EffectTable.empty
|
|
95
109
|
end
|
|
96
110
|
|
|
111
|
+
# ADR-103 WD9 (#391) — the envelope index this run resolved, for `rigor sig-gen`'s annotation
|
|
112
|
+
# emission to consult. Public for the same reason {#effect_table} is: a consumer outside the
|
|
113
|
+
# diagnostic stream needs what the run already computed, and rebuilding it from configuration
|
|
114
|
+
# alone would read a narrower set of strata — the accepted signatures and the rbs-inline virtual
|
|
115
|
+
# RBS both come from the built environment.
|
|
116
|
+
#
|
|
117
|
+
# Built on demand when the run never analysed a file. A WARM whole-run cache hit serves the
|
|
118
|
+
# propagated table from cache, so {#analyze_with_effects} — the only caller of
|
|
119
|
+
# {#effect_envelope_index} — never runs and the ivar stays nil. Returning an empty index there
|
|
120
|
+
# would silently drop sig-gen's "the author already declared a bound" gate on exactly the runs a
|
|
121
|
+
# user makes most often: the same `sig-gen` invocation would withhold on its first run and emit on
|
|
122
|
+
# its second. `@run_environment` is resolved before the cache is consulted, so the warm build reads
|
|
123
|
+
# the same strata the cold one does.
|
|
124
|
+
#
|
|
125
|
+
# `@run_environment` is nil only when the run resolved no environment at all — a run over zero
|
|
126
|
+
# project files, or one that never reached {#compute_run_diagnostics}. The build then falls back to
|
|
127
|
+
# the configuration-only strata (`sig/` annotations, class-level ones and `effects.envelopes:`,
|
|
128
|
+
# without the accepted signatures or the rbs-inline virtual RBS), which is the narrower answer but
|
|
129
|
+
# not a wrong one: a run with no environment analysed no file, so there is no candidate for the
|
|
130
|
+
# missing strata to have bounded.
|
|
131
|
+
def effect_envelopes
|
|
132
|
+
return @effect_envelope_index if @effect_envelope_index
|
|
133
|
+
|
|
134
|
+
effect_envelope_index(@run_environment)
|
|
135
|
+
end
|
|
136
|
+
|
|
97
137
|
# ADR-103 WD2 / WD6 / WD10 / #387 — the loaded plugins' effect contributions, compiled once per
|
|
98
138
|
# process. Memoised on first use rather than built in the constructor for two reasons: the plugin
|
|
99
139
|
# registry is adopted after construction (`apply_prebuilt` / the plugin-load pre-pass), and the
|
|
@@ -214,41 +254,40 @@ module Rigor
|
|
|
214
254
|
end
|
|
215
255
|
end
|
|
216
256
|
|
|
217
|
-
# @param
|
|
218
|
-
# @param
|
|
219
|
-
# @param cache_store [Rigor::Cache::Store, nil] the persistent cache the runner exposes to producers
|
|
257
|
+
# @param explain — surface fail-soft fallback events as `:info` diagnostics.
|
|
258
|
+
# @param cache_store — the persistent cache the runner exposes to producers
|
|
220
259
|
# (`RbsConstantTable` and successors). Pass `nil` to disable caching for this run; the CLI's
|
|
221
260
|
# `--no-cache` flag wires `nil` through. v0.0.9 group A slice 1 introduces the surface; later
|
|
222
261
|
# slices route real producers through it.
|
|
223
|
-
# @param workers
|
|
262
|
+
# @param workers — ADR-15 Phase 4b — when greater than zero, per-file analysis dispatches
|
|
224
263
|
# across a pool of N workers. Default `0` keeps the sequential code path bit-for-bit unchanged.
|
|
225
264
|
# Controlled via the `RIGOR_RACTOR_WORKERS` env var or `.rigor.yml` `parallel.workers:` (Phase 4c,
|
|
226
265
|
# fully wired).
|
|
227
|
-
# @param collect_stats
|
|
266
|
+
# @param collect_stats — when true (default), `#run` builds a {RunStats} summary exposed via
|
|
228
267
|
# `result.stats` — this forces the RBS env build at end-of-run so the `class_decl_paths` snapshot
|
|
229
268
|
# has real source attribution. Set to false to skip the stats summary entirely; the CLI's
|
|
230
269
|
# `--no-stats` threads `false` through to keep trivial-fixture runs from warming `.rigor/cache`.
|
|
231
|
-
# @param prebuilt
|
|
270
|
+
# @param prebuilt — when supplied, the runner adopts the pre-built
|
|
232
271
|
# plugin registry / dependency-source index / scanner outputs from the snapshot and skips the
|
|
233
272
|
# per-call pre-passes that produce them. Used by long-lived integrations
|
|
234
273
|
# (`Rigor::LanguageServer::ProjectContext`) to keep per-buffer requests fast — scanners walk the
|
|
235
274
|
# project once per generation rather than once per request, and plugin `#prepare` runs once per
|
|
236
275
|
# generation rather than once per request. Watched-file invalidation is the owner's responsibility;
|
|
237
276
|
# the runner trusts the snapshot it was given.
|
|
238
|
-
# @param environment
|
|
277
|
+
# @param environment — opt-in Environment override. When supplied, sequential
|
|
239
278
|
# mode uses the provided env instance in `#analyze_files` instead of building a fresh one via
|
|
240
279
|
# `Environment.for_project`, and attaches the runner's per-run reporter pair onto the env's mutable
|
|
241
280
|
# `Reporters` slot via `Environment#attach_reporters!`. Long-lived consumers (LSP `ProjectContext`)
|
|
242
281
|
# pass a shared env so per-publish work doesn't repeat the `Environment.for_project` build (bundler
|
|
243
282
|
# / lockfile / collection discovery, RbsLoader construction). Pool mode ignores the override — each
|
|
244
283
|
# worker continues to build its own Environment.
|
|
245
|
-
# @param discovery_seed
|
|
284
|
+
# @param discovery_seed — issue #260 — opt-in cross-file discovery tables, keyed by
|
|
246
285
|
# {Scope::DiscoveryIndex} slot name, seeded onto every per-file scope through
|
|
247
286
|
# `project_scope_seed_tables`. The ONE deliberate exception to "a `prebuilt:` runner carries no
|
|
248
287
|
# discovery tables": {Protection::DiagnosticOracle} threads the table set Tier 2's site filter already
|
|
249
288
|
# judges anchors against, so a site admitted because a sibling-file class resolved is also a site the
|
|
250
289
|
# oracle can kill at. nil (the default) leaves the prebuilt/LSP contract byte-identical.
|
|
251
|
-
# @param no_tolerated_effects
|
|
290
|
+
# @param no_tolerated_effects — ADR-103 WD1 / #385 — `rigor check --no-tolerated-effects`.
|
|
252
291
|
# Judges effect envelopes as if `effects.tolerated:` were empty. A judgment-time switch only: the
|
|
253
292
|
# run, its collection and its cache identity are unchanged.
|
|
254
293
|
def initialize(configuration:, explain: false, # rubocop:disable Metrics/ParameterLists,Metrics/AbcSize,Metrics/MethodLength
|
|
@@ -257,8 +296,12 @@ module Rigor
|
|
|
257
296
|
buffer: nil, prebuilt: nil, environment: nil,
|
|
258
297
|
record_dependencies: false, record_self_calls: false, analyze_only: nil,
|
|
259
298
|
seed_bundles: nil, collect_seed_bundles: false, param_inferred_types: nil,
|
|
260
|
-
discovery_seed: nil, no_tolerated_effects: false
|
|
299
|
+
discovery_seed: nil, no_tolerated_effects: false,
|
|
300
|
+
restored_run_level_rows: nil)
|
|
261
301
|
@configuration = configuration
|
|
302
|
+
# Issues #796 / #794 — the previous full run's run-level rows, supplied only by
|
|
303
|
+
# {IncrementalSession} on a narrowed run; see {PoolCoordinator#replay_restored_run_level_rows}.
|
|
304
|
+
@restored_run_level_rows = restored_run_level_rows
|
|
262
305
|
@explain = explain
|
|
263
306
|
@cache_store = enforce_read_only_cache(cache_store, buffer)
|
|
264
307
|
@plugin_requirer = plugin_requirer
|
|
@@ -298,6 +341,10 @@ module Rigor
|
|
|
298
341
|
# check reads.
|
|
299
342
|
@no_tolerated_effects = no_tolerated_effects
|
|
300
343
|
@file_effects = {}
|
|
344
|
+
# #392 — the run's template units, synthesised once per run after the plugins load (see
|
|
345
|
+
# {#template_units}). nil until then; a project whose plugins declare no `template_globs:` resolves
|
|
346
|
+
# to the shared empty index and pays one `Array#empty?` for the whole run.
|
|
347
|
+
@template_units = nil
|
|
301
348
|
@effect_table = nil
|
|
302
349
|
@effects_served_from_cache = false
|
|
303
350
|
# #482 — set only by a run served from the summary entry: the two derived tables it carries, and
|
|
@@ -362,6 +409,16 @@ module Rigor
|
|
|
362
409
|
# Issue #682 — the `Module.nesting` each class / module declaration HEADER is written in.
|
|
363
410
|
@project_discovered_header_nestings = {}.freeze
|
|
364
411
|
@project_discovered_includes = {}.freeze
|
|
412
|
+
# Issue #1123 — the instance-side prepend table (`prepend M`, and `Recv.prepend(M)`), in
|
|
413
|
+
# instance-ancestor SEARCH order.
|
|
414
|
+
@project_discovered_prepends = {}.freeze
|
|
415
|
+
# Issue #898 — the singleton-side twin of the include table (`extend M` / `extend self`).
|
|
416
|
+
@project_discovered_extends = {}.freeze
|
|
417
|
+
@project_discovered_deferred_ranges = {}.freeze
|
|
418
|
+
# Issue #1120 — `{refined class => {method => [refining modules]}}`, every `refine X do … end` body.
|
|
419
|
+
@project_discovered_refinements = {}.freeze
|
|
420
|
+
# Issue #1367 — the project's `Inference::GlobalWriteCensus`, which the `global.*` write rules read.
|
|
421
|
+
@project_discovered_global_write_census = Set.new.freeze
|
|
365
422
|
@project_discovered_class_sources = {}.freeze
|
|
366
423
|
# Issue #644 — the cross-file VALUE-constant publication table (`{qualified name => Type::Constant}`,
|
|
367
424
|
# literal writes only) and its per-name write attribution. The first seeds `in_source_constants` on
|
|
@@ -372,8 +429,12 @@ module Rigor
|
|
|
372
429
|
# ...and the raw per-(name, path) publication census the incremental producer diffs.
|
|
373
430
|
@project_constant_writes = {}.freeze
|
|
374
431
|
@published_constant_name_set = nil
|
|
432
|
+
@constant_writer_index = nil
|
|
433
|
+
@constant_shadower_index = nil
|
|
375
434
|
@project_discovered_method_visibilities = {}.freeze
|
|
376
435
|
@project_discovered_methods = {}.freeze
|
|
436
|
+
# Issue #992 — the cross-file parameter-envelope table `call.wrong-arity` reads for an undeclared `def`.
|
|
437
|
+
@project_discovered_parameter_envelopes = {}.freeze
|
|
377
438
|
@project_data_member_layouts = {}.freeze
|
|
378
439
|
@project_struct_member_layouts = {}.freeze
|
|
379
440
|
# Issue #684 — set per run by {#project_discovery_expansion}; nil on every path that does not widen.
|
|
@@ -388,6 +449,9 @@ module Rigor
|
|
|
388
449
|
# (sequential + fork-worker) through `project_scope_seed_tables`. Empty unless the project lists
|
|
389
450
|
# `pre_eval:` files that declare publishable constants, so a project without one is byte-identical.
|
|
390
451
|
@project_pre_eval_constants = {}.freeze
|
|
452
|
+
# Issue #663 — the listed set {#publishable_pre_eval_constants} asks "is this writer one of ours?"
|
|
453
|
+
# against; a function of the configuration alone, so it outlives every discovery rebuild.
|
|
454
|
+
@pre_eval_path_set = nil
|
|
391
455
|
# ADR-84 WD2 — per-run identity token for the user-method return memo's bucket (see
|
|
392
456
|
# Scope::DiscoveryIndex#run_generation). Minted fresh in `run_analysis` so the memo never serves an
|
|
393
457
|
# entry across a run boundary (LSP re-check, ADR-62 warm loop); nil until the first run so
|
|
@@ -432,6 +496,12 @@ module Rigor
|
|
|
432
496
|
@snapshots.reset_for_run
|
|
433
497
|
# Per-run reset of the deferred-discovery memo (see `#ensure_project_discovery`).
|
|
434
498
|
@project_discovery_done = false
|
|
499
|
+
# #392 — re-derive the template units each run: their source files can change between two runs of
|
|
500
|
+
# one long-lived Runner (the LSP's), and a unit is never served from a cache of its own. Since
|
|
501
|
+
# #1038 "re-derive" is not "recompile": a `prebuilt:` runner carries the snapshot's warm index into
|
|
502
|
+
# {#template_units}, which still re-expands every claim and revalidates every template against the
|
|
503
|
+
# filesystem, and only compiles what actually moved.
|
|
504
|
+
@template_units = nil
|
|
435
505
|
# Per-run reset of the environment the cacheable path resolves, reused by the envelope pass so a
|
|
436
506
|
# run never builds two.
|
|
437
507
|
@run_environment = nil
|
|
@@ -479,9 +549,8 @@ module Rigor
|
|
|
479
549
|
# so the result matches a one-file disk run; only the cross-file project pre-pass is empty (there is
|
|
480
550
|
# one file, and the per-file indexer self-discovers its own classes / defs).
|
|
481
551
|
#
|
|
482
|
-
# @param source
|
|
483
|
-
# @param path
|
|
484
|
-
# @return [Result]
|
|
552
|
+
# @param source — Ruby source to analyze.
|
|
553
|
+
# @param path — logical path for diagnostic locations.
|
|
485
554
|
def run_source(source:, path: "(source).rb")
|
|
486
555
|
@in_memory_sources = { path => source }
|
|
487
556
|
run([path])
|
|
@@ -607,7 +676,7 @@ module Rigor
|
|
|
607
676
|
# arg-flooring surface). Only meaningful right after a run populated the memo (baseline / recheck),
|
|
608
677
|
# before the bucket rolls. Keys are held live here; the session Marshals them for the snapshot.
|
|
609
678
|
#
|
|
610
|
-
# @return
|
|
679
|
+
# @return `{ [path, "Class#method" | "Class.method"] => { keys:, returns:, effects: } }`.
|
|
611
680
|
def return_summaries
|
|
612
681
|
memo = Inference::ExpressionTyper.harvest_return_memo
|
|
613
682
|
return {} if memo.empty?
|
|
@@ -665,9 +734,9 @@ module Rigor
|
|
|
665
734
|
# store) exactly as a real run's setup does, then re-drives each spec's def through the ADR-84 return
|
|
666
735
|
# memo. Off any hot path — invoked only when declaration-stable changed pairs carry a persisted summary.
|
|
667
736
|
#
|
|
668
|
-
# @param paths
|
|
669
|
-
# @param specs
|
|
670
|
-
# @return
|
|
737
|
+
# @param paths — analysis roots (nil → the configuration's `paths:`).
|
|
738
|
+
# @param specs — each `{ class_name:, method_name:, singleton:, keys: [[receiver, args], …] }`.
|
|
739
|
+
# @return `{ [class_name, method_name, singleton] => [return_descriptor_or_nil, …] }`.
|
|
671
740
|
def evaluate_return_types(paths, specs)
|
|
672
741
|
return {} if specs.empty?
|
|
673
742
|
|
|
@@ -726,7 +795,10 @@ module Rigor
|
|
|
726
795
|
@run_served_from_cache = false
|
|
727
796
|
return assemble_run_diagnostics(expansion) unless run_result_cacheable?
|
|
728
797
|
|
|
729
|
-
|
|
798
|
+
# #392 — `source_files:` is what a plugin's `source_rbs_synthesizer` is offered at env-build time,
|
|
799
|
+
# and a template unit is not Ruby the synthesiser can read (rbs-inline would be handed `.rbx`
|
|
800
|
+
# bytes). The `.rb` expansion is the right set here; the units join the ANALYSED set only.
|
|
801
|
+
environment = @pool_coordinator.resolve_sequential_environment(source_files: expansion.fetch(:files))
|
|
730
802
|
# Lazy-files descriptor: the cache KEY reads only `gems` + `configs`; the RBS signature-tree `files`
|
|
731
803
|
# are digested solely by `run_dependency_descriptor` on a MISS, so a warm HIT never walks the tree.
|
|
732
804
|
rbs_descriptor = if environment&.rbs_loader
|
|
@@ -795,7 +867,7 @@ module Rigor
|
|
|
795
867
|
# fixpoint over them, which is the pre-split behaviour and the retry the fail-soft posture wants.
|
|
796
868
|
# Only when neither entry answers does the run re-analyse.
|
|
797
869
|
#
|
|
798
|
-
# @return
|
|
870
|
+
# @return whether this run was served.
|
|
799
871
|
def served_from_effect_entries?(descriptor)
|
|
800
872
|
summary = peek_effect_summary(descriptor)
|
|
801
873
|
if summary
|
|
@@ -978,7 +1050,14 @@ module Rigor
|
|
|
978
1050
|
def close_effect_graph
|
|
979
1051
|
return unless @record_effects
|
|
980
1052
|
|
|
981
|
-
|
|
1053
|
+
# `declined_unit_keys:` — #1065. The templates a plugin claimed and produced no unit for; a render
|
|
1054
|
+
# edge's format fallback must not resolve past one of them, because the file exists and the
|
|
1055
|
+
# framework runs it, so the other format's effects are not what that render produces.
|
|
1056
|
+
@effect_table = Effects::Propagator.propagate(
|
|
1057
|
+
effect_collection,
|
|
1058
|
+
discharge: effect_discharge,
|
|
1059
|
+
declined_unit_keys: template_units.declined_unit_keys
|
|
1060
|
+
)
|
|
982
1061
|
rescue StandardError
|
|
983
1062
|
@effect_table = Effects::EffectTable.empty
|
|
984
1063
|
end
|
|
@@ -1009,6 +1088,11 @@ module Rigor
|
|
|
1009
1088
|
# untouched so its lazy build timing is unchanged.
|
|
1010
1089
|
environment = seed_pre_eval_constants(expansion, environment)
|
|
1011
1090
|
diagnostics = @diagnostic_aggregator.pre_file_diagnostics(expansion)
|
|
1091
|
+
# #392 — a template transform that raised, a template that could not be read, or a unit naming a
|
|
1092
|
+
# file it was not offered. Reported through the same `:plugin_loader` `runtime-error` envelope a
|
|
1093
|
+
# raise from `#diagnostics_for_file` uses (ADR-2 § "Plugin Trust and I/O Policy"), rather than
|
|
1094
|
+
# dropped in silence: a plugin author whose view stopped being analysed has nothing else to read.
|
|
1095
|
+
diagnostics += template_unit_failure_diagnostics
|
|
1012
1096
|
# ADR-46 — record which project files this run actually analyzed (the `analyze_only` subset, or
|
|
1013
1097
|
# all of them). The incremental orchestrator serves every analyzed-but-not-affected file from the
|
|
1014
1098
|
# per-file cache, so it needs the full analyzed set to subtract the affected closure from.
|
|
@@ -1025,12 +1109,39 @@ module Rigor
|
|
|
1025
1109
|
# override re-stamps it; and a pool backend folds `.rigor.yml`-positioned prepare / pool-degraded rows
|
|
1026
1110
|
# into the same return, which the slice drops. The run's own stream is stamped once, at the end.
|
|
1027
1111
|
diagnostics += analyze_targets(targets, environment: environment, project_files: expansion.fetch(:files))
|
|
1112
|
+
# Issue #1060 — the positioned batches plugins registered through `Plugin::Base#emit_once`, read once
|
|
1113
|
+
# every worker payload has been merged. Kept beside the per-file stream (their rows name files and
|
|
1114
|
+
# lines) but outside `#per_file_diagnostics`, which `analyze_targets` has already sliced, so no one
|
|
1115
|
+
# file's incremental cache entry carries a project-wide batch.
|
|
1116
|
+
diagnostics += @diagnostic_aggregator.plugin_run_emission_diagnostics
|
|
1028
1117
|
# ADR-103 WD12 — the effect fixpoint, in the post-pool aggregation slot beside the conformance
|
|
1029
1118
|
# results. Graph-only over a finite lattice, so it is a plain worklist to a true fixpoint; it
|
|
1030
1119
|
# contributes NO diagnostics and its result leaves through `#effect_table`, never through the
|
|
1031
1120
|
# stream. Skipped entirely when collection did not run.
|
|
1032
1121
|
close_effect_graph
|
|
1033
|
-
diagnostics
|
|
1122
|
+
diagnostics + post_analysis_diagnostic_streams
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
def template_unit_failure_diagnostics
|
|
1126
|
+
template_units.failures.map do |failure|
|
|
1127
|
+
Diagnostic.new(
|
|
1128
|
+
path: failure.path, line: 1, column: 1,
|
|
1129
|
+
message: "plugin #{failure.plugin_id.inspect} produced no template unit for " \
|
|
1130
|
+
"#{failure.path}: #{failure.message}",
|
|
1131
|
+
severity: :error, rule: "runtime-error", source_family: :plugin_loader
|
|
1132
|
+
)
|
|
1133
|
+
end
|
|
1134
|
+
end
|
|
1135
|
+
private :template_unit_failure_diagnostics
|
|
1136
|
+
|
|
1137
|
+
# The rbs-coverage build-failure ladder plus every remaining post-analysis stream
|
|
1138
|
+
# `#assemble_run_diagnostics` appends, in their fixed contract order (see the comments at each call
|
|
1139
|
+
# below and at the streams' own definitions). Split out of `#assemble_run_diagnostics` so that
|
|
1140
|
+
# method's `Metrics/AbcSize` stays under budget — every stream here is a plain `DiagnosticAggregator`
|
|
1141
|
+
# reader with no branching of its own, so the split changes nothing about WHEN or in WHAT order they
|
|
1142
|
+
# run.
|
|
1143
|
+
def post_analysis_diagnostic_streams
|
|
1144
|
+
diagnostics = @diagnostic_aggregator.rbs_quarantined_signature_diagnostics
|
|
1034
1145
|
diagnostics += @diagnostic_aggregator.rbs_environment_build_failed_diagnostics
|
|
1035
1146
|
# Issue #696 — after its env-wide twin and before the synthesized-namespace notice: the four
|
|
1036
1147
|
# `rbs.coverage.*` build conditions surface widest-consequence first, and their relative order is
|
|
@@ -1040,12 +1151,25 @@ module Rigor
|
|
|
1040
1151
|
# `type` alias would have contributed, never a class's own declared method surface, so it is the
|
|
1041
1152
|
# narrowest-consequence rung on the same ladder.
|
|
1042
1153
|
diagnostics += @diagnostic_aggregator.rbs_hkt_scan_failed_diagnostics
|
|
1043
|
-
|
|
1154
|
+
# The synthesized-namespace notice, then (#610) the plugin-signature stand-down: the outcome that
|
|
1155
|
+
# AVOIDED a definition-build failure, so the quietest row on that ladder.
|
|
1156
|
+
diagnostics += @diagnostic_aggregator.rbs_coverage_notice_diagnostics
|
|
1044
1157
|
diagnostics += @diagnostic_aggregator.conforms_to_diagnostics
|
|
1045
1158
|
diagnostics += @diagnostic_aggregator.rbs_extended_reporter_diagnostics
|
|
1046
1159
|
diagnostics += @diagnostic_aggregator.boundary_cross_diagnostics
|
|
1047
|
-
diagnostics
|
|
1048
|
-
|
|
1160
|
+
diagnostics += @diagnostic_aggregator.source_rbs_synthesis_diagnostics
|
|
1161
|
+
# Issue #1051 — read after `analyze_targets` for the same reason the refusal stream below is: a
|
|
1162
|
+
# plugin may register a disclosure from `#prepare` (the usual case) or while analysing a file, and
|
|
1163
|
+
# both have to be in before the table is harvested. Ordered before the refusals so the run-level
|
|
1164
|
+
# plugin rows read plugin-authored notice first, engine-authored envelope second.
|
|
1165
|
+
diagnostics += @diagnostic_aggregator.plugin_run_disclosure_diagnostics
|
|
1166
|
+
# Issue #959 — read LAST (after `analyze_targets`, which already ran before this method is called),
|
|
1167
|
+
# so every per-file plugin call has had its chance to record a refusal on its (per-plugin-instance
|
|
1168
|
+
# memoised) `IoBoundary`, alongside the prepare-time refusals the same boundary instance may
|
|
1169
|
+
# already carry.
|
|
1170
|
+
diagnostics + @diagnostic_aggregator.plugin_trust_refusal_diagnostics
|
|
1171
|
+
end
|
|
1172
|
+
private :post_analysis_diagnostic_streams
|
|
1049
1173
|
|
|
1050
1174
|
# #788 round 7 — runs per-file analysis over `targets` and exposes what it produced as
|
|
1051
1175
|
# `#per_file_diagnostics`: the `analyze_files` return, stamped with the same severity profile the run's
|
|
@@ -1053,7 +1177,9 @@ module Rigor
|
|
|
1053
1177
|
# re-stamps), sliced to the rows positioned at the targets. Returns the RAW return for the run's stream,
|
|
1054
1178
|
# which is stamped once, at the end of `#run_analysis`.
|
|
1055
1179
|
def analyze_targets(targets, environment:, project_files:)
|
|
1056
|
-
raw =
|
|
1180
|
+
raw = template_units.remap(
|
|
1181
|
+
@pool_coordinator.analyze_files(targets, environment: environment, project_files: project_files)
|
|
1182
|
+
)
|
|
1057
1183
|
analysed = targets.to_set
|
|
1058
1184
|
@per_file_diagnostics = @diagnostic_aggregator.apply_severity_profile(raw)
|
|
1059
1185
|
.select { |diagnostic| analysed.include?(diagnostic.path) }
|
|
@@ -1161,7 +1287,8 @@ module Rigor
|
|
|
1161
1287
|
# reconstructs `rbs.libraries` from config) can never drift out of key agreement.
|
|
1162
1288
|
RunCacheKey.descriptor(
|
|
1163
1289
|
configuration: @configuration, files: expansion.fetch(:files),
|
|
1164
|
-
explain: @explain, rbs_config_entries: rbs_descriptor.configs
|
|
1290
|
+
explain: @explain, rbs_config_entries: rbs_descriptor.configs,
|
|
1291
|
+
template_units_digest: template_units.digest
|
|
1165
1292
|
)
|
|
1166
1293
|
end
|
|
1167
1294
|
|
|
@@ -1178,14 +1305,23 @@ module Rigor
|
|
|
1178
1305
|
|
|
1179
1306
|
def build_run_dependency_descriptor(expansion, rbs_descriptor)
|
|
1180
1307
|
entries = analyzed_file_entries(expansion) + discovery_file_entries(expansion) +
|
|
1181
|
-
pre_eval_file_entries + rbs_descriptor.files
|
|
1182
|
-
|
|
1308
|
+
pre_eval_file_entries + template_unit_file_entries + rbs_descriptor.files
|
|
1309
|
+
# #979 — the signature ROOTS' listings, one glob row each. `rbs_descriptor.files` covers only the
|
|
1310
|
+
# `.rbs` files that existed while the run read them, so without these a signature file written after
|
|
1311
|
+
# the run left the slot validating fresh and the warm run answered without it.
|
|
1312
|
+
globs = rbs_descriptor.globs + template_unit_glob_entries
|
|
1183
1313
|
@plugin_registry.plugins.each do |plugin|
|
|
1184
1314
|
# Read the boundary WITHOUT triggering its lazy `@io_boundary ||=` initializer: plugin instances
|
|
1185
1315
|
# are frozen after the run, and a plugin that never built a boundary read no files through it,
|
|
1186
1316
|
# so it contributes no dependencies.
|
|
1187
1317
|
boundary = plugin.instance_variable_get(:@io_boundary)
|
|
1188
|
-
|
|
1318
|
+
if boundary
|
|
1319
|
+
# #629 — a boundary carries GlobEntry listing rows too (`IoBoundary#list_directory`), and they
|
|
1320
|
+
# are the only edge back to a file the run decided was ABSENT from a directory it consulted.
|
|
1321
|
+
boundary_descriptor = boundary.cache_descriptor
|
|
1322
|
+
entries.concat(boundary_descriptor.files)
|
|
1323
|
+
globs.concat(boundary_descriptor.globs)
|
|
1324
|
+
end
|
|
1189
1325
|
plugin.class.producers.each_value do |prod|
|
|
1190
1326
|
globs.concat(plugin.send(:watch_glob_entries, prod[:watch])) if prod[:watch]
|
|
1191
1327
|
end
|
|
@@ -1221,6 +1357,30 @@ module Rigor
|
|
|
1221
1357
|
# expansion — so without this entry, editing one would leave the run-result cache serving diagnostics
|
|
1222
1358
|
# computed against the previous version. The common case (a `lib/core_ext/` file that is also under
|
|
1223
1359
|
# `paths:`) contributes a duplicate entry, which the descriptor's per-path validation absorbs.
|
|
1360
|
+
# #392 — the TEMPLATE files behind the run's units. The key slot carries the compiled Ruby's digest
|
|
1361
|
+
# (`template_units_digest`), which is what decides whether a cached answer describes this source; these
|
|
1362
|
+
# entries are the validation half, so a template edited between two runs re-globs and re-digests here
|
|
1363
|
+
# exactly as an analysed `.rb` file does. Both are needed: a transform that compiles two different
|
|
1364
|
+
# templates to the same Ruby must still not resurrect the wrong PATH in a diagnostic.
|
|
1365
|
+
# #392 — one `:names` row per claimed `template_globs:` pattern, whether or not it matched. The file
|
|
1366
|
+
# rows below cover edits to templates that EXIST; only a glob row notices one appearing or vanishing,
|
|
1367
|
+
# which is what let a project's first template stay invisible to every warm run.
|
|
1368
|
+
def template_unit_glob_entries
|
|
1369
|
+
template_units.glob_entries
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
# Every template the run READ, successes and failures alike: a `plugin_loader` row produced by a
|
|
1373
|
+
# template that would not compile must not outlive the edit that fixes it, and a buffer-bound path is
|
|
1374
|
+
# digested at the bytes the run actually read.
|
|
1375
|
+
def template_unit_file_entries
|
|
1376
|
+
template_units.source_paths.filter_map do |path|
|
|
1377
|
+
physical = template_units.physical_path(path, @buffer)
|
|
1378
|
+
next unless File.file?(physical)
|
|
1379
|
+
|
|
1380
|
+
Cache::Descriptor::FileEntry.stat(path: physical, digest: Cache::FileDigest.hexdigest(physical))
|
|
1381
|
+
end
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1224
1384
|
def pre_eval_file_entries
|
|
1225
1385
|
@configuration.pre_eval.filter_map do |path|
|
|
1226
1386
|
physical = @buffer ? @buffer.resolve(path) : path
|
|
@@ -1305,18 +1465,39 @@ module Rigor
|
|
|
1305
1465
|
@project_discovered_singleton_def_sources = discovery.discovered_singleton_def_sources
|
|
1306
1466
|
@project_discovered_superclasses = discovery.discovered_superclasses
|
|
1307
1467
|
@project_discovered_header_nestings = discovery.discovered_header_nestings
|
|
1308
|
-
|
|
1468
|
+
apply_discovery_mixin_tables(discovery)
|
|
1469
|
+
@project_discovered_deferred_ranges = discovery.discovered_deferred_ranges
|
|
1470
|
+
apply_discovery_call_surface_tables(discovery)
|
|
1309
1471
|
@project_discovered_class_sources = discovery.discovered_class_sources
|
|
1310
1472
|
@project_constant_values = discovery.constant_values
|
|
1311
1473
|
@published_constant_name_set = nil
|
|
1474
|
+
@constant_writer_index = nil
|
|
1475
|
+
@constant_shadower_index = nil
|
|
1312
1476
|
@project_constant_sources = discovery.constant_sources
|
|
1313
1477
|
@project_constant_writes = discovery.constant_writes
|
|
1314
1478
|
@project_discovered_method_visibilities = discovery.discovered_method_visibilities
|
|
1315
1479
|
@project_discovered_methods = discovery.discovered_methods
|
|
1480
|
+
@project_discovered_parameter_envelopes = discovery.discovered_parameter_envelopes
|
|
1316
1481
|
@project_data_member_layouts = discovery.data_member_layouts
|
|
1317
1482
|
@project_struct_member_layouts = discovery.struct_member_layouts
|
|
1318
1483
|
end
|
|
1319
1484
|
|
|
1485
|
+
# The tables only check rules read beyond dispatch — the issue #1120 refinements and the issue #1367
|
|
1486
|
+
# global-write census. Extracted to keep {#apply_discovery_result} under its ABC budget.
|
|
1487
|
+
def apply_discovery_call_surface_tables(discovery)
|
|
1488
|
+
@project_discovered_refinements = discovery.discovered_refinements
|
|
1489
|
+
@project_discovered_global_write_census = discovery.discovered_global_write_census
|
|
1490
|
+
end
|
|
1491
|
+
|
|
1492
|
+
# The three mixin tables the discovery pass carries — the ADR-24 `include` map, its issue #1123
|
|
1493
|
+
# `prepend` twin, and the #898 `extend` table. Extracted to keep {#apply_discovery_result} under its
|
|
1494
|
+
# ABC budget.
|
|
1495
|
+
def apply_discovery_mixin_tables(discovery)
|
|
1496
|
+
@project_discovered_includes = discovery.discovered_includes
|
|
1497
|
+
@project_discovered_prepends = discovery.discovered_prepends
|
|
1498
|
+
@project_discovered_extends = discovery.discovered_extends
|
|
1499
|
+
end
|
|
1500
|
+
|
|
1320
1501
|
# Internal: builds the deferred cross-file discovery tables at most once per run and adopts them.
|
|
1321
1502
|
# Memoised on `@project_discovery_done` (reset at the start of `#run`). No-op under `@prebuilt` — the
|
|
1322
1503
|
# LSP path deliberately seeds an empty project scope from a snapshot that carries no discovery tables,
|
|
@@ -1399,7 +1580,7 @@ module Rigor
|
|
|
1399
1580
|
3.0.0 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 4.0.0 4.1.0 4.2.0
|
|
1400
1581
|
].freeze
|
|
1401
1582
|
|
|
1402
|
-
# @return
|
|
1583
|
+
# @return the lowest `target_ruby` this Prism build accepts, or nil if none of the
|
|
1403
1584
|
# ladder parses. Memoised per process (the value is constant for a given Prism).
|
|
1404
1585
|
def self.prism_supported_floor
|
|
1405
1586
|
@prism_supported_floor ||= PRISM_VERSION_LADDER.find do |candidate|
|
|
@@ -1450,6 +1631,25 @@ module Rigor
|
|
|
1450
1631
|
# The buffer's logical path is added to the file list even if it's not under `paths:` — per design §
|
|
1451
1632
|
# "Failure envelope": "--instead-of=Y with Y not under any paths: directory → treated as a valid
|
|
1452
1633
|
# logical identity for the buffer".
|
|
1634
|
+
# #392 — the run's template units. Built once per run, on the parent, AFTER the plugin pre-pass has
|
|
1635
|
+
# loaded the registry; a run whose plugins declare no `template_globs:` never globs and never calls a
|
|
1636
|
+
# plugin.
|
|
1637
|
+
#
|
|
1638
|
+
# #1038 — a runner built with `prebuilt:` hands the snapshot's warm index to `collect(previous:)`, so
|
|
1639
|
+
# a per-buffer publish against a long-lived {LanguageServer::ProjectContext} re-runs the transform
|
|
1640
|
+
# only for a template that actually moved on disk (and for the buffer's own, always). The globs are
|
|
1641
|
+
# still re-expanded and every surviving template is still revalidated, so an added, deleted or edited
|
|
1642
|
+
# template is seen on the next publish without the owner invalidating anything. A runner with no
|
|
1643
|
+
# `prebuilt:` — every CLI run — passes no `previous:` and builds the index exactly as before.
|
|
1644
|
+
def template_units
|
|
1645
|
+
@template_units ||= if @plugin_registry.nil?
|
|
1646
|
+
TemplateUnits.empty
|
|
1647
|
+
else
|
|
1648
|
+
TemplateUnits.collect(registry: @plugin_registry, buffer: @buffer,
|
|
1649
|
+
previous: @prebuilt&.template_units)
|
|
1650
|
+
end
|
|
1651
|
+
end
|
|
1652
|
+
|
|
1453
1653
|
def target_files(expansion)
|
|
1454
1654
|
files = expansion.fetch(:files)
|
|
1455
1655
|
# ADR-46 slice 2 — restrict the analyzed set to the affected closure while the pre-pass (run
|
|
@@ -1460,14 +1660,41 @@ module Rigor
|
|
|
1460
1660
|
# the same allowance option A makes below.
|
|
1461
1661
|
files = files.select { |path| @analyze_only.include?(path) }
|
|
1462
1662
|
files |= [@buffer.logical_path] if @buffer && @analyze_only.include?(@buffer.logical_path)
|
|
1463
|
-
return files
|
|
1663
|
+
return template_unit_targets(files)
|
|
1464
1664
|
end
|
|
1465
|
-
return files if @buffer.nil?
|
|
1665
|
+
return template_unit_targets(files) if @buffer.nil?
|
|
1466
1666
|
|
|
1467
|
-
# Editor mode option A — no closure, so the buffer's single logical path IS the analyzed set.
|
|
1667
|
+
# Editor mode option A — no closure, so the buffer's single logical path IS the analyzed set. The
|
|
1668
|
+
# template units deliberately do NOT join it: a per-buffer publish answers about the buffer the
|
|
1669
|
+
# editor is showing, and appending every view would publish diagnostics for files the editor did
|
|
1670
|
+
# not ask about (and re-parse them on every keystroke).
|
|
1468
1671
|
[@buffer.logical_path]
|
|
1469
1672
|
end
|
|
1470
1673
|
|
|
1674
|
+
# #392 — the template units join the analysed set AFTER any narrowing, so an `--incremental` recheck
|
|
1675
|
+
# re-analyses every unit even when its closure is one `.rb` file. Nothing in the ADR-46 dependency
|
|
1676
|
+
# graph names a synthesised file, so there is no edge that could put a unit in a closure — narrowing
|
|
1677
|
+
# first and appending second is what makes "always re-analysed" true rather than a comment. The cost
|
|
1678
|
+
# is one parse per template on the warm path; the alternative silently drops every template
|
|
1679
|
+
# diagnostic from the second run onwards.
|
|
1680
|
+
#
|
|
1681
|
+
# Appended rather than merged in sorted order so the `.rb` expansion's own order — and every output
|
|
1682
|
+
# that follows it — is byte-identical for a project with no units.
|
|
1683
|
+
def template_unit_targets(files)
|
|
1684
|
+
return files if template_units.empty?
|
|
1685
|
+
|
|
1686
|
+
files + (template_units.paths - files)
|
|
1687
|
+
end
|
|
1688
|
+
private :template_unit_targets
|
|
1689
|
+
|
|
1690
|
+
# #392 — the unit paths this run synthesised. Read by {IncrementalSession}, which keeps them OUT of
|
|
1691
|
+
# its analysed-file set: a unit is never served from the per-file cache and never counts as a file
|
|
1692
|
+
# that was removed from the project, because `#target_files` re-analyses it every run.
|
|
1693
|
+
def template_unit_paths
|
|
1694
|
+
template_units.paths
|
|
1695
|
+
end
|
|
1696
|
+
public :template_unit_paths
|
|
1697
|
+
|
|
1471
1698
|
# Editor mode (`buffer:` non-nil) auto-flips the cache store to `read_only: true` so multiple
|
|
1472
1699
|
# debounced editor invocations against the same project don't churn the on-disk cache or race on
|
|
1473
1700
|
# schema-version writes. Cache reads continue unchanged; misses still run the producer block but the
|
|
@@ -1504,7 +1731,9 @@ module Rigor
|
|
|
1504
1731
|
synthetic_method_index: -> { @synthetic_method_index },
|
|
1505
1732
|
project_patched_methods: -> { @project_patched_methods },
|
|
1506
1733
|
project_scope_seed: -> { project_scope_seed_tables },
|
|
1507
|
-
|
|
1734
|
+
template_units: -> { template_units },
|
|
1735
|
+
analyze_file: ->(path, environment) { analyze_file(path, environment) },
|
|
1736
|
+
restored_run_level_rows: @restored_run_level_rows
|
|
1508
1737
|
)
|
|
1509
1738
|
@diagnostic_aggregator = DiagnosticAggregator.new(
|
|
1510
1739
|
configuration: @configuration,
|
|
@@ -1518,10 +1747,12 @@ module Rigor
|
|
|
1518
1747
|
pre_eval_diagnostics_from_scanner: -> { @pre_eval_diagnostics_from_scanner },
|
|
1519
1748
|
synthesized_namespaces_snapshot: -> { @snapshots.synthesized_namespaces },
|
|
1520
1749
|
quarantined_signatures_snapshot: -> { @snapshots.quarantined_signatures },
|
|
1750
|
+
signature_standdowns_snapshot: -> { @snapshots.signature_standdowns },
|
|
1521
1751
|
env_build_failure_snapshot: -> { @snapshots.env_build_failure },
|
|
1522
1752
|
definition_build_failures_snapshot: -> { @snapshots.definition_build_failures },
|
|
1523
1753
|
hkt_scan_failure_snapshot: -> { @snapshots.hkt_scan_failure },
|
|
1524
|
-
conformance_results_snapshot: -> { @snapshots.conformance_results }
|
|
1754
|
+
conformance_results_snapshot: -> { @snapshots.conformance_results },
|
|
1755
|
+
pooled_run_disclosures: -> { @pool_coordinator.collected_run_disclosures }
|
|
1525
1756
|
)
|
|
1526
1757
|
end
|
|
1527
1758
|
|
|
@@ -1548,7 +1779,9 @@ module Rigor
|
|
|
1548
1779
|
RunStats.new(
|
|
1549
1780
|
wall_seconds: Process.clock_gettime(Process::CLOCK_MONOTONIC) - wall_started_at,
|
|
1550
1781
|
peak_rss_bytes: RunStats.peak_rss_bytes,
|
|
1551
|
-
|
|
1782
|
+
# #392 — the template units count too: they are files this run parsed and typed, and a stats line
|
|
1783
|
+
# that omitted them would under-report exactly the work a views-heavy project added.
|
|
1784
|
+
target_files: expansion.fetch(:files).size + template_units.paths.size,
|
|
1552
1785
|
rbs_classes_total: snapshot.size,
|
|
1553
1786
|
rbs_classes_project_sig: project_sig,
|
|
1554
1787
|
rbs_classes_bundled: bundled,
|
|
@@ -1705,6 +1938,12 @@ module Rigor
|
|
|
1705
1938
|
# so Prism's location data carries the LOGICAL path. Non-binding paths go through the cheaper
|
|
1706
1939
|
# `Prism.parse_file` codepath unchanged.
|
|
1707
1940
|
def parse_source(path)
|
|
1941
|
+
entry = template_units[path]
|
|
1942
|
+
if entry
|
|
1943
|
+
return Prism.parse(entry.source, filepath: path, version: @configuration.target_ruby,
|
|
1944
|
+
scopes: template_units.parse_scopes(path))
|
|
1945
|
+
end
|
|
1946
|
+
|
|
1708
1947
|
if @in_memory_sources&.key?(path)
|
|
1709
1948
|
return Prism.parse(@in_memory_sources[path], filepath: path, version: @configuration.target_ruby)
|
|
1710
1949
|
end
|
|
@@ -1752,22 +1991,58 @@ module Rigor
|
|
|
1752
1991
|
unless @project_discovered_header_nestings.empty?
|
|
1753
1992
|
tables[:discovered_header_nestings] = @project_discovered_header_nestings
|
|
1754
1993
|
end
|
|
1755
|
-
tables
|
|
1994
|
+
seed_mixin_tables(tables)
|
|
1756
1995
|
unless @project_discovered_method_visibilities.empty?
|
|
1757
1996
|
tables[:discovered_method_visibilities] = @project_discovered_method_visibilities
|
|
1758
1997
|
end
|
|
1759
1998
|
tables[:discovered_methods] = @project_discovered_methods unless @project_discovered_methods.empty?
|
|
1999
|
+
unless @project_discovered_deferred_ranges.empty?
|
|
2000
|
+
tables[:discovered_deferred_ranges] = @project_discovered_deferred_ranges
|
|
2001
|
+
end
|
|
2002
|
+
seed_call_surface_tables(tables)
|
|
1760
2003
|
seed_opt_in_pre_pass_tables(tables)
|
|
1761
2004
|
seed_member_layout_tables(tables)
|
|
1762
2005
|
seed_dependency_attribution_tables(tables)
|
|
1763
2006
|
tables
|
|
1764
2007
|
end
|
|
1765
2008
|
|
|
2009
|
+
# The tables only check rules read: the issue #992 parameter envelopes (`call.wrong-arity`), the issue #1120
|
|
2010
|
+
# refinements (`call.undefined-method`), and the issue #1367 global-write census (the `global.*` write
|
|
2011
|
+
# rules). Split out of {#project_scope_seed_tables} to keep it under the complexity budget.
|
|
2012
|
+
def seed_call_surface_tables(tables)
|
|
2013
|
+
unless @project_discovered_parameter_envelopes.empty?
|
|
2014
|
+
tables[:discovered_parameter_envelopes] = @project_discovered_parameter_envelopes
|
|
2015
|
+
end
|
|
2016
|
+
tables[:discovered_refinements] = @project_discovered_refinements unless @project_discovered_refinements.empty?
|
|
2017
|
+
# Issue #1367 — read by the `global.*` write rules.
|
|
2018
|
+
return if @project_discovered_global_write_census.empty?
|
|
2019
|
+
|
|
2020
|
+
tables[:discovered_global_write_census] = @project_discovered_global_write_census
|
|
2021
|
+
end
|
|
2022
|
+
|
|
2023
|
+
# The three mixin tables: the ADR-24 instance-side `include` map, its issue #1123 `prepend` twin
|
|
2024
|
+
# (which carries the instance-ancestor order the include table's set-shaped value cannot), and the
|
|
2025
|
+
# #898 singleton-side `extend` table. Grouped here because they are read as one picture of a class's
|
|
2026
|
+
# ancestry, and split out of {#project_scope_seed_tables} to keep it under the complexity budget.
|
|
2027
|
+
def seed_mixin_tables(tables)
|
|
2028
|
+
tables[:discovered_includes] = @project_discovered_includes unless @project_discovered_includes.empty?
|
|
2029
|
+
tables[:discovered_prepends] = @project_discovered_prepends unless @project_discovered_prepends.empty?
|
|
2030
|
+
tables[:discovered_extends] = @project_discovered_extends unless @project_discovered_extends.empty?
|
|
2031
|
+
end
|
|
2032
|
+
|
|
1766
2033
|
# ADR-46 slice 1 / issue #644 — the two SOURCE-ATTRIBUTION tables, read only by the recording accessors
|
|
1767
2034
|
# (`Scope#record_class_dependency` for the class-declaration map, `Scope#record_constant_dependency`
|
|
1768
|
-
# for the constant-write map). A normal run carries neither. Extracted to keep
|
|
2035
|
+
# for the constant-write map). A normal run carries neither of the two. Extracted to keep
|
|
1769
2036
|
# {#project_scope_seed_tables} under the complexity budget.
|
|
2037
|
+
#
|
|
2038
|
+
# Issue #617 — the census's binding writes, grouped by last segment, ride every run instead: a constant
|
|
2039
|
+
# compound write whose plain read resolves nothing reads its binding off them, a TYPE rather than an edge.
|
|
2040
|
+
# Issue #1290's shadowing writes ride beside them for the lexical ladder, for the same reason.
|
|
1770
2041
|
def seed_dependency_attribution_tables(tables)
|
|
2042
|
+
writers = constant_writer_index
|
|
2043
|
+
tables[:constant_writers] = writers unless writers.empty?
|
|
2044
|
+
shadowers = constant_shadower_index
|
|
2045
|
+
tables[:constant_shadowers] = shadowers unless shadowers.empty?
|
|
1771
2046
|
return unless @record_dependencies
|
|
1772
2047
|
|
|
1773
2048
|
tables[:discovered_class_sources] = @project_discovered_class_sources unless
|
|
@@ -1802,12 +2077,44 @@ module Rigor
|
|
|
1802
2077
|
tables[:published_constant_names] = names unless names.empty?
|
|
1803
2078
|
end
|
|
1804
2079
|
|
|
1805
|
-
# Issue #
|
|
1806
|
-
#
|
|
1807
|
-
#
|
|
1808
|
-
#
|
|
1809
|
-
#
|
|
1810
|
-
|
|
2080
|
+
# Issue #617 — the censused names that bind, grouped by last segment (`Scope#bound_constant_names`). A
|
|
2081
|
+
# name some write other than a memo `||=` touches always binds. A memo-only name binds once memos of its
|
|
2082
|
+
# segment span two files: either may load first and set the constant the other then reads, so only a
|
|
2083
|
+
# memo no other file shares keeps the idiom's reading. Files are counted expanded, because discovery can
|
|
2084
|
+
# walk one file under two spellings (`lib/b.rb`, `./lib/b.rb`).
|
|
2085
|
+
def constant_writer_index
|
|
2086
|
+
@constant_writer_index ||= begin
|
|
2087
|
+
memo_files = memo_files_by_segment
|
|
2088
|
+
@project_constant_writes.each_with_object({}) do |(name, by_path), index|
|
|
2089
|
+
segment = name.split("::").last
|
|
2090
|
+
next if memo_only?(by_path) && memo_files.fetch(segment).size < 2
|
|
2091
|
+
|
|
2092
|
+
(index[segment] ||= []) << name
|
|
2093
|
+
end.each_value(&:freeze).freeze
|
|
2094
|
+
end
|
|
2095
|
+
end
|
|
2096
|
+
|
|
2097
|
+
# Issue #1290 — the censused names some write other than a memo `||=` assigns, grouped by last segment
|
|
2098
|
+
# (`Scope#shadowing_constant_names`): the ones that exist whether or not an outer constant of the name
|
|
2099
|
+
# does, and so stop the lexical ladder above it. A memo-only name is left out however many files memoize
|
|
2100
|
+
# it, unlike in {#constant_writer_index}: `X ||= v` resolves `X` through the very lookup whose lower rung
|
|
2101
|
+
# the stop would replace, so wherever that rung answers, the memo finds it and never creates the name.
|
|
2102
|
+
def constant_shadower_index
|
|
2103
|
+
@constant_shadower_index ||= @project_constant_writes.each_with_object({}) do |(name, by_path), index|
|
|
2104
|
+
(index[name.split("::").last] ||= []) << name unless memo_only?(by_path)
|
|
2105
|
+
end.each_value(&:freeze).freeze
|
|
2106
|
+
end
|
|
2107
|
+
|
|
2108
|
+
def memo_files_by_segment
|
|
2109
|
+
@project_constant_writes.each_with_object({}) do |(name, by_path), files|
|
|
2110
|
+
set = (files[name.split("::").last] ||= Set.new)
|
|
2111
|
+
by_path.each { |path, descriptor| set << File.expand_path(path) if memo_descriptor?(descriptor) }
|
|
2112
|
+
end
|
|
2113
|
+
end
|
|
2114
|
+
|
|
2115
|
+
def memo_only?(by_path) = by_path.each_value.all? { |descriptor| memo_descriptor?(descriptor) }
|
|
2116
|
+
def memo_descriptor?(descriptor) = descriptor == Inference::ScopeIndexer::CONSTANT_MEMO
|
|
2117
|
+
|
|
1811
2118
|
# Issue #644 — the LAST SEGMENTS of the published table, the run-wide half of
|
|
1812
2119
|
# `Scope#published_constant?`. Seeded on EVERY run (unlike `constant_sources`, which only a recording
|
|
1813
2120
|
# run needs) because {CheckRules::PublishedConstantGuard} asks the question on every `if` / `unless`.
|
|
@@ -1816,11 +2123,57 @@ module Rigor
|
|
|
1816
2123
|
@project_constant_values.keys.to_set { |name| name.split("::").last }.freeze
|
|
1817
2124
|
end
|
|
1818
2125
|
|
|
2126
|
+
# Issue #644 — the seeded `in_source_constants` table, joining the two cross-file constant producers.
|
|
2127
|
+
# The whole-project literal table wins over a `pre_eval:` publication of the same name: both describe
|
|
2128
|
+
# the same assignment, the literal table pins the value the write actually carries while ADR-17's
|
|
2129
|
+
# widener erases it to the class, and listing a file under `pre_eval:` must never LOSE precision. The
|
|
2130
|
+
# per-file table still wins over both (`ScopeIndexer.index`'s merge) — same-file stays the most
|
|
2131
|
+
# specific authority.
|
|
1819
2132
|
def merged_seed_constants
|
|
1820
|
-
|
|
1821
|
-
return @
|
|
2133
|
+
pre_eval = publishable_pre_eval_constants
|
|
2134
|
+
return @project_constant_values if pre_eval.empty?
|
|
2135
|
+
return pre_eval if @project_constant_values.empty?
|
|
2136
|
+
|
|
2137
|
+
pre_eval.merge(@project_constant_values).freeze
|
|
2138
|
+
end
|
|
1822
2139
|
|
|
1823
|
-
|
|
2140
|
+
# Issue #663 — the `pre_eval:` publication with every name an UNLISTED file also assigns retracted.
|
|
2141
|
+
# Without this a listed `X = :a` answered `Symbol` at every reader while a sibling `X = "str"` decided
|
|
2142
|
+
# the runtime value half the time: a confident wrong type, not lost precision, and the one asymmetry
|
|
2143
|
+
# #644's precedence work left standing. The retraction costs the opt-in nothing where it earns its
|
|
2144
|
+
# keep — a name only listed files write is untouched, and where the literal table also publishes it
|
|
2145
|
+
# already won (above).
|
|
2146
|
+
#
|
|
2147
|
+
# Conflict is read off #644's write attribution, which censuses every assigning form, so a name the
|
|
2148
|
+
# listed file's own typed walk widened is retracted by an unlisted `X += 1` or `A, X = 1, 2` as
|
|
2149
|
+
# readily as by a plain reassignment. Among LISTED files the rule is unchanged: `PreEvalConstants`
|
|
2150
|
+
# widens first and drops only on disagreement, so two listed files writing `1` and `2` still publish
|
|
2151
|
+
# `Integer` rather than being retracted for being two.
|
|
2152
|
+
def publishable_pre_eval_constants
|
|
2153
|
+
return @project_pre_eval_constants if @project_pre_eval_constants.empty?
|
|
2154
|
+
|
|
2155
|
+
listed = pre_eval_path_set
|
|
2156
|
+
kept = @project_pre_eval_constants.reject { |name, _| unlisted_constant_writer?(name, listed) }
|
|
2157
|
+
kept.size == @project_pre_eval_constants.size ? @project_pre_eval_constants : kept.freeze
|
|
2158
|
+
end
|
|
2159
|
+
|
|
2160
|
+
# True when some file outside `listed` assigns `name`. The wildcard key is consulted alongside the
|
|
2161
|
+
# name's own attribution ([#668](https://github.com/rigortype/rigor/issues/668)): a `k::X = 7` names
|
|
2162
|
+
# no target, and a listed file kept out of `paths:` (ADR-17 WD5 permits it) contributes no censused
|
|
2163
|
+
# name of its own for the wildcard's paths to have been folded into.
|
|
2164
|
+
def unlisted_constant_writer?(name, listed)
|
|
2165
|
+
segment = name.split("::").last
|
|
2166
|
+
writers = @project_constant_sources[name]
|
|
2167
|
+
wildcard = @project_constant_sources["#{Inference::ScopeIndexer::DYNAMIC_TARGET_PREFIX}#{segment}"]
|
|
2168
|
+
[writers, wildcard].any? do |paths|
|
|
2169
|
+
paths&.any? { |path| !listed.include?(File.expand_path(path)) }
|
|
2170
|
+
end
|
|
2171
|
+
end
|
|
2172
|
+
|
|
2173
|
+
# The listed `pre_eval:` files, expanded so a census path and a configured one compare as the same
|
|
2174
|
+
# file whichever spelling each arrived in.
|
|
2175
|
+
def pre_eval_path_set
|
|
2176
|
+
@pre_eval_path_set ||= @configuration.pre_eval.to_set { |path| File.expand_path(path) }
|
|
1824
2177
|
end
|
|
1825
2178
|
|
|
1826
2179
|
# ADR-46 — seed the instance + singleton `"path:line"` def-source tables (each only when non-empty).
|
|
@@ -1865,10 +2218,11 @@ module Rigor
|
|
|
1865
2218
|
def analyze_with_effects(path, environment)
|
|
1866
2219
|
return analyze_file_body(path, environment) unless @record_effects
|
|
1867
2220
|
|
|
2221
|
+
entry = template_units[path]
|
|
1868
2222
|
diagnostics = nil
|
|
1869
2223
|
collection = Effects::Collector.collect_for(
|
|
1870
2224
|
path, attribution: @effect_attribution, envelopes: effect_envelope_index(environment),
|
|
1871
|
-
plugin_facts: effect_plugin_facts
|
|
2225
|
+
plugin_facts: effect_plugin_facts, unit_key: entry&.unit_key, unit_owner: entry&.self_type
|
|
1872
2226
|
) do
|
|
1873
2227
|
diagnostics = analyze_file_body(path, environment)
|
|
1874
2228
|
end
|
|
@@ -1907,7 +2261,9 @@ module Rigor
|
|
|
1907
2261
|
# is a per-FILE site, so one `Thread.current` read is already nothing. The per-dispatch site in
|
|
1908
2262
|
# `ExpressionTyper#call_type_for` is the one that pays for the integer fast path.
|
|
1909
2263
|
Effects::Collector.record_root(parse_result.value)
|
|
1910
|
-
scope =
|
|
2264
|
+
scope = template_units.seed(
|
|
2265
|
+
seed_project_scope(Scope.empty(environment: environment, source_path: path)), path
|
|
2266
|
+
)
|
|
1911
2267
|
# ADR-24 slice 4a/4 — record unresolved implicit-self calls during the typing pass ONLY (not
|
|
1912
2268
|
# CheckRules, whose own `type_of` queries would otherwise re-trigger the choke-point).
|
|
1913
2269
|
# `self_call_misses` feeds the `call.self-undefined-method` collector; the recorder is inert unless
|
|
@@ -1947,7 +2303,7 @@ module Rigor
|
|
|
1947
2303
|
# output and the plugin diagnostics are then built from that single walk's results.
|
|
1948
2304
|
def rule_and_plugin_diagnostics(path, parse_result, scope, index, self_call_misses)
|
|
1949
2305
|
root = parse_result.value
|
|
1950
|
-
node_collectors = CheckRules.build_node_collectors(path, index)
|
|
2306
|
+
node_collectors = CheckRules.build_node_collectors(path, index, root)
|
|
1951
2307
|
node_results = node_rule_results_by_plugin(path, root, scope, node_collectors, index)
|
|
1952
2308
|
diagnostics = CheckRules.diagnose(
|
|
1953
2309
|
path: path,
|