rigortype 0.3.8 → 0.4.0
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 +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- 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 +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- 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 +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -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 +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- 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/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- 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/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- 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 +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -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 +3 -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 +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- 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 +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- 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 +112 -14
- 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 +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- 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 +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- 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 +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -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 +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -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 +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- 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 +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -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/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- 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 +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- 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 +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- 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 +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- 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/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -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/match_data_folding.rb +159 -0
- 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 +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- 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/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- 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 +5 -6
- 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 +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- 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 +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -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/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- 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 +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- 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 +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- 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/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- 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 +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- 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 +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- 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 +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- 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 +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- 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/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- 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 +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -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/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- 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 +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- 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 +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -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/lib/rigor.rb +1 -0
- 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/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- 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 +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -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/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -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 +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- 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 +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- 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 +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -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 +2 -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/types.rb +1 -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-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- 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 +2 -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 +12 -7
- 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 +36 -37
- 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 +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -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 +10 -17
- 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/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- 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 +2 -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 +10 -5
- 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 +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
|
|
5
|
+
require_relative "../configuration"
|
|
6
|
+
require_relative "../rbs_extended"
|
|
7
|
+
|
|
8
|
+
module Rigor
|
|
9
|
+
module SigGen
|
|
10
|
+
# The methods the inline reader declares for each analysed file (ADR-112 WD4): what `# @rbs` / `#:` in a
|
|
11
|
+
# `.rb` file says, member by member, as `rigor sig-gen` needs it to copy that declaration into `sig/`.
|
|
12
|
+
#
|
|
13
|
+
# Read from the RBS the `rigor-rbs-inline` synthesizer contributed (`RbsLoader#virtual_rbs`), not from the
|
|
14
|
+
# built environment. The environment is the wrong witness twice over: once `sig/` declares a member, the
|
|
15
|
+
# loader stands one of the two down before the build (ADR-112 WD5), so the declaration a stale `sig/` copy
|
|
16
|
+
# should be compared against may no longer be there to read; and a member's origin is only recoverable off
|
|
17
|
+
# its location, which the ADR-54 environment cache does not keep. The synthesized text is the loader's input,
|
|
18
|
+
# identical on every run.
|
|
19
|
+
#
|
|
20
|
+
# A member the synthesizer marks `rigor:v1:inferred-signature` is in the text only because rbs-inline
|
|
21
|
+
# declares every `def` of a file it reads: the author annotated nothing on it, so it is present here
|
|
22
|
+
# ({#lookup} finds it, which is what `sig_gen.inline_declared: skip` needs) but not {Member#declared?}.
|
|
23
|
+
class InlineDeclarations
|
|
24
|
+
# One inline-declared method.
|
|
25
|
+
#
|
|
26
|
+
# - `method_types` — the declared overloads (`RBS::MethodType`, names as written, unresolved).
|
|
27
|
+
# - `annotations` — the annotation strings the author wrote on the member (`deprecated` for
|
|
28
|
+
# `%a{deprecated}`), without the synthesizer's own `rigor:v1:inferred-*` markers.
|
|
29
|
+
# - `return_inferred` — the author declared the parameters and not the return: rbs-inline defaulted it,
|
|
30
|
+
# and the synthesizer marked it `rigor:v1:inferred-return`.
|
|
31
|
+
# - `signature_inferred` — every type slot defaulted; the author said nothing about this member.
|
|
32
|
+
# - `attr_line` — for an attribute, the member in RBS's own `attr_*` spelling (`attr_reader name: String`),
|
|
33
|
+
# which is what replaces an `attr_*` declaration in `sig/` under `--overwrite`; nil for a `def`.
|
|
34
|
+
Member = Data.define(:method_types, :annotations, :return_inferred, :signature_inferred, :attr_line) do
|
|
35
|
+
def declared?
|
|
36
|
+
!signature_inferred
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The member's annotations as RBS lines, each in a delimiter its content does not close.
|
|
40
|
+
def annotation_lines
|
|
41
|
+
annotations.filter_map { |string| InlineDeclarations.annotation_line(string) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The synthesizer channel this index reads; another plugin's virtual RBS is not an inline declaration.
|
|
46
|
+
SYNTHESIZER_ID = Configuration::AUTOWIRED_RBS_INLINE_ID
|
|
47
|
+
private_constant :SYNTHESIZER_ID
|
|
48
|
+
|
|
49
|
+
MARKERS = [RbsExtended::INFERRED_RETURN_DIRECTIVE, RbsExtended::INFERRED_SIGNATURE_DIRECTIVE].freeze
|
|
50
|
+
private_constant :MARKERS
|
|
51
|
+
|
|
52
|
+
# rbs lexes `%a` with each of these pairs, up to the first matching closer and with no escape
|
|
53
|
+
# (`rbs/src/lexer.re`), so an annotation is spelled in the first pair its content does not close.
|
|
54
|
+
ANNOTATION_DELIMITERS = Ractor.make_shareable([%w[{ }], %w[( )], %w[[ ]], %w[< >], %w[| |]])
|
|
55
|
+
private_constant :ANNOTATION_DELIMITERS
|
|
56
|
+
|
|
57
|
+
def self.annotation_line(string)
|
|
58
|
+
pair = ANNOTATION_DELIMITERS.find { |_open, close| !string.include?(close) }
|
|
59
|
+
pair && "%a#{pair[0]}#{string}#{pair[1]}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Fail-soft: an environment with no loader, or a loader this index cannot read, declares nothing inline,
|
|
63
|
+
# which is the answer for a project without the plugin.
|
|
64
|
+
def self.build(environment)
|
|
65
|
+
loader = environment&.rbs_loader
|
|
66
|
+
new(loader.respond_to?(:virtual_rbs) ? loader.virtual_rbs : [])
|
|
67
|
+
rescue StandardError
|
|
68
|
+
new([])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def initialize(virtual_rbs)
|
|
72
|
+
@by_path = {}
|
|
73
|
+
@generic_classes = {}
|
|
74
|
+
virtual_rbs.each do |name, content|
|
|
75
|
+
prefix, plugin_id, path = name.to_s.split(":", 3)
|
|
76
|
+
next unless prefix == "virtual" && plugin_id == SYNTHESIZER_ID && path
|
|
77
|
+
|
|
78
|
+
decls = parse(content.to_s)
|
|
79
|
+
next if decls.nil?
|
|
80
|
+
|
|
81
|
+
table = (@by_path[path] ||= {})
|
|
82
|
+
each_member(decls, []) { |class_name, member| record(table, class_name, member) }
|
|
83
|
+
end
|
|
84
|
+
@by_path.freeze
|
|
85
|
+
@generic_classes.freeze
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# `{ class name => [type parameter names] }` for the classes and modules an inline declaration gives type
|
|
89
|
+
# parameters (`# @rbs generic T`). sig-gen does not write a class's type parameters, and a `sig/` header
|
|
90
|
+
# without them makes rbs reject the class (`GenericParameterMismatchError`), so the generator writes nothing
|
|
91
|
+
# that would open one of these, nor members into a `sig/` declaration that names the parameters otherwise.
|
|
92
|
+
attr_reader :generic_classes
|
|
93
|
+
|
|
94
|
+
# @return the inline declaration of `class_name`'s `method_name` on the `kind` side, declared in the file
|
|
95
|
+
# at `path` — or nil.
|
|
96
|
+
def lookup(path, class_name, method_name, kind)
|
|
97
|
+
@by_path.dig(path.to_s, [class_name, method_name, kind])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def parse(content)
|
|
103
|
+
return nil if content.empty? || !content.valid_encoding?
|
|
104
|
+
|
|
105
|
+
_buffer, _directives, decls = ::RBS::Parser.parse_signature(content)
|
|
106
|
+
decls
|
|
107
|
+
rescue ::RBS::BaseError
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def each_member(decls, prefix, &block)
|
|
112
|
+
decls.each do |decl|
|
|
113
|
+
next unless decl.is_a?(::RBS::AST::Declarations::Class) || decl.is_a?(::RBS::AST::Declarations::Module)
|
|
114
|
+
|
|
115
|
+
inner = prefix + [decl.name.to_s.delete_prefix("::")]
|
|
116
|
+
@generic_classes[inner.join("::")] ||= decl.type_params.map(&:name) unless decl.type_params.empty?
|
|
117
|
+
decl.members.each { |member| block.call(inner.join("::"), member) }
|
|
118
|
+
each_member(decl.members, inner, &block)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def record(table, class_name, member)
|
|
123
|
+
method_entries(member).each do |method_name, kind, method_types|
|
|
124
|
+
table[[class_name, method_name, kind]] ||= build_member(member, method_types)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# `[method_name, kind, method_types]` per method a member defines, mirroring what the RBS definition
|
|
129
|
+
# builder files it under: an attribute is its reader and / or writer, `def self?.x` is both sides. An
|
|
130
|
+
# `overloading?` member (`def x: ... | ...`) composes with another declaration rather than being one,
|
|
131
|
+
# and an alias declares no signature of its own, so neither is recorded.
|
|
132
|
+
def method_entries(member)
|
|
133
|
+
case member
|
|
134
|
+
when ::RBS::AST::Members::MethodDefinition then definition_entries(member)
|
|
135
|
+
when ::RBS::AST::Members::AttrReader then [reader_entry(member)]
|
|
136
|
+
when ::RBS::AST::Members::AttrWriter then [writer_entry(member)]
|
|
137
|
+
when ::RBS::AST::Members::AttrAccessor then [reader_entry(member), writer_entry(member)]
|
|
138
|
+
else []
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def definition_entries(member)
|
|
143
|
+
return [] if member.overloading?
|
|
144
|
+
|
|
145
|
+
types = member.overloads.map(&:method_type)
|
|
146
|
+
kinds = member.kind == :singleton_instance ? %i[instance singleton] : [member.kind]
|
|
147
|
+
kinds.map { |kind| [member.name, kind, types] }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def reader_entry(member)
|
|
151
|
+
[member.name, member.kind, [::RBS::Parser.parse_method_type("() -> #{member.type}")]]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def writer_entry(member)
|
|
155
|
+
[:"#{member.name}=", member.kind, [::RBS::Parser.parse_method_type("(#{member.type}) -> #{member.type}")]]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
ATTR_KEYWORDS = {
|
|
159
|
+
::RBS::AST::Members::AttrReader => "attr_reader",
|
|
160
|
+
::RBS::AST::Members::AttrWriter => "attr_writer",
|
|
161
|
+
::RBS::AST::Members::AttrAccessor => "attr_accessor"
|
|
162
|
+
}.freeze
|
|
163
|
+
private_constant :ATTR_KEYWORDS
|
|
164
|
+
|
|
165
|
+
def attr_line(member)
|
|
166
|
+
keyword = ATTR_KEYWORDS[member.class]
|
|
167
|
+
return nil if keyword.nil?
|
|
168
|
+
|
|
169
|
+
"#{keyword} #{'self.' if member.kind == :singleton}#{member.name}: #{member.type}"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def build_member(member, method_types)
|
|
173
|
+
strings = member.annotations.map { |annotation| annotation.string.to_s.strip }
|
|
174
|
+
Member.new(
|
|
175
|
+
method_types: method_types.freeze,
|
|
176
|
+
annotations: (strings - MARKERS).freeze,
|
|
177
|
+
return_inferred: strings.include?(RbsExtended::INFERRED_RETURN_DIRECTIVE),
|
|
178
|
+
signature_inferred: strings.include?(RbsExtended::INFERRED_SIGNATURE_DIRECTIVE),
|
|
179
|
+
attr_line: attr_line(member)
|
|
180
|
+
)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -21,20 +21,19 @@ module Rigor
|
|
|
21
21
|
# in multiple files for additive member contributions, but the writer only needs one canonical target per
|
|
22
22
|
# class.
|
|
23
23
|
class LayoutIndex
|
|
24
|
-
# @param signature_paths
|
|
24
|
+
# @param signature_paths —
|
|
25
25
|
# the `.rigor.yml`-configured signature directories.
|
|
26
26
|
# When `nil` or empty, falls back to `<project_root>/sig`
|
|
27
27
|
# if it exists (matching `Environment.for_project`'s
|
|
28
28
|
# auto-detection convention).
|
|
29
|
-
# @param project_root [String, Pathname]
|
|
30
29
|
def initialize(signature_paths:, project_root: Dir.pwd)
|
|
31
30
|
@signature_paths = resolve_paths(signature_paths, project_root)
|
|
32
31
|
@index = nil
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
# @param class_name
|
|
34
|
+
# @param class_name — fully-qualified Ruby class
|
|
36
35
|
# name (e.g. `"Rigor::Type::Top"`).
|
|
37
|
-
# @return
|
|
36
|
+
# @return absolute path of the sig file
|
|
38
37
|
# that already declares this class, or `nil` when no
|
|
39
38
|
# existing declaration is found.
|
|
40
39
|
def file_for(class_name)
|
|
@@ -29,11 +29,9 @@ module Rigor
|
|
|
29
29
|
|
|
30
30
|
module_function
|
|
31
31
|
|
|
32
|
-
# @param
|
|
33
|
-
# @param
|
|
34
|
-
# @param
|
|
35
|
-
# @param keyword_init [Boolean] the `Struct.new(..., keyword_init: true)` flag; ignored for `:data`.
|
|
36
|
-
# @return [Shape]
|
|
32
|
+
# @param members — ordered member names from the ADR-48 layout.
|
|
33
|
+
# @param member_types — erased RBS spellings; a member with no entry renders `untyped`.
|
|
34
|
+
# @param keyword_init — the `Struct.new(..., keyword_init: true)` flag; ignored for `:data`.
|
|
37
35
|
def of(kind:, members:, member_types: {}, keyword_init: false)
|
|
38
36
|
types = members.to_h { |member| [member, member_types[member] || "untyped"] }
|
|
39
37
|
accessors = kind == :struct ? struct_accessors(members, types) : readers(members, types)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "classification"
|
|
4
|
+
require_relative "effect_annotation"
|
|
5
|
+
|
|
3
6
|
module Rigor
|
|
4
7
|
module SigGen
|
|
5
8
|
# Per-method record produced by the generator.
|
|
@@ -15,17 +18,28 @@ module Rigor
|
|
|
15
18
|
# - `inferred_return` — `Rigor::Type` instance (or `nil` when the inference pass disqualified the def).
|
|
16
19
|
# - `declared_return_rbs` — the existing RBS-declared return spelling, or `nil` when no RBS declares the
|
|
17
20
|
# method.
|
|
21
|
+
# - `declared_rbs` — for an `inline_overwrite`, or a `tighter_return` over the class's own declaration, the
|
|
22
|
+
# whole declared line the proposal replaces, so `--diff` and `--check` can show both; `nil` otherwise.
|
|
23
|
+
# - `declared_annotations` — for a member declared inline, the annotations the author wrote on it
|
|
24
|
+
# (`%a{deprecated}`), rendered above `rbs` like `annotations`. Empty otherwise.
|
|
18
25
|
# - `rbs` — the rendered RBS one-liner the generator would emit (`nil` for skipped / equivalent rows).
|
|
19
26
|
# - `skip_reason` — one of {Classification::SKIP_DIAGNOSTIC_IDS} keys when classification is `:skipped`,
|
|
20
27
|
# else `nil`.
|
|
28
|
+
# - `annotations` — RBS annotation lines to render ABOVE `rbs` (`%a{pure}` /
|
|
29
|
+
# `%a{rigor:v1:effect …}`, ADR-103 WD9). Empty unless the effects opt-in is on and the method's
|
|
30
|
+
# summary earned one; see {EffectAnnotation}.
|
|
31
|
+
# - `effect_reason` — one of {EffectAnnotation::DIAGNOSTIC_IDS} keys saying why `annotations` is what
|
|
32
|
+
# it is, or `nil` when the run had nothing to say about this method's effects.
|
|
21
33
|
class MethodCandidate
|
|
22
34
|
attr_reader :path, :class_name, :method_name, :kind, :classification,
|
|
23
35
|
:inferred_return, :declared_return_rbs, :rbs, :skip_reason,
|
|
24
|
-
:namespace_kinds, :class_shells, :class_superclasses
|
|
36
|
+
:namespace_kinds, :class_shells, :class_superclasses,
|
|
37
|
+
:annotations, :effect_reason, :declared_rbs, :declared_annotations
|
|
25
38
|
|
|
26
39
|
def initialize(path:, class_name:, method_name:, kind:, classification:, # rubocop:disable Metrics/ParameterLists
|
|
27
40
|
inferred_return: nil, declared_return_rbs: nil, rbs: nil, skip_reason: nil,
|
|
28
|
-
namespace_kinds: {}, class_shells: [], class_superclasses: {}
|
|
41
|
+
namespace_kinds: {}, class_shells: [], class_superclasses: {},
|
|
42
|
+
annotations: [], effect_reason: nil, declared_rbs: nil, declared_annotations: [])
|
|
29
43
|
@path = path
|
|
30
44
|
@class_name = class_name
|
|
31
45
|
@method_name = method_name
|
|
@@ -41,9 +55,32 @@ module Rigor
|
|
|
41
55
|
# superclasses appear; computed ones are absent. The Writer emits `class Bar < Base` for the leaf when
|
|
42
56
|
# present.
|
|
43
57
|
@class_superclasses = class_superclasses.freeze
|
|
58
|
+
@annotations = annotations.freeze
|
|
59
|
+
@effect_reason = effect_reason
|
|
60
|
+
@declared_rbs = declared_rbs
|
|
61
|
+
@declared_annotations = declared_annotations.freeze
|
|
44
62
|
freeze
|
|
45
63
|
end
|
|
46
64
|
|
|
65
|
+
# Every line this candidate contributes to a declaration body, annotations first. The single place
|
|
66
|
+
# the renderer and the writer agree that an annotation precedes the `def` line it binds.
|
|
67
|
+
def rbs_lines
|
|
68
|
+
@declared_annotations + @annotations + [@rbs].compact
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# A copy carrying a different annotation decision. The generator's effect pass rebuilds rather than
|
|
72
|
+
# mutates, because a candidate is frozen the moment it is built.
|
|
73
|
+
def with_effect_annotation(annotations, reason)
|
|
74
|
+
self.class.new(
|
|
75
|
+
path: @path, class_name: @class_name, method_name: @method_name, kind: @kind,
|
|
76
|
+
classification: @classification, inferred_return: @inferred_return,
|
|
77
|
+
declared_return_rbs: @declared_return_rbs, rbs: @rbs, skip_reason: @skip_reason,
|
|
78
|
+
namespace_kinds: @namespace_kinds, class_shells: @class_shells,
|
|
79
|
+
class_superclasses: @class_superclasses, annotations: annotations, effect_reason: reason,
|
|
80
|
+
declared_rbs: @declared_rbs, declared_annotations: @declared_annotations
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
47
84
|
def to_h
|
|
48
85
|
{
|
|
49
86
|
file: path,
|
|
@@ -54,7 +91,14 @@ module Rigor
|
|
|
54
91
|
rbs: rbs,
|
|
55
92
|
inferred_return: inferred_return&.erase_to_rbs,
|
|
56
93
|
declared_return_rbs: declared_return_rbs,
|
|
57
|
-
|
|
94
|
+
declared_rbs: declared_rbs,
|
|
95
|
+
declared_annotations: declared_annotations.empty? ? nil : declared_annotations,
|
|
96
|
+
skip_reason: skip_reason ? Classification::SKIP_DIAGNOSTIC_IDS.fetch(skip_reason) : nil,
|
|
97
|
+
# Named fields rather than a merge into `rbs`: a consumer routing on the annotation has to be
|
|
98
|
+
# able to find it without re-lexing the rendered line. Both are absent (not empty / null) when
|
|
99
|
+
# the run had no effect answer, so an effects-off payload is byte-identical to a pre-#391 one.
|
|
100
|
+
effect_annotations: annotations.empty? ? nil : annotations,
|
|
101
|
+
effect_reason: effect_reason ? EffectAnnotation::DIAGNOSTIC_IDS.fetch(effect_reason) : nil
|
|
58
102
|
}.compact
|
|
59
103
|
end
|
|
60
104
|
end
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
|
|
5
5
|
require_relative "../environment"
|
|
6
|
+
require_relative "../project_environment"
|
|
6
7
|
require_relative "../scope"
|
|
7
8
|
require_relative "../type"
|
|
9
|
+
require_relative "../source/constant_path"
|
|
8
10
|
require_relative "../source/literals"
|
|
9
11
|
require_relative "../source/node_children"
|
|
10
12
|
require_relative "../inference/scope_indexer"
|
|
@@ -13,12 +15,12 @@ module Rigor
|
|
|
13
15
|
module SigGen
|
|
14
16
|
# ADR-14 slice 3 — caller-side argument-type observation collector.
|
|
15
17
|
#
|
|
16
|
-
# Walks the
|
|
18
|
+
# Walks the `--observe=PATH...` tree (default: the project's test roots), parses every `.rb` file with `Prism`,
|
|
17
19
|
# scope- indexes it the same way the main generator does, and records the per-call-site argument-type tuples
|
|
18
20
|
# for every `Prism::CallNode` whose receiver types as a `Type::Nominal`. The {Generator} consumes the
|
|
19
21
|
# resulting map to render `--params=observed` RBS:
|
|
20
22
|
#
|
|
21
|
-
# @return
|
|
23
|
+
# @return => Array<Array<Rigor::Type>>}]
|
|
22
24
|
#
|
|
23
25
|
# ADR-5 clause 2 compliance: the observed union is the MOST PERMISSIVE parameter contract the existing
|
|
24
26
|
# callers prove sufficient — by construction it accepts every type any caller has already passed. The
|
|
@@ -32,10 +34,9 @@ module Rigor
|
|
|
32
34
|
# the collector cannot attribute them to a specific class.
|
|
33
35
|
# - Zero-argument calls give no observation; methods are matched by `(class_name, method_name)` only.
|
|
34
36
|
class ObservationCollector # rubocop:disable Metrics/ClassLength
|
|
35
|
-
# @param
|
|
36
|
-
# @param paths [Array<String>] observe paths (files /
|
|
37
|
+
# @param paths — observe paths (files /
|
|
37
38
|
# directories).
|
|
38
|
-
# @param source_paths
|
|
39
|
+
# @param source_paths — source-tree paths
|
|
39
40
|
# (defaults to `configuration.paths`) pre-walked to
|
|
40
41
|
# register every project-defined class so that calls
|
|
41
42
|
# like `Foo.new.bar(x)` in the observe tree resolve
|
|
@@ -51,10 +52,11 @@ module Rigor
|
|
|
51
52
|
def collect
|
|
52
53
|
return {} if @paths.empty?
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
resolved = resolve_paths(@paths)
|
|
56
|
+
environment = build_environment(resolved)
|
|
55
57
|
discovered_classes = preindex_source_classes
|
|
56
58
|
observations = Hash.new { |h, k| h[k] = [] }
|
|
57
|
-
|
|
59
|
+
resolved.each do |path|
|
|
58
60
|
collect_from_file(path, environment, discovered_classes, observations)
|
|
59
61
|
end
|
|
60
62
|
observations.transform_values(&:freeze).freeze
|
|
@@ -62,11 +64,11 @@ module Rigor
|
|
|
62
64
|
|
|
63
65
|
private
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
67
|
+
# Issue #821 — same universe as the generator and as `rigor check`; see
|
|
68
|
+
# {Generator#build_environment}. An observation collected against a narrower environment types its
|
|
69
|
+
# argument differently from the run that will consume it.
|
|
70
|
+
def build_environment(source_files = [])
|
|
71
|
+
ProjectEnvironment.build(configuration: @configuration, source_files: source_files)
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
def resolve_paths(args)
|
|
@@ -118,11 +120,11 @@ module Rigor
|
|
|
118
120
|
return unless node.is_a?(Prism::Node)
|
|
119
121
|
|
|
120
122
|
if node.is_a?(Prism::ClassNode) || node.is_a?(Prism::ModuleNode)
|
|
121
|
-
|
|
122
|
-
if
|
|
123
|
-
full =
|
|
123
|
+
child_prefix = Source::ConstantPath.declaration_prefix(prefix, node.constant_path)
|
|
124
|
+
if child_prefix
|
|
125
|
+
full = child_prefix.join("::")
|
|
124
126
|
accumulator[full] = Type::Combinator.singleton_of(full)
|
|
125
|
-
walk_class_decls(node.body,
|
|
127
|
+
walk_class_decls(node.body, child_prefix, accumulator) if node.body
|
|
126
128
|
return
|
|
127
129
|
end
|
|
128
130
|
end
|
|
@@ -21,9 +21,8 @@ module Rigor
|
|
|
21
21
|
# When the source path is not under any configured source root (e.g. files supplied directly on the CLI
|
|
22
22
|
# from outside `lib/`), the full relative path is preserved under the sig root.
|
|
23
23
|
class PathMapper
|
|
24
|
-
# @param
|
|
25
|
-
# @param
|
|
26
|
-
# @param layout_index [LayoutIndex, nil] optional class
|
|
24
|
+
# @param project_root — (defaults to `Dir.pwd`)
|
|
25
|
+
# @param layout_index — optional class
|
|
27
26
|
# → existing sig file index; routes the target to the
|
|
28
27
|
# consolidated file when the class is already declared.
|
|
29
28
|
def initialize(configuration:, project_root: Dir.pwd, layout_index: nil)
|
|
@@ -32,12 +31,11 @@ module Rigor
|
|
|
32
31
|
@layout_index = layout_index
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
# @param
|
|
36
|
-
# @param class_name [String, nil] fully-qualified Ruby
|
|
34
|
+
# @param class_name — fully-qualified Ruby
|
|
37
35
|
# class name. When supplied and matched by the
|
|
38
36
|
# `LayoutIndex`, the consolidated sig file's path is
|
|
39
37
|
# returned instead of the 1:1 mirror.
|
|
40
|
-
# @return
|
|
38
|
+
# @return absolute path of the target `.rbs`
|
|
41
39
|
# file for the candidate.
|
|
42
40
|
def target_for(source_path, class_name: nil)
|
|
43
41
|
existing = existing_target_for(class_name)
|
|
@@ -23,16 +23,16 @@ module Rigor
|
|
|
23
23
|
|
|
24
24
|
module_function
|
|
25
25
|
|
|
26
|
-
# @param line
|
|
27
|
-
# @return
|
|
26
|
+
# @param line — a rendered RBS method line, e.g. `def self.parse: (String) -> Integer`.
|
|
27
|
+
# @return the parse error's first line, or nil when the line is valid.
|
|
28
28
|
def method_line_error(line)
|
|
29
29
|
return nil if line.nil?
|
|
30
30
|
|
|
31
31
|
source_error("class #{PROBE_CLASS}\n #{line}\nend\n")
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# @param source
|
|
35
|
-
# @return
|
|
34
|
+
# @param source — a complete `.rbs` file's text.
|
|
35
|
+
# @return the parse error's first line, or nil when the file is valid.
|
|
36
36
|
def source_error(source)
|
|
37
37
|
::RBS::Parser.parse_signature(::RBS::Buffer.new(name: "(rigor sig-gen)", content: source))
|
|
38
38
|
nil
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
require_relative "classification"
|
|
6
|
+
require_relative "superclass_spelling"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
module SigGen
|
|
@@ -21,10 +22,8 @@ module Rigor
|
|
|
21
22
|
@out = out
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
# @param
|
|
25
|
-
# @param
|
|
26
|
-
# @param format [String] "text" or "json"
|
|
27
|
-
# @param selection [Array<Symbol>] subset of
|
|
25
|
+
# @param format — "text" or "json"
|
|
26
|
+
# @param selection — subset of
|
|
28
27
|
# {Classification} constants to include; an empty
|
|
29
28
|
# array means "all emittable classifications".
|
|
30
29
|
def render(candidates:, mode:, format:, selection:)
|
|
@@ -75,9 +74,13 @@ module Rigor
|
|
|
75
74
|
when Classification::NEW_FILE then "[new-file]"
|
|
76
75
|
when Classification::TIGHTER_RETURN
|
|
77
76
|
"[tighter, was: #{candidate.declared_return_rbs}]"
|
|
77
|
+
when Classification::INLINE_OVERWRITE
|
|
78
|
+
"[inline-overwrite, was: #{candidate.declared_rbs}]"
|
|
78
79
|
end
|
|
79
80
|
@out.puts(" # #{tag}")
|
|
80
|
-
|
|
81
|
+
# Annotations first: an RBS annotation binds the declaration BELOW it, so `%a{pure}` printed
|
|
82
|
+
# after the `def` line would bind the next member — or nothing at all at the end of a class.
|
|
83
|
+
candidate.rbs_lines.each { |line| @out.puts(" #{line}") }
|
|
81
84
|
end
|
|
82
85
|
@out.puts("end")
|
|
83
86
|
end
|
|
@@ -91,7 +94,7 @@ module Rigor
|
|
|
91
94
|
return "module #{class_name}" if candidate.namespace_kinds[class_name] == :module
|
|
92
95
|
|
|
93
96
|
superclass = candidate.class_superclasses[class_name]
|
|
94
|
-
superclass ? "class #{class_name} < #{superclass}" : "class #{class_name}"
|
|
97
|
+
superclass ? "class #{class_name} < #{SuperclassSpelling.absolute(superclass)}" : "class #{class_name}"
|
|
95
98
|
end
|
|
96
99
|
|
|
97
100
|
def render_diff(candidates)
|
|
@@ -102,13 +105,22 @@ module Rigor
|
|
|
102
105
|
|
|
103
106
|
candidates.each do |candidate|
|
|
104
107
|
@out.puts("--- #{candidate.path}: #{candidate.class_name}##{candidate.method_name}")
|
|
105
|
-
|
|
106
|
-
@out.puts("
|
|
107
|
-
@out.puts("+ #{candidate.rbs}")
|
|
108
|
+
render_removed_line(candidate)
|
|
109
|
+
candidate.rbs_lines.each { |line| @out.puts("+ #{line}") }
|
|
108
110
|
@out.puts
|
|
109
111
|
end
|
|
110
112
|
end
|
|
111
113
|
|
|
114
|
+
# A tighter return or an inline update replaces a whole `sig/` line, which it carries; any other row
|
|
115
|
+
# knows only the declared return.
|
|
116
|
+
def render_removed_line(candidate)
|
|
117
|
+
if candidate.declared_rbs
|
|
118
|
+
@out.puts("- #{candidate.declared_rbs}")
|
|
119
|
+
elsif candidate.declared_return_rbs
|
|
120
|
+
@out.puts("- def #{candidate.method_name}: () -> #{candidate.declared_return_rbs}")
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
112
124
|
def render_json(candidates)
|
|
113
125
|
payload = { candidates: candidates.map(&:to_h) }
|
|
114
126
|
@out.puts(JSON.pretty_generate(payload))
|
|
@@ -118,16 +130,94 @@ module Rigor
|
|
|
118
130
|
|
|
119
131
|
# Renders the per-source-file outcomes of a `--write` run. Distinct from {#render} because the write
|
|
120
132
|
# path's reporting surface is action-oriented (created / updated / skipped) rather than candidate-oriented.
|
|
121
|
-
|
|
133
|
+
# @param refused — methods refused as `sig.skipped.inline-differs`; the JSON payload names them under
|
|
134
|
+
# `refused` (absent when there are none, so an ordinary payload is unchanged), and text mode leaves them
|
|
135
|
+
# to the command's stderr `REFUSED` lines.
|
|
136
|
+
def render_write(results:, format:, refused: [])
|
|
122
137
|
case format
|
|
123
|
-
when "json" then render_write_json(results)
|
|
138
|
+
when "json" then render_write_json(results, refused)
|
|
124
139
|
when "text" then render_write_text(results)
|
|
125
140
|
else raise ArgumentError, "unsupported format: #{format}"
|
|
126
141
|
end
|
|
127
142
|
end
|
|
128
143
|
|
|
144
|
+
# ADR-112 WD4 — `sig-gen --check`: the results of a dry-run `--write`. Only the targets `--write` would
|
|
145
|
+
# change (or refuse) are shown, each with the lines it would add; the verdict is the exit status, which
|
|
146
|
+
# the command derives from the same results ({.out_of_date}).
|
|
147
|
+
#
|
|
148
|
+
# @param refused — the methods the generator refused to reconcile (`sig.skipped.inline-differs`):
|
|
149
|
+
# `sig/` is not up to date while one stands, and `--write` cannot fix it.
|
|
150
|
+
def render_check(results:, format:, refused: [])
|
|
151
|
+
stale = self.class.out_of_date(results)
|
|
152
|
+
case format
|
|
153
|
+
when "json"
|
|
154
|
+
@out.puts(JSON.pretty_generate({ up_to_date: stale.empty? && refused.empty?,
|
|
155
|
+
results: stale.map { |r| check_entry(r) },
|
|
156
|
+
refused: refused.map(&:to_h) }))
|
|
157
|
+
when "text" then render_check_text(stale, refused)
|
|
158
|
+
else raise ArgumentError, "unsupported format: #{format}"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# One line per method sig-gen refused to reconcile with its `sig/` copy. Shared by `--write` (on stderr,
|
|
163
|
+
# next to the write report) and `--check`.
|
|
164
|
+
def self.refusal_lines(refused)
|
|
165
|
+
refused.map do |candidate|
|
|
166
|
+
separator = candidate.kind == :singleton ? "." : "#"
|
|
167
|
+
"REFUSED #{candidate.path}: #{candidate.class_name}#{separator}#{candidate.method_name} — its inline " \
|
|
168
|
+
"declaration and its sig/ declaration disagree, so neither was changed " \
|
|
169
|
+
"(#{Classification::SKIP_DIAGNOSTIC_IDS.fetch(candidate.skip_reason)}). Make them agree, or pass " \
|
|
170
|
+
"--overwrite to replace the sig/ member with the inline declaration; `rigor explain " \
|
|
171
|
+
"#{Classification::SKIP_DIAGNOSTIC_IDS.fetch(candidate.skip_reason)}` says when that is not enough."
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# The results that make a `--check` fail: a target `--write` would create or change, and one it would
|
|
176
|
+
# refuse, since a write that cannot happen is not an up-to-date `sig/` either.
|
|
177
|
+
def self.out_of_date(results)
|
|
178
|
+
results.reject { |result| %i[noop skipped_outside_sig_root].include?(result.action) }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Nothing was written, so the entry must not read like one that was: `created` / `updated` become
|
|
182
|
+
# `would_create` / `would_update`. A refusal keeps its action — `--write` would refuse the same way.
|
|
183
|
+
CHECK_ACTIONS = { created: "would_create", updated: "would_update" }.freeze
|
|
184
|
+
private_constant :CHECK_ACTIONS
|
|
185
|
+
|
|
129
186
|
private
|
|
130
187
|
|
|
188
|
+
def check_entry(result)
|
|
189
|
+
entry = result.to_h
|
|
190
|
+
entry[:action] = CHECK_ACTIONS.fetch(result.action, entry[:action])
|
|
191
|
+
entry
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def render_check_text(stale, refused)
|
|
195
|
+
if stale.empty? && refused.empty?
|
|
196
|
+
@out.puts("sig/ is up to date")
|
|
197
|
+
return
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
self.class.refusal_lines(refused).each { |line| @out.puts(line) }
|
|
201
|
+
|
|
202
|
+
stale.each do |result|
|
|
203
|
+
case result.action
|
|
204
|
+
when :created, :updated then render_check_change(result)
|
|
205
|
+
when :skipped_invalid_rbs then render_write_invalid(result)
|
|
206
|
+
when :skipped_invalid_encoding then render_write_invalid_encoding(result)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def render_check_change(result)
|
|
212
|
+
counts = result.action == :created ? "#{result.applied.size} method(s)" : applied_counts(result)
|
|
213
|
+
verb = result.action == :created ? "would create" : "would update"
|
|
214
|
+
@out.puts("#{verb} #{result.target_path} (#{counts})")
|
|
215
|
+
result.applied.each do |candidate|
|
|
216
|
+
@out.puts(" - #{candidate.declared_rbs}") if candidate.declared_rbs
|
|
217
|
+
candidate.rbs_lines.each { |line| @out.puts(" + #{line}") }
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
131
221
|
def render_write_text(results)
|
|
132
222
|
if results.all? { |r| r.action == :noop }
|
|
133
223
|
@out.puts("No changes")
|
|
@@ -145,13 +235,35 @@ module Rigor
|
|
|
145
235
|
end
|
|
146
236
|
end
|
|
147
237
|
|
|
238
|
+
# `+N` counts added lines; an existing line replaced (`--overwrite`, or an inline update) is counted apart,
|
|
239
|
+
# because "added 2" when one of them rewrote a line the project already had would understate the change.
|
|
240
|
+
def applied_counts(result)
|
|
241
|
+
added = "+#{result.applied.size - result.replaced.size}"
|
|
242
|
+
result.replaced.empty? ? added : "#{added}, replaced #{result.replaced.size}"
|
|
243
|
+
end
|
|
244
|
+
|
|
148
245
|
def render_write_created(result)
|
|
149
246
|
@out.puts("created #{result.target_path} (#{result.applied.size} method(s))")
|
|
150
247
|
end
|
|
151
248
|
|
|
152
249
|
def render_write_updated(result)
|
|
153
|
-
@out.puts("updated #{result.target_path} (
|
|
250
|
+
@out.puts("updated #{result.target_path} (#{applied_counts(result)}, " \
|
|
154
251
|
"skipped #{result.skipped.size} user-authored)")
|
|
252
|
+
render_left_unreadable(result)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# ADR-103 WD9 — the declarations whose annotation region the writer refused to rewrite. Named per
|
|
256
|
+
# method rather than counted: the fix is a human reading one existing annotation and deciding what
|
|
257
|
+
# it should say, and there is no count of those a reader could act on.
|
|
258
|
+
def render_left_unreadable(result)
|
|
259
|
+
return if result.left_unreadable.empty?
|
|
260
|
+
|
|
261
|
+
@out.puts(" left #{result.left_unreadable.size} existing annotation(s) byte-untouched " \
|
|
262
|
+
"(sig.effect.left-unreadable):")
|
|
263
|
+
result.left_unreadable.each do |candidate|
|
|
264
|
+
@out.puts(" #{candidate.class_name}##{candidate.method_name} — " \
|
|
265
|
+
"would have emitted #{candidate.annotations.join(' ')}")
|
|
266
|
+
end
|
|
155
267
|
end
|
|
156
268
|
|
|
157
269
|
def render_write_skipped(result)
|
|
@@ -174,8 +286,10 @@ module Rigor
|
|
|
174
286
|
@out.puts(" Re-save the file as UTF-8 and re-run; sig-gen never modifies a file it cannot read faithfully.")
|
|
175
287
|
end
|
|
176
288
|
|
|
177
|
-
def render_write_json(results)
|
|
178
|
-
|
|
289
|
+
def render_write_json(results, refused)
|
|
290
|
+
payload = { results: results.map(&:to_h) }
|
|
291
|
+
payload[:refused] = refused.map(&:to_h) unless refused.empty?
|
|
292
|
+
@out.puts(JSON.pretty_generate(payload))
|
|
179
293
|
end
|
|
180
294
|
end
|
|
181
295
|
end
|