rigortype 0.3.8 → 0.3.9
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 +1 -1
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +72 -1
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +32 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +11 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +81 -22
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +177 -26
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +256 -88
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +133 -35
- data/lib/rigor/analysis/worker_session.rb +9 -10
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +155 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +77 -32
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +2 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +388 -59
- data/lib/rigor/environment.rb +105 -20
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +42 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +61 -21
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +115 -22
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +4 -5
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +5 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +26 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -48,6 +48,8 @@ module Rigor
|
|
|
48
48
|
# with the running Ruby**, where "the analyzer's Ruby is the target's Ruby" already covers them.
|
|
49
49
|
# A third-party gem's `VERSION` is not read: its version is the project's `Gemfile.lock`'s to say,
|
|
50
50
|
# and the lockfile is not visible from the inference layer.
|
|
51
|
+
# * The ROOTED spelling of any of the above — `::RUBY_VERSION`, `::RUBY_ENGINE`, `::Psych::VERSION` —
|
|
52
|
+
# names the same constant as its bare twin and folds identically; see {.read_constant}.
|
|
51
53
|
# * `RUBY_PLATFORM` — **never** folded. Every comparison against it is by construction
|
|
52
54
|
# platform-dependent, and the machine running `rigor` need not be the machine running the program.
|
|
53
55
|
# * `<=>` — never folded (it yields -1/0/1, not a branch verdict), and neither are `defined?(Ractor)`
|
|
@@ -68,7 +70,7 @@ module Rigor
|
|
|
68
70
|
|
|
69
71
|
# Predefined constants read from the analyzer's runtime, mapped to the operand kind they produce.
|
|
70
72
|
# `:string` operands accept every comparison; `:engine` operands accept equality only.
|
|
71
|
-
PREDEFINED = { RUBY_VERSION
|
|
73
|
+
PREDEFINED = { "RUBY_VERSION" => :string, "RUBY_ENGINE" => :engine }.freeze
|
|
72
74
|
private_constant :PREDEFINED
|
|
73
75
|
|
|
74
76
|
# Operand kinds that carry a plain Ruby String, i.e. the ones `Gem::Version.new` may wrap and the
|
|
@@ -88,8 +90,8 @@ module Rigor
|
|
|
88
90
|
GEM_VERSION_PATH = "Gem::Version"
|
|
89
91
|
private_constant :GEM_VERSION_PATH
|
|
90
92
|
|
|
91
|
-
# @param node
|
|
92
|
-
# @return
|
|
93
|
+
# @param node — an `if` / `unless` predicate
|
|
94
|
+
# @return `:truthy` / `:falsey` when the guard is decidable on the analyzer's Ruby,
|
|
93
95
|
# otherwise nil (both arms stay live)
|
|
94
96
|
def verdict(node)
|
|
95
97
|
return nil unless node.is_a?(Prism::CallNode)
|
|
@@ -109,35 +111,40 @@ module Rigor
|
|
|
109
111
|
end
|
|
110
112
|
|
|
111
113
|
# Reads one side of the comparison into `[kind, value]`, or nil when it is not readable.
|
|
112
|
-
#
|
|
113
|
-
# @return [Array(Symbol, Object), nil]
|
|
114
114
|
def read_operand(node)
|
|
115
115
|
case node
|
|
116
116
|
when Prism::StringNode then [:literal_string, node.unescaped]
|
|
117
|
-
when Prism::ConstantReadNode then
|
|
118
|
-
when Prism::ConstantPathNode then read_version_constant(node)
|
|
117
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode then read_constant(node)
|
|
119
118
|
when Prism::CallNode then read_gem_version(node)
|
|
120
119
|
end
|
|
121
120
|
end
|
|
122
121
|
private_class_method :read_operand
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def
|
|
123
|
+
# Dispatches on the RESOLVED name rather than on the node class. `::RUBY_VERSION` names the very
|
|
124
|
+
# constant `RUBY_VERSION` names — the leading `::` only makes the top-level lookup explicit — but
|
|
125
|
+
# Prism spells it as a `ConstantPathNode` with a nil parent, so a node-class dispatch sent it down
|
|
126
|
+
# the `X::VERSION` path and declined it for not being a curated qualified name. The same program
|
|
127
|
+
# then had two diagnostic sets for two spellings of one guard
|
|
128
|
+
# ([#877](https://github.com/rigortype/rigor/issues/877)).
|
|
129
|
+
#
|
|
130
|
+
# The foldable set is unchanged and stays closed: an unqualified name folds only when it is one of
|
|
131
|
+
# {PREDEFINED}, a qualified one only when it is in {VERSION_CONSTANTS}.
|
|
132
|
+
def read_constant(node)
|
|
134
133
|
path = Source::ConstantPath.qualified_name_or_nil(node)
|
|
135
|
-
return nil unless path
|
|
134
|
+
return nil unless path
|
|
135
|
+
|
|
136
|
+
kind =
|
|
137
|
+
if path.include?("::")
|
|
138
|
+
:string if VERSION_CONSTANTS.include?(path)
|
|
139
|
+
else
|
|
140
|
+
PREDEFINED[path]
|
|
141
|
+
end
|
|
142
|
+
return nil unless kind
|
|
136
143
|
|
|
137
144
|
value = runtime_value(path)
|
|
138
|
-
value && [
|
|
145
|
+
value && [kind, value]
|
|
139
146
|
end
|
|
140
|
-
private_class_method :
|
|
147
|
+
private_class_method :read_constant
|
|
141
148
|
|
|
142
149
|
# `Gem::Version.new(<readable>)`. The inner operand must be a plain version String — an engine name
|
|
143
150
|
# is not a version, and `Gem::Version.new` raises on anything `Gem::Version.correct?` rejects, so a
|
|
@@ -165,7 +172,7 @@ module Rigor
|
|
|
165
172
|
# `const_get` would execute the target file inside the analyzer. `Module#autoload?` is what
|
|
166
173
|
# separates the two ([#680](https://github.com/rigortype/rigor/issues/680)).
|
|
167
174
|
#
|
|
168
|
-
# @return
|
|
175
|
+
# @return the constant's value when it is a non-empty String
|
|
169
176
|
def runtime_value(path)
|
|
170
177
|
mod = ::Object
|
|
171
178
|
path.split("::").each do |part|
|
|
@@ -9,11 +9,11 @@ module Rigor
|
|
|
9
9
|
# consistency, normalization, or erasure.
|
|
10
10
|
#
|
|
11
11
|
# @!attribute class_name
|
|
12
|
-
# @return
|
|
12
|
+
# @return the receiver class whose method declared `-> void`.
|
|
13
13
|
# @!attribute method_name
|
|
14
|
-
# @return
|
|
14
|
+
# @return the method whose return was recovered.
|
|
15
15
|
# @!attribute kind
|
|
16
|
-
# @return
|
|
16
|
+
# @return `:instance` or `:singleton`.
|
|
17
17
|
VoidOrigin = Data.define(:class_name, :method_name, :kind) do
|
|
18
18
|
# A human-facing `Class#method` / `Class.method` label for the diagnostic message.
|
|
19
19
|
def label
|
|
@@ -75,10 +75,8 @@ module Rigor
|
|
|
75
75
|
# consult; the memo persists across consults for the run. The memo is probed before the visited
|
|
76
76
|
# set is allocated so the common post-warmup hit path allocates nothing.
|
|
77
77
|
#
|
|
78
|
-
# @param
|
|
79
|
-
# @param
|
|
80
|
-
# @param kind [Symbol] `:instance` or `:singleton`.
|
|
81
|
-
# @return [Inference::VoidOrigin, nil]
|
|
78
|
+
# @param owner — the qualified receiver class the `def` belongs to.
|
|
79
|
+
# @param kind — `:instance` or `:singleton`.
|
|
82
80
|
def origin_for(def_node, owner, kind)
|
|
83
81
|
return nil if def_node.nil?
|
|
84
82
|
|
|
@@ -51,7 +51,7 @@ module Rigor
|
|
|
51
51
|
# computed from the stale text would be wrong. Consumers check {#desynchronized?} and decline to answer
|
|
52
52
|
# rather than answering wrongly; the mark clears on the next `didOpen` or full-text change.
|
|
53
53
|
#
|
|
54
|
-
# @return
|
|
54
|
+
# @return true when the changes were applied.
|
|
55
55
|
def apply_changes(uri:, changes:, version:)
|
|
56
56
|
text = IncrementalSync.apply_all(@entries[uri]&.bytes, changes)
|
|
57
57
|
@desynchronized.delete(uri)
|
|
@@ -63,13 +63,13 @@ module Rigor
|
|
|
63
63
|
false
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
# @return
|
|
66
|
+
# @return true when the last `didChange` for `uri` could not be applied, so the held text no
|
|
67
67
|
# longer matches the editor's.
|
|
68
68
|
def desynchronized?(uri)
|
|
69
69
|
@desynchronized.key?(uri)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
# @return
|
|
72
|
+
# @return why `uri` is desynchronised, for the log line; nil when it is in sync.
|
|
73
73
|
def desynchronization_reason(uri)
|
|
74
74
|
@desynchronized[uri]
|
|
75
75
|
end
|
|
@@ -91,7 +91,7 @@ module Rigor
|
|
|
91
91
|
@dirty.delete(uri)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
# @return
|
|
94
|
+
# @return true when `uri` has unsaved changes. A buffer that is dirty may only be published
|
|
95
95
|
# from an analysis that bound ITS bytes — see the publish-set invariant in
|
|
96
96
|
# `docs/design/20260517-language-server.md`.
|
|
97
97
|
def dirty?(uri)
|
|
@@ -42,7 +42,7 @@ module Rigor
|
|
|
42
42
|
@project_context = project_context
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
# @return
|
|
45
|
+
# @return LSP `CompletionItem[]` or nil
|
|
46
46
|
# when the cursor isn't at a position the provider can
|
|
47
47
|
# enumerate completions for. Returning nil maps to
|
|
48
48
|
# `result: null` per the LSP spec — clients treat it as
|
|
@@ -30,13 +30,13 @@ module Rigor
|
|
|
30
30
|
hint: 4
|
|
31
31
|
}.freeze
|
|
32
32
|
|
|
33
|
-
# @param debouncer
|
|
33
|
+
# @param debouncer —
|
|
34
34
|
# when present, `publish_for` schedules its work through
|
|
35
35
|
# the debouncer (cancels prior pending task for the same
|
|
36
36
|
# URI, fires after `debounce_seconds` quiet-time). Nil
|
|
37
37
|
# keeps the slice 4-7 synchronous behaviour — primarily
|
|
38
38
|
# useful for specs.
|
|
39
|
-
# @param debounce_seconds
|
|
39
|
+
# @param debounce_seconds — quiet-time before the
|
|
40
40
|
# debounced publish fires. 0 with a debouncer means
|
|
41
41
|
# "schedule on next-tick" (still async); without a
|
|
42
42
|
# debouncer the value is unused.
|
|
@@ -212,7 +212,7 @@ module Rigor
|
|
|
212
212
|
notify(uri, diagnostics)
|
|
213
213
|
end
|
|
214
214
|
|
|
215
|
-
# @return
|
|
215
|
+
# @return `{ uri:, path:, bytes: }` when `uri` is eligible for the batch, or nil to
|
|
216
216
|
# exclude it. Mirrors `#run_and_notify`'s own guards: a buffer closed during the debounce window is
|
|
217
217
|
# dropped silently (its didClose empty publish already cleared the markers); a desynchronised buffer
|
|
218
218
|
# publishes an EMPTY set immediately (same as the single-buffer path) rather than joining the batch.
|
|
@@ -320,7 +320,7 @@ module Rigor
|
|
|
320
320
|
end
|
|
321
321
|
end
|
|
322
322
|
|
|
323
|
-
# @return
|
|
323
|
+
# @return the LSP `Diagnostic` Hash, or nil to
|
|
324
324
|
# skip diagnostics outside the buffer's own path (e.g.
|
|
325
325
|
# `.rigor.yml`-anchored info diagnostics get filtered —
|
|
326
326
|
# they belong to the project, not the buffer).
|
|
@@ -30,7 +30,7 @@ module Rigor
|
|
|
30
30
|
@project_context = project_context
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# @return
|
|
33
|
+
# @return LSP `DocumentSymbol[]` for the
|
|
34
34
|
# buffer at `uri`. Returns nil when the URI isn't open or
|
|
35
35
|
# doesn't parse cleanly enough to surface symbols — LSP
|
|
36
36
|
# clients fall back to no-outline in that case.
|
|
@@ -23,7 +23,7 @@ module Rigor
|
|
|
23
23
|
@project_context = project_context
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
# @return
|
|
26
|
+
# @return LSP `FoldingRange[]` for the
|
|
27
27
|
# buffer, or nil when the URI isn't open / parseable.
|
|
28
28
|
def provide(uri)
|
|
29
29
|
path, entry = buffer_for(uri)
|
|
@@ -29,7 +29,7 @@ module Rigor
|
|
|
29
29
|
@renderer = renderer
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
# @return
|
|
32
|
+
# @return an LSP `Hover` payload or nil when no
|
|
33
33
|
# expression sits at the queried position. Returning nil
|
|
34
34
|
# maps to `result: null` per the LSP spec — clients
|
|
35
35
|
# suppress the hover popup in that case.
|
|
@@ -13,7 +13,7 @@ module Rigor
|
|
|
13
13
|
# (method call, constant, local, ivar, literal) gets the most relevant type-aware presentation per
|
|
14
14
|
# `docs/design/20260517-lsp-hover-completion.md`.
|
|
15
15
|
class HoverRenderer
|
|
16
|
-
# @param node_scope_lookup
|
|
16
|
+
# @param node_scope_lookup — node-to-scope table built by `ScopeIndexer.index`. The renderer indexes
|
|
17
17
|
# into it to retrieve the receiver's narrow scope when specialising on `CallNode`. The lookup never
|
|
18
18
|
# returns nil (the indexer's Hash carries `default_scope` as its default value), so the renderer trusts
|
|
19
19
|
# the lookup result.
|
|
@@ -83,7 +83,7 @@ module Rigor
|
|
|
83
83
|
)
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
# @return
|
|
86
|
+
# @return , nil] the resolved method definition, the receiver
|
|
87
87
|
# class name, and the dispatch kind (`:instance` or `:singleton`); nil when the receiver shape isn't
|
|
88
88
|
# yet supported or the method doesn't resolve through the RBS env.
|
|
89
89
|
def lookup_method(receiver_type, method_name, scope)
|
|
@@ -46,10 +46,10 @@ module Rigor
|
|
|
46
46
|
# Applies every change in order, each against the result of the previous — the LSP contract for a
|
|
47
47
|
# multi-change `didChange` notification.
|
|
48
48
|
#
|
|
49
|
-
# @param text
|
|
50
|
-
# @param changes
|
|
51
|
-
# @return
|
|
52
|
-
# @raise
|
|
49
|
+
# @param text — the held buffer text; nil when no buffer is open for the URI.
|
|
50
|
+
# @param changes — the `contentChanges` array.
|
|
51
|
+
# @return the new buffer text.
|
|
52
|
+
# @raise UnappliableChange — if any change cannot be applied.
|
|
53
53
|
def apply_all(text, changes)
|
|
54
54
|
raise UnappliableChange, "contentChanges must be an Array, got #{changes.class}" unless changes.is_a?(Array)
|
|
55
55
|
|
|
@@ -64,7 +64,7 @@ module Rigor
|
|
|
64
64
|
# companion to `range` and is accepted-but-ignored: it is redundant with `range`, historically ambiguous
|
|
65
65
|
# about its units, and `range` is the authoritative field.
|
|
66
66
|
#
|
|
67
|
-
# @raise
|
|
67
|
+
# @raise UnappliableChange
|
|
68
68
|
def apply(text, change)
|
|
69
69
|
raise UnappliableChange, "contentChanges entry must be a Hash, got #{change.class}" unless change.is_a?(Hash)
|
|
70
70
|
|
|
@@ -95,7 +95,7 @@ module Rigor
|
|
|
95
95
|
raise UnappliableChange, "held text is not valid UTF-8: #{e.message}"
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
# @return
|
|
98
|
+
# @return one `[content_start, content_end]` pair per line, in Ruby
|
|
99
99
|
# character indices. `content_end` excludes the line terminator, so it doubles as the clamp target for
|
|
100
100
|
# an over-long `character`. A trailing terminator yields a final empty span — the virtual last line an
|
|
101
101
|
# editor puts the cursor on, and the anchor for an end-of-document insert.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../environment"
|
|
4
|
+
require_relative "../project_environment"
|
|
4
5
|
require_relative "../cache/store"
|
|
5
6
|
require_relative "../analysis/runner"
|
|
6
7
|
require_relative "../analysis/incremental_session"
|
|
@@ -74,11 +75,7 @@ module Rigor
|
|
|
74
75
|
dependency_source_index: project_scan.dependency_source_index,
|
|
75
76
|
synthetic_method_index: project_scan.synthetic_method_index,
|
|
76
77
|
project_patched_methods: project_scan.project_patched_methods,
|
|
77
|
-
|
|
78
|
-
bundler_auto_detect: @configuration.bundler_auto_detect,
|
|
79
|
-
bundler_lockfile: @configuration.bundler_lockfile,
|
|
80
|
-
rbs_collection_lockfile: @configuration.rbs_collection_lockfile,
|
|
81
|
-
rbs_collection_auto_detect: @configuration.rbs_collection_auto_detect
|
|
78
|
+
**ProjectEnvironment.dependency_discovery_options(@configuration)
|
|
82
79
|
)
|
|
83
80
|
end
|
|
84
81
|
|
|
@@ -15,10 +15,10 @@ module Rigor
|
|
|
15
15
|
# dropped. The same claim/consume shape `DiagnosticPublisher#run_project_round` already uses for the
|
|
16
16
|
# whole-project save round (#246), generalised to an arbitrary key type and an arbitrary batch action.
|
|
17
17
|
class PublishBatcher
|
|
18
|
-
# @param on_batch
|
|
18
|
+
# @param on_batch — `(keys) -> void`, called with the deduplicated Array of keys pending at the
|
|
19
19
|
# start of one round. May be called more than once in a row when keys keep arriving while a round
|
|
20
20
|
# runs.
|
|
21
|
-
# @param on_error
|
|
21
|
+
# @param on_error — `(exception) -> void`, called when `on_batch` raises. A round must
|
|
22
22
|
# never wedge the coalescing lock for every future `#enqueue` call — ownership is always released
|
|
23
23
|
# before this fires. Whatever was mid-flight when the round raised is lost; anything enqueued by a
|
|
24
24
|
# concurrent `#enqueue` call after this round's drain but before the rescue stays pending and rides
|
|
@@ -20,9 +20,9 @@ module Rigor
|
|
|
20
20
|
@project_context = project_context
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# @param positions
|
|
23
|
+
# @param positions — LSP `Position[]` — each
|
|
24
24
|
# `{ line:, character: }` 0-based.
|
|
25
|
-
# @return
|
|
25
|
+
# @return one `SelectionRange` per
|
|
26
26
|
# position, or nil when the URI / buffer isn't resolvable.
|
|
27
27
|
def provide(uri, positions)
|
|
28
28
|
path, entry = buffer_for(uri)
|
|
@@ -42,11 +42,11 @@ module Rigor
|
|
|
42
42
|
:signature_help_provider, :folding_range_provider,
|
|
43
43
|
:selection_range_provider, :project_context
|
|
44
44
|
|
|
45
|
-
# @param completion_provider
|
|
45
|
+
# @param completion_provider —
|
|
46
46
|
# resolves `textDocument/completion`. Nil → `MethodNotFound`.
|
|
47
|
-
# @param signature_help_provider
|
|
47
|
+
# @param signature_help_provider —
|
|
48
48
|
# resolves `textDocument/signatureHelp`. Nil → `MethodNotFound`.
|
|
49
|
-
# @param project_context
|
|
49
|
+
# @param project_context — the per-session cache of
|
|
50
50
|
# `Environment` + `Cache::Store` the providers read on every request. When present,
|
|
51
51
|
# `workspace/didChangeWatchedFiles` and `workspace/didChangeConfiguration` invalidate the cache; nil
|
|
52
52
|
# means "no project context": each request rebuilds env from scratch (mainly for specs and backward
|
|
@@ -69,7 +69,7 @@ module Rigor
|
|
|
69
69
|
@project_context = project_context
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
# @return
|
|
72
|
+
# @return true once the client has called `exit` and
|
|
73
73
|
# the server has set its terminal exit code. The CLI loop
|
|
74
74
|
# reads this between dispatches to know when to stop.
|
|
75
75
|
def exited?
|
|
@@ -78,10 +78,10 @@ module Rigor
|
|
|
78
78
|
|
|
79
79
|
# Routes one LSP method call.
|
|
80
80
|
#
|
|
81
|
-
# @param method
|
|
82
|
-
# @param params
|
|
81
|
+
# @param method — the LSP method name (e.g. "initialize").
|
|
82
|
+
# @param params — the LSP `params` payload (Hash for
|
|
83
83
|
# request / notification methods; nil for the empty case).
|
|
84
|
-
# @return
|
|
84
|
+
# @return one of:
|
|
85
85
|
# - the response result Hash for request methods,
|
|
86
86
|
# - nil for notification methods,
|
|
87
87
|
# - { error: { code:, message: } } for state / shape errors.
|
|
@@ -191,8 +191,8 @@ module Rigor
|
|
|
191
191
|
caps
|
|
192
192
|
end
|
|
193
193
|
|
|
194
|
-
# `initialized` is a notification — no response body.
|
|
195
|
-
# `workspace/didChangeWatchedFiles`
|
|
194
|
+
# `initialized` is a notification — no response body. Nothing is registered here yet: the server handles
|
|
195
|
+
# `workspace/didChangeWatchedFiles` when a client sends it, but does not register for it dynamically.
|
|
196
196
|
def handle_initialized
|
|
197
197
|
nil
|
|
198
198
|
end
|
|
@@ -44,7 +44,7 @@ module Rigor
|
|
|
44
44
|
@project_context = project_context
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# @return
|
|
47
|
+
# @return LSP `SignatureHelp` payload or nil
|
|
48
48
|
# when the cursor isn't inside a resolvable method call.
|
|
49
49
|
def provide(uri:, line:, character:, context: nil)
|
|
50
50
|
_ = context # Trigger info accepted but not routed in v1.
|
|
@@ -14,7 +14,7 @@ module Rigor
|
|
|
14
14
|
FILE_SCHEME = "file://"
|
|
15
15
|
private_constant :FILE_SCHEME
|
|
16
16
|
|
|
17
|
-
# @return
|
|
17
|
+
# @return absolute filesystem path for a
|
|
18
18
|
# `file://` URI, or nil for unsupported schemes.
|
|
19
19
|
def to_path(uri)
|
|
20
20
|
return nil unless uri.is_a?(String) && uri.start_with?(FILE_SCHEME)
|
data/lib/rigor/plugin/base.rb
CHANGED
|
@@ -40,6 +40,13 @@ module Rigor
|
|
|
40
40
|
#
|
|
41
41
|
# Rigor::Plugin.register(MyRailsPlugin)
|
|
42
42
|
class Base # rubocop:disable Metrics/ClassLength
|
|
43
|
+
# Issue #701 — the kind wrapper a `dynamic_return receivers:` entry may carry, spelled as RBS spells a
|
|
44
|
+
# class object and as the `call.undefined-method` message prints one, so an author writes the gate the
|
|
45
|
+
# way the diagnostic they are answering names the receiver. Declared on the class rather than inside
|
|
46
|
+
# `class << self` because both the load-time validator and the per-dispatch gate read it.
|
|
47
|
+
SINGLETON_RECEIVER_PATTERN = /\Asingleton\((.+)\)\z/
|
|
48
|
+
private_constant :SINGLETON_RECEIVER_PATTERN
|
|
49
|
+
|
|
43
50
|
class << self
|
|
44
51
|
# Declares the plugin's manifest. Called once at class definition time — the resulting {Manifest} is
|
|
45
52
|
# cached on the class so {Rigor::Plugin::Loader} reads it without constructing the plugin.
|
|
@@ -241,8 +248,21 @@ module Rigor
|
|
|
241
248
|
# end
|
|
242
249
|
#
|
|
243
250
|
# `receivers:` is a non-empty Array of class names; the engine calls the block only when the call's
|
|
244
|
-
# receiver type's class equals or inherits from one of them (via `Environment#class_ordering`)
|
|
245
|
-
# MAY be omitted — then the rule is receiver-independent and
|
|
251
|
+
# receiver type's class equals or inherits from one of them (via `Environment#class_ordering`) AND
|
|
252
|
+
# is of the kind the entry names. It MAY be omitted — then the rule is receiver-independent and
|
|
253
|
+
# fires on `methods:` alone.
|
|
254
|
+
#
|
|
255
|
+
# Issue #701 — an entry carries the receiver KIND in RBS's own spelling. `"Widget"` matches an
|
|
256
|
+
# INSTANCE receiver; `"singleton(Widget)"` matches the class object itself; a rule that wants both
|
|
257
|
+
# lists both:
|
|
258
|
+
#
|
|
259
|
+
# dynamic_return receivers: ["Widget"], methods: [:price] # Widget#price
|
|
260
|
+
# dynamic_return receivers: ["singleton(Widget)"], methods: [:build] # Widget.build
|
|
261
|
+
# dynamic_return receivers: ["Widget", "singleton(Widget)"] # either
|
|
262
|
+
#
|
|
263
|
+
# An instance rule that also answered on the class typed a call the plugin never modelled, and since
|
|
264
|
+
# #653 a plugin's answer suppresses `call.undefined-method` — so the class-level miss went silent on
|
|
265
|
+
# the say-so of a rule written for the instance.
|
|
246
266
|
#
|
|
247
267
|
# `methods:` is an Array of Symbol method names. When provided, the block is skipped unless
|
|
248
268
|
# `call_node.name` is in the list — declarative and cheaper than an in-block guard (the engine
|
|
@@ -261,6 +281,9 @@ module Rigor
|
|
|
261
281
|
# # found; the block does the precise per-call lookup
|
|
262
282
|
# end
|
|
263
283
|
#
|
|
284
|
+
# A callable's entries carry the kind the same way — `-> { names.map { "singleton(#{_1})" } }` for a
|
|
285
|
+
# discovered set of class-level receivers.
|
|
286
|
+
#
|
|
264
287
|
# The callable runs through `instance_exec`, so it reads the plugin's own `#prepare`-built indexes.
|
|
265
288
|
# It MUST be idempotent and post-`#prepare`-safe — reference a lazily-built / memoised index (as
|
|
266
289
|
# activestorage's `attachment_index` and activerecord's `model_index` are), never a value captured at
|
|
@@ -376,11 +399,23 @@ module Rigor
|
|
|
376
399
|
# ADR-52 slice 3 — a run-time callable is resolved per instance after `#prepare`; its shape is
|
|
377
400
|
# checked at resolution time.
|
|
378
401
|
return if receivers.respond_to?(:call)
|
|
379
|
-
return if receivers.is_a?(Array) && !receivers.empty? &&
|
|
402
|
+
return if receivers.is_a?(Array) && !receivers.empty? &&
|
|
403
|
+
receivers.all? { |r| valid_dynamic_return_receiver?(r) }
|
|
380
404
|
|
|
381
405
|
raise ArgumentError,
|
|
382
406
|
"Plugin::Base.dynamic_return receivers: must be a non-empty Array of class-name Strings " \
|
|
383
|
-
"
|
|
407
|
+
"(\"Foo\" for an instance receiver, \"singleton(Foo)\" for the class itself) or a " \
|
|
408
|
+
"callable, got #{receivers.inspect}"
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Issue #701 — the entry grammar: a non-empty class name, optionally wrapped in RBS's own
|
|
412
|
+
# `singleton(...)`. A bare `singleton()` is rejected rather than read as a class literally named
|
|
413
|
+
# that, so a typo in the kind wrapper fails at load instead of never matching.
|
|
414
|
+
def valid_dynamic_return_receiver?(entry)
|
|
415
|
+
return false unless entry.is_a?(String) && !entry.empty?
|
|
416
|
+
return SINGLETON_RECEIVER_PATTERN.match?(entry) if entry.start_with?("singleton(")
|
|
417
|
+
|
|
418
|
+
true
|
|
384
419
|
end
|
|
385
420
|
|
|
386
421
|
def validate_dynamic_return_methods!(methods)
|
|
@@ -397,7 +432,8 @@ module Rigor
|
|
|
397
432
|
end
|
|
398
433
|
|
|
399
434
|
private :validate_dynamic_return_gate!, :validate_dynamic_return_receivers!,
|
|
400
|
-
:validate_dynamic_return_methods!, :validate_dynamic_return_file_methods
|
|
435
|
+
:validate_dynamic_return_methods!, :validate_dynamic_return_file_methods!,
|
|
436
|
+
:valid_dynamic_return_receiver?
|
|
401
437
|
|
|
402
438
|
# ADR-37 slice 2 — declares a predicate/assertion narrowing contribution, method-gated. The narrow
|
|
403
439
|
# successor to the `post_return_facts` slot of the deleted `flow_contribution_for` hook (ADR-52 WD3):
|
|
@@ -545,19 +581,15 @@ module Rigor
|
|
|
545
581
|
|
|
546
582
|
# ADR-37 slice 2 — the return type contributed by this plugin's {.dynamic_return} rules for a call, or
|
|
547
583
|
# nil. The engine calls this from `MethodDispatcher`; a rule fires only when `receiver_type`'s class
|
|
548
|
-
# equals or inherits from one of its declared `receivers
|
|
549
|
-
# Failures isolate to nil.
|
|
584
|
+
# equals or inherits from one of its declared `receivers:` AND is of that entry's kind (#701). First
|
|
585
|
+
# non-nil wins (declaration order). Failures isolate to nil.
|
|
550
586
|
def dynamic_return_type(call_node:, scope:, receiver_type:)
|
|
551
587
|
rules = self.class.dynamic_returns
|
|
552
588
|
return nil if rules.empty? || receiver_type.nil?
|
|
553
589
|
|
|
554
|
-
# `class_name` is nil for a receiver carrier with no nominal class (a refinement dimension, an
|
|
555
|
-
# inferred shape) — fine for a receiver-less (methods-only) rule (ADR-52 WD2), which gates on the
|
|
556
|
-
# method name alone and reads the receiver shape inside its own block.
|
|
557
|
-
class_name = dynamic_return_receiver_class_name(receiver_type)
|
|
558
590
|
environment = scope&.environment
|
|
559
591
|
rules.each do |rule|
|
|
560
|
-
next unless dynamic_return_rule_applies?(rule, call_node,
|
|
592
|
+
next unless dynamic_return_rule_applies?(rule, call_node, receiver_type, environment, scope)
|
|
561
593
|
|
|
562
594
|
result = instance_exec(call_node, scope, &rule[:block])
|
|
563
595
|
return result if result
|
|
@@ -803,10 +835,9 @@ module Rigor
|
|
|
803
835
|
# survives only as the building block for the rare producer that needs `FileEntry` rows directly;
|
|
804
836
|
# plugin code calls `watch:`.
|
|
805
837
|
#
|
|
806
|
-
# @param roots
|
|
807
|
-
# @param patterns
|
|
838
|
+
# @param roots — search roots (relative to the project root, or absolute paths)
|
|
839
|
+
# @param patterns — glob suffixes joined under each root via `File.join(root, pattern)`.
|
|
808
840
|
# Multiple patterns union into one descriptor (`"**/*.erb", "**/*.html"` etc.).
|
|
809
|
-
# @return [Rigor::Cache::Descriptor]
|
|
810
841
|
def glob_descriptor(roots, *patterns)
|
|
811
842
|
files = collect_glob_files(Array(roots), patterns)
|
|
812
843
|
entries = files.map do |path|
|
|
@@ -836,7 +867,9 @@ module Rigor
|
|
|
836
867
|
|
|
837
868
|
# ADR-37 slice 2 — the class name to match a `dynamic_return` `receivers:` entry against, from a
|
|
838
869
|
# receiver `Type`. Covers the instance (`Nominal[X]`) and class (`Singleton[X]`) shapes; other carriers
|
|
839
|
-
# decline (nil → no match).
|
|
870
|
+
# decline (nil → no match). Which of the two KINDS the name is then matched as is
|
|
871
|
+
# {#dynamic_return_receiver_matches?}'s question — the `Result` / `Maybe` carriers are instances of
|
|
872
|
+
# their class, like `Nominal`.
|
|
840
873
|
def dynamic_return_receiver_class_name(receiver_type)
|
|
841
874
|
case receiver_type
|
|
842
875
|
when Rigor::Type::Nominal, Rigor::Type::Singleton then receiver_type.class_name
|
|
@@ -848,7 +881,7 @@ module Rigor
|
|
|
848
881
|
# The gate for one `dynamic_return` rule. Method-name gate first — a Symbol-array probe vs the receiver
|
|
849
882
|
# ancestry resolution below (ADR-52 WD1); both are pure predicates, so order only affects cost. A
|
|
850
883
|
# receiver-less rule (ADR-52 WD2) skips the ancestry check entirely and fires on the method name alone.
|
|
851
|
-
def dynamic_return_rule_applies?(rule, call_node,
|
|
884
|
+
def dynamic_return_rule_applies?(rule, call_node, receiver_type, environment, scope)
|
|
852
885
|
return false if rule[:methods] && !resolved_dynamic_return_methods(rule).include?(call_node.name)
|
|
853
886
|
|
|
854
887
|
if rule[:file_methods]
|
|
@@ -858,11 +891,29 @@ module Rigor
|
|
|
858
891
|
return false unless resolved_dynamic_return_file_methods(rule, path).include?(call_node.name)
|
|
859
892
|
end
|
|
860
893
|
|
|
861
|
-
|
|
862
|
-
return true if
|
|
894
|
+
entries = resolved_dynamic_return_receiver_entries(rule)
|
|
895
|
+
return true if entries.nil?
|
|
896
|
+
|
|
897
|
+
dynamic_return_receiver_matches?(entries, receiver_type, environment)
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
# Issue #701 — the receiver gate, kind included. An entry written for an instance (`"Widget"`) must not
|
|
901
|
+
# answer for the class object: the block was never given the class-level call to model, and since #653
|
|
902
|
+
# its answer would suppress that call's `call.undefined-method`, hiding a genuine miss on the plugin's
|
|
903
|
+
# say-so. A rule that wants the class object declares `"singleton(Widget)"`, and one that wants both
|
|
904
|
+
# lists both.
|
|
905
|
+
#
|
|
906
|
+
# A nil class name is a carrier with no nominal class (a refinement dimension, an inferred shape); a
|
|
907
|
+
# receiver-gated rule cannot speak about it and declines. A receiver-less rule (ADR-52 WD2) never
|
|
908
|
+
# reaches here.
|
|
909
|
+
def dynamic_return_receiver_matches?(entries, receiver_type, environment)
|
|
910
|
+
class_name = dynamic_return_receiver_class_name(receiver_type)
|
|
863
911
|
return false if class_name.nil?
|
|
864
912
|
|
|
865
|
-
|
|
913
|
+
singleton = receiver_type.is_a?(Rigor::Type::Singleton)
|
|
914
|
+
entries.any? do |name, singleton_entry|
|
|
915
|
+
singleton_entry == singleton && class_matches_receiver?(class_name, name, environment)
|
|
916
|
+
end
|
|
866
917
|
end
|
|
867
918
|
|
|
868
919
|
# ADR-52 slice 4 — the rule's method-name set. A static Array is returned as-is (`#include?` over
|
|
@@ -910,6 +961,24 @@ module Rigor
|
|
|
910
961
|
Array(instance_exec(&receivers)).map { |c| c.to_s.dup.freeze }.freeze
|
|
911
962
|
end
|
|
912
963
|
|
|
964
|
+
# Issue #701 — the resolved `receivers:` entries as `[class_name, singleton?]` pairs, or nil for a
|
|
965
|
+
# receiver-less rule. Memoised per rule beside the callable resolution above, so the kind is parsed
|
|
966
|
+
# once per run rather than once per dispatch (this sits on the per-dispatch plugin path).
|
|
967
|
+
def resolved_dynamic_return_receiver_entries(rule)
|
|
968
|
+
receivers = resolved_dynamic_return_receivers(rule)
|
|
969
|
+
return nil if receivers.nil?
|
|
970
|
+
|
|
971
|
+
(@dynamic_return_runtime_cache ||= {})[[:receiver_entries, rule]] ||=
|
|
972
|
+
receivers.map { |entry| parse_dynamic_return_receiver(entry) }.freeze
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def parse_dynamic_return_receiver(entry)
|
|
976
|
+
match = SINGLETON_RECEIVER_PATTERN.match(entry)
|
|
977
|
+
return [match[1].freeze, true].freeze if match
|
|
978
|
+
|
|
979
|
+
[entry, false].freeze
|
|
980
|
+
end
|
|
981
|
+
|
|
913
982
|
# True when `class_name` equals or inherits from `constraint`, matched through
|
|
914
983
|
# `Environment#class_ordering` (the mechanism `MacroBlockSelfType` / `additional_initializers` use).
|
|
915
984
|
# Degrades to "no match" on any resolution failure (false-positive-safe).
|
|
@@ -976,7 +1045,7 @@ module Rigor
|
|
|
976
1045
|
Cache::Descriptor.new(
|
|
977
1046
|
files: boundary.files,
|
|
978
1047
|
configs: boundary.configs,
|
|
979
|
-
globs: watch_glob_entries(producer[:watch])
|
|
1048
|
+
globs: (watch_glob_entries(producer[:watch]) + boundary.globs).uniq
|
|
980
1049
|
)
|
|
981
1050
|
end
|
|
982
1051
|
|