rigortype 0.2.7 → 0.2.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 +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -4,30 +4,22 @@ require_relative "blueprint"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
|
-
# ADR-52 WD1 — the compiled contribution table. Categorises a loaded
|
|
8
|
-
# plugin
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# top hotspot on plugin-heavy projects (GitLab's 11 plugins, of
|
|
14
|
-
# which only 2 implement any per-call path). Built once per
|
|
15
|
-
# {Registry}.
|
|
7
|
+
# ADR-52 WD1 — the compiled contribution table. Categorises a loaded plugin set by which per-call
|
|
8
|
+
# contribution paths each plugin actually implements, AND compiles the declarative gates (method names,
|
|
9
|
+
# `block_as_methods` method names, `owns_receivers`) into frozen lookup structures, so the engine's hot
|
|
10
|
+
# sites discover "no plugin cares about this call" in O(1) instead of O(plugins × rules) — a top hotspot
|
|
11
|
+
# on plugin-heavy projects (GitLab's 11 plugins, of which only 2 implement any per-call path). Built once
|
|
12
|
+
# per {Registry}.
|
|
16
13
|
#
|
|
17
|
-
# Ordering contract: the gates only PRUNE consultations that could
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# ungated walk produced — diagnostics stay byte-identical. The
|
|
23
|
-
# receiver-class ancestry match for `dynamic_return` still happens
|
|
24
|
-
# per-dispatch inside `Plugin::Base#dynamic_return_type`.
|
|
14
|
+
# Ordering contract: the gates only PRUNE consultations that could not fire (every pruned rule would have
|
|
15
|
+
# failed its own `methods:` / `method_names:` check); the engine still iterates the plugin subsets in
|
|
16
|
+
# registry order and each plugin's rules in declaration order, so the surviving contributions arrive in
|
|
17
|
+
# exactly the order the ungated walk produced — diagnostics stay byte-identical. The receiver-class
|
|
18
|
+
# ancestry match for `dynamic_return` still happens per-dispatch inside `Plugin::Base#dynamic_return_type`.
|
|
25
19
|
class ContributionIndex
|
|
26
|
-
# Ordered (registry-order) subsets relevant to each collector, and
|
|
27
|
-
#
|
|
28
|
-
# `
|
|
29
|
-
# diagnostic loop visits: plugins overriding
|
|
30
|
-
# `#diagnostics_for_file` or declaring at least one `node_rule`.
|
|
20
|
+
# Ordered (registry-order) subsets relevant to each collector, and the membership sets used to gate the
|
|
21
|
+
# paths within a plugin. `for_file_diagnostics` is the subset the runner's per-file diagnostic loop
|
|
22
|
+
# visits: plugins overriding `#diagnostics_for_file` or declaring at least one `node_rule`.
|
|
31
23
|
attr_reader :for_method_dispatch, :for_statement, :for_file_diagnostics
|
|
32
24
|
|
|
33
25
|
EMPTY_BLOCK_ENTRIES = [].freeze
|
|
@@ -38,9 +30,8 @@ module Rigor
|
|
|
38
30
|
compile_gates
|
|
39
31
|
@block_entries_by_method_name = build_block_entries(plugins)
|
|
40
32
|
@owns_receivers = plugins.flat_map { |p| manifest_for(p)&.owns_receivers || [] }.uniq.freeze
|
|
41
|
-
# Per-run ancestry verdict memo, keyed by environment identity
|
|
42
|
-
#
|
|
43
|
-
# because the class graph is fixed for the lifetime of a run.
|
|
33
|
+
# Per-run ancestry verdict memo, keyed by environment identity then class name. Mutable inside the
|
|
34
|
+
# frozen index — sound because the class graph is fixed for the lifetime of a run.
|
|
44
35
|
@owns_receiver_memo = {}.compare_by_identity
|
|
45
36
|
freeze
|
|
46
37
|
end
|
|
@@ -48,30 +39,27 @@ module Rigor
|
|
|
48
39
|
def dynamic?(plugin) = @dynamic.include?(plugin)
|
|
49
40
|
def type_specifier?(plugin) = @type_specifier.include?(plugin)
|
|
50
41
|
|
|
51
|
-
# O(1) "could any plugin contribute a return type for a call named
|
|
52
|
-
# `
|
|
53
|
-
#
|
|
54
|
-
# would have produced zero contributions too.
|
|
42
|
+
# O(1) "could any plugin contribute a return type for a call named `method_name`?" — false only when
|
|
43
|
+
# every `dynamic_return` rule is `methods:`-gated on other names, in which case the ungated walk would
|
|
44
|
+
# have produced zero contributions too.
|
|
55
45
|
def dispatch_candidate?(method_name)
|
|
56
46
|
return true if @dynamic_global_gate.nil?
|
|
57
47
|
|
|
58
48
|
@dynamic_global_gate.include?(method_name)
|
|
59
49
|
end
|
|
60
50
|
|
|
61
|
-
# O(1) statement-path sibling of {#dispatch_candidate?} over the
|
|
62
|
-
#
|
|
51
|
+
# O(1) statement-path sibling of {#dispatch_candidate?} over the `type_specifier` rules (which are
|
|
52
|
+
# always `methods:`-gated).
|
|
63
53
|
def statement_candidate?(method_name)
|
|
64
54
|
return true if @type_specifier_global_gate.nil?
|
|
65
55
|
|
|
66
56
|
@type_specifier_global_gate.include?(method_name)
|
|
67
57
|
end
|
|
68
58
|
|
|
69
|
-
# Per-plugin gate: false when the plugin declares no
|
|
70
|
-
# `
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# rule block. Subsumes the old `dynamic?(plugin)` membership
|
|
74
|
-
# check at the collector's call site.
|
|
59
|
+
# Per-plugin gate: false when the plugin declares no `dynamic_return` rules at all, or when every rule
|
|
60
|
+
# is `methods:`-gated and none lists `method_name` — i.e. when `#dynamic_return_type` would return nil
|
|
61
|
+
# without ever entering a rule block. Subsumes the old `dynamic?(plugin)` membership check at the
|
|
62
|
+
# collector's call site.
|
|
75
63
|
def dynamic_candidate_for?(plugin, method_name)
|
|
76
64
|
return false unless @dynamic.include?(plugin)
|
|
77
65
|
|
|
@@ -79,8 +67,7 @@ module Rigor
|
|
|
79
67
|
gate.nil? || gate.include?(method_name)
|
|
80
68
|
end
|
|
81
69
|
|
|
82
|
-
# Per-plugin gate over `type_specifier` rules; same contract as
|
|
83
|
-
# {#dynamic_candidate_for?}.
|
|
70
|
+
# Per-plugin gate over `type_specifier` rules; same contract as {#dynamic_candidate_for?}.
|
|
84
71
|
def type_specifier_candidate_for?(plugin, method_name)
|
|
85
72
|
return false unless @type_specifier.include?(plugin)
|
|
86
73
|
|
|
@@ -88,18 +75,16 @@ module Rigor
|
|
|
88
75
|
gate.nil? || gate.include?(method_name)
|
|
89
76
|
end
|
|
90
77
|
|
|
91
|
-
# The `Macro::BlockAsMethod` entries whose `method_names` include
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
# entries walk visited.
|
|
78
|
+
# The `Macro::BlockAsMethod` entries whose `method_names` include `method_name`, in (plugin
|
|
79
|
+
# registration, manifest declaration) order — the same first-match order the previous plugins × entries
|
|
80
|
+
# walk visited.
|
|
95
81
|
def block_entries_for(method_name)
|
|
96
82
|
@block_entries_by_method_name.fetch(method_name, EMPTY_BLOCK_ENTRIES)
|
|
97
83
|
end
|
|
98
84
|
|
|
99
|
-
# True when `class_name` equals or inherits from any plugin's
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
# verdicts memoise per environment.
|
|
85
|
+
# True when `class_name` equals or inherits from any plugin's manifest-declared `owns_receivers:` entry.
|
|
86
|
+
# The union is compiled at build time (almost always empty → O(1) false) and per-class verdicts
|
|
87
|
+
# memoise per environment.
|
|
103
88
|
def owns_receiver?(class_name, environment)
|
|
104
89
|
return false if @owns_receivers.empty? || class_name.nil?
|
|
105
90
|
|
|
@@ -135,12 +120,10 @@ module Rigor
|
|
|
135
120
|
@type_specifier_global_gate = union_gate(@type_specifier_gates)
|
|
136
121
|
end
|
|
137
122
|
|
|
138
|
-
# ADR-52 WD3 — the legacy ungated `flow_contribution_for` hook was
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
# instead. (The Base default is gone, so any definer wrote it
|
|
143
|
-
# themselves.)
|
|
123
|
+
# ADR-52 WD3 — the legacy ungated `flow_contribution_for` hook was deleted pre-1.0. A plugin still
|
|
124
|
+
# defining it would silently never be called, which is the worst failure mode for its author — surface
|
|
125
|
+
# a loud load-time error with the migration mapping instead. (The Base default is gone, so any definer
|
|
126
|
+
# wrote it themselves.)
|
|
144
127
|
def reject_legacy_flow_hook!(plugin)
|
|
145
128
|
return unless plugin.respond_to?(:flow_contribution_for)
|
|
146
129
|
|
|
@@ -151,26 +134,23 @@ module Rigor
|
|
|
151
134
|
"facts via `narrowing_facts` — see the CHANGELOG migration note."
|
|
152
135
|
end
|
|
153
136
|
|
|
154
|
-
# Same `Method#owner` trick for the per-file diagnostics hook —
|
|
155
|
-
#
|
|
156
|
-
# skipped without calling it.
|
|
137
|
+
# Same `Method#owner` trick for the per-file diagnostics hook — the Base default returns `[]`, so a
|
|
138
|
+
# non-overriding plugin can be skipped without calling it.
|
|
157
139
|
def file_diagnostics_overridden?(plugin)
|
|
158
140
|
plugin.method(:diagnostics_for_file).owner != Rigor::Plugin::Base
|
|
159
141
|
end
|
|
160
142
|
|
|
161
|
-
# `plugin → Set[Symbol] | nil`. A frozen Set when EVERY rule of
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
# method name, exactly as before).
|
|
143
|
+
# `plugin → Set[Symbol] | nil`. A frozen Set when EVERY rule of the plugin is `methods:`-gated (the
|
|
144
|
+
# union of those names); nil when any rule is ungated (the plugin must be consulted for every method
|
|
145
|
+
# name, exactly as before).
|
|
165
146
|
def build_name_gates(members)
|
|
166
147
|
gates = {}
|
|
167
148
|
members.each do |plugin|
|
|
168
149
|
rules = yield(plugin)
|
|
169
|
-
# A static method-name Array can be compiled into the gate. A
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
# every dispatch and filtered in the instance path.
|
|
150
|
+
# A static method-name Array can be compiled into the gate. A run-time callable `methods:` (ADR-52
|
|
151
|
+
# slice 4) is unknown until after `#prepare`, and a receiver-only rule has no `methods:` — either
|
|
152
|
+
# makes the plugin ungated-by-name (nil), consulted on every dispatch and filtered in the instance
|
|
153
|
+
# path.
|
|
174
154
|
gates[plugin] =
|
|
175
155
|
if rules.all? { |rule| rule[:methods].is_a?(Array) }
|
|
176
156
|
rules.flat_map { |rule| rule[:methods] }.to_set.freeze
|
|
@@ -179,19 +159,17 @@ module Rigor
|
|
|
179
159
|
gates.freeze
|
|
180
160
|
end
|
|
181
161
|
|
|
182
|
-
# The registry-wide union of per-plugin gates, or nil when any
|
|
183
|
-
# plugin
|
|
184
|
-
#
|
|
185
|
-
# `relevant.empty?` early return fires before it is consulted.
|
|
162
|
+
# The registry-wide union of per-plugin gates, or nil when any plugin is ungated (no global pruning
|
|
163
|
+
# possible). An empty plugin set unions to an empty frozen Set — the collectors' `relevant.empty?`
|
|
164
|
+
# early return fires before it is consulted.
|
|
186
165
|
def union_gate(gates)
|
|
187
166
|
return nil if gates.value?(nil)
|
|
188
167
|
|
|
189
168
|
gates.values.reduce(Set.new) { |acc, names| acc.merge(names) }.freeze
|
|
190
169
|
end
|
|
191
170
|
|
|
192
|
-
# `method-name Symbol → [BlockAsMethod entries]`, insertion-ordered
|
|
193
|
-
#
|
|
194
|
-
# `Macro::BlockAsMethod#initialize`.
|
|
171
|
+
# `method-name Symbol → [BlockAsMethod entries]`, insertion-ordered by (plugin, declaration). Method
|
|
172
|
+
# names are Symbol-normalised by `Macro::BlockAsMethod#initialize`.
|
|
195
173
|
def build_block_entries(plugins)
|
|
196
174
|
table = {}
|
|
197
175
|
plugins.each do |plugin|
|
|
@@ -204,9 +182,8 @@ module Rigor
|
|
|
204
182
|
table.freeze
|
|
205
183
|
end
|
|
206
184
|
|
|
207
|
-
# Mirrors `MethodDispatcher`'s previous per-dispatch matching:
|
|
208
|
-
#
|
|
209
|
-
# degrading to "no match" on any resolution failure.
|
|
185
|
+
# Mirrors `MethodDispatcher`'s previous per-dispatch matching: exact-name fast path, then
|
|
186
|
+
# `Environment#class_ordering`, degrading to "no match" on any resolution failure.
|
|
210
187
|
def class_matches_owner?(class_name, owner, environment)
|
|
211
188
|
return true if class_name == owner
|
|
212
189
|
return false if environment.nil?
|
|
@@ -216,9 +193,8 @@ module Rigor
|
|
|
216
193
|
false
|
|
217
194
|
end
|
|
218
195
|
|
|
219
|
-
# Manifest access tolerant of manifest-less plugin doubles in unit
|
|
220
|
-
#
|
|
221
|
-
# validates it).
|
|
196
|
+
# Manifest access tolerant of manifest-less plugin doubles in unit specs (a real loaded plugin always
|
|
197
|
+
# carries one — the loader validates it).
|
|
222
198
|
def manifest_for(plugin)
|
|
223
199
|
plugin.manifest
|
|
224
200
|
rescue StandardError
|
|
@@ -226,58 +202,43 @@ module Rigor
|
|
|
226
202
|
end
|
|
227
203
|
end
|
|
228
204
|
|
|
229
|
-
# Read-side query API over the plugins loaded for a single
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
# contribution merger (slice 3) and diagnostic provenance
|
|
233
|
-
# (slice 5) can iterate over loaded plugin instances in
|
|
234
|
-
# deterministic order.
|
|
205
|
+
# Read-side query API over the plugins loaded for a single `Analysis::Runner.run`. Constructed by
|
|
206
|
+
# {Rigor::Plugin::Loader.load} and exposed downstream so the contribution merger (slice 3) and diagnostic
|
|
207
|
+
# provenance (slice 5) can iterate over loaded plugin instances in deterministic order.
|
|
235
208
|
#
|
|
236
|
-
# The registry is read-only after construction; ordering is
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
# plugin-id alphabetical as the tie-breaker.
|
|
209
|
+
# The registry is read-only after construction; ordering is the order in which {Rigor::Plugin::Loader}
|
|
210
|
+
# resolved configuration entries, which is project-config order with plugin-id alphabetical as the
|
|
211
|
+
# tie-breaker.
|
|
240
212
|
#
|
|
241
|
-
# ADR-15 Phase 3 — alongside the instantiated `plugins`, the
|
|
242
|
-
#
|
|
243
|
-
# `
|
|
244
|
-
#
|
|
245
|
-
# pool ships `blueprints` across the boundary and calls
|
|
246
|
-
# {.materialize} per-Ractor; the live `plugins` carriage on
|
|
247
|
-
# the coordinator registry stays unchanged.
|
|
213
|
+
# ADR-15 Phase 3 — alongside the instantiated `plugins`, the registry carries `blueprints`: a frozen,
|
|
214
|
+
# Ractor-shareable `Array<Blueprint>` that records how to re-instantiate the same plugin set in a worker
|
|
215
|
+
# Ractor. The eventual Phase 4 pool ships `blueprints` across the boundary and calls {.materialize}
|
|
216
|
+
# per-Ractor; the live `plugins` carriage on the coordinator registry stays unchanged.
|
|
248
217
|
class Registry
|
|
249
218
|
attr_reader :plugins, :load_errors, :blueprints, :contribution_index
|
|
250
219
|
|
|
251
|
-
# @param plugins [Array<Rigor::Plugin::Base>] instantiated
|
|
252
|
-
#
|
|
253
|
-
#
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
#
|
|
257
|
-
# Ractor-shareable replay descriptors aligned 1:1 with
|
|
258
|
-
# `plugins`. The loader fills this in; callers that
|
|
259
|
-
# construct Registry manually MAY pass `[]` and accept
|
|
260
|
-
# that {.materialize} cannot replay the set.
|
|
220
|
+
# @param plugins [Array<Rigor::Plugin::Base>] instantiated plugin instances in deterministic order.
|
|
221
|
+
# @param load_errors [Array<Rigor::Plugin::LoadError>] failures surfaced during loading. Each error is
|
|
222
|
+
# also turned into a diagnostic by the runner.
|
|
223
|
+
# @param blueprints [Array<Rigor::Plugin::Blueprint>] frozen, Ractor-shareable replay descriptors
|
|
224
|
+
# aligned 1:1 with `plugins`. The loader fills this in; callers that construct Registry manually MAY
|
|
225
|
+
# pass `[]` and accept that {.materialize} cannot replay the set.
|
|
261
226
|
def initialize(plugins: [], load_errors: [], blueprints: [])
|
|
262
227
|
@plugins = plugins.dup.freeze
|
|
263
228
|
@load_errors = load_errors.dup.freeze
|
|
264
229
|
@blueprints = blueprints.dup.freeze
|
|
265
230
|
@contribution_index = ContributionIndex.new(@plugins)
|
|
266
|
-
# ADR-52 WD1 — aggregate queries the engine issues per def /
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
# mutable per-path memo inside the frozen registry — safe
|
|
271
|
-
# because the contract set and the glob semantics are fixed
|
|
272
|
-
# for the lifetime of the run.
|
|
231
|
+
# ADR-52 WD1 — aggregate queries the engine issues per def / per diagnostic candidate / per path are
|
|
232
|
+
# compiled once here (the registry is frozen, so the flat_map-on-every-call versions re-derived an
|
|
233
|
+
# invariant). `@contracts_by_path` is a mutable per-path memo inside the frozen registry — safe
|
|
234
|
+
# because the contract set and the glob semantics are fixed for the lifetime of the run.
|
|
273
235
|
@additional_initializers = @plugins.flat_map { |p| safe_manifest(p)&.additional_initializers || [] }.freeze
|
|
274
236
|
@open_receivers = @plugins.flat_map { |p| (safe_manifest(p)&.open_receivers || []).map(&:to_s) }.uniq.freeze
|
|
275
237
|
@open_receivers_set = @open_receivers.to_set.freeze
|
|
276
238
|
@protocol_contracts = @plugins.flat_map { |p| safe_protocol_contracts(p) }.freeze
|
|
277
239
|
@contracts_by_path = {}
|
|
278
|
-
# ADR-52 WD4 — the single engine-owned node-rule walk, compiled
|
|
279
|
-
#
|
|
280
|
-
# The runner reuses it for every file; it builds fresh per-file
|
|
240
|
+
# ADR-52 WD4 — the single engine-owned node-rule walk, compiled once per run from the node-rule
|
|
241
|
+
# plugin subset (registry order). The runner reuses it for every file; it builds fresh per-file
|
|
281
242
|
# state internally, so it is safe to freeze and share.
|
|
282
243
|
@node_rule_walk = NodeRuleWalk.new(@plugins)
|
|
283
244
|
freeze
|
|
@@ -286,15 +247,12 @@ module Rigor
|
|
|
286
247
|
# ADR-52 WD4 — the per-run node-rule walk (see {NodeRuleWalk}).
|
|
287
248
|
attr_reader :node_rule_walk
|
|
288
249
|
|
|
289
|
-
# ADR-15 Phase 3 — build a fresh Registry from the supplied
|
|
290
|
-
#
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
#
|
|
295
|
-
# losing the replay handle. `load_errors` is intentionally
|
|
296
|
-
# empty: load-time failures already surfaced in the
|
|
297
|
-
# coordinator registry and don't repeat per worker.
|
|
250
|
+
# ADR-15 Phase 3 — build a fresh Registry from the supplied blueprint set by replaying
|
|
251
|
+
# {Blueprint#materialize} per entry against `services`. The returned registry carries NEW plugin
|
|
252
|
+
# instances (mutable per-Ractor accumulators included) and the same blueprint set, so a worker can hand
|
|
253
|
+
# the materialised registry to Environment without losing the replay handle. `load_errors` is
|
|
254
|
+
# intentionally empty: load-time failures already surfaced in the coordinator registry and don't repeat
|
|
255
|
+
# per worker.
|
|
298
256
|
def self.materialize(blueprints:, services:)
|
|
299
257
|
plugins = blueprints.map { |bp| bp.materialize(services: services) }
|
|
300
258
|
new(plugins: plugins, blueprints: blueprints, load_errors: [])
|
|
@@ -317,27 +275,20 @@ module Rigor
|
|
|
317
275
|
!load_errors.empty?
|
|
318
276
|
end
|
|
319
277
|
|
|
320
|
-
# ADR-13 — flat ordered list of every loaded plugin's
|
|
321
|
-
#
|
|
322
|
-
#
|
|
323
|
-
#
|
|
324
|
-
# The first non-nil `#resolve(node, scope)` return wins per
|
|
325
|
-
# ADR-13 WD3 / WD5 — registration order is the user's lever.
|
|
278
|
+
# ADR-13 — flat ordered list of every loaded plugin's manifest-declared {TypeNodeResolver} instances,
|
|
279
|
+
# in plugin registration order. `Environment#build_name_scope` builds a `TypeNode::ResolverChain` from
|
|
280
|
+
# this list (environment.rb). The first non-nil `#resolve(node, scope)` return wins per ADR-13 WD3 /
|
|
281
|
+
# WD5 — registration order is the user's lever.
|
|
326
282
|
def type_node_resolvers
|
|
327
283
|
plugins.flat_map { |plugin| plugin.manifest.type_node_resolvers }
|
|
328
284
|
end
|
|
329
285
|
|
|
330
|
-
# ADR-20 slice 6 — aggregate every loaded plugin's
|
|
331
|
-
#
|
|
332
|
-
#
|
|
333
|
-
# `
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
# determined by the user's `plugins:` list); user
|
|
337
|
-
# `.rbs` overlays merge on top of this overlay last.
|
|
338
|
-
# Returns `Inference::HktRegistry::EMPTY` when no
|
|
339
|
-
# plugin contributes HKT entries so callers can skip
|
|
340
|
-
# the merge.
|
|
286
|
+
# ADR-20 slice 6 — aggregate every loaded plugin's manifest-declared HKT registrations + definitions
|
|
287
|
+
# into a single `Inference::HktRegistry` overlay that `Environment#hkt_registry` merges on top of the
|
|
288
|
+
# bundled `Builtins::HktBuiltins.registry`. Last plugin to register a URI wins (registration order
|
|
289
|
+
# determined by the user's `plugins:` list); user `.rbs` overlays merge on top of this overlay last.
|
|
290
|
+
# Returns `Inference::HktRegistry::EMPTY` when no plugin contributes HKT entries so callers can skip the
|
|
291
|
+
# merge.
|
|
341
292
|
def hkt_overlay_registry
|
|
342
293
|
registrations = plugins.flat_map { |plugin| plugin.manifest.hkt_registrations }
|
|
343
294
|
definitions = plugins.flat_map { |plugin| plugin.manifest.hkt_definitions }
|
|
@@ -346,25 +297,20 @@ module Rigor
|
|
|
346
297
|
Inference::HktRegistry.new(registrations: registrations, definitions: definitions)
|
|
347
298
|
end
|
|
348
299
|
|
|
349
|
-
# ADR-25 — flat, ordered list of every loaded plugin's
|
|
350
|
-
#
|
|
351
|
-
#
|
|
352
|
-
#
|
|
353
|
-
# `RbsLoader`, alongside the configuration's `signature_paths:`
|
|
354
|
-
# and the `bundler:` / `rbs_collection:` discovery output.
|
|
300
|
+
# ADR-25 — flat, ordered list of every loaded plugin's resolved RBS signature directories (absolute
|
|
301
|
+
# paths), in plugin registration order. `Environment.for_project` merges these into the signature-path
|
|
302
|
+
# set fed to `RbsLoader`, alongside the configuration's `signature_paths:` and the `bundler:` /
|
|
303
|
+
# `rbs_collection:` discovery output.
|
|
355
304
|
def signature_paths
|
|
356
305
|
plugins.flat_map(&:signature_paths)
|
|
357
306
|
end
|
|
358
307
|
|
|
359
|
-
# ADR-26 — the aggregate set of "open" receiver class names
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
# Compiled at construction (ADR-52 WD1) — the predicate runs per
|
|
366
|
-
# undefined-method candidate, so the previous per-call flat_map
|
|
367
|
-
# re-derived a frozen invariant.
|
|
308
|
+
# ADR-26 — the aggregate set of "open" receiver class names declared across loaded plugins (manifest
|
|
309
|
+
# `open_receivers:`). A class is open when a plugin vouches that it responds beyond its RBS-declared
|
|
310
|
+
# method surface. `open_receiver?` is the membership predicate `Analysis::CheckRules` consults to skip
|
|
311
|
+
# the `call.undefined-method` rule for such a class. Compiled at construction (ADR-52 WD1) — the
|
|
312
|
+
# predicate runs per undefined-method candidate, so the previous per-call flat_map re-derived a frozen
|
|
313
|
+
# invariant.
|
|
368
314
|
attr_reader :open_receivers
|
|
369
315
|
|
|
370
316
|
def open_receiver?(class_name)
|
|
@@ -373,42 +319,30 @@ module Rigor
|
|
|
373
319
|
@open_receivers_set.include?(class_name.to_s)
|
|
374
320
|
end
|
|
375
321
|
|
|
376
|
-
# ADR-28 — flat, ordered list of every loaded plugin's
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
# `#diagnostics_for_file` hooks (the presence + return-type
|
|
384
|
-
# check). Compiled at construction (ADR-52 WD1); a plugin's
|
|
385
|
-
# config-folding `#protocol_contracts` override is stable for the
|
|
386
|
-
# run because config is injected at construction.
|
|
322
|
+
# ADR-28 — flat, ordered list of every loaded plugin's path-scoped method-protocol contracts, in
|
|
323
|
+
# plugin registration order. Read from each plugin's `#protocol_contracts` (which the manifest backs
|
|
324
|
+
# by default but a plugin MAY override to fold in per-project config). Consumed by
|
|
325
|
+
# `Inference::MethodParameterBinder` (the parameter-type provision) and by contributing plugins'
|
|
326
|
+
# `#diagnostics_for_file` hooks (the presence + return-type check). Compiled at construction (ADR-52
|
|
327
|
+
# WD1); a plugin's config-folding `#protocol_contracts` override is stable for the run because config
|
|
328
|
+
# is injected at construction.
|
|
387
329
|
attr_reader :protocol_contracts
|
|
388
330
|
|
|
389
|
-
# ADR-38 — flat, ordered list of every loaded plugin's
|
|
390
|
-
#
|
|
391
|
-
#
|
|
392
|
-
#
|
|
393
|
-
#
|
|
394
|
-
# entry's `receiver_constraint`, is treated like `initialize`.
|
|
395
|
-
# Compiled at construction (ADR-52 WD1) — consulted per `def`
|
|
396
|
-
# node, ×2 sites in `ScopeIndexer`.
|
|
331
|
+
# ADR-38 — flat, ordered list of every loaded plugin's manifest-declared
|
|
332
|
+
# `Rigor::Plugin::AdditionalInitializer` entries. `Inference::ScopeIndexer` consults the set at its
|
|
333
|
+
# read-before-write nil soundness gate: a `def` whose name an entry covers, on a class that equals or
|
|
334
|
+
# inherits from the entry's `receiver_constraint`, is treated like `initialize`. Compiled at
|
|
335
|
+
# construction (ADR-52 WD1) — consulted per `def` node, ×2 sites in `ScopeIndexer`.
|
|
397
336
|
attr_reader :additional_initializers
|
|
398
337
|
|
|
399
|
-
# ADR-28 — the subset of `protocol_contracts` whose
|
|
400
|
-
# `
|
|
401
|
-
# project-
|
|
402
|
-
#
|
|
403
|
-
#
|
|
404
|
-
#
|
|
405
|
-
#
|
|
406
|
-
#
|
|
407
|
-
# `File::FNM_EXTGLOB` enables `{a,b}` groups. Returns `[]` for
|
|
408
|
-
# a nil path so the binder can call this unconditionally.
|
|
409
|
-
# Memoised per path (ADR-52 WD1) — consulted per `def` node by
|
|
410
|
-
# `MethodParameterBinder`, and the fnmatch sweep over every
|
|
411
|
-
# contract is pure in (contract set, path).
|
|
338
|
+
# ADR-28 — the subset of `protocol_contracts` whose `path_glob` matches `path`. Contract globs are
|
|
339
|
+
# authored project-root-relative (`lib/controller/**/*.rb`); the analyzer may hand this method either a
|
|
340
|
+
# project-relative path (`rigor check` run from the project root) or an absolute one (run from
|
|
341
|
+
# elsewhere, or a spec tmpdir), so the glob is matched both directly and as a `**/`-prefixed path
|
|
342
|
+
# suffix. `File::FNM_PATHNAME` keeps `*` from crossing `/`; `File::FNM_EXTGLOB` enables `{a,b}` groups.
|
|
343
|
+
# Returns `[]` for a nil path so the binder can call this unconditionally. Memoised per path (ADR-52
|
|
344
|
+
# WD1) — consulted per `def` node by `MethodParameterBinder`, and the fnmatch sweep over every contract
|
|
345
|
+
# is pure in (contract set, path).
|
|
412
346
|
def contracts_for_path(path)
|
|
413
347
|
return [] if path.nil?
|
|
414
348
|
|
|
@@ -417,17 +351,12 @@ module Rigor
|
|
|
417
351
|
protocol_contracts.select { |contract| path_matches_glob?(contract.path_glob, path_s) }.freeze
|
|
418
352
|
end
|
|
419
353
|
|
|
420
|
-
# ADR-32 WD4 + WD5 — flat ordered list of
|
|
421
|
-
#
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
#
|
|
426
|
-
# The full plugin instance is carried alongside the
|
|
427
|
-
# callable so the engine's cache layer (WD5) can compose
|
|
428
|
-
# `plugin.plugin_entry` into its per-file descriptor — a
|
|
429
|
-
# config change to the plugin (e.g. flipping
|
|
430
|
-
# `require_magic_comment:`) invalidates the dependent
|
|
354
|
+
# ADR-32 WD4 + WD5 — flat ordered list of `[plugin, callable]` pairs for every loaded plugin that
|
|
355
|
+
# declares a `source_rbs_synthesizer:` in its manifest. The engine invokes each callable once per
|
|
356
|
+
# analysed Ruby source file at env-build time; non-nil return strings are merged into the RBS
|
|
357
|
+
# environment as virtual signature sources. The full plugin instance is carried alongside the callable
|
|
358
|
+
# so the engine's cache layer (WD5) can compose `plugin.plugin_entry` into its per-file descriptor — a
|
|
359
|
+
# config change to the plugin (e.g. flipping `require_magic_comment:`) invalidates the dependent
|
|
431
360
|
# synthesizer cache without any plugin-side bookkeeping.
|
|
432
361
|
def source_rbs_synthesizers
|
|
433
362
|
plugins.filter_map do |plugin|
|
|
@@ -448,9 +377,8 @@ module Rigor
|
|
|
448
377
|
File.fnmatch?(File.join("**", glob), path, FNMATCH_FLAGS)
|
|
449
378
|
end
|
|
450
379
|
|
|
451
|
-
# Construction-time manifest access tolerant of manifest-less
|
|
452
|
-
# plugin
|
|
453
|
-
# carries one — the loader validates it). Mirrors
|
|
380
|
+
# Construction-time manifest access tolerant of manifest-less plugin doubles in unit specs (a real
|
|
381
|
+
# loaded plugin always carries one — the loader validates it). Mirrors
|
|
454
382
|
# `ContributionIndex#manifest_for`.
|
|
455
383
|
def safe_manifest(plugin)
|
|
456
384
|
plugin.manifest
|
|
@@ -465,9 +393,8 @@ module Rigor
|
|
|
465
393
|
end
|
|
466
394
|
end
|
|
467
395
|
|
|
468
|
-
# Assigned after the class body completes — `Registry.new` runs at
|
|
469
|
-
#
|
|
470
|
-
# late in the body.
|
|
396
|
+
# Assigned after the class body completes — `Registry.new` runs at assignment time and `#initialize` calls
|
|
397
|
+
# private helpers defined late in the body.
|
|
471
398
|
Registry::EMPTY = Registry.new.freeze
|
|
472
399
|
end
|
|
473
400
|
end
|
|
@@ -2,43 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
|
-
# Dependency-injection container handed to every plugin's
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# constructed once per `Analysis::Runner.run` and destroyed
|
|
9
|
-
# at the end of the run.
|
|
5
|
+
# Dependency-injection container handed to every plugin's {Rigor::Plugin::Base#init} method. Plugins read
|
|
6
|
+
# from the container; they MUST NOT mutate it. The container is constructed once per
|
|
7
|
+
# `Analysis::Runner.run` and destroyed at the end of the run.
|
|
10
8
|
#
|
|
11
|
-
# ADR-2 § "Registration, Configuration, and Caching" reserves
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# loggers, and configuration readers". Slice 1 wires four
|
|
15
|
-
# of those:
|
|
9
|
+
# ADR-2 § "Registration, Configuration, and Caching" reserves this surface for "constructor injection for
|
|
10
|
+
# analyzer services such as reflection providers, type factories, loggers, and configuration readers".
|
|
11
|
+
# Slice 1 wires four of those:
|
|
16
12
|
#
|
|
17
13
|
# - `reflection`: the {Rigor::Reflection} read-side facade.
|
|
18
14
|
# - `type`: the {Rigor::Type::Combinator} factory module.
|
|
19
15
|
# - `configuration`: the project's {Rigor::Configuration}.
|
|
20
|
-
# - `cache_store`: the {Rigor::Cache::Store} the run is using
|
|
21
|
-
#
|
|
22
|
-
# plugin-side cache producers through this entry.
|
|
16
|
+
# - `cache_store`: the {Rigor::Cache::Store} the run is using (or `nil` when caching is disabled). Slice 6
|
|
17
|
+
# wires plugin-side cache producers through this entry.
|
|
23
18
|
#
|
|
24
|
-
# Loggers are not yet a public surface in the core analyzer;
|
|
25
|
-
#
|
|
26
|
-
# progress channel.
|
|
19
|
+
# Loggers are not yet a public surface in the core analyzer; they will be added when the diagnostics
|
|
20
|
+
# formatter grows a progress channel.
|
|
27
21
|
#
|
|
28
|
-
# Slice 2 (Plugin trust / I/O policy) extends the container
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# feed cache invalidation; ADR-2 § "Plugin Trust and I/O
|
|
33
|
-
# Policy" documents the trust model the boundary enforces.
|
|
22
|
+
# Slice 2 (Plugin trust / I/O policy) extends the container with `trust_policy` and a per-plugin
|
|
23
|
+
# `io_boundary_for(plugin_id)` factory. Plugins should reach for the boundary rather than raw `File.read`
|
|
24
|
+
# so reads stay within the trusted scope and feed cache invalidation; ADR-2 § "Plugin Trust and I/O Policy"
|
|
25
|
+
# documents the trust model the boundary enforces.
|
|
34
26
|
#
|
|
35
|
-
# ADR-9 slice 2 adds `fact_store`: the per-run cross-plugin
|
|
36
|
-
# `
|
|
37
|
-
#
|
|
38
|
-
# `#
|
|
39
|
-
# A fresh `FactStore` instance is constructed per Services
|
|
40
|
-
# when none is supplied — the runner threads its own instance
|
|
41
|
-
# in once slice 3 wires `#prepare` invocation.
|
|
27
|
+
# ADR-9 slice 2 adds `fact_store`: the per-run cross-plugin `Plugin::FactStore`. Producer plugins publish
|
|
28
|
+
# their facts in `#prepare(services)` (slice 3); consumer plugins read in `#diagnostics_for_file` via
|
|
29
|
+
# `services.fact_store.read(...)`. A fresh `FactStore` instance is constructed per Services when none is
|
|
30
|
+
# supplied — the runner threads its own instance in once slice 3 wires `#prepare` invocation.
|
|
42
31
|
class Services
|
|
43
32
|
attr_reader :reflection, :type, :configuration, :cache_store, :trust_policy, :fact_store
|
|
44
33
|
|
|
@@ -55,10 +44,9 @@ module Rigor
|
|
|
55
44
|
freeze
|
|
56
45
|
end
|
|
57
46
|
|
|
58
|
-
# Returns a fresh {IoBoundary} bound to `plugin_id` and the
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
# constructs one boundary per plugin per run.
|
|
47
|
+
# Returns a fresh {IoBoundary} bound to `plugin_id` and the current `trust_policy`. The boundary
|
|
48
|
+
# accumulates per-plugin cache descriptor entries; the loader / contribution merger constructs one
|
|
49
|
+
# boundary per plugin per run.
|
|
62
50
|
def io_boundary_for(plugin_id)
|
|
63
51
|
IoBoundary.new(policy: @trust_policy, plugin_id: plugin_id)
|
|
64
52
|
end
|