rigortype 0.4.6 → 0.4.8
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 +4 -2
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +45 -13
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- 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 +6 -3
- data/docs/handbook/11-sig-gen.md +85 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +455 -113
- data/docs/manual/03-configuration.md +76 -5
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +21 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +32 -15
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +23 -1
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +12 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +16 -4
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +41 -12
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +9 -2
- 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 +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules.rb +720 -141
- data/lib/rigor/analysis/crash_signature.rb +45 -3
- data/lib/rigor/analysis/dependency_recorder.rb +237 -80
- 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 +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +4 -3
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +306 -53
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +39 -3
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +8 -8
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +264 -112
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +4 -9
- data/lib/rigor/analysis/runner/pool_coordinator.rb +173 -328
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- 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/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +298 -109
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +62 -23
- 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 +65 -71
- data/lib/rigor/bleeding_edge.rb +22 -10
- 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/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +95 -17
- 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 +90 -4
- data/lib/rigor/cache/rbs_environment.rb +8 -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 +160 -57
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +112 -104
- 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 +25 -20
- 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 +26 -18
- 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 +29 -10
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- 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 +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- 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 +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +92 -27
- 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 +2 -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 +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- 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 +214 -56
- data/lib/rigor/config_audit.rb +33 -19
- data/lib/rigor/configuration/severity_profile.rb +14 -5
- data/lib/rigor/configuration.rb +104 -35
- data/lib/rigor/effects/collector.rb +53 -21
- 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 +64 -33
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +18 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +381 -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/hkt_registry_holder.rb +6 -0
- 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_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +12 -15
- data/lib/rigor/environment/rbs_loader.rb +772 -110
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +169 -42
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +136 -40
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +185 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -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 +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +258 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +33 -15
- data/lib/rigor/inference/def_return_typer.rb +47 -5
- data/lib/rigor/inference/definer_resolution.rb +19 -9
- data/lib/rigor/inference/definers_index.rb +162 -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 +16 -0
- data/lib/rigor/inference/expression_typer.rb +1559 -320
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +81 -5
- 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/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +61 -15
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +154 -8
- data/lib/rigor/inference/key_presence_guard.rb +51 -24
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +66 -14
- data/lib/rigor/inference/match_rebinding/frame.rb +57 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +101 -0
- data/lib/rigor/inference/match_rebinding.rb +28 -5
- 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 +44 -30
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +51 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +606 -78
- 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 +3 -3
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +467 -84
- 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/singleton_type_params.rb +104 -0
- 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 +123 -25
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +24 -3
- data/lib/rigor/inference/multi_target_binder.rb +2 -2
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +199 -29
- data/lib/rigor/inference/narrowing.rb +238 -50
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +134 -9
- data/lib/rigor/inference/origin_lookup.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/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +30 -9
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +57 -17
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -16
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +287 -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 +0 -1
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +70 -26
- 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 +295 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2213 -226
- data/lib/rigor/inference/self_call_ivar_writes.rb +103 -12
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +42 -8
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +3268 -358
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +40 -17
- data/lib/rigor/inference/toplevel_def_census.rb +67 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -9
- data/lib/rigor/language_server/buffer_table.rb +3 -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 +8 -3
- 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 +39 -1
- 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 +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +26 -4
- 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 +16 -16
- data/lib/rigor/plugin/registry.rb +16 -5
- 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 +48 -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 +44 -5
- data/lib/rigor/protection/mutation_cache.rb +4 -1
- 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 +81 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +32 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +168 -8
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +901 -54
- data/lib/rigor/scope.rb +644 -37
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +18 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +588 -66
- 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 +37 -4
- data/lib/rigor/sig_gen/observation_collector.rb +14 -7
- 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/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +62 -2
- 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 +238 -37
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- 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 +173 -21
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type.rb +1 -0
- 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/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- 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 +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -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 +3 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +115 -36
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- 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 +132 -33
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +54 -17
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- 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 +11 -14
- 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 +30 -9
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +55 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -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 +1 -1
- 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 +8 -7
- 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-graphql/lib/rigor/plugin/graphql.rb +12 -2
- 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 +8 -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 +200 -4
- 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 +4 -3
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +5 -5
- 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 +3 -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 +210 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +97 -24
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +4 -8
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -2
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cache/descriptor.rbs +14 -0
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/environment.rbs +4 -1
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +53 -18
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +43 -4
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- 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/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +17 -2
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +82 -3
|
@@ -39,12 +39,10 @@ module Rigor
|
|
|
39
39
|
# lexical receiver class equals or inherits from this constraint.
|
|
40
40
|
# - `method_name` — Symbol naming the DSL method (e.g. `:devise`).
|
|
41
41
|
# - `symbol_arg_position` — `:rest` (all positional Symbol args are traits, slice 3a's only supported
|
|
42
|
-
# form) or a non-negative Integer (the index of a single trait symbol
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# `macro.tier_b.unknown-trait` `:info` provenance marker per WD9 / WD13).
|
|
47
|
-
# - `always_included` — Array<String>. Fully-qualified module names that are added to every call site
|
|
42
|
+
# form) or a non-negative Integer (the index of a single trait symbol).
|
|
43
|
+
# - `modules_by_symbol` — Maps each recognised trait symbol to a fully-qualified module name. Symbols not
|
|
44
|
+
# in the table are silently skipped.
|
|
45
|
+
# - `always_included` — Fully-qualified module names that are added to every call site
|
|
48
46
|
# (even when no symbols match). Mirrors Devise's `always_include` modules.
|
|
49
47
|
#
|
|
50
48
|
# ## Floor / ceiling per ADR-16 WD13
|
|
@@ -53,7 +51,7 @@ module Rigor
|
|
|
53
51
|
# methods into the existing `SyntheticMethodIndex` (slice 2b primitive). The synthesised methods adopt
|
|
54
52
|
# the module's authored RBS return types — Tier B is NOT subject to the Tier C `Dynamic[T]` floor
|
|
55
53
|
# because the source-of-truth (the module's authored RBS) is not a manifest-declared string. Per ADR-5
|
|
56
|
-
# robustness, the substrate does not fabricate precision; it simply replays the
|
|
54
|
+
# robustness, the substrate does not fabricate precision; it simply replays the module's signatures.
|
|
57
55
|
#
|
|
58
56
|
# **Out of scope for slice 3** (deferred follow-ups):
|
|
59
57
|
# - `class_methods_module:` per-trait (Devise's `ClassMethods` extend-pattern); slice 3 covers instance
|
|
@@ -106,8 +104,7 @@ module Rigor
|
|
|
106
104
|
end
|
|
107
105
|
|
|
108
106
|
# @return fully-qualified module name for the given trait symbol, or nil when the
|
|
109
|
-
# registry doesn't know the symbol (caller
|
|
110
|
-
# through).
|
|
107
|
+
# registry doesn't know the symbol (the caller skips it).
|
|
111
108
|
def module_for(symbol)
|
|
112
109
|
modules_by_symbol[symbol.to_sym]
|
|
113
110
|
end
|
|
@@ -168,9 +168,8 @@ module Rigor
|
|
|
168
168
|
end
|
|
169
169
|
private :assign_additional_initializers
|
|
170
170
|
|
|
171
|
-
# ADR-103 WD2 / WD6 / WD10 / WD14 — the
|
|
172
|
-
#
|
|
173
|
-
# The six `effect_*` fields validate together, so {#initialize} carries one call rather than six.
|
|
171
|
+
# ADR-103 WD2 / WD6 / WD10 / WD14 — the six `effect_*` fields validate together here, so {#initialize}
|
|
172
|
+
# carries one call rather than six.
|
|
174
173
|
def validate_effect_fields!(effect_root, effect_labels, effect_attributions, effect_edges,
|
|
175
174
|
effect_entry_points, effect_ancestry)
|
|
176
175
|
validate_effect_root!(effect_root)
|
|
@@ -305,11 +304,15 @@ module Rigor
|
|
|
305
304
|
FirstParty.bundled?(id)
|
|
306
305
|
end
|
|
307
306
|
|
|
308
|
-
# Whether the
|
|
309
|
-
#
|
|
307
|
+
# Whether the manifest declares anything for the effect surfaces — a convenience predicate over the
|
|
308
|
+
# manifest-declared fields only, true exactly when a `Registry::Contribution` built from these
|
|
309
|
+
# declarations would not be empty (`Contribution#empty?` reads the same five fields,
|
|
310
|
+
# `effect_ancestry:` included). A plugin that overrides the `Base#effect_*` readers instead of
|
|
311
|
+
# declaring rows here (rigor-sidekiq) can contribute while this answers false. The compiled
|
|
312
|
+
# per-run tables filter on `Contribution#empty?` themselves; nothing consults this predicate.
|
|
310
313
|
def effects?
|
|
311
314
|
!effect_labels.empty? || !effect_attributions.empty? || !effect_edges.empty? ||
|
|
312
|
-
!effect_entry_points.empty?
|
|
315
|
+
!effect_entry_points.empty? || !effect_ancestry.empty?
|
|
313
316
|
end
|
|
314
317
|
|
|
315
318
|
def ==(other)
|
|
@@ -475,10 +478,9 @@ module Rigor
|
|
|
475
478
|
end
|
|
476
479
|
end
|
|
477
480
|
|
|
478
|
-
# ADR-13
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
# registration order; the parser integration that actually drives the chain lands in slice 3.
|
|
481
|
+
# ADR-13 — `type_node_resolvers:` declares the plugin-supplied `TypeNodeResolver` instances the parser
|
|
482
|
+
# consults when an RBS::Extended payload's named- or generic-type head misses the built-in registry. The
|
|
483
|
+
# registry exposes them in registration order, and `Environment#build_name_scope` builds the chain.
|
|
482
484
|
def validate_type_node_resolvers!(resolvers)
|
|
483
485
|
validate_array_of!("type_node_resolvers", resolvers, "Rigor::Plugin::TypeNodeResolver instances") do |r|
|
|
484
486
|
r.is_a?(TypeNodeResolver)
|
|
@@ -486,8 +488,7 @@ module Rigor
|
|
|
486
488
|
end
|
|
487
489
|
|
|
488
490
|
# ADR-16 slice 1a — `block_as_methods:` declares the Tier A substrate entries the plugin contributes.
|
|
489
|
-
#
|
|
490
|
-
# `Scope#self_type` for matching blocks arrives in a subsequent slice.
|
|
491
|
+
# The engine hook that narrows `Scope#self_type` for matching blocks is `Inference::MacroBlockSelfType`.
|
|
491
492
|
def validate_block_as_methods!(entries)
|
|
492
493
|
validate_array_of!("block_as_methods", entries, "Rigor::Plugin::Macro::BlockAsMethod instances") do |e|
|
|
493
494
|
e.is_a?(Macro::BlockAsMethod)
|
|
@@ -495,8 +496,7 @@ module Rigor
|
|
|
495
496
|
end
|
|
496
497
|
|
|
497
498
|
# ADR-16 slice 2a — `heredoc_templates:` declares the Tier C substrate entries (heredoc-template
|
|
498
|
-
# synthesis on class-level DSL calls).
|
|
499
|
-
# `SyntheticMethodIndex` that actually emit synthetic methods arrive in slice 2b.
|
|
499
|
+
# synthesis on class-level DSL calls). `Inference::SyntheticMethodScanner` emits the synthetic methods.
|
|
500
500
|
def validate_heredoc_templates!(entries)
|
|
501
501
|
validate_array_of!("heredoc_templates", entries, "Rigor::Plugin::Macro::HeredocTemplate instances") do |e|
|
|
502
502
|
e.is_a?(Macro::HeredocTemplate)
|
|
@@ -515,8 +515,8 @@ module Rigor
|
|
|
515
515
|
end
|
|
516
516
|
|
|
517
517
|
# ADR-16 slice 3a — `trait_registries:` declares the Tier B substrate entries (trait-inlining via
|
|
518
|
-
# bundled module registry).
|
|
519
|
-
#
|
|
518
|
+
# bundled module registry). `Inference::SyntheticMethodScanner#collect_trait_registries` explodes them
|
|
519
|
+
# per method through `SyntheticMethodIndex`.
|
|
520
520
|
def validate_trait_registries!(entries)
|
|
521
521
|
validate_array_of!("trait_registries", entries, "Rigor::Plugin::Macro::TraitRegistry instances") do |e|
|
|
522
522
|
e.is_a?(Macro::TraitRegistry)
|
|
@@ -4,6 +4,7 @@ require_relative "blueprint"
|
|
|
4
4
|
# Issue #806 — {Registry#guarded_manifest} constructs one. `Rigor::Plugin::LoadError` MUST be defined by
|
|
5
5
|
# then: an unresolved bare `LoadError` in this lexical scope silently falls back to Ruby's own ::LoadError.
|
|
6
6
|
require_relative "load_error"
|
|
7
|
+
require_relative "../typing_state"
|
|
7
8
|
|
|
8
9
|
module Rigor
|
|
9
10
|
module Plugin
|
|
@@ -20,6 +21,10 @@ module Rigor
|
|
|
20
21
|
# exactly the order the ungated walk produced — diagnostics stay byte-identical. The receiver-class
|
|
21
22
|
# ancestry match for `dynamic_return` still happens per-dispatch inside `Plugin::Base#dynamic_return_type`.
|
|
22
23
|
class ContributionIndex
|
|
24
|
+
TypingState.memo_field(self, :@owns_receiver_memo,
|
|
25
|
+
reason: "keyed on the environment's identity and the class name; the plugins' " \
|
|
26
|
+
"owns_receivers set is fixed at construction")
|
|
27
|
+
|
|
23
28
|
# Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the
|
|
24
29
|
# paths within a plugin. `for_file_diagnostics` is the subset the runner's per-file diagnostic loop
|
|
25
30
|
# visits: plugins overriding `#diagnostics_for_file` or declaring at least one `node_rule`.
|
|
@@ -103,8 +108,8 @@ module Rigor
|
|
|
103
108
|
# The categorisation sets + the ordered per-collector subsets.
|
|
104
109
|
def compile_memberships(plugins)
|
|
105
110
|
plugins.each { |p| reject_legacy_flow_hook!(p) }
|
|
106
|
-
@dynamic = plugins.reject { |p| p.class.dynamic_returns.empty? }.to_set
|
|
107
|
-
@narrowing_facts = plugins.reject { |p| p.class.narrowing_facts_rules.empty? }.to_set
|
|
111
|
+
@dynamic = plugins.reject { |p| p.class.dynamic_returns.empty? }.to_set.freeze
|
|
112
|
+
@narrowing_facts = plugins.reject { |p| p.class.narrowing_facts_rules.empty? }.to_set.freeze
|
|
108
113
|
compile_collector_subsets(plugins)
|
|
109
114
|
end
|
|
110
115
|
|
|
@@ -214,10 +219,16 @@ module Rigor
|
|
|
214
219
|
# tie-breaker.
|
|
215
220
|
#
|
|
216
221
|
# ADR-15 Phase 3 — alongside the instantiated `plugins`, the registry carries `blueprints`: a frozen,
|
|
217
|
-
# Ractor-shareable
|
|
222
|
+
# Ractor-shareable list of {Blueprint} that records how to re-instantiate the same plugin set in a worker
|
|
218
223
|
# Ractor. The eventual Phase 4 pool ships `blueprints` across the boundary and calls {.materialize}
|
|
219
224
|
# per-Ractor; the live `plugins` carriage on the coordinator registry stays unchanged.
|
|
220
225
|
class Registry
|
|
226
|
+
TypingState.memo_field(self, :@contracts_by_path, :@effect_memo,
|
|
227
|
+
reason: "keyed on the path, and on the one effect-contribution compile; the contract " \
|
|
228
|
+
"set, glob semantics and plugin set are fixed for the run (ADR-52 WD1), and the " \
|
|
229
|
+
"compile, which may read project facts across the I/O boundary, rests on the " \
|
|
230
|
+
"run's stable-filesystem premise, as FileDigest's run tables do")
|
|
231
|
+
|
|
221
232
|
attr_reader :plugins, :load_errors, :blueprints, :contribution_index, :resolved_gem_paths
|
|
222
233
|
|
|
223
234
|
# @param plugins — instantiated plugin instances in deterministic order.
|
|
@@ -556,8 +567,8 @@ module Rigor
|
|
|
556
567
|
# Issue #806 — {#safe_manifest} with a receipt. The construction-time aggregates degraded silently
|
|
557
568
|
# when a manifest read raised, so a plugin that contributed nothing looked identical to a plugin that
|
|
558
569
|
# was never asked; the load-error channel is where "a plugin could not be loaded" already lives, and
|
|
559
|
-
# `Analysis::Runner` turns each entry into one `
|
|
560
|
-
# plugin ref is the CLASS, not `manifest.id`: the manifest is the surface that just failed.
|
|
570
|
+
# `Analysis::Runner` turns each entry into one `load-error` row (source family `plugin_loader`) naming
|
|
571
|
+
# the plugin. The plugin ref is the CLASS, not `manifest.id`: the manifest is the surface that just failed.
|
|
561
572
|
def guarded_manifest(plugin, errors)
|
|
562
573
|
plugin.manifest
|
|
563
574
|
rescue StandardError => e
|
|
@@ -25,9 +25,8 @@ module Rigor
|
|
|
25
25
|
# documents the trust model the boundary enforces.
|
|
26
26
|
#
|
|
27
27
|
# ADR-9 slice 2 adds `fact_store`: the per-run cross-plugin `Plugin::FactStore`. Producer plugins publish
|
|
28
|
-
# their facts in `#prepare(services)
|
|
29
|
-
# `services.fact_store.read(...)`. A fresh `FactStore`
|
|
30
|
-
# supplied — the runner threads its own instance in once slice 3 wires `#prepare` invocation.
|
|
28
|
+
# their facts in `#prepare(services)`; consumer plugins read in `#diagnostics_for_file` via
|
|
29
|
+
# `services.fact_store.read(...)`. A fresh `FactStore` is constructed when none is supplied.
|
|
31
30
|
class Services
|
|
32
31
|
attr_reader :reflection, :type, :configuration, :cache_store, :trust_policy, :fact_store
|
|
33
32
|
|
|
@@ -61,6 +61,17 @@ module Rigor
|
|
|
61
61
|
def empty?
|
|
62
62
|
@entries.empty?
|
|
63
63
|
end
|
|
64
|
+
|
|
65
|
+
# The pool drain ({Rigor::Analysis::WorkerSession#drain_reporters}): the frozen entries.
|
|
66
|
+
def snapshot
|
|
67
|
+
entries
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Replays one worker's {#snapshot}, `kind:` (#824) and `line:` (#1075) included; the dedup above
|
|
71
|
+
# collapses every worker's copy. Nil records nothing.
|
|
72
|
+
def absorb(snapshot)
|
|
73
|
+
Array(snapshot).each { |entry| record(**entry.to_h) }
|
|
74
|
+
end
|
|
64
75
|
end
|
|
65
76
|
end
|
|
66
77
|
end
|
|
@@ -19,8 +19,8 @@ module Rigor
|
|
|
19
19
|
# - `trusted_gems`: gem names the user has authorised. Derived from the `plugins:` section of `.rigor.yml`
|
|
20
20
|
# plus any gems they reach transitively. Used today for documentation and future trust diagnostics.
|
|
21
21
|
# - `allowed_read_roots`: absolute paths plugin code may read from through the {IoBoundary}. The default
|
|
22
|
-
# set covers the project root, the project's `signature_paths`,
|
|
23
|
-
#
|
|
22
|
+
# set covers the project root, the project's `signature_paths`, and each trusted
|
|
23
|
+
# gem's `Gem::Specification#full_gem_path`. The user extends this with `.rigor.yml`'s
|
|
24
24
|
# `plugins_io.allowed_paths:`.
|
|
25
25
|
# - `network_policy`: one of {VALID_NETWORK_POLICIES}. `:disabled` (default) makes
|
|
26
26
|
# {IoBoundary#open_url} always raise. `:allowlist` (v0.1.2) consults `allowed_url_hosts` on every fetch —
|
|
@@ -45,6 +45,52 @@ module Rigor
|
|
|
45
45
|
freeze
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# Builds the run's policy from the project configuration — the one derivation `rigor check`
|
|
49
|
+
# ({Analysis::Runner}), pooled workers ({Analysis::WorkerSession}) and `rigor unused`'s plugin roots
|
|
50
|
+
# ({Analysis::Reachability::PluginRoots}) share, so every `Plugin::Services` container enforces the
|
|
51
|
+
# same scope (#2586).
|
|
52
|
+
#
|
|
53
|
+
# `trusted_gems` is the gem-name half of every `Configuration#plugins` entry. `allowed_read_roots`
|
|
54
|
+
# is the project root (CWD), every `signature_paths` entry, each trusted gem's
|
|
55
|
+
# `Gem.loaded_specs` `full_gem_path` (silently skipped when the gem has no loaded spec), and every
|
|
56
|
+
# `plugins_io.allowed_paths` entry. `network_policy` / `allowed_url_hosts` come from
|
|
57
|
+
# `plugins_io.network` / `plugins_io.allowed_url_hosts`.
|
|
58
|
+
def self.for_configuration(configuration)
|
|
59
|
+
trusted_gems = configuration.plugins.map { |entry| trusted_gem_name(entry) }.uniq
|
|
60
|
+
roots = [Dir.pwd]
|
|
61
|
+
Array(configuration.signature_paths).each { |sp| roots << File.absolute_path(sp) }
|
|
62
|
+
trusted_gems.each do |gem_name|
|
|
63
|
+
path = trusted_gem_root(gem_name)
|
|
64
|
+
roots << path if path
|
|
65
|
+
end
|
|
66
|
+
configuration.plugins_io_allowed_paths.each { |p| roots << File.absolute_path(p) }
|
|
67
|
+
|
|
68
|
+
new(
|
|
69
|
+
trusted_gems: trusted_gems,
|
|
70
|
+
allowed_read_roots: roots,
|
|
71
|
+
network_policy: configuration.plugins_io_network,
|
|
72
|
+
allowed_url_hosts: configuration.plugins_io_allowed_url_hosts
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.trusted_gem_name(entry)
|
|
77
|
+
case entry
|
|
78
|
+
when String then entry
|
|
79
|
+
when Hash then entry["gem"] || entry["id"]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
private_class_method :trusted_gem_name
|
|
83
|
+
|
|
84
|
+
def self.trusted_gem_root(gem_name)
|
|
85
|
+
return nil if gem_name.nil? || gem_name.empty?
|
|
86
|
+
|
|
87
|
+
spec = Gem.loaded_specs[gem_name]
|
|
88
|
+
spec&.full_gem_path
|
|
89
|
+
rescue StandardError
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
private_class_method :trusted_gem_root
|
|
93
|
+
|
|
48
94
|
# @return true when the absolute path falls inside any allowed read root. Symlinks are
|
|
49
95
|
# resolved through `File.absolute_path` only (no `realpath`); plugins with adversarial intent are out of
|
|
50
96
|
# scope per ADR-2.
|
|
@@ -28,10 +28,8 @@ module Rigor
|
|
|
28
28
|
# Resolvers SHOULD be stateless and re-entrant; the registry builds the chain once per
|
|
29
29
|
# `Analysis::Runner.run` and may consult any resolver multiple times for the same node.
|
|
30
30
|
class TypeNodeResolver
|
|
31
|
-
# @param node — the parser-emitted node the chain is
|
|
32
|
-
#
|
|
33
|
-
# @param scope — companion value object (slice 3); slice 2 invocations MAY pass
|
|
34
|
-
# `nil` because the chain doesn't exist yet.
|
|
31
|
+
# @param node — the parser-emitted node the chain is asking about.
|
|
32
|
+
# @param scope — the scope the chain was invoked with.
|
|
35
33
|
# @return resolved type, or `nil` to fall through.
|
|
36
34
|
def resolve(node, scope) # rubocop:disable Lint/UnusedMethodArgument
|
|
37
35
|
nil
|
data/lib/rigor/plugin.rb
CHANGED
|
@@ -21,14 +21,12 @@ require_relative "plugin/first_party"
|
|
|
21
21
|
module Rigor
|
|
22
22
|
module Plugin
|
|
23
23
|
@registered = {}
|
|
24
|
-
# ADR-88 WD4b — process-global map `gem name (String) => [
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# in-process analysis (the `--verify-incremental` full-run oracle, the incremental session's subset
|
|
31
|
-
# re-analysis, the LSP's re-loads) load the same plugins the first run did.
|
|
24
|
+
# ADR-88 WD4b — process-global map `gem name (String) => [plugin id, ...]`, recorded by the loader on a gem's
|
|
25
|
+
# first `require`. A second in-process `Loader.load` of the same bare-string entry sees `require` return false
|
|
26
|
+
# and an empty newly-registered delta; the loader then recovers the ids from this memo instead of failing with
|
|
27
|
+
# "did not register any plugin". Populated by {.record_gem_registration}, read by {.ids_for_gem}. This is what
|
|
28
|
+
# lets a second in-process analysis (the `--verify-incremental` oracle, the incremental subset re-analysis,
|
|
29
|
+
# the LSP's re-loads) load the same plugins the first run did.
|
|
32
30
|
@gem_registrations = {}
|
|
33
31
|
@mutex = Mutex.new
|
|
34
32
|
|
|
@@ -26,7 +26,11 @@ module Rigor
|
|
|
26
26
|
"rails" => %w[
|
|
27
27
|
actioncable actionmailer actionpack actiontext actionview activejob activemodel
|
|
28
28
|
activerecord activestorage activesupport railties
|
|
29
|
-
].freeze
|
|
29
|
+
].freeze,
|
|
30
|
+
# `rspec` and `rspec-rails` are the same shape: a project names the umbrella and never `rspec-core`, the
|
|
31
|
+
# gem rigor-rspec targets. rspec-rails depends on the three rspec gems listed here.
|
|
32
|
+
"rspec" => %w[rspec-core rspec-expectations rspec-mocks].freeze,
|
|
33
|
+
"rspec-rails" => %w[rspec-core rspec-expectations rspec-mocks].freeze
|
|
30
34
|
}.freeze
|
|
31
35
|
|
|
32
36
|
class << self
|
|
@@ -72,6 +72,9 @@ module Rigor
|
|
|
72
72
|
required_features: features,
|
|
73
73
|
**dependency_discovery_options(configuration)
|
|
74
74
|
)
|
|
75
|
+
rescue Environment::CoreRootError
|
|
76
|
+
# Issue #2517 — an unusable selected core is the user's to fix, never a reason to type against the default.
|
|
77
|
+
raise
|
|
75
78
|
rescue StandardError
|
|
76
79
|
bare(configuration, features)
|
|
77
80
|
end
|
|
@@ -111,8 +114,15 @@ module Rigor
|
|
|
111
114
|
# The dependency-discovery axes `check` reads off the configuration, as a keyword hash. Extracted so the
|
|
112
115
|
# list lives in one place: every command that types against the project's real dependencies passes exactly
|
|
113
116
|
# these, and adding an axis to `Environment.for_project` means adding it here once.
|
|
117
|
+
#
|
|
118
|
+
# Issue #2517 — `core_root:` rides here too although it is not discovered: it is the other half of the RBS
|
|
119
|
+
# universe `check` reads off the configuration, and every site that builds one already passes this hash.
|
|
114
120
|
def dependency_discovery_options(configuration)
|
|
115
121
|
{
|
|
122
|
+
core_root: configuration.core_root,
|
|
123
|
+
paths: configuration.paths,
|
|
124
|
+
exclude_patterns: configuration.exclude_patterns,
|
|
125
|
+
exclude_base: configuration.exclude_base,
|
|
116
126
|
bundler_bundle_path: configuration.bundler_bundle_path,
|
|
117
127
|
bundler_auto_detect: configuration.bundler_auto_detect,
|
|
118
128
|
bundler_lockfile: configuration.bundler_lockfile,
|
|
@@ -166,17 +176,21 @@ module Rigor
|
|
|
166
176
|
required_features: features,
|
|
167
177
|
**dependency_discovery_options(configuration)
|
|
168
178
|
)
|
|
179
|
+
rescue Environment::CoreRootError
|
|
180
|
+
raise
|
|
169
181
|
rescue StandardError
|
|
170
182
|
minimal(configuration, features)
|
|
171
183
|
end
|
|
172
184
|
|
|
173
185
|
# The last floor: RBS core plus the project's own signature paths, which cannot fail on anything outside
|
|
174
|
-
# the project itself.
|
|
186
|
+
# the project itself. The core is still the selected one (issue #2517): a floor that dropped it would type
|
|
187
|
+
# the project against APIs its Ruby does not have.
|
|
175
188
|
def minimal(configuration, features = [])
|
|
176
189
|
Environment.for_project(
|
|
177
190
|
libraries: configuration.libraries,
|
|
178
191
|
signature_paths: configuration.signature_paths,
|
|
179
|
-
required_features: features
|
|
192
|
+
required_features: features,
|
|
193
|
+
core_root: configuration.core_root
|
|
180
194
|
)
|
|
181
195
|
end
|
|
182
196
|
end
|
|
@@ -8,7 +8,7 @@ module Rigor
|
|
|
8
8
|
# nothing about the code that was analysed.
|
|
9
9
|
#
|
|
10
10
|
# A named class, not a bare RuntimeError: {MutationScanner#classify} already folds a per-mutant
|
|
11
|
-
# `StandardError` into the
|
|
11
|
+
# `StandardError` into the `harness_errors` bucket, and the scanner's file-level rescue must catch THIS
|
|
12
12
|
# and nothing else, so the two failure modes stay distinguishable at every site that handles either.
|
|
13
13
|
#
|
|
14
14
|
# Issue #790 — it says WHICH of the two refusals below fired, because they want different recovery. A
|
|
@@ -4,6 +4,7 @@ require_relative "../inference/parameter_inference_collector"
|
|
|
4
4
|
require_relative "../inference/scope_indexer"
|
|
5
5
|
require_relative "../inference/project_seed_tables"
|
|
6
6
|
require_relative "../cache/incremental_snapshot"
|
|
7
|
+
require_relative "../cache/file_digest"
|
|
7
8
|
require_relative "../analysis/path_expansion"
|
|
8
9
|
require_relative "../analysis/buffer_binding"
|
|
9
10
|
|
|
@@ -107,11 +108,40 @@ module Rigor
|
|
|
107
108
|
paths = Analysis::PathExpansion.configured_files(configuration)
|
|
108
109
|
return nil if paths.empty?
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
payload = snapshot_payload(configuration)
|
|
112
|
+
bundles = payload&.seed_bundles
|
|
111
113
|
return nil if bundles.nil? || bundles.empty?
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
spelled = respell_for_buffer(paths, buffer)
|
|
116
|
+
tables = tables_for_buffer(paths: spelled, bundles: bundles, buffer: buffer, constant_sources: true)
|
|
117
|
+
with_snapshot_param_table(tables, payload.param_table, configuration,
|
|
118
|
+
paths: spelled, bundles: bundles, buffer: buffer)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Issue #2282 — under `parameter_inference: true` the snapshot also carries the call-site parameter table the
|
|
122
|
+
# writing run seeded its analysis from (`param_table`, ADR-67 WD6c), so a probe reads `@v = v` as `check`
|
|
123
|
+
# does. The table is whole-project (a callee's parameter type comes from callers in other files), so it is
|
|
124
|
+
# only as fresh as every file: it rides along ONLY when the fold re-walked nothing, that is, every path is a
|
|
125
|
+
# snapshot bundle with an unchanged digest and no path was added, removed or replaced by the editor buffer.
|
|
126
|
+
# Otherwise it is dropped, as {Analysis::IncrementalSession#fresh_param_table} recomputes rather than reuses
|
|
127
|
+
# it. Absent when the gate is off or the table is empty, which keeps the bundle-only seed.
|
|
128
|
+
def with_snapshot_param_table(tables, param_table, configuration, paths:, bundles:, buffer:)
|
|
129
|
+
return tables unless configuration.parameter_inference
|
|
130
|
+
return tables if param_table.nil? || param_table.empty?
|
|
131
|
+
return tables unless snapshot_current?(paths, bundles, buffer)
|
|
132
|
+
|
|
133
|
+
tables.merge(param_inferred_types: param_table).freeze
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def snapshot_current?(paths, bundles, buffer)
|
|
137
|
+
return false unless paths.size == bundles.size
|
|
138
|
+
|
|
139
|
+
paths.all? do |path|
|
|
140
|
+
cached = bundles[path]
|
|
141
|
+
cached && cached[:digest] == Cache::FileDigest.hexdigest(buffer ? buffer.resolve(path) : path)
|
|
142
|
+
end
|
|
143
|
+
rescue SystemCallError
|
|
144
|
+
false
|
|
115
145
|
end
|
|
116
146
|
|
|
117
147
|
# The configured file list with the entry that reaches `buffer`'s file respelled as the buffer's logical
|
|
@@ -128,12 +158,21 @@ module Rigor
|
|
|
128
158
|
end
|
|
129
159
|
end
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
# The bare single-file scope, or that scope with `seed`'s tables folded in. The one place `rigor type-of` and the
|
|
162
|
+
# language server's editor queries (#2282) fold a seed into a scope.
|
|
163
|
+
def seeded_scope(environment:, seed:)
|
|
164
|
+
base = Scope.empty(environment: environment)
|
|
165
|
+
return base if seed.nil? || seed.empty?
|
|
166
|
+
|
|
167
|
+
base.with_discovery(base.discovery.with(**seed))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def snapshot_payload(configuration)
|
|
132
171
|
fingerprint = Cache::IncrementalSnapshot.fingerprint(configuration: configuration, roots: configuration.paths)
|
|
133
172
|
return nil if fingerprint.nil?
|
|
134
173
|
|
|
135
174
|
loaded = Cache::IncrementalSnapshot.new(root: configuration.cache_path).load_any(fingerprints: [fingerprint])
|
|
136
|
-
loaded&.last
|
|
175
|
+
loaded&.last
|
|
137
176
|
end
|
|
138
177
|
|
|
139
178
|
# The whole-project discovery tables, from the single-walk combined pass (one parse per file) that
|
|
@@ -215,7 +215,10 @@ module Rigor
|
|
|
215
215
|
end,
|
|
216
216
|
"patched_overrides" => project_scan.project_patched_methods.overrides.map do |key, visibility|
|
|
217
217
|
[*key, visibility].map(&:to_s)
|
|
218
|
-
end
|
|
218
|
+
end,
|
|
219
|
+
"patched_singleton_copies" => project_scan.project_patched_methods.singleton_copies.map do |owner, name|
|
|
220
|
+
[owner.to_s, name.to_s]
|
|
221
|
+
end.sort
|
|
219
222
|
}
|
|
220
223
|
Digest::SHA256.hexdigest(JSON.generate(payload))
|
|
221
224
|
rescue StandardError
|
|
@@ -138,7 +138,7 @@ module Rigor
|
|
|
138
138
|
QUOTES = ['"', "'"].freeze
|
|
139
139
|
# Mutating an argument to a universal-equality method is always an equivalent mutant: Ruby's `==` / `<=>`
|
|
140
140
|
# family returns false / nil on a type mismatch rather than raising, so the engine exempts them
|
|
141
|
-
# (`UNIVERSAL_EQUALITY_METHODS
|
|
141
|
+
# (`CheckRules::UNIVERSAL_EQUALITY_METHODS`; keep the two in step). Skip them to keep survivors meaningful.
|
|
142
142
|
UNIVERSAL_EQUALITY = %w[== != eql? equal? <=>].freeze
|
|
143
143
|
|
|
144
144
|
# Every operator the mutator knows. Each maps to the diagnostic rule family it is *engineered* to trip when
|
|
@@ -52,11 +52,9 @@ module Rigor
|
|
|
52
52
|
# `.rbs` files, plus the virtual entries rbs-inline and plugin `source_rbs` synthesis contribute.
|
|
53
53
|
# @param registry — the vocabulary an unknown label is judged against.
|
|
54
54
|
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# documentation promises, and what every warm envelope-lane run was paying a full
|
|
59
|
-
# `RBS::Parser.parse_signature` per file for.
|
|
55
|
+
# A source with no honoured payload can contribute neither an envelope nor an unresolved report, so the
|
|
56
|
+
# `ANNOTATION_HINT` test skips it before any parse: one regex per file, not a full
|
|
57
|
+
# `RBS::Parser.parse_signature`.
|
|
60
58
|
def scan(sources:, registry:)
|
|
61
59
|
reporter = Reporter.new
|
|
62
60
|
methods = {}
|
|
@@ -128,7 +126,7 @@ module Rigor
|
|
|
128
126
|
def walk(decl, prefix, methods, classes, registry, reporter)
|
|
129
127
|
return unless decl.is_a?(::RBS::AST::Declarations::Class) || decl.is_a?(::RBS::AST::Declarations::Module)
|
|
130
128
|
|
|
131
|
-
nested =
|
|
129
|
+
nested = ::Rigor::Environment::RbsLoader.declared_class_path(decl, prefix)
|
|
132
130
|
class_name = nested.join("::")
|
|
133
131
|
envelope = RbsExtended.read_effect_envelope(
|
|
134
132
|
decl.annotations, owner_key: class_name, source: :class_annotation,
|
|
@@ -287,17 +287,13 @@ module Rigor
|
|
|
287
287
|
source_location.respond_to?(:start_line) ? source_location.start_line : nil
|
|
288
288
|
end
|
|
289
289
|
|
|
290
|
-
# Issue #785 — routes a declined directive to the per-run reporter. The
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
# dropped in every real run, while the doc comments claimed an `:info` entry was recorded. The
|
|
295
|
-
# position is flattened at record time through {RbsExtended::Reporter.position_of}, the one place
|
|
296
|
-
# every stream flattens through since #805, because the entry has to reach the pool drain channel as
|
|
297
|
-
# primitives (see {RbsExtended::Reporter}).
|
|
290
|
+
# Issue #785 — routes a declined directive to the per-run reporter. The first arm matters: the production
|
|
291
|
+
# {RbsExtended::Reporter} has `record_hkt_error` and neither `#record` nor `#<<`, so before this arm existed
|
|
292
|
+
# every malformed HKT directive was dropped in real runs. The position is flattened at record time through
|
|
293
|
+
# {RbsExtended::Reporter.position_of} (see {RbsExtended::Reporter} on why the entry carries primitives).
|
|
298
294
|
#
|
|
299
|
-
# The `#record` / `#<<` arms
|
|
300
|
-
#
|
|
295
|
+
# The `#record` / `#<<` arms serve the collecting doubles the directive specs and plugin authors use; the
|
|
296
|
+
# contract is the one `scan_rbs_loader` documents for its `reporter` parameter.
|
|
301
297
|
def record_hkt_error(reporter, message, source_location)
|
|
302
298
|
return if reporter.nil?
|
|
303
299
|
|
|
@@ -48,6 +48,16 @@ module Rigor
|
|
|
48
48
|
HktDirectiveEntry = Data.define(:message, :path, :line, :column)
|
|
49
49
|
DeprecatedFormEntry = Data.define(:payload, :replacement, :path, :line, :column)
|
|
50
50
|
|
|
51
|
+
# Every stream, by its reader, with the record method that replays one of its entries: an entry's
|
|
52
|
+
# members are that method's keywords. {#snapshot} and {#absorb} walk this table, so a new stream is
|
|
53
|
+
# declared here and nowhere else in the pool drain (ADR-116 WD3).
|
|
54
|
+
STREAMS = {
|
|
55
|
+
unresolved_payloads: :record_unresolved,
|
|
56
|
+
lossy_projections: :record_lossy_projection,
|
|
57
|
+
hkt_directive_errors: :record_hkt_error,
|
|
58
|
+
deprecated_forms: :record_deprecated_form
|
|
59
|
+
}.freeze
|
|
60
|
+
|
|
51
61
|
# Flattens an `RBS::Location` (or anything answering the same readers) to the `(path, line, column)`
|
|
52
62
|
# triple every entry carries. `column` is 1-based, since `RBS::Location#start_column` is 0-based and
|
|
53
63
|
# diagnostics are not. Each component is `nil` when the location cannot supply it, and the diagnostic
|
|
@@ -160,9 +170,23 @@ module Rigor
|
|
|
160
170
|
# True when no events have accumulated. Used by callers that want to skip the diagnostic-emission pass
|
|
161
171
|
# entirely on the common no-event path.
|
|
162
172
|
def empty?
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
STREAMS.each_key.all? { |stream| public_send(stream).empty? }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# The drain a pool worker hands back: every stream's frozen entries by reader name. Marshal-clean and
|
|
177
|
+
# shareable, since each entry carries `(path, line, column)` primitives (#785, #805).
|
|
178
|
+
def snapshot
|
|
179
|
+
STREAMS.each_key.to_h { |stream| [stream, public_send(stream)] }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Replays one worker's {#snapshot} through the record methods, whose dedup collapses the copies every
|
|
183
|
+
# worker hands over to the single row a `--workers=0` run prints. A missing stream (an older drain
|
|
184
|
+
# shape) or a nil snapshot records nothing.
|
|
185
|
+
def absorb(snapshot)
|
|
186
|
+
return if snapshot.nil?
|
|
187
|
+
|
|
188
|
+
STREAMS.each do |stream, record|
|
|
189
|
+
Array(snapshot[stream]).each { |entry| public_send(record, **entry.to_h) }
|
|
166
190
|
end
|
|
167
191
|
end
|
|
168
192
|
|
data/lib/rigor/rbs_extended.rb
CHANGED
|
@@ -513,7 +513,7 @@ module Rigor
|
|
|
513
513
|
Type::Nominal.new(normalized)
|
|
514
514
|
end
|
|
515
515
|
|
|
516
|
-
# Returned for `rigor:v1:param: <name> <refinement>`. The parameter name is a Ruby identifier
|
|
516
|
+
# Returned for `rigor:v1:param: <name> <refinement>`. The parameter name is a Ruby identifier; the
|
|
517
517
|
# type is any `Rigor::Type` the refinement parser resolves (bare kebab-case name, parameterised form, or
|
|
518
518
|
# `Integer[a..b]` range, or the deprecated `int<a, b>` — the same grammar the `return:` directive accepts).
|
|
519
519
|
ParamOverride = Data.define(:param_name, :type)
|
|
@@ -554,7 +554,7 @@ module Rigor
|
|
|
554
554
|
end
|
|
555
555
|
|
|
556
556
|
# Convenience reader for call sites that want to look up a single override by parameter name. Returns a
|
|
557
|
-
# frozen
|
|
557
|
+
# frozen map from parameter name to type; missing keys mean "use the RBS-declared type". Callers MUST treat the
|
|
558
558
|
# hash as read-only.
|
|
559
559
|
def param_type_override_map(method_def, environment: nil)
|
|
560
560
|
overrides = read_param_type_overrides(method_def, environment: environment)
|
|
@@ -728,7 +728,6 @@ module Rigor
|
|
|
728
728
|
NO_EFFECT_LABELS = [].freeze
|
|
729
729
|
private_constant :NO_EFFECT_LABELS
|
|
730
730
|
|
|
731
|
-
# Whether `string` is the bare `%a{pure}` annotation.
|
|
732
731
|
def pure_annotation?(string)
|
|
733
732
|
!string.nil? && PURE_ANNOTATION_PATTERN.match?(string)
|
|
734
733
|
end
|