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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
require_relative "../../rbs_extended"
|
|
5
|
+
require_relative "../../scope/resolution_chain"
|
|
6
|
+
|
|
7
|
+
module Rigor
|
|
8
|
+
module Lens
|
|
9
|
+
class Claims
|
|
10
|
+
# Normalizes RBS ASTs without erasing unsupported forms or using display text as identity.
|
|
11
|
+
class TypeReader
|
|
12
|
+
Atom = Data.define(:kind, :value, :arguments, :relative) do
|
|
13
|
+
def identity
|
|
14
|
+
[kind, value, arguments.map { |arms| arms.to_set(&:identity) }]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def display
|
|
18
|
+
return value.inspect if kind == :literal
|
|
19
|
+
|
|
20
|
+
suffix = arguments.empty? ? "" : "[#{arguments.map { |arms| arms.map(&:display).join(' | ') }.join(', ')}]"
|
|
21
|
+
"::#{value}#{suffix}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attr_reader :reasons
|
|
26
|
+
|
|
27
|
+
def self.parse(text)
|
|
28
|
+
# An empty, blank or comment-only text parses to nil rather than raising.
|
|
29
|
+
type = ::RBS::Parser.parse_type(text, require_eof: true)
|
|
30
|
+
type ? [type, nil] : [nil, "syntax_error"]
|
|
31
|
+
rescue ::RBS::ParsingError
|
|
32
|
+
extended = RbsExtended.parse_return_type_override("rigor:v1:return: #{text}")
|
|
33
|
+
[nil, extended ? "unsupported_grammar_feature" : "syntax_error"]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# `owner` is the member's owner; an RBS declaration of the member sits in its namespace, which a builder
|
|
37
|
+
# block's lexical nesting does not name.
|
|
38
|
+
def initialize(scope:, nesting:, singleton_nesting: false, owner: nil)
|
|
39
|
+
@scope = scope
|
|
40
|
+
@loader = scope.environment.rbs_loader
|
|
41
|
+
@resolver = @loader.type_name_resolver
|
|
42
|
+
@nesting = nesting
|
|
43
|
+
@singleton_nesting = singleton_nesting
|
|
44
|
+
@context = rbs_context(Array(nesting))
|
|
45
|
+
@owner_context = owner && owner != "Object" ? rbs_context(owner_namespaces(owner)) : nil
|
|
46
|
+
@reasons = Set.new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def read(type, claim: false, aliases: Set.new)
|
|
50
|
+
case type
|
|
51
|
+
when ::RBS::Types::Bases::Any
|
|
52
|
+
@reasons << "dynamic_type"
|
|
53
|
+
[]
|
|
54
|
+
when ::RBS::Types::Bases::Bool then [literal(true), literal(false)]
|
|
55
|
+
when ::RBS::Types::Bases::Nil then [literal(nil)]
|
|
56
|
+
when ::RBS::Types::Literal then [literal(type.literal)]
|
|
57
|
+
when ::RBS::Types::Union then type.types.flat_map { |part| read(part, claim: claim, aliases: aliases) }
|
|
58
|
+
when ::RBS::Types::Optional then read(type.type, claim: claim, aliases: aliases) + [literal(nil)]
|
|
59
|
+
when ::RBS::Types::Alias then read_alias(type, claim, aliases)
|
|
60
|
+
when ::RBS::Types::ClassInstance then read_class(type, claim, aliases)
|
|
61
|
+
else
|
|
62
|
+
@reasons << "unsupported_type"
|
|
63
|
+
type.each_type { |part| read(part, claim: claim, aliases: aliases) }
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def rbs_context(names)
|
|
71
|
+
names.reduce(nil) do |outer, name|
|
|
72
|
+
type_name = ::RBS::TypeName.parse("::#{name}")
|
|
73
|
+
@loader.class_known?(name) ? [outer, type_name] : outer
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def owner_namespaces(owner)
|
|
78
|
+
segments = owner.split("::")
|
|
79
|
+
segments.each_index.map { |index| segments[0..index].join("::") }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def literal(value, relative: false)
|
|
83
|
+
Atom.new(kind: :literal, value: value, arguments: [], relative: relative)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def resolve(name, claim)
|
|
87
|
+
resolved = @resolver&.resolve(name, context: claim ? @context : nil)
|
|
88
|
+
if resolved.nil?
|
|
89
|
+
@reasons << "unresolved_name"
|
|
90
|
+
elsif claim && !name.absolute? && name.class?
|
|
91
|
+
compare_ruby_name(name, resolved)
|
|
92
|
+
end
|
|
93
|
+
resolved
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def compare_ruby_name(name, resolved)
|
|
97
|
+
# An unlocated alias body has no known cref. A singleton class's anonymous cref is not a
|
|
98
|
+
# named namespace either; its constant table and ancestry cannot be read as the owner's.
|
|
99
|
+
if @nesting.nil? || @singleton_nesting
|
|
100
|
+
@reasons << "ambiguous_name"
|
|
101
|
+
return
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
ruby = ruby_name(name.to_s)
|
|
105
|
+
@reasons << "ambiguous_name" if ruby && ruby != resolved.to_s.delete_prefix("::")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def read_class(type, claim, aliases)
|
|
109
|
+
name = resolve(type.name, claim)
|
|
110
|
+
arguments = type.args.map { |arg| read(arg, claim: claim, aliases: aliases) }
|
|
111
|
+
return [] unless name
|
|
112
|
+
|
|
113
|
+
key = name.to_s.delete_prefix("::")
|
|
114
|
+
if !@loader.class_known?(key) || arguments.size != @loader.class_type_param_names(key).size
|
|
115
|
+
@reasons << "unsupported_type"
|
|
116
|
+
end
|
|
117
|
+
singles = { "TrueClass" => true, "FalseClass" => false, "NilClass" => nil }
|
|
118
|
+
if arguments.empty? && singles.key?(key)
|
|
119
|
+
return [literal(singles.fetch(key), relative: claim && !type.name.absolute?)]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
[Atom.new(kind: :class, value: key, arguments: arguments, relative: claim && !type.name.absolute?)]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def read_alias(type, claim, aliases)
|
|
126
|
+
name = resolve(type.name, claim)
|
|
127
|
+
type.args.each { |arg| read(arg, claim: claim, aliases: aliases) }
|
|
128
|
+
return [] unless name
|
|
129
|
+
|
|
130
|
+
relative = claim && !type.name.absolute?
|
|
131
|
+
return [] if relative && !alias_name_settled?(type.name, name)
|
|
132
|
+
|
|
133
|
+
entry = @loader.type_alias_declaration(name)
|
|
134
|
+
if entry.nil? || !entry.type_params.empty? || !type.args.empty? || aliases.include?(name)
|
|
135
|
+
@reasons << "unsupported_type"
|
|
136
|
+
return []
|
|
137
|
+
end
|
|
138
|
+
# The resolved declaration binds names in the alias's namespace, not the claim's lexical scope. Arms
|
|
139
|
+
# reached through a relatively written name stay relative, so the conflict guard still applies.
|
|
140
|
+
arms = read(entry.type, aliases: aliases | [name])
|
|
141
|
+
relative ? arms.map { |arm| arm.with(relative: true) } : arms
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# A type alias has no Ruby meaning, so the only reading to cross-check is the RBS one: the claim's lexical
|
|
145
|
+
# context and the member's RBS namespace must resolve a relative alias name alike. An unlocated body or a
|
|
146
|
+
# singleton-class body has no context to read it in.
|
|
147
|
+
def alias_name_settled?(written, resolved)
|
|
148
|
+
if @nesting.nil? || @singleton_nesting
|
|
149
|
+
@reasons << "ambiguous_name"
|
|
150
|
+
return false
|
|
151
|
+
end
|
|
152
|
+
return true if @owner_context.nil? || @owner_context == @context
|
|
153
|
+
|
|
154
|
+
declared = @resolver&.resolve(written, context: @owner_context)
|
|
155
|
+
return true if declared == resolved
|
|
156
|
+
|
|
157
|
+
@reasons << "ambiguous_name"
|
|
158
|
+
false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Project constants only: a missing entry falls back to RBS, which also knows libraries and gems.
|
|
162
|
+
# Resolve the first segment before the rest, so a Ruby-only namespace cannot fall through to core.
|
|
163
|
+
def ruby_name(written)
|
|
164
|
+
head, *tail = written.split("::")
|
|
165
|
+
found = project_constant_in(@nesting.reverse, head)
|
|
166
|
+
found ||= ancestor_constant(head)
|
|
167
|
+
found = head if found.nil? && (@nesting.empty? || @loader.rbs_module?(@nesting.last)) && project_name?(head)
|
|
168
|
+
found && ([found] + tail).join("::")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def project_constant_in(bases, name)
|
|
172
|
+
bases.each do |base|
|
|
173
|
+
candidate = base == "Object" ? name : "#{base}::#{name}"
|
|
174
|
+
return candidate if project_name?(candidate)
|
|
175
|
+
end
|
|
176
|
+
nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def project_name?(name)
|
|
180
|
+
@scope.declared_class?(name) || @scope.bound_constant_names(name).include?(name)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def ancestor_constant(name)
|
|
184
|
+
chain = Scope::ResolutionChain.for(@scope, @nesting.last || "Object", :instance, :constants)
|
|
185
|
+
found = chain_constant(chain, name)
|
|
186
|
+
settled = chain.settle(@scope, found) { |retro| chain_constant(retro, name) }
|
|
187
|
+
if chain.truncated? || chain.wildcard_mixin? || settled != :chain || opaque_ancestry?(chain)
|
|
188
|
+
@reasons << "ambiguous_name"
|
|
189
|
+
return nil
|
|
190
|
+
end
|
|
191
|
+
found
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# A superclass the tables cannot name (`Class.new(Base)`, `< pick`, a builder class's `Struct`/`Data`) or an
|
|
195
|
+
# external ancestor no RBS declares (`< SomeAlias`): the constants it holds are not on the chain.
|
|
196
|
+
def opaque_ancestry?(chain)
|
|
197
|
+
return true if chain.opaque_tail?(@scope)
|
|
198
|
+
|
|
199
|
+
chain.entries.any? { |entry| entry.external? && entry.candidates.none? { |name| @loader.class_known?(name) } }
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def chain_constant(chain, name)
|
|
203
|
+
chain.search(@scope) do |entry|
|
|
204
|
+
bases = entry.external? ? external_ancestors(entry) : [entry.name]
|
|
205
|
+
project_constant_in(bases, name)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def external_ancestors(entry)
|
|
210
|
+
name = entry.candidates.find { |candidate| @loader.class_known?(candidate) }
|
|
211
|
+
name ? @loader.ancestor_names_for(name) : []
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "claims/request"
|
|
4
|
+
require_relative "claims/type_reader"
|
|
5
|
+
require_relative "claims/comparison"
|
|
6
|
+
|
|
7
|
+
module Rigor
|
|
8
|
+
module Lens
|
|
9
|
+
# Read-only documentation coverage against the contracts retained by this lens run.
|
|
10
|
+
class Claims
|
|
11
|
+
REASONS = %w[no_such_declaration unsupported_declaration declaration_mismatch unsupported_subject
|
|
12
|
+
no_authored_contract unsupported_contract_source extrbs_contract refined_contract
|
|
13
|
+
unsupported_overloads no_such_parameter unsupported_parameter_kind unmatched_parameter
|
|
14
|
+
unsupported_grammar_feature unresolved_name ambiguous_name dynamic_type unsupported_type
|
|
15
|
+
unproven].freeze
|
|
16
|
+
POSITIONALS = %w[required optional rest post].freeze
|
|
17
|
+
|
|
18
|
+
def initialize(request:, outcome:, run:)
|
|
19
|
+
@request = request
|
|
20
|
+
@outcome = outcome
|
|
21
|
+
@run = run
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def call
|
|
25
|
+
@request.verify_sources!(@outcome.targets)
|
|
26
|
+
{ "schema" => "lens-claims/v0", "revision" => 1, "request_digest" => @request.digest,
|
|
27
|
+
"grammar" => "rbs", "capabilities" => %w[return required_param required_keyword],
|
|
28
|
+
"results" => @request.claims.map { |claim| result(claim) } }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def result(claim)
|
|
34
|
+
answer = { "id" => claim.fetch("id"), "verdict" => "unknown", "reason" => "unproven",
|
|
35
|
+
"relation" => nil, "direction" => nil, "site" => nil, "member" => nil,
|
|
36
|
+
"slot" => nil, "contract" => nil, "evidence" => [] }
|
|
37
|
+
target = @outcome.targets.find { |entry| entry.absolute == @request.paths.fetch(claim.fetch("file")) }
|
|
38
|
+
return answer.merge("verdict" => "unavailable", "reason" => target.status) unless target.status == "ok"
|
|
39
|
+
|
|
40
|
+
parsed, grammar_reason = TypeReader.parse(claim.fetch("claim"))
|
|
41
|
+
if grammar_reason == "syntax_error"
|
|
42
|
+
return answer.merge("verdict" => "invalid_claim",
|
|
43
|
+
"reason" => "syntax_error")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
site, member, reason = bind(claim.fetch("declaration"), target.reader)
|
|
47
|
+
return answer.merge("reason" => reason) if reason
|
|
48
|
+
|
|
49
|
+
answer.merge!("site" => site.data.fetch("key"), "member" => member.slice("owner", "scope", "name"))
|
|
50
|
+
check_slot(claim, parsed, grammar_reason, site, member, target, answer)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def bind(declaration, reader)
|
|
54
|
+
sites = reader.sites.select { |site| same_span?(site.data.fetch("span"), declaration.fetch("span")) }
|
|
55
|
+
if sites.empty?
|
|
56
|
+
omission = reader.omissions.any? { |entry| same_span?(entry.fetch("span"), declaration.fetch("span")) }
|
|
57
|
+
return [nil, nil, omission ? "unsupported_declaration" : "no_such_declaration"]
|
|
58
|
+
end
|
|
59
|
+
return [nil, nil, "unsupported_declaration"] unless sites.one? && sites.first.data["kind"] == "method"
|
|
60
|
+
|
|
61
|
+
site = sites.first
|
|
62
|
+
member = @outcome.member_rows.find do |row|
|
|
63
|
+
row.values_at("owner", "scope", "name") == declaration.values_at("owner", "scope", "name") &&
|
|
64
|
+
row.fetch("sites").include?(site.data.fetch("key")) && declaration["kind"] == "method"
|
|
65
|
+
end
|
|
66
|
+
member ? [site, member, nil] : [nil, nil, "declaration_mismatch"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def same_span?(left, right)
|
|
70
|
+
left.values_at("start_offset", "end_offset") == right.values_at("start_offset", "end_offset")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def check_slot(claim, parsed, grammar_reason, site, member, target, answer)
|
|
74
|
+
tag = claim.fetch("tag")
|
|
75
|
+
return answer.merge("reason" => "unsupported_subject") unless supported_subject?(tag)
|
|
76
|
+
|
|
77
|
+
raw = @run.raw_contracts[member.values_at("owner", "scope", "name")]
|
|
78
|
+
overloads = member.fetch("overloads")
|
|
79
|
+
reasons = member_reasons(site, member) + [grammar_reason].compact
|
|
80
|
+
slot, index, subject_reason = subject(tag, site, overloads.one? ? overloads.first : nil)
|
|
81
|
+
reasons << subject_reason if subject_reason
|
|
82
|
+
if slot
|
|
83
|
+
read_slot(slot, index, tag, overloads.first, raw, answer, reasons)
|
|
84
|
+
type = authored_type(raw, tag, index)
|
|
85
|
+
compare_types(parsed, type, site, target, answer, reasons) if parsed && type
|
|
86
|
+
end
|
|
87
|
+
reason = REASONS.find { |candidate| reasons.include?(candidate) }
|
|
88
|
+
reason ? answer.merge("verdict" => "unknown", "reason" => reason, "evidence" => []) : answer
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def supported_subject?(tag)
|
|
92
|
+
%w[param return].include?(tag.fetch("name")) && (tag["name"] == "return" || tag["subject"])
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def authored_type(raw, tag, index)
|
|
96
|
+
contract_type(raw.types.first.type, tag, index) if raw&.types&.one?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def member_reasons(site, member)
|
|
100
|
+
reasons = []
|
|
101
|
+
overloads = member.fetch("overloads")
|
|
102
|
+
reasons << "no_authored_contract" if member["basis"] != "contract"
|
|
103
|
+
reasons << "unsupported_overloads" unless overloads.one? && overloads.first["params"]
|
|
104
|
+
reasons << "extrbs_contract" if site.contract_comments.any? do |comment|
|
|
105
|
+
comment.location.slice.match?(/\A#\s*@extrbs\b/)
|
|
106
|
+
end
|
|
107
|
+
reasons
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def read_slot(slot, index, tag, overload, raw, answer, reasons)
|
|
111
|
+
answer.merge!("relation" => "documentation_coverage", "slot" => slot,
|
|
112
|
+
"direction" => tag["name"] == "param" ? "claim_within_contract" : "contract_within_claim")
|
|
113
|
+
contract = tag["name"] == "return" ? overload["return"] : overload.fetch("params")[index]["type"]
|
|
114
|
+
inspect_contract(contract, raw, tag, index, answer, reasons)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def inspect_contract(contract, raw, tag, index, answer, reasons)
|
|
118
|
+
if contract.nil? || contract["state"] == "unavailable" || contract["provenance"] == "inferred"
|
|
119
|
+
reasons << "no_authored_contract"
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
provenance = contract["provenance"]
|
|
123
|
+
reasons << "unsupported_contract_source" if provenance == "library" || provenance&.start_with?("plugin:")
|
|
124
|
+
answer["contract"] = contract.slice("type", "provenance", "path")
|
|
125
|
+
reasons << "refined_contract" if refined?(raw, tag, index)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def refined?(raw, tag, index)
|
|
129
|
+
return false if raw.nil?
|
|
130
|
+
return raw.annotations.any? { |text| text.start_with?("rigor:v1:return:") } if tag["name"] == "return"
|
|
131
|
+
|
|
132
|
+
raw.types.any? do |method_type|
|
|
133
|
+
function = method_type.type
|
|
134
|
+
param = function_params(function)[index]
|
|
135
|
+
if function.respond_to?(:required_keywords)
|
|
136
|
+
keyword = function.required_keywords.find do |_key, value|
|
|
137
|
+
value.equal?(param)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
name = keyword ? keyword.first : param&.name
|
|
141
|
+
name && raw.annotations.any? { |text| text.match?(/\Arigor:v1:param:\s*#{Regexp.escape(name.to_s)}\s/) }
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def subject(tag, site, overload)
|
|
146
|
+
return [{ "kind" => "return" }, nil, nil] if tag["name"] == "return" && overload
|
|
147
|
+
return [nil, nil, nil] if tag["name"] == "return"
|
|
148
|
+
|
|
149
|
+
params = site.data["params"] || []
|
|
150
|
+
param = params.find { |entry| entry["name"] == tag["subject"] }
|
|
151
|
+
return [nil, nil, "no_such_parameter"] unless param
|
|
152
|
+
return [nil, nil, "unsupported_parameter_kind"] unless %w[required keyreq].include?(param["kind"])
|
|
153
|
+
return [nil, nil, nil] unless overload && overload["params"]
|
|
154
|
+
|
|
155
|
+
declared = overload.fetch("params")
|
|
156
|
+
index = parameter_index(param, params, declared)
|
|
157
|
+
return [nil, nil, "unmatched_parameter"] unless index
|
|
158
|
+
|
|
159
|
+
[{ "kind" => "param", "name" => param["name"], "param_kind" => param["kind"], "index" => index }, index, nil]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def parameter_index(param, params, declared)
|
|
163
|
+
if param["kind"] == "keyreq"
|
|
164
|
+
return declared.index { |entry| entry["kind"] == "keyreq" && entry["name"] == param["name"] }
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
source_positions = params.select { |entry| POSITIONALS.include?(entry["kind"]) }
|
|
168
|
+
contract_positions = declared.select { |entry| POSITIONALS.include?(entry["kind"]) }
|
|
169
|
+
return unless source_positions.map { |entry| entry["kind"] } == contract_positions.map { |entry| entry["kind"] }
|
|
170
|
+
|
|
171
|
+
source_positions.index(param)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def contract_type(function, tag, index)
|
|
175
|
+
tag["name"] == "return" ? function.return_type : function_params(function)[index]&.type
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def function_params(function)
|
|
179
|
+
return [] unless function.respond_to?(:required_positionals)
|
|
180
|
+
|
|
181
|
+
function.required_positionals + function.optional_positionals + [function.rest_positionals].compact +
|
|
182
|
+
function.trailing_positionals + function.required_keywords.values + function.optional_keywords.values +
|
|
183
|
+
[function.rest_keywords].compact
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def compare_types(parsed, contract, site, target, answer, reasons)
|
|
187
|
+
scope = @run.claim_contexts.fetch(target.absolute)
|
|
188
|
+
nesting = site.data.fetch("lexical_nesting")
|
|
189
|
+
reader = TypeReader.new(scope: scope, nesting: nesting, singleton_nesting: site.data["singleton_nesting"],
|
|
190
|
+
owner: site.data["owner"])
|
|
191
|
+
claim_arms = reader.read(parsed, claim: true)
|
|
192
|
+
contract_arms = reader.read(contract)
|
|
193
|
+
reasons.concat(reader.reasons.to_a)
|
|
194
|
+
return unless reasons.empty?
|
|
195
|
+
|
|
196
|
+
left, right = if answer["direction"] == "claim_within_contract"
|
|
197
|
+
[claim_arms, contract_arms]
|
|
198
|
+
else
|
|
199
|
+
[contract_arms, claim_arms]
|
|
200
|
+
end
|
|
201
|
+
comparator = Comparison.new(scope.environment.rbs_loader,
|
|
202
|
+
relative_conflict: nesting == [] && site.data["owner"] == "Object")
|
|
203
|
+
verdict, reason, evidence = comparator.call(left, right)
|
|
204
|
+
answer.merge!("verdict" => verdict, "reason" => reason, "evidence" => evidence)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -16,9 +16,13 @@ module Rigor
|
|
|
16
16
|
# `overloads` hold `{rbs, params, block, return}`; a return the contract leaves to inference is nil there,
|
|
17
17
|
# with `return_inferred` set. `buffers` are the declaring buffer names.
|
|
18
18
|
Contract = Data.define(:overloads, :provenance, :path, :return_inferred, :buffers)
|
|
19
|
+
RawContract = Data.define(:types, :annotations)
|
|
20
|
+
|
|
21
|
+
attr_reader :raw_contracts
|
|
19
22
|
|
|
20
23
|
def initialize(provenance)
|
|
21
24
|
@provenance = provenance
|
|
25
|
+
@raw_contracts = {}
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
# The member's contract, or nil when it has none of its own. `name` is the Ruby method name.
|
|
@@ -28,6 +32,7 @@ module Rigor
|
|
|
28
32
|
return nil if defs.empty?
|
|
29
33
|
|
|
30
34
|
annotations = annotations_of(method, defs)
|
|
35
|
+
@raw_contracts[[owner, scope.to_s, name]] = RawContract.new(types: defs.map(&:type), annotations: annotations)
|
|
31
36
|
return nil if annotations.include?(INFERRED_SIGNATURE)
|
|
32
37
|
|
|
33
38
|
contract(defs, annotations)
|
data/lib/rigor/lens/document.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Rigor
|
|
|
24
24
|
def to_h
|
|
25
25
|
{ "schema" => SCHEMA, "revision" => REVISION, "producer" => producer, "context" => context,
|
|
26
26
|
"capabilities" => CAPABILITIES, "files" => @outcome.targets.map { |target| file(target) },
|
|
27
|
-
"members" => @outcome.member_rows }
|
|
27
|
+
"members" => @outcome.member_rows, "claims" => nil }
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
private
|
|
@@ -26,7 +26,10 @@ module Rigor
|
|
|
26
26
|
# `kind` is :module, :class or :singleton. `module_function` is :off, :on (a bare `module_function` written
|
|
27
27
|
# directly in a module body covers the later direct defs) or :unknown (the reading Ruby gives and the one
|
|
28
28
|
# `check`'s tables give could differ, so the later defs are omissions).
|
|
29
|
-
|
|
29
|
+
# `lexical` is the named part of the body's Ruby cref chain, which a builder block does not extend (Ruby
|
|
30
|
+
# `class_eval`s the block on the new class, but its constants resolve in the scope that wrote it) and a
|
|
31
|
+
# `class << self` body extends only with its anonymous singleton class, left out here.
|
|
32
|
+
Body = Struct.new(:current, :uncertain, :detached, :kind, :module_function, :lexical)
|
|
30
33
|
|
|
31
34
|
ATTRIBUTE_CALLS = { attr_reader: "reader", attr_writer: "writer", attr_accessor: "accessor" }.freeze
|
|
32
35
|
OMITTED_CALLS = {
|
|
@@ -92,7 +95,7 @@ module Rigor
|
|
|
92
95
|
end
|
|
93
96
|
|
|
94
97
|
def detached
|
|
95
|
-
@bodies.push(Body.new("public", false, true, :detached, :off))
|
|
98
|
+
@bodies.push(Body.new("public", false, true, :detached, :off, @bodies.last&.lexical))
|
|
96
99
|
yield
|
|
97
100
|
ensure
|
|
98
101
|
@bodies.pop
|
|
@@ -124,14 +127,14 @@ module Rigor
|
|
|
124
127
|
return detached { walk(node.body, nesting, singleton: singleton, in_block: true) } if node.body
|
|
125
128
|
end
|
|
126
129
|
|
|
127
|
-
walk_body(node.body, nesting, singleton: true, kind: :singleton)
|
|
130
|
+
walk_body(node.body, nesting, singleton: true, kind: :singleton, lexical: lexical_nesting(nesting))
|
|
128
131
|
end
|
|
129
132
|
|
|
130
133
|
# A class body's statements, tracking the running visibility and `module_function`.
|
|
131
|
-
def walk_body(body, nesting, singleton:, kind:)
|
|
134
|
+
def walk_body(body, nesting, singleton:, kind:, lexical: nesting)
|
|
132
135
|
return if body.nil?
|
|
133
136
|
|
|
134
|
-
@bodies.push(Body.new("public", false, false, kind, :off))
|
|
137
|
+
@bodies.push(Body.new("public", false, false, kind, :off, lexical))
|
|
135
138
|
statements = body.is_a?(Prism::StatementsNode) ? body.body : [body]
|
|
136
139
|
statements.each { |child| walk_body_statement(child, nesting, singleton) }
|
|
137
140
|
ensure
|
|
@@ -425,7 +428,7 @@ module Rigor
|
|
|
425
428
|
"block" => nil, "body_return" => nil }, contracts: trailing ? :trailing : false)
|
|
426
429
|
end
|
|
427
430
|
block = node.value.block
|
|
428
|
-
walk_body(block.body, nesting + [name], singleton: false, kind: :builder) if block&.body
|
|
431
|
+
walk_body(block.body, nesting + [name], singleton: false, kind: :builder, lexical: nesting) if block&.body
|
|
429
432
|
end
|
|
430
433
|
|
|
431
434
|
# Ruby forces a field reader named `initialize_copy` (say) private, but not its `Struct` writer: a `Data`
|
|
@@ -539,7 +542,9 @@ module Rigor
|
|
|
539
542
|
data = { "kind" => "method", "name" => node.name.to_s, "owner" => owner, "scope" => scope.to_s,
|
|
540
543
|
"attribute" => nil, "members" => [node.name.to_s], "module_function" => module_function,
|
|
541
544
|
"visibility" => module_function ? "private" : visibility(node, nesting, scope),
|
|
542
|
-
"params" => shape_params, "block" => shape_block, "body_return" => returns
|
|
545
|
+
"params" => shape_params, "block" => shape_block, "body_return" => returns,
|
|
546
|
+
"lexical_nesting" => lexical_nesting(nesting),
|
|
547
|
+
"singleton_nesting" => scope == :singleton && node.receiver.nil? }
|
|
543
548
|
return data unless module_function
|
|
544
549
|
|
|
545
550
|
# Internal to the member pass: the singleton copy is public until `private_class_method` says otherwise,
|
|
@@ -549,6 +554,12 @@ module Rigor
|
|
|
549
554
|
data.merge("singleton_visibility" => "public", "singleton_body_return" => copy)
|
|
550
555
|
end
|
|
551
556
|
|
|
557
|
+
# The Ruby cref chain a def written here reads its constants through: the enclosing body's, which differs
|
|
558
|
+
# from the owner nesting under a builder block.
|
|
559
|
+
def lexical_nesting(nesting)
|
|
560
|
+
@bodies.last&.lexical || nesting
|
|
561
|
+
end
|
|
562
|
+
|
|
552
563
|
# Whether the instance-scope return may differ from the singleton copy's: the body reads `self`, instance or
|
|
553
564
|
# class state, or `super` (nested defs excluded, blocks included, which over-declines safely), or the return
|
|
554
565
|
# names the owner's type, which is where a `self` that flowed through `itself`, `tap` or another module
|
|
@@ -628,13 +639,15 @@ module Rigor
|
|
|
628
639
|
def alias_site(names, owner)
|
|
629
640
|
new_name, old_name = names
|
|
630
641
|
last, copy = alias_original(owner, old_name)
|
|
642
|
+
copied = copy&.data || {}
|
|
631
643
|
visibility = FORCED_PRIVATE.include?(new_name) ? "private" : last&.data&.fetch("visibility")
|
|
632
644
|
# `initialize` reads `void` by its name, which neither side of an alias across it keeps.
|
|
633
645
|
returns = copy && ![new_name, old_name].include?("initialize") ? copy.data["body_return"] : nil
|
|
634
646
|
{ "kind" => "method", "name" => new_name, "owner" => owner, "scope" => "instance", "attribute" => nil,
|
|
635
647
|
"members" => [new_name], "module_function" => false, "visibility" => visibility,
|
|
636
|
-
"params" =>
|
|
648
|
+
"params" => copied["params"], "block" => copied["block"],
|
|
637
649
|
"body_return" => returns || Slot.unavailable("not_computed"),
|
|
650
|
+
"lexical_nesting" => copied["lexical_nesting"], "singleton_nesting" => copied["singleton_nesting"],
|
|
638
651
|
"alias_of" => old_name, "aliased_node" => copy && aliased_node(copy) }
|
|
639
652
|
end
|
|
640
653
|
|
data/lib/rigor/lens/plugins.rb
CHANGED
|
@@ -29,7 +29,7 @@ module Rigor
|
|
|
29
29
|
return Rigor::VERSION if absolute.start_with?("#{BUNDLED_PLUGINS}/")
|
|
30
30
|
|
|
31
31
|
spec = Gem.loaded_specs.each_value.find do |gem|
|
|
32
|
-
absolute.start_with?("#{gem.full_gem_path}/")
|
|
32
|
+
absolute.start_with?("#{gem.full_gem_path}/")
|
|
33
33
|
end
|
|
34
34
|
spec&.version&.to_s
|
|
35
35
|
rescue StandardError
|
data/lib/rigor/lens/run.rb
CHANGED
|
@@ -23,6 +23,12 @@ module Rigor
|
|
|
23
23
|
Target = Data.define(:argument, :path, :absolute, :status, :reason, :reader, :diagnostics, :inputs)
|
|
24
24
|
Outcome = Data.define(:targets, :member_rows, :plugins, :warm)
|
|
25
25
|
|
|
26
|
+
attr_reader :claim_contexts
|
|
27
|
+
|
|
28
|
+
def raw_contracts
|
|
29
|
+
@contract_reader&.raw_contracts || {}
|
|
30
|
+
end
|
|
31
|
+
|
|
26
32
|
# @param root — the project root (absolute); every path in the answer is relative to it
|
|
27
33
|
def initialize(configuration:, root:, arguments:, workers:)
|
|
28
34
|
@configuration = configuration
|
|
@@ -80,6 +86,7 @@ module Rigor
|
|
|
80
86
|
@contracts = {}
|
|
81
87
|
@defaulted_blocks = {}
|
|
82
88
|
@site_paths = {}
|
|
89
|
+
@claim_contexts = {}
|
|
83
90
|
end
|
|
84
91
|
|
|
85
92
|
# A file requested again, in any spelling, is answered once: the later entries read `duplicate`, naming the
|
|
@@ -134,6 +141,7 @@ module Rigor
|
|
|
134
141
|
end
|
|
135
142
|
end
|
|
136
143
|
@captured[absolute] = reader
|
|
144
|
+
@claim_contexts[absolute] = scope
|
|
137
145
|
end
|
|
138
146
|
|
|
139
147
|
# The constant's type as `check` reads it ({Reflection.constant_type_for}): the value the project's source
|
data/lib/rigor/lens.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Rigor
|
|
|
10
10
|
# Bumped on every breaking change to the `lens/v0` document (docs/internal-spec/lens.md § Status).
|
|
11
11
|
REVISION = 1
|
|
12
12
|
CAPABILITIES = %w[class module method attribute constant module_function builder alias body_return
|
|
13
|
-
diagnostics inputs].freeze
|
|
13
|
+
diagnostics inputs claims].freeze
|
|
14
14
|
|
|
15
15
|
module_function
|
|
16
16
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "environment/required_features"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
# Issue #2961 — answers what `RBS::EnvironmentLoader#has_library?(version: nil)` answers, for the
|
|
7
|
+
# {ConfigAudit} library warnings. The CLI has not loaded `rbs` when that audit runs, and loading it costs
|
|
8
|
+
# ~90 ms on the warm boot-slim path, so without a loaded `rbs` this probes the filesystem instead: a gem's
|
|
9
|
+
# `sig/` directory, or a release-versioned directory under the bundled rbs gem's `stdlib/<name>/`
|
|
10
|
+
# (`Repository::GemRBS#load!`). A probe that cannot place the rbs gem answers true: it never warns when unsure.
|
|
11
|
+
module LibraryProbe
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def predicate
|
|
15
|
+
if defined?(::RBS::EnvironmentLoader)
|
|
16
|
+
return ->(lib) { ::RBS::EnvironmentLoader.new.has_library?(library: lib, version: nil) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
stdlib = stdlib_root
|
|
20
|
+
return ->(_lib) { true } if stdlib.nil?
|
|
21
|
+
|
|
22
|
+
->(lib) { gem_sig_dir?(lib) || stdlib_library?(stdlib, lib) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The names of `library_names` the environment loads: a default library, a vendored feature token, or a name
|
|
26
|
+
# RBS has. The loader drops any other name (`RbsLoader.library_loader` keeps only `has_library?` ones), so it
|
|
27
|
+
# covers nothing. The predicate is built only when a name needs it: building it can construct an RBS loader.
|
|
28
|
+
# Callers have `Environment` loaded, which defines `DEFAULT_LIBRARIES`.
|
|
29
|
+
def loadable(library_names)
|
|
30
|
+
has = nil
|
|
31
|
+
library_names.select do |name|
|
|
32
|
+
Environment::DEFAULT_LIBRARIES.include?(name) || Environment::RequiredFeatures.feature_of_token(name) ||
|
|
33
|
+
(has ||= predicate).call(name)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The `libraries:` names worth auditing: a vendored feature name (`prime`) becomes a vendored feature token
|
|
38
|
+
# that the loader never asks `has_library?` about, so it is not an RBS library name to check.
|
|
39
|
+
def auditable(libraries)
|
|
40
|
+
Array(libraries).map(&:to_s) - Environment::RequiredFeatures::VENDORED_DIRS.keys
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def stdlib_root
|
|
44
|
+
dir = File.join(Gem::Specification.find_by_name("rbs").gem_dir, "stdlib")
|
|
45
|
+
File.directory?(dir) ? dir : nil
|
|
46
|
+
rescue Gem::LoadError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def gem_sig_dir?(name)
|
|
51
|
+
File.directory?(File.join(Gem::Specification.find_by_name(name).gem_dir, "sig"))
|
|
52
|
+
rescue Gem::MissingSpecError
|
|
53
|
+
false
|
|
54
|
+
rescue Gem::LoadError
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def stdlib_library?(stdlib, name)
|
|
59
|
+
return false if name.include?("/") || name.include?("\0")
|
|
60
|
+
|
|
61
|
+
Dir.children(File.join(stdlib, name)).any? do |child|
|
|
62
|
+
Gem::Version.correct?(child) && !Gem::Version.create(child).prerelease?
|
|
63
|
+
end
|
|
64
|
+
rescue SystemCallError
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|