rigortype 0.4.5 → 0.4.7
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/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +61 -5
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +192 -27
- data/docs/manual/03-configuration.md +38 -4
- data/docs/manual/04-diagnostics.md +1 -1
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +47 -3
- data/docs/manual/12-caching.md +9 -1
- data/docs/manual/plugins/rigor-actionmailer.md +30 -0
- data/docs/manual/plugins/rigor-actionpack.md +49 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/docs/manual/plugins/rigor-devise.md +15 -0
- data/docs/manual/plugins/rigor-rspec.md +2 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/buffer_binding.rb +14 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +105 -12
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +143 -15
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +4 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +66 -3
- data/lib/rigor/analysis/check_rules/rebinding_block_callees/dispatch.rb +112 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +394 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +7 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +53 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +217 -52
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +15 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +154 -0
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +37 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +202 -43
- data/lib/rigor/analysis/path_expansion.rb +41 -0
- data/lib/rigor/analysis/require_relative_closure.rb +100 -0
- data/lib/rigor/analysis/rule_catalog.rb +7 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +80 -0
- data/lib/rigor/analysis/run_disclosure_ledger.rb +155 -0
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +8 -4
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +204 -96
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +157 -320
- data/lib/rigor/analysis/runner/project_pre_passes.rb +48 -6
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/scan_environment.rb +51 -0
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +233 -120
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +38 -33
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +60 -18
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +188 -93
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +27 -21
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +17 -13
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +14 -8
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +60 -4
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +22 -18
- data/lib/rigor/cli/plugins_renderer.rb +34 -8
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +23 -16
- data/lib/rigor/cli/sig_gen_command.rb +130 -34
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +18 -12
- data/lib/rigor/cli/type_of_project_scope.rb +24 -0
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +17 -6
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +86 -34
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +592 -70
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +136 -32
- data/lib/rigor/environment/ruby_library_roots.rb +122 -0
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +44 -11
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +126 -0
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +170 -0
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +204 -12
- data/lib/rigor/inference/definer_resolution.rb +21 -5
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/error_info.rb +17 -3
- data/lib/rigor/inference/expression_typer.rb +173 -57
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +110 -1
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +246 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +57 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +65 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +113 -12
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -3
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +59 -24
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +109 -29
- data/lib/rigor/inference/module_function_state/spellings.rb +64 -0
- data/lib/rigor/inference/module_function_state.rb +23 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +162 -29
- data/lib/rigor/inference/narrowing.rb +113 -38
- data/lib/rigor/inference/object_mixins.rb +13 -1
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_seed_tables.rb +2 -1
- data/lib/rigor/inference/project_yielder.rb +122 -0
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +9 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_ivar_types.rb +64 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +205 -0
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer/unseen_ivar_writers.rb +133 -0
- data/lib/rigor/inference/scope_indexer.rb +614 -146
- data/lib/rigor/inference/self_call_ivar_writes.rb +101 -17
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +3036 -278
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_index.rb +23 -0
- data/lib/rigor/inference/synthetic_method_scanner/project_members.rb +130 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +73 -14
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +9 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +28 -9
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +98 -4
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +12 -6
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +82 -3
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +26 -11
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +38 -16
- data/lib/rigor/plugin/registry.rb +41 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +96 -2
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +25 -2
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +379 -36
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +668 -84
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +7 -6
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/rbs_validity.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +21 -12
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_elaborator.rb +21 -5
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +13 -16
- data/lib/rigor/type/constant.rb +48 -7
- data/lib/rigor/type/hash_shape.rb +26 -40
- data/lib/rigor/type/struct_instance.rb +3 -2
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +89 -70
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +25 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +79 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +6 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +5 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +7 -6
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +102 -11
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +5 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +1 -1
- data/sig/rigor/analysis/baseline.rbs +0 -2
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/file_collection.rbs +5 -6
- data/sig/rigor/effects/registry.rbs +8 -6
- data/sig/rigor/effects/summary.rbs +6 -5
- data/sig/rigor/environment.rbs +5 -3
- data/sig/rigor/inference/optimistic_origin.rbs +11 -0
- data/sig/rigor/inference.rbs +10 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_ancestry.rbs +6 -4
- data/sig/rigor/plugin/effect_attribution.rbs +25 -10
- data/sig/rigor/plugin/effect_edge.rbs +12 -5
- data/sig/rigor/plugin/effect_entry_points.rbs +8 -3
- data/sig/rigor/plugin/io_boundary.rbs +6 -5
- data/sig/rigor/plugin/manifest.rbs +16 -18
- data/sig/rigor/plugin/protocol_contract.rbs +6 -9
- data/sig/rigor/plugin/registry.rbs +1 -1
- data/sig/rigor/scope.rbs +51 -50
- data/sig/rigor/type.rbs +0 -6
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +55 -3
|
@@ -5,6 +5,7 @@ require "prism"
|
|
|
5
5
|
require "tmpdir"
|
|
6
6
|
|
|
7
7
|
require_relative "../environment"
|
|
8
|
+
require_relative "../run_scoped_slots"
|
|
8
9
|
require_relative "../scope"
|
|
9
10
|
require_relative "../cache/store"
|
|
10
11
|
require_relative "../cache/rbs_descriptor"
|
|
@@ -12,6 +13,8 @@ require_relative "../cache/file_digest"
|
|
|
12
13
|
require_relative "../cache/incremental_snapshot"
|
|
13
14
|
require_relative "run_cache_key"
|
|
14
15
|
require_relative "path_expansion"
|
|
16
|
+
require_relative "require_relative_closure"
|
|
17
|
+
require_relative "run_disclosure_credit"
|
|
15
18
|
require_relative "../plugin"
|
|
16
19
|
require_relative "../plugin/source_rbs_synthesis_reporter"
|
|
17
20
|
require_relative "../rbs_extended/reporter"
|
|
@@ -75,18 +78,20 @@ module Rigor
|
|
|
75
78
|
# this and serves reused files from it without re-stamping: a run-level row is regenerated
|
|
76
79
|
# every run wherever it is positioned, and slicing the run's full stream by path cached the
|
|
77
80
|
# file-positioned ones (`effect.annotations-unchecked`, `source-rbs-*`).
|
|
78
|
-
:per_file_diagnostics
|
|
81
|
+
:per_file_diagnostics,
|
|
82
|
+
# PR #2286 review M1 — the ADR-16 index this run's pre-pass built; `IncrementalSession` digests it
|
|
83
|
+
# to tell when a class-body DSL edit moved what a served file's dispatch read.
|
|
84
|
+
:synthetic_method_index
|
|
79
85
|
|
|
80
86
|
# Issues #796 / #794 — the two run-level rows a NARROWED run cannot re-derive from the files it
|
|
81
87
|
# analyses: the `definition-build-failed` set (whose producer is the analysis's own demand, and #696
|
|
82
88
|
# forbids Rigor demanding in its place) and the HKT-scan outcome (whose producer is an environment a
|
|
83
89
|
# nothing-changed recheck otherwise has no reason to build). {IncrementalSession} persists what a full
|
|
84
90
|
# run answers here and hands it back to the next narrowed run.
|
|
91
|
+
#
|
|
92
|
+
# Which rows those are is declared, not listed: every {RunLevelFacts} fact marked `replay`.
|
|
85
93
|
def run_level_rows
|
|
86
|
-
Cache::IncrementalSnapshot::RunLevelRows.new(
|
|
87
|
-
definition_build_failures: @snapshots.definition_build_failures,
|
|
88
|
-
hkt_scan_failure: @snapshots.hkt_scan_failure
|
|
89
|
-
)
|
|
94
|
+
Cache::IncrementalSnapshot::RunLevelRows.new(**@snapshots.to_h.slice(*RunLevelFacts.replayable_names))
|
|
90
95
|
end
|
|
91
96
|
|
|
92
97
|
# ADR-46 — the per-file cross-file read records this run captured (empty unless
|
|
@@ -109,6 +114,13 @@ module Rigor
|
|
|
109
114
|
pooled.empty? ? @analysis_reads : @analysis_reads.merge(pooled)
|
|
110
115
|
end
|
|
111
116
|
|
|
117
|
+
# Issue #2020 — `{path => [run-disclosure record]}`, the run-scoped rows each analysed file's plugin hooks
|
|
118
|
+
# registered ({RunDisclosureCredit}), sequential and pooled alike; empty unless `record_dependencies:`.
|
|
119
|
+
def analysis_disclosures
|
|
120
|
+
pooled = @pool_coordinator.collected_analysis_disclosures
|
|
121
|
+
pooled.empty? ? @analysis_disclosures : @analysis_disclosures.merge(pooled)
|
|
122
|
+
end
|
|
123
|
+
|
|
112
124
|
# ADR-103 — the run's propagated effect graph, or {Effects::EffectTable.empty} when collection did
|
|
113
125
|
# not run. Reconciled from the sequential and pooled halves exactly as {#file_dependencies} is, then
|
|
114
126
|
# closed by the post-pool fixpoint in {#assemble_run_diagnostics}.
|
|
@@ -268,8 +280,7 @@ module Rigor
|
|
|
268
280
|
# @param explain — surface fail-soft fallback events as `:info` diagnostics.
|
|
269
281
|
# @param cache_store — the persistent cache the runner exposes to producers
|
|
270
282
|
# (`RbsConstantTable` and successors). Pass `nil` to disable caching for this run; the CLI's
|
|
271
|
-
# `--no-cache` flag wires `nil` through.
|
|
272
|
-
# slices route real producers through it.
|
|
283
|
+
# `--no-cache` flag wires `nil` through.
|
|
273
284
|
# @param workers — ADR-15 Phase 4b — when greater than zero, per-file analysis dispatches
|
|
274
285
|
# across a pool of N workers. Default `0` keeps the sequential code path bit-for-bit unchanged.
|
|
275
286
|
# Controlled via the `RIGOR_RACTOR_WORKERS` env var or `.rigor.yml` `parallel.workers:` (Phase 4c,
|
|
@@ -294,10 +305,11 @@ module Rigor
|
|
|
294
305
|
# worker continues to build its own Environment.
|
|
295
306
|
# @param discovery_seed — issue #260 — opt-in cross-file discovery tables, keyed by
|
|
296
307
|
# {Scope::DiscoveryIndex} slot name, seeded onto every per-file scope through
|
|
297
|
-
# `project_scope_seed_tables`.
|
|
298
|
-
#
|
|
299
|
-
# judges anchors against,
|
|
300
|
-
#
|
|
308
|
+
# `project_scope_seed_tables`. A `prebuilt:` runner computes no discovery tables of its own, so this is
|
|
309
|
+
# how one learns the project: {Protection::DiagnosticOracle} threads the table set Tier 2's site filter
|
|
310
|
+
# already judges anchors against, and (issue #2147, ADR-124) the LSP's per-buffer publish threads
|
|
311
|
+
# `LanguageServer::ProjectContext#discovery_seed_for`, so a class another file declares is not an
|
|
312
|
+
# external ancestor there. nil (the default) seeds nothing.
|
|
301
313
|
# @param no_tolerated_effects — ADR-103 WD1 / #385 — `rigor check --no-tolerated-effects`.
|
|
302
314
|
# Judges effect envelopes as if `effects.tolerated:` were empty. A judgment-time switch only: the
|
|
303
315
|
# run, its collection and its cache identity are unchanged.
|
|
@@ -309,7 +321,7 @@ module Rigor
|
|
|
309
321
|
seed_bundles: nil, collect_seed_bundles: false, param_inferred_types: nil,
|
|
310
322
|
discovery_seed: nil, no_tolerated_effects: false,
|
|
311
323
|
restored_run_level_rows: nil, served_per_file_diagnostics: nil, served_effect_collections: nil,
|
|
312
|
-
on_file_indexed: nil)
|
|
324
|
+
served_run_disclosures: nil, on_file_indexed: nil)
|
|
313
325
|
@configuration = configuration
|
|
314
326
|
# ADR-113 WD2 — `rigor lens` reads a target's seeded index here: called with `(path, parse_result, scope,
|
|
315
327
|
# index)` for every file this process indexes, after its rules ran and inside the run window, so the reader
|
|
@@ -327,6 +339,9 @@ module Rigor
|
|
|
327
339
|
# effect graph this run closes (and the envelope pass judges) spans the whole project, not just the closure.
|
|
328
340
|
# Never part of {#effect_collections_by_path}, which stays what THIS run collected. Empty on every other run.
|
|
329
341
|
@served_effect_collections = served_effect_collections || {}
|
|
342
|
+
# Issue #2020 — the run-scoped plugin rows ({RunDisclosureCredit}) those unanalysed files registered when
|
|
343
|
+
# they were last analysed, emitted beside this run's own registrations. Empty on every other run.
|
|
344
|
+
@served_run_disclosures = served_run_disclosures || []
|
|
330
345
|
@explain = explain
|
|
331
346
|
@cache_store = enforce_read_only_cache(cache_store, buffer)
|
|
332
347
|
@plugin_requirer = plugin_requirer
|
|
@@ -336,8 +351,8 @@ module Rigor
|
|
|
336
351
|
@prebuilt = prebuilt
|
|
337
352
|
@environment_override = environment
|
|
338
353
|
# ADR-46 slice 1 — opt-in cross-file dependency recording. Off by default; when true,
|
|
339
|
-
# `analyze_file` records each file's cross-file reads into `file_dependencies
|
|
340
|
-
# cache
|
|
354
|
+
# `analyze_file` records each file's cross-file reads into `file_dependencies`; the incremental
|
|
355
|
+
# cache consumes them.
|
|
341
356
|
@record_dependencies = record_dependencies
|
|
342
357
|
# ADR-24 slice 4a — opt-in unresolved-implicit-self-call recording. Off by default; when true,
|
|
343
358
|
# `analyze_file` activates the engine choke-point recorder and collects each file's misses into
|
|
@@ -382,6 +397,7 @@ module Rigor
|
|
|
382
397
|
# rows as they stood around the per-file loop; see {#incremental_slot_rows}. Recorded only by a
|
|
383
398
|
# dependency-recording (incremental) run.
|
|
384
399
|
@analysis_reads = {}
|
|
400
|
+
@analysis_disclosures = {}
|
|
385
401
|
@pre_analysis_plugin_rows = nil
|
|
386
402
|
@post_analysis_plugin_rows = nil
|
|
387
403
|
# Memoised activation decision for the `call.self-undefined-method` rule (nil = not yet computed).
|
|
@@ -496,6 +512,9 @@ module Rigor
|
|
|
496
512
|
# entry across a run boundary (LSP re-check, ADR-62 warm loop); nil until the first run so
|
|
497
513
|
# runner-less probes keep the per-file fallback.
|
|
498
514
|
@run_generation = nil
|
|
515
|
+
# The return memo bucket the last `run` filled, kept for {#return_summaries} once the run has released the
|
|
516
|
+
# thread's slot; nil before the first run.
|
|
517
|
+
@return_memo = nil
|
|
499
518
|
build_collaborators
|
|
500
519
|
end
|
|
501
520
|
|
|
@@ -518,9 +537,39 @@ module Rigor
|
|
|
518
537
|
# freshness path for this run; the `auto` default resolves strict in CI (#190), stat-first elsewhere.
|
|
519
538
|
Cache::FileDigest.with_run(strict: @configuration.cache_validation_strict?) do
|
|
520
539
|
Inference::DefNodeResolver.with_run { run_analysis(paths) }
|
|
540
|
+
ensure
|
|
541
|
+
# ADR-89 WD2 — {#return_summaries} reads the return memo after the run, so the runner keeps the bucket the
|
|
542
|
+
# run filled before the thread's run-scoped slots are released (issues #2412, #2399).
|
|
543
|
+
@return_memo = Inference::ExpressionTyper.current_return_memo
|
|
544
|
+
RunScopedSlots.release
|
|
521
545
|
end
|
|
522
546
|
end
|
|
523
547
|
|
|
548
|
+
# ADR-45 WD2 (#1507) / #2020 — the per-run reset of what each file's analysis is credited with: its plugin
|
|
549
|
+
# reads, its run-scoped plugin registrations, and the boundary rows around the per-file loop.
|
|
550
|
+
def reset_analysis_attribution
|
|
551
|
+
@analysis_reads = {}
|
|
552
|
+
@analysis_disclosures = {}
|
|
553
|
+
@pre_analysis_plugin_rows = nil
|
|
554
|
+
@post_analysis_plugin_rows = nil
|
|
555
|
+
end
|
|
556
|
+
private :reset_analysis_attribution
|
|
557
|
+
|
|
558
|
+
# Issue #2392 — the sequential half of the per-run reset, beside {#reset_analysis_attribution}: the
|
|
559
|
+
# dependency graph and per-file effect collections a `--workers 0` run records, and the effect-slot state a
|
|
560
|
+
# served run leaves behind. The loader is the one that matters: a served run's collections loader would
|
|
561
|
+
# otherwise feed the next analysing run the previous run's collections. Runs before any `adopt_*`, which the
|
|
562
|
+
# served lanes call later in the same run, so an adopted slot is this run's own.
|
|
563
|
+
def reset_sequential_run_tables
|
|
564
|
+
@file_dependencies = {}
|
|
565
|
+
@file_effects = {}
|
|
566
|
+
@cached_effect_sources = nil
|
|
567
|
+
@cached_effect_ancestry = nil
|
|
568
|
+
@cached_collections_loader = nil
|
|
569
|
+
@effects_served_from_cache = false
|
|
570
|
+
end
|
|
571
|
+
private :reset_sequential_run_tables
|
|
572
|
+
|
|
524
573
|
def run_analysis(paths)
|
|
525
574
|
Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths =
|
|
526
575
|
@configuration.fold_platform_specific_paths
|
|
@@ -534,6 +583,10 @@ module Rigor
|
|
|
534
583
|
@project_discovery_expansion = project_discovery_expansion(paths, expansion)
|
|
535
584
|
@discovery_widened = widen_discovery_to_project?(paths)
|
|
536
585
|
@snapshots.reset_for_run
|
|
586
|
+
# Issue #2392 — the coordinator's run-accumulated tables (disclosures, trust refusals, the dependency and
|
|
587
|
+
# effect graphs) are per run too: a reused Runner must not re-emit or sum the previous run's rows.
|
|
588
|
+
@pool_coordinator.reset_for_run
|
|
589
|
+
reset_sequential_run_tables
|
|
537
590
|
# Per-run reset of the deferred-discovery memo (see `#ensure_project_discovery`).
|
|
538
591
|
@project_discovery_done = false
|
|
539
592
|
# #392 — re-derive the template units each run: their source files can change between two runs of
|
|
@@ -548,9 +601,7 @@ module Rigor
|
|
|
548
601
|
# #788 — the per-file reader is assigned only on the analysis (miss) path; reset it here so a run the
|
|
549
602
|
# ADR-45 result cache serves does not answer with the previous run's rows.
|
|
550
603
|
@per_file_diagnostics = [].freeze
|
|
551
|
-
|
|
552
|
-
@pre_analysis_plugin_rows = nil
|
|
553
|
-
@post_analysis_plugin_rows = nil
|
|
604
|
+
reset_analysis_attribution
|
|
554
605
|
# ADR-84 WD2 — roll the return-memo bucket: a fresh frozen token per run makes every per-file scope
|
|
555
606
|
# of THIS run share one memo bucket while entries from any earlier run in this process (stale after
|
|
556
607
|
# an edit) become unreachable.
|
|
@@ -743,9 +794,10 @@ module Rigor
|
|
|
743
794
|
# arg-flooring surface). Only meaningful right after a run populated the memo (baseline / recheck),
|
|
744
795
|
# before the bucket rolls. Keys are held live here; the session Marshals them for the snapshot.
|
|
745
796
|
#
|
|
746
|
-
# @return `
|
|
797
|
+
# @return the summaries keyed by `[path, "Class#method"]` (or `"Class.method"`), each holding `keys:`,
|
|
798
|
+
# `returns:` and `effects:`.
|
|
747
799
|
def return_summaries
|
|
748
|
-
memo = Inference::ExpressionTyper.harvest_return_memo
|
|
800
|
+
memo = Inference::ExpressionTyper.harvest_return_memo(@return_memo)
|
|
749
801
|
return {} if memo.empty?
|
|
750
802
|
|
|
751
803
|
result = {}
|
|
@@ -803,13 +855,15 @@ module Rigor
|
|
|
803
855
|
#
|
|
804
856
|
# @param paths — analysis roots (nil → the configuration's `paths:`).
|
|
805
857
|
# @param specs — each `{ class_name:, method_name:, singleton:, keys: [[receiver, args], …] }`.
|
|
806
|
-
# @return
|
|
858
|
+
# @return the re-evaluated return descriptors, one per key, keyed by `[class_name, method_name, singleton]`.
|
|
807
859
|
def evaluate_return_types(paths, specs)
|
|
808
860
|
return {} if specs.empty?
|
|
809
861
|
|
|
810
862
|
Cache::FileDigest.with_run(strict: @configuration.cache_validation_strict?) do
|
|
811
863
|
Inference::DefNodeResolver.with_run { evaluate_return_types_setup(paths, specs) }
|
|
812
864
|
end
|
|
865
|
+
ensure
|
|
866
|
+
RunScopedSlots.release
|
|
813
867
|
end
|
|
814
868
|
|
|
815
869
|
# Builds the discovery index + environment (a real run's prologue, minus per-file analysis) and
|
|
@@ -996,17 +1050,12 @@ module Rigor
|
|
|
996
1050
|
nil
|
|
997
1051
|
end
|
|
998
1052
|
|
|
999
|
-
# The write half, run only after a miss, so
|
|
1000
|
-
# collections the analysis just produced — and the table the analysis already closed over them, so
|
|
1001
|
-
# a warm hit re-runs neither the merge nor the fixpoint — validated against the same post-run
|
|
1002
|
-
# dependency descriptor the diagnostics slot records. Fail-soft — a collection that will not
|
|
1003
|
-
# Marshal (which nothing in {Effects::FileCollection} should be, and the fork pool already proves
|
|
1004
|
-
# per file) costs the next run its warm start and nothing else.
|
|
1005
|
-
# The write half, run only after a miss, so neither block recomputes anything. Two entries under one
|
|
1053
|
+
# The write half, run only after a miss, so nothing here recomputes anything. Two entries under one
|
|
1006
1054
|
# key descriptor and one dependency descriptor (#482): the summary a warm run serves from, and the
|
|
1007
1055
|
# collections the incremental and fail-soft paths read. The summary is written LAST, so a run
|
|
1008
1056
|
# interrupted between the two leaves a collections entry that the next run's summary miss simply
|
|
1009
|
-
# re-collects — never a summary whose collections are absent.
|
|
1057
|
+
# re-collects — never a summary whose collections are absent. A collection that will not Marshal
|
|
1058
|
+
# costs the next run its warm start and nothing else.
|
|
1010
1059
|
def store_effect_collections(descriptor, expansion, rbs_descriptor)
|
|
1011
1060
|
return if descriptor.nil?
|
|
1012
1061
|
|
|
@@ -1208,40 +1257,13 @@ module Rigor
|
|
|
1208
1257
|
end
|
|
1209
1258
|
private :template_unit_failure_diagnostics
|
|
1210
1259
|
|
|
1211
|
-
#
|
|
1212
|
-
#
|
|
1213
|
-
#
|
|
1214
|
-
#
|
|
1215
|
-
#
|
|
1216
|
-
# run.
|
|
1260
|
+
# Every remaining post-analysis stream `#assemble_run_diagnostics` appends — the `rbs.coverage.*`
|
|
1261
|
+
# build-failure ladder (widest consequence first: quarantine, env build, definition build #696, HKT scan
|
|
1262
|
+
# #784), its notices, the conformance rows, the reporter streams, the plugin run disclosures (#1051)
|
|
1263
|
+
# and, last, the trust-refusal envelope (#959) — in the contract order ADR-116 WD3's
|
|
1264
|
+
# {RunLevelFacts} declares. Read after `analyze_targets`, so every worker payload has been merged.
|
|
1217
1265
|
def post_analysis_diagnostic_streams
|
|
1218
|
-
|
|
1219
|
-
diagnostics += @diagnostic_aggregator.rbs_environment_build_failed_diagnostics
|
|
1220
|
-
# Issue #696 — after its env-wide twin and before the synthesized-namespace notice: the four
|
|
1221
|
-
# `rbs.coverage.*` build conditions surface widest-consequence first, and their relative order is
|
|
1222
|
-
# the diagnostic output contract.
|
|
1223
|
-
diagnostics += @diagnostic_aggregator.rbs_definition_build_failed_diagnostics
|
|
1224
|
-
# Issue #784 — last of the four, deliberately: it loses only the IMPLICIT HKT registrations a
|
|
1225
|
-
# `type` alias would have contributed, never a class's own declared method surface, so it is the
|
|
1226
|
-
# narrowest-consequence rung on the same ladder.
|
|
1227
|
-
diagnostics += @diagnostic_aggregator.rbs_hkt_scan_failed_diagnostics
|
|
1228
|
-
# The synthesized-namespace notice, then (#610) the plugin-signature stand-down: the outcome that
|
|
1229
|
-
# AVOIDED a definition-build failure, so the quietest row on that ladder.
|
|
1230
|
-
diagnostics += @diagnostic_aggregator.rbs_coverage_notice_diagnostics
|
|
1231
|
-
diagnostics += @diagnostic_aggregator.conforms_to_diagnostics
|
|
1232
|
-
diagnostics += @diagnostic_aggregator.rbs_extended_reporter_diagnostics
|
|
1233
|
-
diagnostics += @diagnostic_aggregator.boundary_cross_diagnostics
|
|
1234
|
-
diagnostics += @diagnostic_aggregator.source_rbs_synthesis_diagnostics
|
|
1235
|
-
# Issue #1051 — read after `analyze_targets` for the same reason the refusal stream below is: a
|
|
1236
|
-
# plugin may register a disclosure from `#prepare` (the usual case) or while analysing a file, and
|
|
1237
|
-
# both have to be in before the table is harvested. Ordered before the refusals so the run-level
|
|
1238
|
-
# plugin rows read plugin-authored notice first, engine-authored envelope second.
|
|
1239
|
-
diagnostics += @diagnostic_aggregator.plugin_run_disclosure_diagnostics
|
|
1240
|
-
# Issue #959 — read LAST (after `analyze_targets`, which already ran before this method is called),
|
|
1241
|
-
# so every per-file plugin call has had its chance to record a refusal on its (per-plugin-instance
|
|
1242
|
-
# memoised) `IoBoundary`, alongside the prepare-time refusals the same boundary instance may
|
|
1243
|
-
# already carry.
|
|
1244
|
-
diagnostics + @diagnostic_aggregator.plugin_trust_refusal_diagnostics
|
|
1266
|
+
@diagnostic_aggregator.run_level_diagnostics
|
|
1245
1267
|
end
|
|
1246
1268
|
private :post_analysis_diagnostic_streams
|
|
1247
1269
|
|
|
@@ -1414,7 +1436,7 @@ module Rigor
|
|
|
1414
1436
|
end
|
|
1415
1437
|
|
|
1416
1438
|
def build_run_dependency_descriptor(expansion, rbs_descriptor)
|
|
1417
|
-
entries = analyzed_file_entries(expansion) + discovery_file_entries(expansion) +
|
|
1439
|
+
entries = analyzed_file_entries(expansion) + discovery_file_entries(expansion) + required_missing_entries +
|
|
1418
1440
|
pre_eval_file_entries + template_unit_file_entries + rbs_descriptor.files +
|
|
1419
1441
|
root_presence_entries(expansion)
|
|
1420
1442
|
# #979 — the signature ROOTS' listings, one glob row each. `rbs_descriptor.files` covers only the
|
|
@@ -1509,7 +1531,8 @@ module Rigor
|
|
|
1509
1531
|
IncrementalSlotRows.new(
|
|
1510
1532
|
observed: plugin_boundary_rows,
|
|
1511
1533
|
derived: Cache::Descriptor.new(
|
|
1512
|
-
files: template_unit_file_entries + kind_entries(Array(roots) + @configuration.pre_eval)
|
|
1534
|
+
files: template_unit_file_entries + kind_entries(Array(roots) + @configuration.pre_eval) +
|
|
1535
|
+
required_missing_entries,
|
|
1513
1536
|
globs: template_unit_glob_entries
|
|
1514
1537
|
),
|
|
1515
1538
|
by_file: @analysis_reads.transform_values do |reads|
|
|
@@ -1557,7 +1580,9 @@ module Rigor
|
|
|
1557
1580
|
# change time it cannot read, and passes over a `pinned` one.
|
|
1558
1581
|
BaselineRows = Data.define(:owned, :pinned)
|
|
1559
1582
|
|
|
1560
|
-
|
|
1583
|
+
# A loader's two readers {Cache::RbsDescriptor} takes signature roots from. `core_root` (issue #2517) is the
|
|
1584
|
+
# selected core, which the slot key names by path only, so its files are `owned` rows like the project's own.
|
|
1585
|
+
SignatureRoots = Struct.new(:signature_paths, :core_root)
|
|
1561
1586
|
private_constant :SignatureRoots
|
|
1562
1587
|
|
|
1563
1588
|
# @param files — the run's analysed-path set.
|
|
@@ -1568,7 +1593,8 @@ module Rigor
|
|
|
1568
1593
|
BaselineRows.new(
|
|
1569
1594
|
owned: Cache::Descriptor.new(
|
|
1570
1595
|
files: own.files + kind_entries(signature_root_candidates) +
|
|
1571
|
-
discovery_file_entries({ files: files }) +
|
|
1596
|
+
discovery_file_entries({ files: files }) + required_missing_entries +
|
|
1597
|
+
unanalysed_pre_eval_entries(files),
|
|
1572
1598
|
globs: (own.globs + discovery_glob_entries).uniq
|
|
1573
1599
|
),
|
|
1574
1600
|
pinned: pinned
|
|
@@ -1577,8 +1603,9 @@ module Rigor
|
|
|
1577
1603
|
|
|
1578
1604
|
# The signature tree's rows, the project's own and the rest.
|
|
1579
1605
|
def signature_rows
|
|
1580
|
-
roots = SignatureRoots.new(@snapshots.signature_paths)
|
|
1581
|
-
own = signature_root_candidates
|
|
1606
|
+
roots = SignatureRoots.new(@snapshots.signature_paths, @configuration.core_root)
|
|
1607
|
+
own = (signature_root_candidates + [@configuration.core_root].compact)
|
|
1608
|
+
.map { |root| File.join(File.absolute_path(root.to_s), "") }
|
|
1582
1609
|
own_files, other_files = Cache::RbsDescriptor.file_entries(roots, comparator: :stat)
|
|
1583
1610
|
.partition { |row| within?(row.path, own) }
|
|
1584
1611
|
own_globs, other_globs = Cache::RbsDescriptor.glob_entries(roots).partition { |row| within?(row.root, own) }
|
|
@@ -1808,20 +1835,19 @@ module Rigor
|
|
|
1808
1835
|
end
|
|
1809
1836
|
|
|
1810
1837
|
# Internal: builds the deferred cross-file discovery tables at most once per run and adopts them.
|
|
1811
|
-
# Memoised on `@project_discovery_done` (reset at the start of `#run`). No-op under `@prebuilt
|
|
1812
|
-
#
|
|
1813
|
-
#
|
|
1814
|
-
#
|
|
1815
|
-
#
|
|
1816
|
-
#
|
|
1817
|
-
# cache HIT (which never assembles) never pays the double parse.
|
|
1838
|
+
# Memoised on `@project_discovery_done` (reset at the start of `#run`). No-op under `@prebuilt`: the
|
|
1839
|
+
# snapshot carries no discovery tables, and a per-request re-walk of the project is what `prebuilt:` exists
|
|
1840
|
+
# to avoid. A caller that wants cross-file knowledge under `prebuilt:` supplies it through `discovery_seed:`
|
|
1841
|
+
# (issue #260), as the LSP publish does since issue #2147 (ADR-124). Called eagerly from `#run` for the
|
|
1842
|
+
# recording / subset (ADR-46) modes and lazily from `#assemble_run_diagnostics` on the analysis path, so a
|
|
1843
|
+
# warm cache HIT (which never assembles) never pays the double parse.
|
|
1818
1844
|
def ensure_project_discovery(expansion)
|
|
1819
1845
|
return if @prebuilt
|
|
1820
1846
|
return if @project_discovery_done
|
|
1821
1847
|
|
|
1822
1848
|
@project_discovery_done = true
|
|
1823
1849
|
# Issue #684 — the cross-file index spans the PROJECT even when the analysis targets a file list.
|
|
1824
|
-
expansion = @project_discovery_expansion || once_each(expansion)
|
|
1850
|
+
expansion = buffer_spelled(@project_discovery_expansion || once_each(expansion))
|
|
1825
1851
|
if @collect_seed_bundles
|
|
1826
1852
|
# ADR-85 WD2 — rebuild discovery from the prior run's bundles (re-walking only changed files) and
|
|
1827
1853
|
# capture the refreshed bundle set for the session to persist.
|
|
@@ -1853,7 +1879,13 @@ module Rigor
|
|
|
1853
1879
|
# on what else was on the command line.
|
|
1854
1880
|
#
|
|
1855
1881
|
# Excluded, each because its expansion is already the one it means: the LSP `prebuilt:` path (which
|
|
1856
|
-
# seeds discovery from a snapshot
|
|
1882
|
+
# seeds discovery from a snapshot, ADR-124) and `run_source`'s in-memory single file.
|
|
1883
|
+
#
|
|
1884
|
+
# Issue #2165 — editor `buffer:` mode (`rigor check --tmp-file T --instead-of F F`) widens like a plain run.
|
|
1885
|
+
# It was excluded on the reading that its expansion is already the one it means, but an editor passes the
|
|
1886
|
+
# buffer's own path, so discovery saw that file alone: every class another file declares read as an external
|
|
1887
|
+
# ancestor, and the run reported what `rigor check F` does not. The discovery pre-pass reads through the
|
|
1888
|
+
# binding, so the buffer's file is walked from the buffer's bytes.
|
|
1857
1889
|
#
|
|
1858
1890
|
# Issue #1583 — ADR-46's `analyze_only` subset mode widens like a full run. It was excluded on the
|
|
1859
1891
|
# reading that it "already passes the full expansion", which holds only when the incremental session
|
|
@@ -1867,15 +1899,51 @@ module Rigor
|
|
|
1867
1899
|
# the pre-pass then saw two writers for every constant a file declares and withheld its publication (#644),
|
|
1868
1900
|
# and every file was a discovered-not-analysed dependency of the run's cache entry.
|
|
1869
1901
|
#
|
|
1902
|
+
# Issue #2021 — an analysed file outside the configured paths has no project there, so the widened set also
|
|
1903
|
+
# holds what it loads with a literal `require_relative` ({#required_outside_paths}). A plugin file checked on
|
|
1904
|
+
# its own otherwise missed its sibling's nested `Effects` and resolved the project's `Rigor::Effects`.
|
|
1905
|
+
#
|
|
1870
1906
|
# The widening decision itself compares the paths as spelled. `exclude:` patterns apply to both spellings
|
|
1871
1907
|
# alike (#1576), so the configured absolute `lib` and the argument `lib` exclude the same files.
|
|
1872
1908
|
def project_discovery_expansion(paths, expansion)
|
|
1873
1909
|
return nil unless widen_discovery_to_project?(paths)
|
|
1874
1910
|
|
|
1875
1911
|
analysed = expansion.fetch(:files)
|
|
1876
|
-
|
|
1912
|
+
project = expand_paths(@configuration.paths | paths).fetch(:files)
|
|
1913
|
+
walked = required_outside_paths(analysed)
|
|
1914
|
+
files = discovery_files(project + walked.found, analysed)
|
|
1877
1915
|
# Overlapping arguments (`lib lib/user.rb`) name an analysed file twice; the widened set names it once.
|
|
1878
|
-
files.size > analysed.uniq { |path| File.absolute_path(path) }.size ?
|
|
1916
|
+
return nil unless files.size > analysed.uniq { |path| File.absolute_path(path) }.size || walked.missing.any?
|
|
1917
|
+
|
|
1918
|
+
{ files: files, errors: [], uncertain: walked.found.to_set.freeze, missing: walked.missing }
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
# Issue #2021 — what the analysed files outside the configured `paths:` load with a literal `require_relative`,
|
|
1922
|
+
# through targets that are themselves outside them ({RequireRelativeClosure}). A file under a configured path
|
|
1923
|
+
# is discovered already, so the walk adds nothing for a run whose files all lie inside them. The comparison is
|
|
1924
|
+
# by real path, so a symlinked spelling of a configured file does not join discovery a second time (two
|
|
1925
|
+
# writers would withhold its constants, #644). `exclude:` drops a target from discovery as it drops a
|
|
1926
|
+
# configured file; the walk still follows what an excluded target requires.
|
|
1927
|
+
#
|
|
1928
|
+
# The found files are discovered as `uncertain` ({Analysis::Runner::ProjectPrePasses#uncertain_paths}): the walk
|
|
1929
|
+
# sees one entry point's load graph, and a file it does not reach may redefine what they define.
|
|
1930
|
+
def required_outside_paths(analysed)
|
|
1931
|
+
roots = @configuration.paths.map { |root| RequireRelativeClosure.real_path(root) }
|
|
1932
|
+
covered = ->(real) { roots.any? { |root| real == root || real.start_with?(File.join(root, "")) } }
|
|
1933
|
+
seeds = analysed.reject { |path| covered.call(RequireRelativeClosure.real_path(path)) }
|
|
1934
|
+
return RequireRelativeClosure::Result.new(found: [], missing: []) if seeds.empty?
|
|
1935
|
+
|
|
1936
|
+
read = ->(path) { File.read(@buffer ? @buffer.resolve(path) : path) }
|
|
1937
|
+
walked = RequireRelativeClosure.closure(seeds, covered: covered, read: read)
|
|
1938
|
+
walked.with(found: PathExpansion.reject_excluded(walked.found, @configuration.exclude_patterns,
|
|
1939
|
+
base: @configuration.exclude_base))
|
|
1940
|
+
end
|
|
1941
|
+
|
|
1942
|
+
# Issue #2021 — a kind row per `require_relative` target the walk named and found absent: a file appearing
|
|
1943
|
+
# there joins the discovery, so it moves the answer of the run-result cache and the `--incremental` slot.
|
|
1944
|
+
def required_missing_entries
|
|
1945
|
+
missing = @project_discovery_expansion&.fetch(:missing, nil)
|
|
1946
|
+
missing.nil? || missing.empty? ? [] : kind_entries(missing)
|
|
1879
1947
|
end
|
|
1880
1948
|
|
|
1881
1949
|
# The expansion with each file once, first spelling kept: overlapping arguments (`lib ./lib`) that do not
|
|
@@ -1887,6 +1955,23 @@ module Rigor
|
|
|
1887
1955
|
unique.size == files.size ? expansion : expansion.merge(files: unique)
|
|
1888
1956
|
end
|
|
1889
1957
|
|
|
1958
|
+
# Issue #2165 — the discovery set with the buffer's file under the binding's own spelling, once. The binding
|
|
1959
|
+
# substitutes bytes only for a path spelled exactly as its logical path, while the file can reach discovery as
|
|
1960
|
+
# the argument's spelling, the configured one, or through a symlink; each of those read it from disk, and a
|
|
1961
|
+
# second spelling made it a second declarer. Every member whose real path is the buffer's file is replaced by
|
|
1962
|
+
# the logical path, and the duplicates that leaves are dropped (`IncrementalSession#rebind_buffer` is option
|
|
1963
|
+
# B's counterpart).
|
|
1964
|
+
def buffer_spelled(expansion)
|
|
1965
|
+
return expansion if @buffer.nil?
|
|
1966
|
+
|
|
1967
|
+
target = Analysis::BufferBinding.real_path(@buffer.logical_path)
|
|
1968
|
+
files = expansion.fetch(:files)
|
|
1969
|
+
spelled = files.map do |path|
|
|
1970
|
+
Analysis::BufferBinding.real_path(path) == target ? @buffer.logical_path : path
|
|
1971
|
+
end.uniq
|
|
1972
|
+
spelled == files ? expansion : expansion.merge(files: spelled)
|
|
1973
|
+
end
|
|
1974
|
+
|
|
1890
1975
|
# Each file once, in project order, under the spelling the analysis uses when it is analysed.
|
|
1891
1976
|
def discovery_files(project_files, analysed_files)
|
|
1892
1977
|
spelling = analysed_files.to_h { |path| [File.absolute_path(path), path] }
|
|
@@ -1898,7 +1983,7 @@ module Rigor
|
|
|
1898
1983
|
end
|
|
1899
1984
|
|
|
1900
1985
|
def widen_discovery_to_project?(paths)
|
|
1901
|
-
@prebuilt.nil? && @
|
|
1986
|
+
@prebuilt.nil? && @in_memory_sources.nil? && paths != @configuration.paths
|
|
1902
1987
|
end
|
|
1903
1988
|
|
|
1904
1989
|
# ADR-46 — the dependency-recording and subset-analysis modes read the discovery tables OUTSIDE the
|
|
@@ -1912,7 +1997,8 @@ module Rigor
|
|
|
1912
1997
|
|
|
1913
1998
|
private :run_project_pre_passes, :adopt_prebuilt_project_scan, :apply_pre_passes_result,
|
|
1914
1999
|
:apply_discovery_result, :ensure_project_discovery, :force_eager_discovery?,
|
|
1915
|
-
:project_discovery_expansion, :discovery_files, :once_each, :widen_discovery_to_project
|
|
2000
|
+
:project_discovery_expansion, :discovery_files, :once_each, :widen_discovery_to_project?,
|
|
2001
|
+
:required_outside_paths, :required_missing_entries
|
|
1916
2002
|
|
|
1917
2003
|
# Ruby versions probed (ascending) to discover the lowest one this Prism build accepts for
|
|
1918
2004
|
# `version:`. Prism exposes no version list, so the floor is found empirically — only when a
|
|
@@ -1970,8 +2056,7 @@ module Rigor
|
|
|
1970
2056
|
# Editor mode § "Scope choice — option A". Under `buffer:` non-nil the per-file analysis emits
|
|
1971
2057
|
# diagnostics ONLY for the buffer's logical path; the rest of `paths:` is consumed by the
|
|
1972
2058
|
# project-wide pre-passes (synthetic methods, project-patched methods, plugin facts) but contributes
|
|
1973
|
-
# no per-file diagnostics.
|
|
1974
|
-
# (full project + incremental cache) is queued.
|
|
2059
|
+
# no per-file diagnostics. Option B (#146) narrows to the closure instead; see {#target_files}.
|
|
1975
2060
|
#
|
|
1976
2061
|
# The buffer's logical path is added to the file list even if it's not under `paths:` — per design §
|
|
1977
2062
|
# "Failure envelope": "--instead-of=Y with Y not under any paths: directory → treated as a valid
|
|
@@ -2004,7 +2089,13 @@ module Rigor
|
|
|
2004
2089
|
# The logical path joins even when it is not on disk under `paths:` (design § "Failure envelope"),
|
|
2005
2090
|
# the same allowance option A makes below.
|
|
2006
2091
|
files = files.select { |path| @analyze_only.include?(path) }
|
|
2007
|
-
|
|
2092
|
+
# Issue #2233 — a buffer that is a claimed template joins as its unit, appended by
|
|
2093
|
+
# {#template_unit_targets}, never as a `.rb` file: the logical path in its absolute spelling would
|
|
2094
|
+
# otherwise analyse the same template twice. The registry is loaded by now, which is why the test is here
|
|
2095
|
+
# and not in the incremental session, where it is not.
|
|
2096
|
+
if @buffer && @analyze_only.include?(@buffer.logical_path) && !template_path?(@buffer.logical_path)
|
|
2097
|
+
files |= [@buffer.logical_path]
|
|
2098
|
+
end
|
|
2008
2099
|
return template_unit_targets(files)
|
|
2009
2100
|
end
|
|
2010
2101
|
return template_unit_targets(files) if @buffer.nil?
|
|
@@ -2040,6 +2131,14 @@ module Rigor
|
|
|
2040
2131
|
end
|
|
2041
2132
|
public :template_unit_paths
|
|
2042
2133
|
|
|
2134
|
+
# Issue #2233 — whether `path` is a template of this run: a claimed glob matches it, or it names a unit. The
|
|
2135
|
+
# runner keeps the buffer's logical path out of the targets when this is true, so a template buffer is
|
|
2136
|
+
# analysed once, as a unit ({#template_unit_targets} appends it), and never also as a plain `.rb` file.
|
|
2137
|
+
def template_path?(path)
|
|
2138
|
+
template_units.claims?(path) ||
|
|
2139
|
+
template_unit_paths.include?(Analysis::TemplateUnitPaths.relative(path, Dir.pwd))
|
|
2140
|
+
end
|
|
2141
|
+
|
|
2043
2142
|
# Editor mode (`buffer:` non-nil) auto-flips the cache store to `read_only: true` so multiple
|
|
2044
2143
|
# debounced editor invocations against the same project don't churn the on-disk cache or race on
|
|
2045
2144
|
# schema-version writes. Cache reads continue unchanged; misses still run the producer block but the
|
|
@@ -2093,15 +2192,9 @@ module Rigor
|
|
|
2093
2192
|
pool_mode: -> { pool_mode? },
|
|
2094
2193
|
cached_plugin_prepare_diagnostics: -> { @cached_plugin_prepare_diagnostics },
|
|
2095
2194
|
pre_eval_diagnostics_from_scanner: -> { @pre_eval_diagnostics_from_scanner },
|
|
2096
|
-
|
|
2097
|
-
quarantined_signatures_snapshot: -> { @snapshots.quarantined_signatures },
|
|
2098
|
-
signature_standdowns_snapshot: -> { @snapshots.signature_standdowns },
|
|
2099
|
-
vendored_standdowns_snapshot: -> { @snapshots.vendored_standdowns },
|
|
2100
|
-
env_build_failure_snapshot: -> { @snapshots.env_build_failure },
|
|
2101
|
-
definition_build_failures_snapshot: -> { @snapshots.definition_build_failures },
|
|
2102
|
-
hkt_scan_failure_snapshot: -> { @snapshots.hkt_scan_failure },
|
|
2103
|
-
conformance_results_snapshot: -> { @snapshots.conformance_results },
|
|
2195
|
+
snapshots: @snapshots,
|
|
2104
2196
|
pooled_run_disclosures: -> { @pool_coordinator.collected_run_disclosures },
|
|
2197
|
+
served_run_disclosures: -> { @served_run_disclosures },
|
|
2105
2198
|
pooled_trust_refusals: -> { @pool_coordinator.collected_trust_refusals }
|
|
2106
2199
|
)
|
|
2107
2200
|
end
|
|
@@ -2249,10 +2342,8 @@ module Rigor
|
|
|
2249
2342
|
# client editing a brand-new file.
|
|
2250
2343
|
elsif accept_as_ruby_file?(path)
|
|
2251
2344
|
files << path
|
|
2252
|
-
elsif File.exist?(path)
|
|
2253
|
-
bad << [path, "not a Ruby file (expected `.rb` or a directory)"]
|
|
2254
2345
|
else
|
|
2255
|
-
bad << [path,
|
|
2346
|
+
bad << [path, PathExpansion.unusable_message(path)]
|
|
2256
2347
|
end
|
|
2257
2348
|
end
|
|
2258
2349
|
{ files: files, roots: Array(paths).map(&:to_s), errors: path_expansion_errors(bad, any_files: files.any?) }
|
|
@@ -2262,27 +2353,24 @@ module Rigor
|
|
|
2262
2353
|
# app lib` with no `lib/` (the 20260620 field trial's strap case) analyses `app` instead of aborting
|
|
2263
2354
|
# on exit 1. A bad path that leaves NOTHING to analyse stays an error so a lone typo (`rigor check
|
|
2264
2355
|
# typo.rb`) is not silently masked (the regression the path-error check was added to catch in the
|
|
2265
|
-
# first place).
|
|
2356
|
+
# first place). The wording and grading live in {PathExpansion.diagnostics}, shared with `sig-gen` (#1991).
|
|
2266
2357
|
def path_expansion_errors(bad, any_files:)
|
|
2267
|
-
|
|
2268
|
-
suffix = any_files ? " (skipped)" : ""
|
|
2269
|
-
bad.map { |path, message| path_error(path, "#{message}#{suffix}", severity: severity) }
|
|
2358
|
+
PathExpansion.diagnostics(bad, any_files: any_files)
|
|
2270
2359
|
end
|
|
2271
2360
|
|
|
2361
|
+
# #2191 — the buffer's logical path is accepted under any spelling that names the same file (relative, absolute,
|
|
2362
|
+
# or through a symlinked root), since the discovery set respells it to the logical path (`buffer_spelled`).
|
|
2272
2363
|
def accept_as_ruby_file?(path)
|
|
2273
2364
|
(File.file?(path) && path.end_with?(".rb")) ||
|
|
2274
|
-
(
|
|
2365
|
+
buffer_path?(path) ||
|
|
2275
2366
|
@in_memory_sources&.key?(path)
|
|
2276
2367
|
end
|
|
2277
2368
|
|
|
2278
|
-
def
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
message: message,
|
|
2284
|
-
severity: severity
|
|
2285
|
-
)
|
|
2369
|
+
def buffer_path?(path)
|
|
2370
|
+
return false if @buffer.nil?
|
|
2371
|
+
|
|
2372
|
+
path == @buffer.logical_path ||
|
|
2373
|
+
Analysis::BufferBinding.real_path(path) == Analysis::BufferBinding.real_path(@buffer.logical_path)
|
|
2286
2374
|
end
|
|
2287
2375
|
|
|
2288
2376
|
# Reads + parses the source at `path`. Under editor mode (`@buffer` set) reads bytes from
|
|
@@ -2438,14 +2526,14 @@ module Rigor
|
|
|
2438
2526
|
@discovery_seed ? @discovery_seed.dup : {}
|
|
2439
2527
|
end
|
|
2440
2528
|
|
|
2441
|
-
# Seeds the
|
|
2442
|
-
#
|
|
2443
|
-
#
|
|
2529
|
+
# Seeds the parameter-inference and constant-publication tables, so a pooled `WorkerSession` scope resolves
|
|
2530
|
+
# identically to the sequential path (ADR-15 sequential equivalence). The parameter-inference table is absent
|
|
2531
|
+
# unless its opt-in ran; the constant tables are seeded whenever the run has project constants.
|
|
2444
2532
|
#
|
|
2445
2533
|
# - ADR-67 WD6a `param_inferred_types`: the call-site parameter-inference table, populated only when the
|
|
2446
2534
|
# `parameter_inference:` gate ran the pre-pass.
|
|
2447
|
-
# - Issue #352 `in_source_constants`: the `pre_eval:` constant publication,
|
|
2448
|
-
#
|
|
2535
|
+
# - Issue #352 `in_source_constants`: the `pre_eval:` constant publication, merged with the project's
|
|
2536
|
+
# literal constant table (#644, see {#merged_seed_constants}).
|
|
2449
2537
|
#
|
|
2450
2538
|
# Extracted to keep {#project_scope_seed_tables} under the complexity budget.
|
|
2451
2539
|
def seed_opt_in_pre_pass_tables(tables)
|
|
@@ -2481,12 +2569,31 @@ module Rigor
|
|
|
2481
2569
|
# widener erases it to the class, and listing a file under `pre_eval:` must never LOSE precision. The
|
|
2482
2570
|
# per-file table still wins over both (`ScopeIndexer.index`'s merge) — same-file stays the most
|
|
2483
2571
|
# specific authority.
|
|
2572
|
+
#
|
|
2573
|
+
# ADR-124 — a `prebuilt:` runner computes no literal table of its own; a `discovery_seed:` (the editor
|
|
2574
|
+
# publish, ADR-124) brings the project's, which then plays the same part.
|
|
2484
2575
|
def merged_seed_constants
|
|
2485
2576
|
pre_eval = publishable_pre_eval_constants
|
|
2486
|
-
|
|
2487
|
-
return
|
|
2577
|
+
literal = literal_seed_constants
|
|
2578
|
+
return literal if pre_eval.empty?
|
|
2579
|
+
return pre_eval if literal.empty?
|
|
2580
|
+
|
|
2581
|
+
pre_eval.merge(literal).freeze
|
|
2582
|
+
end
|
|
2583
|
+
|
|
2584
|
+
# The project's literal constant table: this run's, or the one a `discovery_seed:` carries (ADR-124).
|
|
2585
|
+
def literal_seed_constants
|
|
2586
|
+
return @project_constant_values unless @project_constant_values.empty? && @discovery_seed
|
|
2587
|
+
|
|
2588
|
+
@discovery_seed.fetch(:in_source_constants, @project_constant_values)
|
|
2589
|
+
end
|
|
2590
|
+
|
|
2591
|
+
# The per-name writer paths the #663 retraction reads: this run's census, or the one a `discovery_seed:` carries
|
|
2592
|
+
# (ADR-124).
|
|
2593
|
+
def constant_writer_sources
|
|
2594
|
+
return @project_constant_sources unless @project_constant_sources.empty? && @discovery_seed
|
|
2488
2595
|
|
|
2489
|
-
|
|
2596
|
+
@discovery_seed.fetch(:constant_sources, @project_constant_sources)
|
|
2490
2597
|
end
|
|
2491
2598
|
|
|
2492
2599
|
# Issue #663 — the `pre_eval:` publication with every name an UNLISTED file also assigns retracted.
|
|
@@ -2515,8 +2622,9 @@ module Rigor
|
|
|
2515
2622
|
# name of its own for the wildcard's paths to have been folded into.
|
|
2516
2623
|
def unlisted_constant_writer?(name, listed)
|
|
2517
2624
|
segment = name.split("::").last
|
|
2518
|
-
|
|
2519
|
-
|
|
2625
|
+
sources = constant_writer_sources
|
|
2626
|
+
writers = sources[name]
|
|
2627
|
+
wildcard = sources["#{Inference::ScopeIndexer::DYNAMIC_TARGET_PREFIX}#{segment}"]
|
|
2520
2628
|
[writers, wildcard].any? do |paths|
|
|
2521
2629
|
paths&.any? { |path| !listed.include?(File.absolute_path(path)) }
|
|
2522
2630
|
end
|
|
@@ -2560,13 +2668,18 @@ module Rigor
|
|
|
2560
2668
|
@pre_analysis_plugin_rows ||= plugin_boundary_rows
|
|
2561
2669
|
reads = []
|
|
2562
2670
|
diagnostics = nil
|
|
2563
|
-
record =
|
|
2564
|
-
|
|
2565
|
-
|
|
2671
|
+
record = nil
|
|
2672
|
+
# Issue #2020 — and every run-scoped row its analysis registered, with the registering plugins' reads.
|
|
2673
|
+
disclosures = RunDisclosureCredit.collect do
|
|
2674
|
+
record = Plugin::IoBoundary.attributing(reads) do
|
|
2675
|
+
DependencyRecorder.record_for(path) do
|
|
2676
|
+
diagnostics = analyze_with_effects(path, environment)
|
|
2677
|
+
end
|
|
2566
2678
|
end
|
|
2567
2679
|
end
|
|
2568
2680
|
@file_dependencies[path] = record
|
|
2569
2681
|
@analysis_reads[path] = reads unless reads.empty?
|
|
2682
|
+
@analysis_disclosures[path] = disclosures unless disclosures.empty?
|
|
2570
2683
|
diagnostics
|
|
2571
2684
|
end
|
|
2572
2685
|
|