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
|
@@ -107,8 +107,9 @@ module Rigor
|
|
|
107
107
|
# difference is worth stating because the two look like the same problem. There, a stale
|
|
108
108
|
# `bundler/gems/` directory left behind by a gem that moved to a released version made the loader
|
|
109
109
|
# load the WRONG SIGNATURES, collapsing the RBS environment. Here the index's whole output is a gem
|
|
110
|
-
# NAME, so reading a stale checkout of the same gem yields the same answer; and the
|
|
111
|
-
# is consulted FIRST in {.build}, so a gem
|
|
110
|
+
# NAME, so reading a stale checkout of the same gem yields the same answer; and the RubyGems-layout
|
|
111
|
+
# bundle directory is consulted FIRST in {.build}, so a gem installed from RubyGems at its locked
|
|
112
|
+
# version never reaches this map.
|
|
112
113
|
def git_gem_dirs(bundle_path)
|
|
113
114
|
return {} if bundle_path.nil?
|
|
114
115
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../analysis/path_expansion"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
class Environment
|
|
7
|
+
# Issue #2441 — the locked gems that ARE the analysed project: a `PATH` stanza whose directory Rigor analyses
|
|
8
|
+
# as project source. `rbs collection install` still fetches community RBS for such a gem (its generator skips
|
|
9
|
+
# only a `gemspec` source), and the project's `sig/` declares the same classes, so the collection copy would
|
|
10
|
+
# double-declare every member. The same gem is not `:missing` RBS either, so it must not make an ADR-72
|
|
11
|
+
# overlay or a WD9 missing-gem index entry eligible.
|
|
12
|
+
#
|
|
13
|
+
# "Analysed as project source" means the gem's directory is at or under one of the configured `paths:`
|
|
14
|
+
# entries, or contains one: rails lists `actionpack/lib` in `paths:` and locks `actionpack` from
|
|
15
|
+
# `PATH remote: actionpack`. A `PATH` gem no `paths:` entry reaches — a vendored `vendor/gems/foo`, a sibling
|
|
16
|
+
# checkout — is a dependency and keeps its collection RBS.
|
|
17
|
+
#
|
|
18
|
+
# #2592 — a reached gem counts only when the file walker would analyse at least one of its Ruby files: some
|
|
19
|
+
# `**/*.rb` under the part of the gem a `paths:` entry covers survives `Analysis::PathExpansion.reject_excluded`.
|
|
20
|
+
# A gem whose Ruby the configuration's `exclude:` patterns all leave out — `vendor/**`, `vendor/**/*.rb`, or
|
|
21
|
+
# `vendor/gems/foo/lib/**` when `lib/` holds all of it — keeps its collection RBS, and so does a reached
|
|
22
|
+
# directory with no Ruby at all. A `paths:` entry naming one `.rb` file inside the gem counts that file. The
|
|
23
|
+
# overlap is found on real paths, so a symlinked spelling of the same directory matches, but the files are
|
|
24
|
+
# walked and matched against `exclude:` through the `paths:` entry as written, as the walker matches them.
|
|
25
|
+
module ProjectPathGems
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
# @param locked — `{name => LockfileResolver::LockedGem}`.
|
|
29
|
+
# @param paths — the configured `paths:` entries; relative ones resolve against `root`.
|
|
30
|
+
# @param exclude_patterns — the configuration's `exclude_patterns`, matched against `exclude_base`.
|
|
31
|
+
# @return frozen set of gem names. Empty when `paths` is nil or empty.
|
|
32
|
+
def names(locked, paths:, root: Dir.pwd, exclude_patterns: [], exclude_base: root)
|
|
33
|
+
entries = Array(paths).map do |path|
|
|
34
|
+
logical = File.expand_path(path.to_s, root.to_s)
|
|
35
|
+
[logical, real(logical)]
|
|
36
|
+
end.uniq
|
|
37
|
+
return Set.new.freeze if entries.empty?
|
|
38
|
+
|
|
39
|
+
locked.each_value.filter_map do |gem|
|
|
40
|
+
dir = gem.path_source
|
|
41
|
+
next unless dir
|
|
42
|
+
|
|
43
|
+
dir = real(dir)
|
|
44
|
+
covered = entries.filter_map { |logical, real_entry| covered_part(dir, logical, real_entry) }
|
|
45
|
+
gem.name if covered.uniq.any? { |part| analysed_ruby?(part, Array(exclude_patterns), exclude_base.to_s) }
|
|
46
|
+
end.to_set.freeze
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The part of the gem at real directory `dir` that the `paths:` entry covers, spelled through the entry as
|
|
50
|
+
# written (`logical`), as the file walker spells the files it matches `exclude:` against: the entry itself
|
|
51
|
+
# when it lies at or under the gem, or the gem's directory reached through the entry when the gem lies under
|
|
52
|
+
# it. Nil when they do not overlap.
|
|
53
|
+
def covered_part(dir, logical, real_entry)
|
|
54
|
+
return logical if at_or_under?(real_entry, dir)
|
|
55
|
+
return unless at_or_under?(dir, real_entry)
|
|
56
|
+
|
|
57
|
+
rest = dir.byteslice(real_entry.bytesize..).delete_prefix("/")
|
|
58
|
+
rest.empty? ? logical : File.join(logical, rest)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# True when `path` is `dir` or lies under it. Joined with a `/` only when `dir` does not already end in one,
|
|
62
|
+
# so `/` reaches everything without spelling `//`, and `/proj/lib2` is not under `/proj/lib`.
|
|
63
|
+
def at_or_under?(path, dir)
|
|
64
|
+
return true if path == dir
|
|
65
|
+
|
|
66
|
+
path.start_with?(dir.end_with?("/") ? dir : "#{dir}/")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Files are matched in slices as the walk finds them, so a large gem stops at the first slice holding a
|
|
70
|
+
# surviving file instead of listing its whole tree first (`Dir.glob` with a block still builds the list).
|
|
71
|
+
EXCLUDE_SLICE = 64
|
|
72
|
+
private_constant :EXCLUDE_SLICE
|
|
73
|
+
|
|
74
|
+
# True when the file walker ({Analysis::PathExpansion.ruby_files}) would analyse some `.rb` file of `part`:
|
|
75
|
+
# the `.rb` file itself when `part` names one, else a `**/*.rb` under the directory, that survives `patterns`.
|
|
76
|
+
def analysed_ruby?(part, patterns, base)
|
|
77
|
+
return surviving?([part], patterns, base) if File.file?(part)
|
|
78
|
+
return false unless File.directory?(part)
|
|
79
|
+
|
|
80
|
+
slice = []
|
|
81
|
+
found = each_ruby_file(part) do |file|
|
|
82
|
+
slice << file
|
|
83
|
+
next false if slice.size < EXCLUDE_SLICE
|
|
84
|
+
|
|
85
|
+
hit = surviving?(slice, patterns, base)
|
|
86
|
+
slice = []
|
|
87
|
+
hit
|
|
88
|
+
end
|
|
89
|
+
found || surviving?(slice, patterns, base)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Walks `dir` as `Dir.glob("dir/**/*.rb")` matches: sorted, no dot-named entries, no descent through a
|
|
93
|
+
# symlinked directory. Stops and returns true as soon as the block returns true.
|
|
94
|
+
def each_ruby_file(dir, &)
|
|
95
|
+
Dir.children(dir).sort.each do |name|
|
|
96
|
+
next if name.start_with?(".")
|
|
97
|
+
|
|
98
|
+
path = File.join(dir, name)
|
|
99
|
+
if name.end_with?(".rb") && !File.directory?(path)
|
|
100
|
+
return true if File.exist?(path) && yield(path)
|
|
101
|
+
elsif File.directory?(path) && !File.symlink?(path)
|
|
102
|
+
return true if each_ruby_file(path, &)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
false
|
|
106
|
+
rescue SystemCallError
|
|
107
|
+
false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def surviving?(files, patterns, base)
|
|
111
|
+
return false if files.empty?
|
|
112
|
+
return files.any? { |file| file.end_with?(".rb") } if patterns.empty?
|
|
113
|
+
|
|
114
|
+
Analysis::PathExpansion.reject_excluded(files, patterns, base: base).any? { |file| file.end_with?(".rb") }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def real(path)
|
|
118
|
+
File.realpath(path)
|
|
119
|
+
rescue SystemCallError
|
|
120
|
+
File.expand_path(path)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -19,12 +19,16 @@ module Rigor
|
|
|
19
19
|
# access. Failure modes (missing lockfile, malformed YAML, missing collection directory) silently
|
|
20
20
|
# degrade to an empty list.
|
|
21
21
|
module RbsCollectionDiscovery
|
|
22
|
-
# `stdlib`-typed entries
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
22
|
+
# `stdlib`-typed entries (`source: { type: stdlib }`) name a library rbs ships under its own `stdlib/`, and
|
|
23
|
+
# produce no directory under the collection root, so {.discover} never returns one. Issue #2946 — they are
|
|
24
|
+
# loaded all the same, as the `rbs` CLI's `EnvironmentLoader#add_collection` loads them: as RBS LIBRARIES.
|
|
25
|
+
# {.stdlib_library_names} lists them, and `Environment::BaseLibraries.resolve` appends them to the library list,
|
|
26
|
+
# which is de-duplicated, so an entry `DEFAULT_LIBRARIES` already names is not loaded twice. A collection
|
|
27
|
+
# gem that subclasses one (actionview's `NodeParser < ::Ripper`) then builds. An unknown name is dropped by
|
|
28
|
+
# the loader's `has_library?` filter, as a `libraries:` name is, and `ConfigAudit` reports it. The other
|
|
29
|
+
# documented source types — `git` (the gem_rbs_collection repo), `rubygems` (sigs lifted from a gem's
|
|
30
|
+
# bundled `sig/`), and `local` (a user-managed RBS dir) — all produce a directory under the collection root
|
|
31
|
+
# and are admitted by {.discover}.
|
|
28
32
|
#
|
|
29
33
|
# The `source.type` filter alone is NOT sufficient: gems that were extracted from Ruby's stdlib into
|
|
30
34
|
# standalone default gems (e.g. `cgi`, `logger`, `base64`, `csv`, `bigdecimal`) are published in
|
|
@@ -77,6 +81,110 @@ module Rigor
|
|
|
77
81
|
Rigor::ConfigPath.absolute(lockfile_path.to_s, project_root)
|
|
78
82
|
end
|
|
79
83
|
|
|
84
|
+
# Issue #2946 — the `name` of every `source: { type: stdlib }` entry in the lockfile, in lockfile order and
|
|
85
|
+
# de-duplicated, whether or not rbs ships that library: the caller loads them as RBS libraries, and the
|
|
86
|
+
# loader's `has_library?` filter drops an unknown one. Unlike {.discover}, the collection directory need not
|
|
87
|
+
# exist, since a stdlib entry installs nothing there. Returns `[]` when no lockfile resolves or its YAML is
|
|
88
|
+
# unreadable. A pure YAML read, so the ADR-87 boot-slimming probe can rebuild the library list from it.
|
|
89
|
+
def self.stdlib_library_names(lockfile_path:, project_root: Dir.pwd, auto_detect: true)
|
|
90
|
+
resolved = resolve_lockfile_path(lockfile_path: lockfile_path, project_root: project_root,
|
|
91
|
+
auto_detect: auto_detect)
|
|
92
|
+
return [] if resolved.nil?
|
|
93
|
+
|
|
94
|
+
data = read_lockfile_yaml(resolved)
|
|
95
|
+
return [] if data.nil?
|
|
96
|
+
|
|
97
|
+
Array(data["gems"]).filter_map do |entry|
|
|
98
|
+
next unless entry.is_a?(Hash) && SKIPPED_SOURCE_TYPES.include?(source_type(entry))
|
|
99
|
+
|
|
100
|
+
name = entry["name"]
|
|
101
|
+
name.to_s if name.is_a?(String) && !name.empty?
|
|
102
|
+
end.uniq
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Issue #2971 — the `name` of every lockfile entry that is NOT a `stdlib` source and whose
|
|
106
|
+
# `<root>/<name>/<version>/` directory exists: the gems whose signatures come from the collection ({.discover}).
|
|
107
|
+
# The `libraries:` audit uses it so a name the collection provides is not reported as an unknown RBS library.
|
|
108
|
+
# A pure file read, like {.stdlib_library_names}.
|
|
109
|
+
def self.collection_gem_names(lockfile_path:, project_root: Dir.pwd, auto_detect: true)
|
|
110
|
+
resolved = resolve_lockfile_path(lockfile_path: lockfile_path, project_root: project_root,
|
|
111
|
+
auto_detect: auto_detect)
|
|
112
|
+
return [] if resolved.nil?
|
|
113
|
+
|
|
114
|
+
data = read_lockfile_yaml(resolved)
|
|
115
|
+
return [] if data.nil?
|
|
116
|
+
|
|
117
|
+
collection_root = resolve_collection_root(resolved, data)
|
|
118
|
+
gem_paths_from(collection_root, data, Set.new).map { |dir| dir.parent.basename.to_s }.uniq
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Issue #3030 — whether `file`, found under the collection gem directory `root`, sits below a `_`-prefixed
|
|
122
|
+
# directory (`_test/`, `_scripts/`). Such a file is not part of the gem's signatures: rbs's
|
|
123
|
+
# `EnvironmentLoader` loads a collection gem as a library, and `RBS::FileFinder.each_file(skip_hidden: true)`
|
|
124
|
+
# drops every file with a `_`-prefixed directory between it and the library root. A `git` source never
|
|
125
|
+
# copies them into the collection (`Sources::Git#cp_r` prunes them), but a `local` source symlinks the whole
|
|
126
|
+
# `<name>/<version>/` directory, so gem_rbs_collection's own `bin/test` setup brings each gem's `_test/`
|
|
127
|
+
# fixtures along. Only the directories count, as in rbs: a `_`-prefixed file name is loaded.
|
|
128
|
+
def self.hidden_file?(root, file)
|
|
129
|
+
relative = Pathname(file.to_s).relative_path_from(Pathname(root.to_s))
|
|
130
|
+
relative.ascend.drop(1).any? { |part| part.basename.to_s.start_with?("_") }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Issue #3030 — `collection_paths` ({.discover}) without each gem directory a `signature_paths:` root already
|
|
134
|
+
# loads a copy of. A root is a copy of the entry `<collection>/<name>/<version>` when its real path is the
|
|
135
|
+
# entry's real path (a `local` source symlinks the working tree in), or when it is a gem_rbs_collection working
|
|
136
|
+
# tree for the same gem and version, `.../gems/<name>/<version>` (a `git` source installs a copy of it). That is
|
|
137
|
+
# what an author editing the tree points `signature_paths:` at from its `_test/` directory while the lockfile
|
|
138
|
+
# installs the same gem, and loading both declares every member twice. The `signature_paths:` copy is kept, as
|
|
139
|
+
# it is the one being edited. Any other root, such as a partial override `sig/overrides/foo/1.0`, leaves the
|
|
140
|
+
# collection copy loaded. Real paths are read so `..` and a symlinked spelling answer the same; a root that
|
|
141
|
+
# does not exist matches nothing.
|
|
142
|
+
def self.without_signature_path_copies(collection_paths, signature_roots)
|
|
143
|
+
reals = signature_roots.filter_map { |root| real_path(root) }
|
|
144
|
+
return collection_paths if reals.empty?
|
|
145
|
+
|
|
146
|
+
trees = reals.filter_map do |real|
|
|
147
|
+
real = Pathname(real)
|
|
148
|
+
[real.parent.basename.to_s, real.basename.to_s] if real.parent.parent.basename.to_s == "gems"
|
|
149
|
+
end.to_set
|
|
150
|
+
reals = reals.to_set
|
|
151
|
+
collection_paths.reject do |path|
|
|
152
|
+
path = Pathname(path.to_s)
|
|
153
|
+
trees.include?([path.parent.basename.to_s, path.basename.to_s]) || reals.include?(real_path(path))
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def self.real_path(path)
|
|
158
|
+
File.realpath(path.to_s)
|
|
159
|
+
rescue SystemCallError
|
|
160
|
+
nil
|
|
161
|
+
end
|
|
162
|
+
private_class_method :real_path
|
|
163
|
+
|
|
164
|
+
# Issue #3030 — why a run with no collection lockfile looks like it was meant to have one: `:collection_test_dir`
|
|
165
|
+
# when `project_root` is a gem_rbs_collection test directory (`gems/<name>/<version>/_test/`, whose lockfile
|
|
166
|
+
# gem_rbs_collection's `bin/test` setup writes), `:collection_config` when it holds an `rbs_collection.yaml`
|
|
167
|
+
# (`rbs collection install` has not run), and nil otherwise, or when a lockfile resolves or the lookup is off.
|
|
168
|
+
# Rigor resolves no `manifest.yaml` or gemspec dependency itself, so without the lockfile the dependency RBS
|
|
169
|
+
# is absent. Two `stat`s and no read.
|
|
170
|
+
def self.missing_lockfile_hint(lockfile_path:, project_root: Dir.pwd, auto_detect: true)
|
|
171
|
+
return nil if lockfile_path.nil? && !auto_detect
|
|
172
|
+
return nil if resolve_lockfile_path(lockfile_path: lockfile_path, project_root: project_root,
|
|
173
|
+
auto_detect: auto_detect)
|
|
174
|
+
|
|
175
|
+
root = Pathname(File.expand_path(project_root.to_s))
|
|
176
|
+
return :collection_test_dir if collection_test_dir?(root)
|
|
177
|
+
return :collection_config if root.join("rbs_collection.yaml").file?
|
|
178
|
+
|
|
179
|
+
nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# `gems/<name>/<version>/_test/`, the layout of a gem_rbs_collection working tree.
|
|
183
|
+
def self.collection_test_dir?(root)
|
|
184
|
+
root.basename.to_s == "_test" && root.parent.parent.parent.basename.to_s == "gems"
|
|
185
|
+
end
|
|
186
|
+
private_class_method :collection_test_dir?
|
|
187
|
+
|
|
80
188
|
# Returns the resolved lockfile path (`Pathname`) or `nil` when neither explicit nor auto-detect
|
|
81
189
|
# produces one. Public so the stats banner can surface what rigor found.
|
|
82
190
|
def self.resolve_lockfile_path(lockfile_path:, project_root: Dir.pwd, auto_detect: true)
|
|
@@ -110,12 +218,19 @@ module Rigor
|
|
|
110
218
|
end
|
|
111
219
|
private_class_method :resolve_collection_root
|
|
112
220
|
|
|
221
|
+
# An entry's `source.type`, or "" when `source:` is absent or not a mapping (`source: stdlib`): a malformed
|
|
222
|
+
# entry fails soft (ADR-5) instead of raising out of the run.
|
|
223
|
+
def self.source_type(entry)
|
|
224
|
+
source = entry["source"]
|
|
225
|
+
source.is_a?(Hash) ? source["type"].to_s : ""
|
|
226
|
+
end
|
|
227
|
+
private_class_method :source_type
|
|
228
|
+
|
|
113
229
|
def self.gem_paths_from(collection_root, data, skip_gem_names)
|
|
114
230
|
Array(data["gems"]).filter_map do |entry|
|
|
115
231
|
next unless entry.is_a?(Hash)
|
|
116
232
|
|
|
117
|
-
|
|
118
|
-
next if SKIPPED_SOURCE_TYPES.include?(source_type)
|
|
233
|
+
next if SKIPPED_SOURCE_TYPES.include?(source_type(entry))
|
|
119
234
|
|
|
120
235
|
name = entry["name"]
|
|
121
236
|
version = entry["version"]
|
|
@@ -5,8 +5,9 @@ module Rigor
|
|
|
5
5
|
# Open item O4 Layer 3 slice 3 — graceful-degradation coverage report.
|
|
6
6
|
#
|
|
7
7
|
# When the user has a `Gemfile.lock` (via slice 1) and rigor has resolved its target-project RBS sources
|
|
8
|
-
# (
|
|
9
|
-
# `rbs_collection.lock.yaml` paths), this module classifies each
|
|
8
|
+
# (the resolved library list — `Environment::BaseLibraries.resolve`, `data/vendored_gem_sigs/`,
|
|
9
|
+
# slice-1 bundle-shipped `sig/`, slice-2 `rbs_collection.lock.yaml` paths), this module classifies each
|
|
10
|
+
# locked gem by RBS provenance and
|
|
10
11
|
# surfaces the "no RBS available" set so the run-start diagnostic in {Rigor::Analysis::Runner} can
|
|
11
12
|
# suggest `rbs collection install` or `dependencies.source_inference:` for the uncovered gems.
|
|
12
13
|
#
|
|
@@ -37,9 +38,9 @@ module Rigor
|
|
|
37
38
|
|
|
38
39
|
# @param locked_gems — The lockfile-resolved gem set. Empty
|
|
39
40
|
# hash → no coverage analysis to do.
|
|
40
|
-
# @param default_libraries —
|
|
41
|
-
# `
|
|
42
|
-
# running in a project context.
|
|
41
|
+
# @param default_libraries — the resolved list of names rigor loads as RBS libraries
|
|
42
|
+
# (`Environment::BaseLibraries.resolve`: `DEFAULT_LIBRARIES` + `libraries:` + the collection
|
|
43
|
+
# lockfile's stdlib entries). Pass it from callers running in a project context.
|
|
43
44
|
# @param bundle_sig_paths — the discovered `<bundle>/.../gems/<name>-<ver>/sig`
|
|
44
45
|
# paths from {BundleSigDiscovery.discover}.
|
|
45
46
|
# @param rbs_collection_paths — the discovered `<collection>/<name>/<version>/`
|
|
@@ -48,7 +49,7 @@ module Rigor
|
|
|
48
49
|
def self.classify(locked_gems:, default_libraries:,
|
|
49
50
|
bundle_sig_paths:, rbs_collection_paths:)
|
|
50
51
|
default_set = default_libraries.to_set
|
|
51
|
-
bundle_names = extract_gem_names_from_bundle_paths(bundle_sig_paths)
|
|
52
|
+
bundle_names = extract_gem_names_from_bundle_paths(bundle_sig_paths, locked_gems)
|
|
52
53
|
collection_names = extract_gem_names_from_collection_paths(rbs_collection_paths)
|
|
53
54
|
|
|
54
55
|
locked_gems.each_value.map do |locked|
|
|
@@ -73,11 +74,11 @@ module Rigor
|
|
|
73
74
|
coverage_rows.select { |row| row.source == :missing }
|
|
74
75
|
end
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
# Issue #2978 — each path's gem name as the locked entry it matches ({BundleSigDiscovery.locked_names_of}), not
|
|
78
|
+
# a parse of its directory name, which reads `foo-2fa-1.0` as `foo` and reported `foo-2fa` as missing RBS.
|
|
79
|
+
def self.extract_gem_names_from_bundle_paths(paths, locked_gems)
|
|
80
|
+
pathnames = paths.map { |path| path.is_a?(Pathname) ? path : Pathname.new(path) }
|
|
81
|
+
BundleSigDiscovery.locked_names_of(pathnames, locked_gems).to_set
|
|
81
82
|
end
|
|
82
83
|
private_class_method :extract_gem_names_from_bundle_paths
|
|
83
84
|
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../typing_state"
|
|
4
|
+
|
|
3
5
|
module Rigor
|
|
4
6
|
class Environment
|
|
5
7
|
# Small hierarchy oracle backed by RBS instance definitions.
|
|
6
8
|
class RbsHierarchy
|
|
9
|
+
TypingState.memo_field(self, :@ancestor_names_cache, :@class_ordering_cache,
|
|
10
|
+
reason: "keyed on the class names; answered from the loader's RBS environment, fixed " \
|
|
11
|
+
"for the loader's lifetime")
|
|
12
|
+
|
|
7
13
|
def initialize(loader)
|
|
8
14
|
@loader = loader
|
|
9
15
|
@ancestor_names_cache = {}
|
|
@@ -41,21 +47,12 @@ module Rigor
|
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
|
|
44
|
-
# Issue #696 review, second pass — the ancestry lookup
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# classes failed to build" — 504 on a cold store, 0 on a warm one, 2 with no store. On the DEFAULT
|
|
51
|
-
# `--workers=0` path nothing pre-warms the store, so the cold answer was the one written into the
|
|
52
|
-
# run-result cache and replayed until a file changed.
|
|
53
|
-
#
|
|
54
|
-
# The cache-state branch still exists — it is worth 50x on the warm path — but it lives behind the
|
|
55
|
-
# loader now, where both of its sides are marked as RIGOR'S OWN demand. Ordering two classes is not
|
|
56
|
-
# the analysis asking whether either one's methods resolve, so neither side reaches the diagnostic,
|
|
57
|
-
# and the answer is identical on both (the table's producer computes exactly this, keyed the same
|
|
58
|
-
# way). What this method keeps is its own per-name memo, which is about repeated comparisons.
|
|
50
|
+
# Issue #696 review, second pass — the ancestry lookup lives in {RbsLoader#ancestor_names_for}.
|
|
51
|
+
# Read directly from `Cache::RbsClassAncestorTable`, the same question gave 504 failed classes on a
|
|
52
|
+
# cold store, 0 on a warm one and 2 with no store, and the cold answer was cached into the run result.
|
|
53
|
+
# Through the loader, both cache states are marked as Rigor's own demand, so ordering two classes
|
|
54
|
+
# never reaches the "which classes failed to build" diagnostic. The cache-state branch stays behind
|
|
55
|
+
# the loader (it is worth 50x on the warm path); this method keeps only its per-name memo.
|
|
59
56
|
def ancestor_names(class_name)
|
|
60
57
|
key = normalize_name(class_name)
|
|
61
58
|
return @ancestor_names_cache[key] if @ancestor_names_cache.key?(key)
|