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
|
@@ -15,8 +15,8 @@ module Rigor
|
|
|
15
15
|
# reason has no severity, no profile mapping and no suppression, and forcing it into {RuleCatalog::Entry}
|
|
16
16
|
# would mean inventing four fields that do not apply.
|
|
17
17
|
#
|
|
18
|
-
# Every id in {Classification::SKIP_DIAGNOSTIC_IDS} MUST have an entry here; the gate is
|
|
19
|
-
# `spec/rigor/
|
|
18
|
+
# Every id in {Classification::SKIP_DIAGNOSTIC_IDS} MUST have an entry here; the gate is the
|
|
19
|
+
# `sig.skipped.*` example in `spec/rigor/cli_spec.rb`.
|
|
20
20
|
module SkipReasonCatalog
|
|
21
21
|
class Entry < Data.define(:id, :summary, :explanation, :next_step)
|
|
22
22
|
# Hash-shaped form for `rigor explain --format=json`. String keys, and `kind` distinguishes a skip
|
|
@@ -110,6 +110,19 @@ module Rigor
|
|
|
110
110
|
next_step: "Declare the class in `sig/` with the same type parameters as the inline declaration " \
|
|
111
111
|
"(`class Box[T]` ... `end`) and re-run; sig-gen then writes the members into it."
|
|
112
112
|
),
|
|
113
|
+
"sig.skipped.generic-reopening" => Entry.new(
|
|
114
|
+
id: "sig.skipped.generic-reopening",
|
|
115
|
+
summary: "The method reopens a generic class whose type parameters sig-gen cannot copy onto a header.",
|
|
116
|
+
explanation: "The class (or one it is nested in) is declared generic by loaded RBS — core, stdlib, a gem " \
|
|
117
|
+
"or `sig/` — and one of its type parameters has an upper bound or a default. sig-gen copies " \
|
|
118
|
+
"a declaration's type parameters onto the header it writes only when every one is plain, " \
|
|
119
|
+
"because a bound or default is a type spelled relative to the declaring file and can name " \
|
|
120
|
+
"a different class under another nesting. A header without the parameters, or with ones " \
|
|
121
|
+
"that differ, is rejected by rbs (`GenericParameterMismatchError`): the class, and every " \
|
|
122
|
+
"class whose signature mentions it, would fail its definition build.",
|
|
123
|
+
next_step: "Declare the class in `sig/` with the declaration's own type parameters (`class Box[T < " \
|
|
124
|
+
"Comparable]` ... `end`) and re-run; sig-gen then writes the members into that declaration."
|
|
125
|
+
),
|
|
113
126
|
"sig.skipped.inline-differs" => Entry.new(
|
|
114
127
|
id: "sig.skipped.inline-differs",
|
|
115
128
|
summary: "The method's inline declaration and its `sig/` declaration disagree; neither was changed.",
|
|
@@ -136,6 +149,38 @@ module Rigor
|
|
|
136
149
|
next_step: "Generate signatures for the overriding subclass too — widen the `sig-gen` path set to " \
|
|
137
150
|
"cover it — and the parent's declaration becomes safe to emit."
|
|
138
151
|
),
|
|
152
|
+
"sig.skipped.overridden-bot" => Entry.new(
|
|
153
|
+
id: "sig.skipped.overridden-bot",
|
|
154
|
+
summary: "The method's body never returns, and the analysed code overrides the method.",
|
|
155
|
+
explanation: "The inferred return is `bot`, but the analysed code defines the method again, with `def` " \
|
|
156
|
+
"or `define_method`: a subclass (signed or not), a class that includes the method's module, " \
|
|
157
|
+
"a module included later or prepended, or an extending class's own singleton method. " \
|
|
158
|
+
"`bot` describes only the base body the overrides replace, and every override returns a " \
|
|
159
|
+
"value, so the declaration would contradict each of them (#3029).",
|
|
160
|
+
next_step: "Declare the return every implementation shares (often `untyped` or the overrides' common " \
|
|
161
|
+
"type) by hand in `sig/`."
|
|
162
|
+
),
|
|
163
|
+
"sig.skipped.abstract-method" => Entry.new(
|
|
164
|
+
id: "sig.skipped.abstract-method",
|
|
165
|
+
summary: "The method is abstract: its body only raises an error asking for an implementation.",
|
|
166
|
+
explanation: "The body ends in `raise NotImplementedError`, in an error class named `Abstract...` or " \
|
|
167
|
+
"`NotImplemented...`, or in a raise whose message asks for the method to be implemented, " \
|
|
168
|
+
"defined or overridden. Its inferred return is `bot`, but the method is meant to be " \
|
|
169
|
+
"replaced, and the replacements may live outside the analysed code, as in a plugin gem " \
|
|
170
|
+
"(#3029).",
|
|
171
|
+
next_step: "Declare the return the implementations must provide by hand in `sig/`."
|
|
172
|
+
),
|
|
173
|
+
"sig.skipped.template-method" => Entry.new(
|
|
174
|
+
id: "sig.skipped.template-method",
|
|
175
|
+
summary: "The method's `bot` return may come only from calling an overridden or abstract method.",
|
|
176
|
+
explanation: "The inferred return is `bot`, and the body does not end in a direct `raise`, `fail`, " \
|
|
177
|
+
"`throw`, `exit` or `abort`. It calls a method the analysed code overrides or declares " \
|
|
178
|
+
"abstract, directly or through a chain of self-dispatched calls, so the `bot` may be only " \
|
|
179
|
+
"the base body of that call, which an override replaces at run time. The call is matched " \
|
|
180
|
+
"by name, whatever its receiver (#3029).",
|
|
181
|
+
next_step: "Declare the return by hand in `sig/`, usually the return the overridden hook's " \
|
|
182
|
+
"implementations share."
|
|
183
|
+
),
|
|
139
184
|
"sig.skipped.top-level-def" => Entry.new(
|
|
140
185
|
id: "sig.skipped.top-level-def",
|
|
141
186
|
summary: "A top-level `def` defines a private `Object` method, and sig-gen writes no signature for it.",
|
|
@@ -158,6 +203,21 @@ module Rigor
|
|
|
158
203
|
"writes neither rather than guess (#1968).",
|
|
159
204
|
next_step: "Move the visibility call to the module body's own statements, or name the methods it " \
|
|
160
205
|
"should cover (`public :name`, `module_function :name`), so the reading is certain."
|
|
206
|
+
),
|
|
207
|
+
"sig.skipped.platform-guarded" => Entry.new(
|
|
208
|
+
id: "sig.skipped.platform-guarded",
|
|
209
|
+
summary: "The method is defined in a file loaded only under a platform guard, so its proposal was withheld.",
|
|
210
|
+
explanation: "The file is `require`d / `require_relative`d only inside a conditional on " \
|
|
211
|
+
"`RUBY_ENGINE`, `RUBY_PLATFORM` or `defined?(…)`, so it is not an ordinary definition " \
|
|
212
|
+
"for every platform — the shape is `if RUBY_ENGINE == 'truffleruby'` guarding a " \
|
|
213
|
+
"pure-Ruby fallback whose real methods a C extension provides elsewhere. sig-gen " \
|
|
214
|
+
"withholds the proposal when another scanned file also defines the method (the " \
|
|
215
|
+
"guarded copy would compete with or duplicate the definition this platform loads), " \
|
|
216
|
+
"or when the inferred return is `bot` — the shape a raising stub takes, and never a " \
|
|
217
|
+
"contract worth writing from a file the current engine may never read (#3035).",
|
|
218
|
+
next_step: "Declare the method for the platform the project targets — hand-write the `sig/` " \
|
|
219
|
+
"entry, or cover the file that defines it on this platform in the `sig-gen` paths — " \
|
|
220
|
+
"rather than taking the guarded file's stub as the contract."
|
|
161
221
|
)
|
|
162
222
|
}.freeze
|
|
163
223
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module SigGen
|
|
7
|
+
# Issue [#2230](https://github.com/rigortype/rigor/issues/2230) — a rendered type names every class by its
|
|
8
|
+
# fully qualified name, but without the leading `::`: `Type::Nominal#erase_to_rbs` writes `Set[untyped]` for
|
|
9
|
+
# `::Set`. RBS resolves a relative name against the declaration it is written in, innermost namespace first,
|
|
10
|
+
# so inside `module Foo` that declares a `Foo::Set` the written `Set[untyped]` names `::Foo::Set`. A generic
|
|
11
|
+
# name then fails validation ("expects parameters [], but given args [untyped]"); a non-generic one types the
|
|
12
|
+
# method as the wrong class without a word.
|
|
13
|
+
#
|
|
14
|
+
# This anchors a name with `::` only where the namespace the member is written in, or one enclosing it,
|
|
15
|
+
# declares a constant with the name's first segment. Where nothing shadows it the spelling is unchanged, so
|
|
16
|
+
# output for the common case does not churn. The check is over every enclosing namespace of the owner, which
|
|
17
|
+
# covers both the nested `module Foo` / `class Bar` layout the writer emits and a compact `class Foo::Bar`
|
|
18
|
+
# header, and it may anchor a name RBS would have resolved correctly anyway: an anchored name is never wrong,
|
|
19
|
+
# while a missed one is.
|
|
20
|
+
module TypeNameQualification
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
NAMED_TYPES = [
|
|
24
|
+
RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Alias, RBS::Types::Interface
|
|
25
|
+
].freeze
|
|
26
|
+
private_constant :NAMED_TYPES
|
|
27
|
+
|
|
28
|
+
# A capitalised word not already preceded by `::` or part of a longer identifier: the first segment of a
|
|
29
|
+
# relative class name. A cheap filter so the common case never reaches the parser.
|
|
30
|
+
RELATIVE_HEAD = /(?<![\w:])[A-Z]\w*/
|
|
31
|
+
private_constant :RELATIVE_HEAD
|
|
32
|
+
|
|
33
|
+
# @param rendered — an erased RBS type whose names each spell the class they mean from the top level.
|
|
34
|
+
# @param owner — the qualified name of the class or module the type is written in; nil at the top level.
|
|
35
|
+
# @param declared — called with a qualified name (`"Foo::Set"`); true when the project or the RBS
|
|
36
|
+
# environment declares a constant there.
|
|
37
|
+
def qualify(rendered, owner, &declared)
|
|
38
|
+
namespaces = enclosing_namespaces(owner)
|
|
39
|
+
return rendered if namespaces.empty?
|
|
40
|
+
return rendered unless rendered.scan(RELATIVE_HEAD).any? { |head| shadowed?(head, namespaces, declared) }
|
|
41
|
+
|
|
42
|
+
positions = []
|
|
43
|
+
collect_positions(RBS::Parser.parse_type(rendered, require_eof: true), namespaces, declared, positions)
|
|
44
|
+
positions.sort.reverse_each.with_object(+rendered) { |position, out| out.insert(position, "::") }
|
|
45
|
+
rescue RBS::ParsingError
|
|
46
|
+
rendered
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# `"A::B::C"` → `["A::B::C", "A::B", "A"]`: every namespace a relative name written in `A::B::C`'s
|
|
50
|
+
# declaration is looked up in before the top level.
|
|
51
|
+
def enclosing_namespaces(owner)
|
|
52
|
+
segments = owner.to_s.delete_prefix("::").split("::")
|
|
53
|
+
segments.size.downto(1).map { |n| segments.first(n).join("::") }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def collect_positions(type, namespaces, declared, positions)
|
|
57
|
+
if NAMED_TYPES.any? { |klass| type.is_a?(klass) } && !type.name.absolute?
|
|
58
|
+
head = (type.name.namespace.path.first || type.name.name).to_s
|
|
59
|
+
positions << type.location[:name].start_pos if shadowed?(head, namespaces, declared)
|
|
60
|
+
end
|
|
61
|
+
type.each_type { |child| collect_positions(child, namespaces, declared, positions) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def shadowed?(head, namespaces, declared)
|
|
65
|
+
namespaces.any? { |namespace| declared.call("#{namespace}::#{head}") }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
|
+
require_relative "../cli/json_document"
|
|
6
|
+
|
|
5
7
|
require_relative "classification"
|
|
6
8
|
|
|
7
9
|
module Rigor
|
|
@@ -18,10 +20,13 @@ module Rigor
|
|
|
18
20
|
# @param refused — methods refused as `sig.skipped.inline-differs`; the JSON payload names them under
|
|
19
21
|
# `refused` (absent when there are none, so an ordinary payload is unchanged), and text mode leaves them
|
|
20
22
|
# to the command's stderr `REFUSED` lines.
|
|
21
|
-
|
|
23
|
+
# @param left_bare — the generic classes whose bare headers the writer held back from the repair (#2605,
|
|
24
|
+
# {Writer#left_bare}); the JSON payload names them under `left_bare` (absent when there are none), and text
|
|
25
|
+
# mode prints one `generic header left bare` line each.
|
|
26
|
+
def render_write(results:, format:, refused: [], left_bare: [])
|
|
22
27
|
case format
|
|
23
|
-
when "json" then render_write_json(results, refused)
|
|
24
|
-
when "text" then
|
|
28
|
+
when "json" then render_write_json(results, refused, left_bare)
|
|
29
|
+
when "text" then render_write_text_with_left_bare(results, left_bare)
|
|
25
30
|
else raise ArgumentError, "unsupported format: #{format}"
|
|
26
31
|
end
|
|
27
32
|
end
|
|
@@ -32,14 +37,19 @@ module Rigor
|
|
|
32
37
|
#
|
|
33
38
|
# @param refused — the methods the generator refused to reconcile (`sig.skipped.inline-differs`):
|
|
34
39
|
# `sig/` is not up to date while one stands, and `--write` cannot fix it.
|
|
35
|
-
|
|
40
|
+
#
|
|
41
|
+
# @param left_bare — as for {#render_write}; reported, but it does not make `sig/` out of date.
|
|
42
|
+
def render_check(results:, format:, refused: [], left_bare: [])
|
|
36
43
|
stale = self.class.out_of_date(results)
|
|
37
44
|
case format
|
|
38
45
|
when "json"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
payload = { up_to_date: stale.empty? && refused.empty?, results: stale.map { |r| check_entry(r) },
|
|
47
|
+
refused: refused.map(&:to_h) }
|
|
48
|
+
payload[:left_bare] = left_bare unless left_bare.empty?
|
|
49
|
+
@out.puts(JSON.pretty_generate(CLI::JsonDocument.stamp(payload)))
|
|
50
|
+
when "text"
|
|
51
|
+
render_check_text(stale, refused)
|
|
52
|
+
render_left_bare(left_bare)
|
|
43
53
|
else raise ArgumentError, "unsupported format: #{format}"
|
|
44
54
|
end
|
|
45
55
|
end
|
|
@@ -89,6 +99,7 @@ module Rigor
|
|
|
89
99
|
when :created, :updated then render_check_change(result)
|
|
90
100
|
when :skipped_invalid_rbs then render_write_invalid(result)
|
|
91
101
|
when :skipped_invalid_encoding then render_write_invalid_encoding(result)
|
|
102
|
+
when :skipped_unparseable then render_write_unparseable(result)
|
|
92
103
|
end
|
|
93
104
|
end
|
|
94
105
|
end
|
|
@@ -103,12 +114,17 @@ module Rigor
|
|
|
103
114
|
end
|
|
104
115
|
end
|
|
105
116
|
|
|
106
|
-
|
|
117
|
+
# "No changes" only when nothing at all is reported: a header held back is news even when no file changed.
|
|
118
|
+
def render_write_text_with_left_bare(results, left_bare)
|
|
107
119
|
if results.all? { |r| r.action == :noop && r.skipped.empty? }
|
|
108
|
-
@out.puts("No changes")
|
|
109
|
-
|
|
120
|
+
@out.puts("No changes") if left_bare.empty?
|
|
121
|
+
else
|
|
122
|
+
render_write_text(results)
|
|
110
123
|
end
|
|
124
|
+
render_left_bare(left_bare)
|
|
125
|
+
end
|
|
111
126
|
|
|
127
|
+
def render_write_text(results)
|
|
112
128
|
results.each do |result|
|
|
113
129
|
case result.action
|
|
114
130
|
when :created then render_write_created(result)
|
|
@@ -117,6 +133,7 @@ module Rigor
|
|
|
117
133
|
when :skipped_outside_sig_root then render_write_skipped(result)
|
|
118
134
|
when :skipped_invalid_rbs then render_write_invalid(result)
|
|
119
135
|
when :skipped_invalid_encoding then render_write_invalid_encoding(result)
|
|
136
|
+
when :skipped_unparseable then render_write_unparseable(result)
|
|
120
137
|
end
|
|
121
138
|
end
|
|
122
139
|
end
|
|
@@ -125,7 +142,29 @@ module Rigor
|
|
|
125
142
|
# because "added 2" when one of them rewrote a line the project already had would understate the change.
|
|
126
143
|
def applied_counts(result)
|
|
127
144
|
added = "+#{result.applied.size - result.replaced.size}"
|
|
128
|
-
|
|
145
|
+
added = "#{added}, replaced #{result.replaced.size}" unless result.replaced.empty?
|
|
146
|
+
repaired = result.repaired_headers
|
|
147
|
+
repaired.empty? ? added : "#{added}, repaired #{repaired.size} generic header(s): #{repaired.join(', ')}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# #2605 — one line per generic class the writer left with a bare header: every file holding one, and the
|
|
151
|
+
# parameter names the blocking bodies spell. rbs keeps rejecting the class until those names are anchored
|
|
152
|
+
# (`::E`) or the headers are given parameters by hand.
|
|
153
|
+
def render_left_bare(left_bare)
|
|
154
|
+
left_bare.each do |entry|
|
|
155
|
+
reasons = entry.fetch(:blocking).map { |blocking| left_bare_reason(blocking) }
|
|
156
|
+
@out.puts("generic header left bare: #{entry.fetch(:class)} in #{entry.fetch(:targets).join(', ')} " \
|
|
157
|
+
"(#{reasons.join('; ')})")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def left_bare_reason(blocking)
|
|
162
|
+
if blocking.fetch(:reason) == "outside_sig_root"
|
|
163
|
+
"an opening outside the sig root at #{blocking.fetch(:target)}, which --write does not rewrite"
|
|
164
|
+
else
|
|
165
|
+
"#{blocking.fetch(:target)} names #{blocking.fetch(:names).join(', ')}, which the type parameter would " \
|
|
166
|
+
"capture"
|
|
167
|
+
end
|
|
129
168
|
end
|
|
130
169
|
|
|
131
170
|
def render_write_created(result)
|
|
@@ -193,10 +232,20 @@ module Rigor
|
|
|
193
232
|
@out.puts(" Re-save the file as UTF-8 and re-run; sig-gen never modifies a file it cannot read faithfully.")
|
|
194
233
|
end
|
|
195
234
|
|
|
196
|
-
|
|
235
|
+
# The EXISTING target file does not parse as RBS, so the writer will not merge into it (#2480). Like the
|
|
236
|
+
# encoding refusal the fix is the user's: the file is quarantined whole by `rigor check` until it parses.
|
|
237
|
+
def render_write_unparseable(result)
|
|
238
|
+
@out.puts("REFUSED #{result.target_path} — the existing file was not updated")
|
|
239
|
+
@out.puts(" #{result.error}")
|
|
240
|
+
@out.puts(" Fix the syntax error and re-run; sig-gen never modifies a file it cannot parse.")
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def render_write_json(results, refused, left_bare)
|
|
197
244
|
payload = { results: results.map(&:to_h) }
|
|
198
245
|
payload[:refused] = refused.map(&:to_h) unless refused.empty?
|
|
199
|
-
|
|
246
|
+
# Absent when every bare generic header was repaired, so an ordinary payload is unchanged (#2605).
|
|
247
|
+
payload[:left_bare] = left_bare unless left_bare.empty?
|
|
248
|
+
@out.puts(JSON.pretty_generate(CLI::JsonDocument.stamp(payload)))
|
|
200
249
|
end
|
|
201
250
|
end
|
|
202
251
|
end
|
|
@@ -11,7 +11,7 @@ module Rigor
|
|
|
11
11
|
# - `target_path` — `.rbs` file the writer was responsible for (`nil` when the source path falls outside
|
|
12
12
|
# the project signature tree, in which case `action` is `:skipped_outside_sig_root`).
|
|
13
13
|
# - `action` — one of `:created` / `:updated` / `:noop` / `:skipped_outside_sig_root` /
|
|
14
|
-
# `:skipped_invalid_rbs` / `:skipped_invalid_encoding`.
|
|
14
|
+
# `:skipped_invalid_rbs` / `:skipped_invalid_encoding` / `:skipped_unparseable`.
|
|
15
15
|
# - `applied` — the {MethodCandidate}s that actually landed on disk.
|
|
16
16
|
# - `replaced` — the subset of `applied` that replaced an existing declaration rather than adding one
|
|
17
17
|
# (`--overwrite`'s tighter returns, and inline updates).
|
|
@@ -23,16 +23,20 @@ module Rigor
|
|
|
23
23
|
# target declaration already carries annotations, so its bytes were left alone
|
|
24
24
|
# (`sig.effect.left-unreadable`; see {Writer#splice_annotations}). The signature line itself was
|
|
25
25
|
# still updated.
|
|
26
|
+
# - `repaired_headers` — the existing class or module headers the writer gave a generic class's type
|
|
27
|
+
# parameters (`"Array[unchecked out E]"`), because the file opened it with none (#2580).
|
|
26
28
|
# - `error` — the refusal cause, when `action` is a refusal: for `:skipped_invalid_rbs` the file the writer
|
|
27
29
|
# assembled does not parse, so it was NOT written (writing it would poison the project's sig tree — the
|
|
28
30
|
# consumer quarantines an unparseable `.rbs`, taking every other type in that file down with it); for
|
|
29
31
|
# `:skipped_invalid_encoding` the EXISTING target file is not valid UTF-8, so the writer refuses to merge
|
|
30
|
-
# into content it cannot read faithfully
|
|
32
|
+
# into content it cannot read faithfully; for `:skipped_unparseable` the EXISTING target file does not parse
|
|
33
|
+
# as RBS, so the writer refuses to merge into it (#2480).
|
|
31
34
|
class WriteResult
|
|
32
|
-
attr_reader :source_path, :target_path, :action, :applied, :skipped, :error, :left_unreadable, :replaced
|
|
35
|
+
attr_reader :source_path, :target_path, :action, :applied, :skipped, :error, :left_unreadable, :replaced,
|
|
36
|
+
:repaired_headers
|
|
33
37
|
|
|
34
38
|
def initialize(source_path:, target_path:, action:, applied: [], skipped: [], error: nil, # rubocop:disable Metrics/ParameterLists
|
|
35
|
-
left_unreadable: [], replaced: [])
|
|
39
|
+
left_unreadable: [], replaced: [], repaired_headers: [])
|
|
36
40
|
@source_path = source_path
|
|
37
41
|
@target_path = target_path
|
|
38
42
|
@action = action
|
|
@@ -41,6 +45,7 @@ module Rigor
|
|
|
41
45
|
@error = error
|
|
42
46
|
@left_unreadable = left_unreadable.freeze
|
|
43
47
|
@replaced = replaced.freeze
|
|
48
|
+
@repaired_headers = repaired_headers.freeze
|
|
44
49
|
freeze
|
|
45
50
|
end
|
|
46
51
|
|
|
@@ -51,14 +56,20 @@ module Rigor
|
|
|
51
56
|
action: action.to_s,
|
|
52
57
|
applied: applied.map(&:to_h),
|
|
53
58
|
skipped: skipped.map { |c, reason| c.to_h.merge(write_skip_reason: reason.to_s) }
|
|
54
|
-
}.tap
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
}.tap { |h| add_optional_entries(h) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def add_optional_entries(hash)
|
|
65
|
+
hash[:error] = error if error
|
|
66
|
+
# Absent when nothing was replaced, so a run that only adds lines keeps its pre-#1076 payload.
|
|
67
|
+
hash[:replaced] = replaced.map(&:to_h) unless replaced.empty?
|
|
68
|
+
# Absent when no header was repaired (#2580), for the same reason.
|
|
69
|
+
hash[:repaired_headers] = repaired_headers unless repaired_headers.empty?
|
|
70
|
+
# Absent rather than empty when nothing was left: an effects-off payload stays byte-identical
|
|
71
|
+
# to a pre-#391 one.
|
|
72
|
+
hash[:effect_left_unreadable] = left_unreadable.map(&:to_h) unless left_unreadable.empty?
|
|
62
73
|
end
|
|
63
74
|
end
|
|
64
75
|
end
|