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
|
@@ -4,6 +4,7 @@ require "tempfile"
|
|
|
4
4
|
|
|
5
5
|
require_relative "uri"
|
|
6
6
|
require_relative "publish_batcher"
|
|
7
|
+
require_relative "config_warning_announcer"
|
|
7
8
|
require_relative "../analysis/runner"
|
|
8
9
|
require_relative "../analysis/buffer_binding"
|
|
9
10
|
|
|
@@ -19,7 +20,7 @@ module Rigor
|
|
|
19
20
|
# buffers' debounce timers elapse around the same moment, the `PublishBatcher` coalesces them into one
|
|
20
21
|
# `#publish_many` round dispatched across the fork-based worker pool (issue #142) instead of N
|
|
21
22
|
# independent, GVL-serialized `Runner` calls.
|
|
22
|
-
class DiagnosticPublisher
|
|
23
|
+
class DiagnosticPublisher # rubocop:disable Metrics/ClassLength
|
|
23
24
|
# Maps Rigor severity symbols to LSP DiagnosticSeverity
|
|
24
25
|
# integers per spec § "Diagnostic":
|
|
25
26
|
# 1 = Error, 2 = Warning, 3 = Information, 4 = Hint.
|
|
@@ -51,6 +52,7 @@ module Rigor
|
|
|
51
52
|
@project_context = project_context
|
|
52
53
|
@debouncer = debouncer
|
|
53
54
|
@debounce_seconds = debounce_seconds
|
|
55
|
+
@config_warning_announcer = ConfigWarningAnnouncer.new(writer: writer, project_context: project_context)
|
|
54
56
|
@round_lock = Mutex.new
|
|
55
57
|
@round_running = false
|
|
56
58
|
@round_pending = false
|
|
@@ -130,6 +132,9 @@ module Rigor
|
|
|
130
132
|
notify(uri, [])
|
|
131
133
|
end
|
|
132
134
|
|
|
135
|
+
# Issue #2231 — shows the configuration warnings the editor has not seen yet ({ConfigWarningAnnouncer}).
|
|
136
|
+
def announce_config_warnings = @config_warning_announcer.announce
|
|
137
|
+
|
|
133
138
|
# Cancels every in-flight debounced task. Called from `Server#handle_shutdown` so pending publishes
|
|
134
139
|
# don't fire against a closed STDOUT.
|
|
135
140
|
def cancel_pending
|
|
@@ -167,8 +172,7 @@ module Rigor
|
|
|
167
172
|
|
|
168
173
|
# True when a save arrived mid-round and the loop should run once more. Releases ownership otherwise.
|
|
169
174
|
# `next`, not `break`: inside `Mutex#synchronize`'s block, `break` returns from the SYNCHRONIZE call, so
|
|
170
|
-
# a `break`
|
|
171
|
-
# before this was split out.
|
|
175
|
+
# a `break` here would leave the caller's `loop` spinning forever.
|
|
172
176
|
def consume_pending
|
|
173
177
|
@round_lock.synchronize do
|
|
174
178
|
next(@round_running = false) unless @round_pending
|
|
@@ -185,6 +189,7 @@ module Rigor
|
|
|
185
189
|
def execute_project_round(saved_uri)
|
|
186
190
|
generation = @project_context.generation
|
|
187
191
|
diagnostics = @project_context.project_diagnostics
|
|
192
|
+
announce_config_warnings # the round re-read the configuration; the reload stands even if the result does not
|
|
188
193
|
return if generation != @project_context.generation
|
|
189
194
|
|
|
190
195
|
by_path = diagnostics.group_by(&:path)
|
|
@@ -30,7 +30,7 @@ module Rigor
|
|
|
30
30
|
@project_context = project_context
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
# @return LSP
|
|
33
|
+
# @return LSP document symbols 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,8 +23,7 @@ module Rigor
|
|
|
23
23
|
@project_context = project_context
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
# @return LSP
|
|
27
|
-
# buffer, or nil when the URI isn't open / parseable.
|
|
26
|
+
# @return LSP folding ranges for the buffer, or nil when the URI isn't open / parseable.
|
|
28
27
|
def provide(uri)
|
|
29
28
|
path, entry = buffer_for(uri)
|
|
30
29
|
return nil if entry.nil?
|
|
@@ -44,7 +44,7 @@ module Rigor
|
|
|
44
44
|
node = locate_node(source: entry.bytes, root: parse_result.value, line: line + 1, character: character + 1)
|
|
45
45
|
return nil if node.nil?
|
|
46
46
|
|
|
47
|
-
scope =
|
|
47
|
+
scope = @project_context.seeded_scope_for(path: path, bytes: entry.bytes)
|
|
48
48
|
index = Inference::ScopeIndexer.index(parse_result.value, default_scope: scope)
|
|
49
49
|
node_scope = index[node]
|
|
50
50
|
type = node_scope.type_of(node)
|
|
@@ -59,12 +59,6 @@ module Rigor
|
|
|
59
59
|
rescue Source::NodeLocator::OutOfRangeError
|
|
60
60
|
nil
|
|
61
61
|
end
|
|
62
|
-
|
|
63
|
-
def base_scope(_path)
|
|
64
|
-
# Pulls the Environment from the cached ProjectContext so each hover avoids repeating the RBS-load
|
|
65
|
-
# build.
|
|
66
|
-
Scope.empty(environment: @project_context.environment)
|
|
67
|
-
end
|
|
68
62
|
end
|
|
69
63
|
end
|
|
70
64
|
end
|
|
@@ -60,9 +60,8 @@ module Rigor
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
# Renders a `CallNode` hover when the receiver's type can be mapped to a known RBS class and the method
|
|
63
|
-
# is declared there. Returns nil for shapes
|
|
64
|
-
# Refined / Shape receivers
|
|
65
|
-
# default body.
|
|
63
|
+
# is declared there. Returns nil for shapes this renderer does not handle (implicit `self`, Union /
|
|
64
|
+
# Refined / Shape receivers); the caller falls back to the default body.
|
|
66
65
|
def render_call(call_node, return_type, node_scope_lookup)
|
|
67
66
|
receiver_node = call_node.receiver
|
|
68
67
|
return nil if receiver_node.nil?
|
|
@@ -133,17 +132,16 @@ module Rigor
|
|
|
133
132
|
body << "#{return_type.describe}\n"
|
|
134
133
|
body << "```"
|
|
135
134
|
if (doc = rbs_documentation(definition))
|
|
136
|
-
#
|
|
137
|
-
# necessary — plain markdown below the code reads better in clients.
|
|
135
|
+
# The fence is already closed, so the RBS comment renders as plain markdown below the code.
|
|
138
136
|
body << "\n\n---\n\n#{doc}"
|
|
139
137
|
end
|
|
140
138
|
body
|
|
141
139
|
end
|
|
142
140
|
|
|
143
141
|
# Returns the concatenated text of every RBS comment attached to the method definition, or nil when no
|
|
144
|
-
# comments exist. `RBS::Definition::Method#comments` is
|
|
145
|
-
# `.string`
|
|
146
|
-
#
|
|
142
|
+
# comments exist. `RBS::Definition::Method#comments` is a list of `AST::Comment`s, each with its raw text
|
|
143
|
+
# in `.string` (newline-terminated `# foo` lines). Multiple comments are joined with a blank line so each
|
|
144
|
+
# upstream `# Foo bar` paragraph is preserved.
|
|
147
145
|
def rbs_documentation(definition)
|
|
148
146
|
comments = definition.respond_to?(:comments) ? definition.comments : nil
|
|
149
147
|
return nil if comments.nil? || comments.empty?
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "tempfile"
|
|
4
|
+
|
|
3
5
|
require_relative "../environment"
|
|
4
6
|
require_relative "../project_environment"
|
|
5
7
|
require_relative "../cache/store"
|
|
@@ -9,6 +11,7 @@ require_relative "../cache/incremental_snapshot"
|
|
|
9
11
|
require_relative "../effects/identity"
|
|
10
12
|
require_relative "../analysis/path_expansion"
|
|
11
13
|
require_relative "../protection/discovery_seed"
|
|
14
|
+
require_relative "../config_audit"
|
|
12
15
|
|
|
13
16
|
module Rigor
|
|
14
17
|
module LanguageServer
|
|
@@ -68,6 +71,24 @@ module Rigor
|
|
|
68
71
|
@project_scan = nil
|
|
69
72
|
@incremental_session = nil
|
|
70
73
|
@session_primed = false
|
|
74
|
+
@announced_config_warnings = Set.new
|
|
75
|
+
@announce_lock = Mutex.new
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Issue #2231 — the {ConfigAudit} warnings for the configuration as last loaded that the editor has not been
|
|
79
|
+
# shown yet, or an empty array. `rigor check` prints these on every run; the server is one long run, so it
|
|
80
|
+
# announces each warning once: at `initialized` for the configuration it started with, and after a later reload
|
|
81
|
+
# (every save round re-reads `.rigor.yml`) only the warnings that were not in the previous reload's set. The
|
|
82
|
+
# comparison is by message, not by order, so reordering entries announces nothing, and fixing one of two
|
|
83
|
+
# warnings does not show the other again. A warning that was fixed and then comes back is new and is shown.
|
|
84
|
+
# Called from the dispatch thread and the save round's thread alike, hence the lock.
|
|
85
|
+
def unannounced_config_warnings
|
|
86
|
+
@announce_lock.synchronize do
|
|
87
|
+
warnings = ConfigAudit.warnings(@configuration)
|
|
88
|
+
fresh = warnings.reject { |warning| @announced_config_warnings.include?(warning.message) }
|
|
89
|
+
@announced_config_warnings = warnings.to_set(&:message)
|
|
90
|
+
fresh
|
|
91
|
+
end
|
|
71
92
|
end
|
|
72
93
|
|
|
73
94
|
# Returns the cached `Rigor::Environment` for this session, building it on first access. The build
|
|
@@ -132,6 +153,22 @@ module Rigor
|
|
|
132
153
|
buffer: buffer, constant_sources: true)
|
|
133
154
|
end
|
|
134
155
|
|
|
156
|
+
# Issue #2282 — the base scope an editor query (hover, completion, signature help) probes with: the same
|
|
157
|
+
# cross-file discovery seed the diagnostic publisher hands its `Runner` ({#discovery_seed_for}), so a constant
|
|
158
|
+
# or method another file defines answers what `rigor check` would. The seed fold reads the buffer through a
|
|
159
|
+
# {Analysis::BufferBinding}, so `bytes` is staged in a tempfile for the call. An empty seed (no configured
|
|
160
|
+
# files, or nothing discovered) leaves the bare single-file scope every query used before.
|
|
161
|
+
def seeded_scope_for(path:, bytes:)
|
|
162
|
+
seed = Tempfile.create(["rigor-lsp-query-", ".rb"]) do |tmp|
|
|
163
|
+
# Staged as the publisher stages them; the seed's job is to withhold the stale on-disk declarations of
|
|
164
|
+
# this file, so an empty-bytes stage is not observable by design.
|
|
165
|
+
tmp.write(bytes)
|
|
166
|
+
tmp.flush
|
|
167
|
+
discovery_seed_for(Analysis::BufferBinding.new(logical_path: path, physical_path: tmp.path))
|
|
168
|
+
end
|
|
169
|
+
Protection::DiscoverySeed.seeded_scope(environment: environment, seed: seed)
|
|
170
|
+
end
|
|
171
|
+
|
|
135
172
|
# Builds what {#discovery_seed_for} reads once per generation, so a fork batch's children inherit it instead
|
|
136
173
|
# of each walking the project.
|
|
137
174
|
def prepare_discovery_seed
|
|
@@ -251,7 +288,8 @@ module Rigor
|
|
|
251
288
|
def reload_configuration
|
|
252
289
|
return unless @configuration_loader
|
|
253
290
|
|
|
254
|
-
|
|
291
|
+
loaded = @configuration_loader.call
|
|
292
|
+
@announce_lock.synchronize { @configuration = loaded }
|
|
255
293
|
rescue StandardError
|
|
256
294
|
nil
|
|
257
295
|
end
|
|
@@ -15,10 +15,9 @@ 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 —
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# @param on_error — `(exception) -> void`, called when `on_batch` raises. A round must
|
|
18
|
+
# @param on_batch — called with the deduplicated keys pending at the start of one round. May be called
|
|
19
|
+
# more than once in a row when keys keep arriving while a round runs.
|
|
20
|
+
# @param on_error — called with the exception when `on_batch` raises. A round must
|
|
22
21
|
# never wedge the coalescing lock for every future `#enqueue` call — ownership is always released
|
|
23
22
|
# before this fires. Whatever was mid-flight when the round raised is lost; anything enqueued by a
|
|
24
23
|
# concurrent `#enqueue` call after this round's drain but before the rescue stays pending and rides
|
|
@@ -20,10 +20,8 @@ module Rigor
|
|
|
20
20
|
@project_context = project_context
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# @param positions — LSP `
|
|
24
|
-
#
|
|
25
|
-
# @return one `SelectionRange` per
|
|
26
|
-
# position, or nil when the URI / buffer isn't resolvable.
|
|
23
|
+
# @param positions — LSP positions, each `{ line:, character: }` 0-based.
|
|
24
|
+
# @return one `SelectionRange` per position, or nil when the URI / buffer isn't resolvable.
|
|
27
25
|
def provide(uri, positions)
|
|
28
26
|
path, entry = buffer_for(uri)
|
|
29
27
|
return nil if entry.nil?
|
|
@@ -194,7 +194,12 @@ module Rigor
|
|
|
194
194
|
|
|
195
195
|
# `initialized` is a notification — no response body. Nothing is registered here yet: the server handles
|
|
196
196
|
# `workspace/didChangeWatchedFiles` when a client sends it, but does not register for it dynamically.
|
|
197
|
+
#
|
|
198
|
+
# Issue #2231 — the configuration the server started with is audited here, the first point at which the
|
|
199
|
+
# client is listening, so a `.rigor.yml` key that does nothing is named in the editor as `rigor check`
|
|
200
|
+
# names it on STDERR.
|
|
197
201
|
def handle_initialized
|
|
202
|
+
@publisher&.announce_config_warnings
|
|
198
203
|
nil
|
|
199
204
|
end
|
|
200
205
|
|
|
@@ -267,8 +272,7 @@ module Rigor
|
|
|
267
272
|
|
|
268
273
|
# textDocument/hover REQUEST. Slice 5 returns either a `Hover` payload (markdown contents wrapping type
|
|
269
274
|
# + erased-RBS info) or nil when no expression is at the queried position. Nil maps to `result: null`
|
|
270
|
-
# per LSP spec; clients suppress the popup. Returns `MethodNotFound` when no hover_provider is wired
|
|
271
|
-
# (slice 1-4 behaviour).
|
|
275
|
+
# per LSP spec; clients suppress the popup. Returns `MethodNotFound` when no hover_provider is wired.
|
|
272
276
|
def handle_hover(params)
|
|
273
277
|
return method_not_found("textDocument/hover") unless @hover_provider
|
|
274
278
|
|
|
@@ -351,7 +355,7 @@ module Rigor
|
|
|
351
355
|
)
|
|
352
356
|
end
|
|
353
357
|
|
|
354
|
-
# textDocument/documentSymbol REQUEST. Returns the
|
|
358
|
+
# textDocument/documentSymbol REQUEST. Returns the document-symbol outline for the buffer at the
|
|
355
359
|
# requested URI. Returns `MethodNotFound` when no provider is wired.
|
|
356
360
|
def handle_document_symbol(params)
|
|
357
361
|
return method_not_found("textDocument/documentSymbol") unless @document_symbol_provider
|
|
@@ -25,7 +25,7 @@ module Rigor
|
|
|
25
25
|
# parses the buffer, locates the enclosing `CallNode`, infers the receiver's type, and returns the
|
|
26
26
|
# method's first overload as a `SignatureInformation`.
|
|
27
27
|
#
|
|
28
|
-
# Slice C1
|
|
28
|
+
# Slice C1 ships:
|
|
29
29
|
# - Sentinel patching for `obj.foo(|` so Prism's parse succeeds (mirrors `CompletionProvider`'s slice B4
|
|
30
30
|
# pattern).
|
|
31
31
|
# - First-overload signature only.
|
|
@@ -111,7 +111,7 @@ module Rigor
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def build_signature(call_node, root, path, bytes, line, character)
|
|
114
|
-
scope_index = build_scope_index(root, path)
|
|
114
|
+
scope_index = build_scope_index(root, path, bytes)
|
|
115
115
|
receiver_node = call_node.receiver
|
|
116
116
|
return nil if receiver_node.nil?
|
|
117
117
|
|
|
@@ -197,8 +197,8 @@ module Rigor
|
|
|
197
197
|
end
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
-
def build_scope_index(root,
|
|
201
|
-
scope =
|
|
200
|
+
def build_scope_index(root, path, bytes)
|
|
201
|
+
scope = @project_context.seeded_scope_for(path: path, bytes: bytes)
|
|
202
202
|
Inference::ScopeIndexer.index(root, default_scope: scope)
|
|
203
203
|
end
|
|
204
204
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../environment/member_consistency"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Lens
|
|
7
|
+
class Claims
|
|
8
|
+
# The deliberately small proof fragment of lens-claims.md. Unknown is not a failed subtype check.
|
|
9
|
+
class Comparison
|
|
10
|
+
def initialize(loader, relative_conflict:)
|
|
11
|
+
@loader = loader
|
|
12
|
+
@proof = Environment::MemberConsistency::RbsProof.new(loader)
|
|
13
|
+
@relative_conflict = relative_conflict
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def call(sub, sup)
|
|
17
|
+
included = sub.map do |arm|
|
|
18
|
+
match = sup.filter_map do |other|
|
|
19
|
+
(rule = inclusion(arm, other)) && evidence(rule, arm, other.display)
|
|
20
|
+
end.first
|
|
21
|
+
match
|
|
22
|
+
end
|
|
23
|
+
return ["compatible", "proven_inclusion", included] if included.none?(nil)
|
|
24
|
+
|
|
25
|
+
sub.each do |arm|
|
|
26
|
+
rules = sup.map { |other| disjoint(arm, other) }
|
|
27
|
+
next if rules.any?(nil)
|
|
28
|
+
|
|
29
|
+
return ["conflict", "proven_disjoint_arm", [evidence(rules.first, arm, sup.map(&:display).join(" | "))]]
|
|
30
|
+
end
|
|
31
|
+
["unknown", "unproven", []]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def evidence(rule, arm, against)
|
|
37
|
+
{ "rule" => rule, "arm" => arm.display, "against" => against }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def inclusion(sub, sup)
|
|
41
|
+
return "equal" if sub.identity == sup.identity
|
|
42
|
+
return nil unless sup.kind == :class && sup.arguments.empty?
|
|
43
|
+
return nil unless @loader.class_type_param_names(sup.value).empty?
|
|
44
|
+
|
|
45
|
+
name = sub.kind == :literal ? sub.value.class.name : sub.value
|
|
46
|
+
unreliable = Environment::MemberConsistency::RbsProof::UNRELIABLE_ANCESTRY
|
|
47
|
+
return nil if unreliable.include?(name) || unreliable.include?(sup.value)
|
|
48
|
+
return nil unless @loader.ancestor_names_for(name).include?(sup.value)
|
|
49
|
+
|
|
50
|
+
sub.kind == :literal ? "literal_class_ancestor" : "class_ancestor"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def disjoint(left, right)
|
|
54
|
+
return nil if !@relative_conflict && (left.relative || right.relative)
|
|
55
|
+
return "distinct_literals" if left.kind == :literal && right.kind == :literal && !left.value.eql?(right.value)
|
|
56
|
+
|
|
57
|
+
disjoint_classes(left, right)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def disjoint_classes(left, right)
|
|
61
|
+
left_name = left.kind == :literal ? left.value.class.name : left.value
|
|
62
|
+
right_name = right.kind == :literal ? right.value.class.name : right.value
|
|
63
|
+
left_ancestors = @proof.class_ancestors(left_name)
|
|
64
|
+
right_ancestors = @proof.class_ancestors(right_name)
|
|
65
|
+
return nil if left_ancestors.nil? || right_ancestors.nil?
|
|
66
|
+
|
|
67
|
+
if left.kind == :literal
|
|
68
|
+
"literal_outside_class" unless left_ancestors.include?(right_name)
|
|
69
|
+
elsif right.kind == :literal
|
|
70
|
+
"literal_outside_class" unless right_ancestors.include?(left_name)
|
|
71
|
+
elsif !left_ancestors.include?(right_name) && !right_ancestors.include?(left_name)
|
|
72
|
+
"unrelated_classes"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Lens
|
|
7
|
+
class Claims
|
|
8
|
+
class IntegrityError < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Validates transport and source identity before the incremental session is started.
|
|
11
|
+
class Request
|
|
12
|
+
attr_reader :claims, :digest, :paths
|
|
13
|
+
|
|
14
|
+
def self.read(path, root:, arguments:)
|
|
15
|
+
bytes = File.binread(path).force_encoding(Encoding::UTF_8)
|
|
16
|
+
raise IntegrityError, "claims request is not UTF-8" unless bytes.valid_encoding?
|
|
17
|
+
|
|
18
|
+
new(JSON.parse(bytes), digest: Lens.digest(bytes), root: root, arguments: arguments)
|
|
19
|
+
rescue SystemCallError, JSON::ParserError => e
|
|
20
|
+
raise IntegrityError, "cannot read claims request: #{e.message}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize(data, digest:, root:, arguments:)
|
|
24
|
+
@digest = digest
|
|
25
|
+
@root = root
|
|
26
|
+
@arguments = arguments.map { |argument| File.expand_path(argument, root) }
|
|
27
|
+
validate_header(data)
|
|
28
|
+
@claims = data.fetch("claims")
|
|
29
|
+
@files = data.fetch("files")
|
|
30
|
+
@paths = {}
|
|
31
|
+
@readable_paths = Set.new
|
|
32
|
+
@preflight = true
|
|
33
|
+
@files.each { |file| validate_file(file) }
|
|
34
|
+
ids = []
|
|
35
|
+
@claims.each do |claim|
|
|
36
|
+
validate_claim(claim)
|
|
37
|
+
ids << claim.fetch("id")
|
|
38
|
+
end
|
|
39
|
+
require_value(ids.uniq.size == ids.size, "duplicate claim id")
|
|
40
|
+
verify_sources!
|
|
41
|
+
@preflight = false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def verify_sources!(targets = [])
|
|
45
|
+
@files.each do |file|
|
|
46
|
+
absolute = @paths.fetch(file.fetch("path"))
|
|
47
|
+
bytes = readable(absolute)
|
|
48
|
+
target = targets.find { |entry| entry.absolute == absolute }
|
|
49
|
+
require_value(bytes || (!@readable_paths.include?(absolute) && !target&.reader),
|
|
50
|
+
"source became unreadable during analysis: #{file['path']}")
|
|
51
|
+
@readable_paths << absolute if @preflight && bytes
|
|
52
|
+
next unless bytes
|
|
53
|
+
|
|
54
|
+
require_value(Lens.digest(bytes) == file.fetch("digest"), "stale claims digest: #{file['path']}")
|
|
55
|
+
if target&.reader
|
|
56
|
+
require_value(target.reader.digest == file.fetch("digest"),
|
|
57
|
+
"source changed during analysis: #{file['path']}")
|
|
58
|
+
end
|
|
59
|
+
verify_spans(file, bytes.bytesize)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def verify_spans(file, size)
|
|
66
|
+
@claims.select { |claim| claim.fetch("file") == file.fetch("path") }.each do |claim|
|
|
67
|
+
%w[declaration tag].each do |field|
|
|
68
|
+
require_value(claim.fetch(field).fetch("span").fetch("end_offset") <= size,
|
|
69
|
+
"#{field} span outside #{file['path']}")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def validate_header(data)
|
|
75
|
+
require_value(data.is_a?(Hash), "claims request must be an object")
|
|
76
|
+
require_value(data["schema"] == "lens-claims-request/v0", "unsupported claims schema")
|
|
77
|
+
require_value(data["revision"].is_a?(Integer) && data["revision"] == 1, "unsupported claims revision")
|
|
78
|
+
require_value(data["grammar"] == "rbs", "unsupported claims grammar")
|
|
79
|
+
%w[files claims].each { |field| require_value(data[field].is_a?(Array), "#{field} must be an array") }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def validate_file(file)
|
|
83
|
+
strings(file, %w[path digest])
|
|
84
|
+
path = file.fetch("path")
|
|
85
|
+
absolute = File.expand_path(path, @root)
|
|
86
|
+
relative = Pathname(absolute).relative_path_from(Pathname(@root)).to_s
|
|
87
|
+
require_value(path == relative, "file path must be root-relative: #{path}")
|
|
88
|
+
require_value(@arguments.include?(absolute), "claims file is not a target: #{path}")
|
|
89
|
+
require_value(!@paths.key?(path), "duplicate claims file: #{path}")
|
|
90
|
+
require_value(file.fetch("digest").match?(/\Axxh3-64:[0-9a-f]{16}\z/), "invalid claims file digest")
|
|
91
|
+
@paths[path] = absolute
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def validate_claim(claim)
|
|
95
|
+
strings(claim, %w[id file claim])
|
|
96
|
+
require_value(@paths.key?(claim.fetch("file")), "claim file is missing from files")
|
|
97
|
+
declaration = claim["declaration"]
|
|
98
|
+
strings(declaration, %w[kind owner scope name])
|
|
99
|
+
tag = claim["tag"]
|
|
100
|
+
strings(tag, %w[name])
|
|
101
|
+
require_value(tag.key?("subject") && (tag["subject"].nil? || tag["subject"].is_a?(String)),
|
|
102
|
+
"tag subject must be a string or null")
|
|
103
|
+
[declaration, tag].each { |entry| validate_span(entry["span"]) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validate_span(span)
|
|
107
|
+
require_value(span.is_a?(Hash), "span must be an object")
|
|
108
|
+
start = span["start_offset"]
|
|
109
|
+
finish = span["end_offset"]
|
|
110
|
+
require_value(start.is_a?(Integer) && finish.is_a?(Integer) && start >= 0 && finish >= start,
|
|
111
|
+
"invalid byte span")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def strings(object, fields)
|
|
115
|
+
require_value(object.is_a?(Hash), "claims entry must be an object")
|
|
116
|
+
fields.each { |field| require_value(object[field].is_a?(String), "#{field} must be a string") }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def require_value(condition, message)
|
|
120
|
+
raise IntegrityError, message unless condition
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def readable(path)
|
|
124
|
+
File.binread(path) if File.file?(path)
|
|
125
|
+
rescue SystemCallError
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|