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
|
@@ -2,50 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Analysis
|
|
5
|
-
# ADR-24 slice 4a — records every *implicit-self* method call the
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# `Dynamic[top]` (`ExpressionTyper#call_type_for` → `fallback_for`).
|
|
5
|
+
# ADR-24 slice 4a — records every *implicit-self* method call the inference engine could not resolve to any
|
|
6
|
+
# method (RBS tier miss + user-class ancestor-walk miss + not a `Dynamic` receiver), captured at the single
|
|
7
|
+
# engine choke-point where such a call falls through to `Dynamic[top]` (`ExpressionTyper#call_type_for` →
|
|
8
|
+
# `fallback_for`).
|
|
10
9
|
#
|
|
11
10
|
# ## Why a recorder, not a check-rule
|
|
12
11
|
#
|
|
13
|
-
# Slice 4 attempt 1 reimplemented self-call resolution inside
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# resolution — those methods resolve before the miss, so they never
|
|
21
|
-
# reach the recorder. This module is the ADR-46 / ADR-47 "collect at
|
|
22
|
-
# evaluation time, never recompute" lesson applied to self-calls.
|
|
12
|
+
# Slice 4 attempt 1 reimplemented self-call resolution inside `CheckRules` and produced 135 false
|
|
13
|
+
# positives on Rigor's own `lib` ([ADR-24](../../../docs/adr/24-self-method-call-resolution.md) § "Slice
|
|
14
|
+
# 4"): the second, weaker resolution path could not see `module_function` siblings, `Data.define` /
|
|
15
|
+
# `Struct` accessors, or mixin-contributed methods that the *engine's* real resolution handles. Recording
|
|
16
|
+
# at the engine's own miss point reuses that real resolution — those methods resolve before the miss, so
|
|
17
|
+
# they never reach the recorder. This module is the ADR-46 / ADR-47 "collect at evaluation time, never
|
|
18
|
+
# recompute" lesson applied to self-calls.
|
|
23
19
|
#
|
|
24
|
-
# ADR-24 slice 4 (`call.self-undefined-method`) consumes the recorded
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# nothing. Recording is purely observational; it never changes a
|
|
29
|
-
# diagnostic.
|
|
20
|
+
# ADR-24 slice 4 (`call.self-undefined-method`) consumes the recorded misses behind a confidently-closed-class
|
|
21
|
+
# gate (see `CheckRules` L775). The rule ships `:off` by default — {active?} is false on a normal run, so
|
|
22
|
+
# the instrumented choke-point pays a single integer read and records nothing. Recording is purely
|
|
23
|
+
# observational; it never changes a diagnostic.
|
|
30
24
|
#
|
|
31
|
-
# Modelled on {DependencyRecorder}: process-thread-local accumulator,
|
|
32
|
-
#
|
|
25
|
+
# Modelled on {DependencyRecorder}: process-thread-local accumulator, a cheap disabled fast path, and a
|
|
26
|
+
# frozen snapshot for consumers.
|
|
33
27
|
module SelfCallResolutionRecorder
|
|
34
28
|
KEY = :__rigor_self_call_resolution_recorder__
|
|
35
29
|
private_constant :KEY
|
|
36
30
|
|
|
37
|
-
# One unresolved implicit-self call. `class_name` is the receiver's
|
|
38
|
-
#
|
|
39
|
-
# the
|
|
40
|
-
#
|
|
41
|
-
# scope index and apply the closed-class gate); `path` / `line` /
|
|
42
|
-
# `column` locate the call site for the diagnostic.
|
|
31
|
+
# One unresolved implicit-self call. `class_name` is the receiver's statically known class (the
|
|
32
|
+
# enclosing `self` type); `method_name` the called name; `node` the Prism `CallNode` (held in-memory so
|
|
33
|
+
# the `call.self-undefined-method` collector can resolve its scope from the scope index and apply the
|
|
34
|
+
# closed-class gate); `path` / `line` / `column` locate the call site for the diagnostic.
|
|
43
35
|
UnresolvedSelfCall = Data.define(:class_name, :method_name, :node, :path, :line, :column)
|
|
44
36
|
|
|
45
|
-
# Mutable per-consumer accumulator, frozen into a {Record} snapshot
|
|
46
|
-
#
|
|
47
|
-
# method body re-typed under several call-site signatures records the
|
|
48
|
-
# miss once.
|
|
37
|
+
# Mutable per-consumer accumulator, frozen into a {Record} snapshot when {record_for} returns. Dedupes by
|
|
38
|
+
# the full call tuple so a method body re-typed under several call-site signatures records the miss once.
|
|
49
39
|
class Accumulator
|
|
50
40
|
attr_reader :consumer, :calls
|
|
51
41
|
|
|
@@ -68,18 +58,16 @@ module Rigor
|
|
|
68
58
|
|
|
69
59
|
Record = Data.define(:consumer, :calls)
|
|
70
60
|
|
|
71
|
-
# Module-level activation count so the disabled fast path ({active?})
|
|
72
|
-
#
|
|
73
|
-
# the instrumented choke-point is on the dispatch miss path, so a
|
|
61
|
+
# Module-level activation count so the disabled fast path ({active?}) is a plain integer read rather
|
|
62
|
+
# than a `Thread.current` hash lookup — the instrumented choke-point is on the dispatch miss path, so a
|
|
74
63
|
# normal (non-recording) run must pay as little as possible.
|
|
75
64
|
@active_count = 0
|
|
76
65
|
@mutex = Mutex.new
|
|
77
66
|
|
|
78
67
|
module_function
|
|
79
68
|
|
|
80
|
-
# Activates recording for `consumer` (the path being analyzed) for the
|
|
81
|
-
#
|
|
82
|
-
# restores the previous recorder on exit.
|
|
69
|
+
# Activates recording for `consumer` (the path being analyzed) for the duration of the block and returns
|
|
70
|
+
# the frozen {Record}. Nests safely; restores the previous recorder on exit.
|
|
83
71
|
def record_for(consumer)
|
|
84
72
|
previous = Thread.current[KEY]
|
|
85
73
|
accumulator = Accumulator.new(consumer.to_s)
|
|
@@ -92,14 +80,13 @@ module Rigor
|
|
|
92
80
|
@mutex.synchronize { @active_count -= 1 }
|
|
93
81
|
end
|
|
94
82
|
|
|
95
|
-
# Plain integer read (GVL-atomic) — no `Thread.current` lookup on the
|
|
96
|
-
# disabled fast path.
|
|
83
|
+
# Plain integer read (GVL-atomic) — no `Thread.current` lookup on the disabled fast path.
|
|
97
84
|
def active?
|
|
98
85
|
@active_count.positive?
|
|
99
86
|
end
|
|
100
87
|
|
|
101
|
-
# Records one unresolved implicit-self call. No-op when no consumer is
|
|
102
|
-
#
|
|
88
|
+
# Records one unresolved implicit-self call. No-op when no consumer is active on this thread (another
|
|
89
|
+
# thread may have flipped {active?}).
|
|
103
90
|
def record(class_name:, method_name:, node:, path:, line:, column:)
|
|
104
91
|
accumulator = Thread.current[KEY]
|
|
105
92
|
return if accumulator.nil?
|
|
@@ -19,69 +19,49 @@ require_relative "erb_template_detector"
|
|
|
19
19
|
|
|
20
20
|
module Rigor
|
|
21
21
|
module Analysis
|
|
22
|
-
# ADR-15 Phase 4a — per-worker analysis substrate.
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# This class exists so the per-worker ownership boundary is testable
|
|
28
|
-
# independently of any pool coordinator.
|
|
22
|
+
# ADR-15 Phase 4a — per-worker analysis substrate. [ADR-15](../../../docs/adr/15-ractor-concurrency.md) §
|
|
23
|
+
# Phase 4 carves the Ractor-isolated worker pool into sub-phases; 4a/4b/4c all landed, but the Ractor
|
|
24
|
+
# pool (4b) is blocked by Ruby Bug #22075 (UAF) — the active pool backend is fork (ADR-15 Amendment).
|
|
25
|
+
# This class exists so the per-worker ownership boundary is testable independently of any pool
|
|
26
|
+
# coordinator.
|
|
29
27
|
#
|
|
30
28
|
# The constructor takes only `Ractor.shareable?` inputs:
|
|
31
29
|
#
|
|
32
|
-
# - `configuration` — Phase 2a ({Rigor::Configuration} is
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# workers share it rather than building their own at `cache_root`.
|
|
37
|
-
# - `plugin_blueprints` — Phase 3a
|
|
38
|
-
# (`Array<Plugin::Blueprint>` is `Ractor.shareable?`).
|
|
30
|
+
# - `configuration` — Phase 2a ({Rigor::Configuration} is `Ractor.shareable?`).
|
|
31
|
+
# - `cache_store` — the fork backend passes the parent runner's pre-built Store (`cache_store:
|
|
32
|
+
# @cache_store` in PoolCoordinator); workers share it rather than building their own at `cache_root`.
|
|
33
|
+
# - `plugin_blueprints` — Phase 3a (`Array<Plugin::Blueprint>` is `Ractor.shareable?`).
|
|
39
34
|
# - `explain` — Boolean.
|
|
40
|
-
# - `synthetic_method_index` / `project_patched_methods` /
|
|
41
|
-
# `
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
# `
|
|
48
|
-
# the cross-file discovery tables `seed_project_scope` applies
|
|
49
|
-
# to every per-file scope on the sequential path; without it a
|
|
50
|
-
# worker cannot resolve calls to methods defined in OTHER
|
|
51
|
-
# project files and emits `call.undefined-method` false
|
|
52
|
-
# positives the sequential path does not.
|
|
35
|
+
# - `synthetic_method_index` / `project_patched_methods` / `project_scope_seed` — optional (default `nil`
|
|
36
|
+
# / `{}`). NOT `Ractor.shareable?` (the seed tables carry Prism def nodes), so the Ractor pool path
|
|
37
|
+
# leaves them unset; the fork backend (ADR-15 Amendment), which builds the session pre-fork on the
|
|
38
|
+
# parent, threads the runner's project-scan results through so per-file inference matches the
|
|
39
|
+
# sequential path exactly. `project_scope_seed` is `Runner#project_scope_seed_tables` — the cross-file
|
|
40
|
+
# discovery tables `seed_project_scope` applies to every per-file scope on the sequential path;
|
|
41
|
+
# without it a worker cannot resolve calls to methods defined in OTHER project files and emits
|
|
42
|
+
# `call.undefined-method` false positives the sequential path does not.
|
|
53
43
|
#
|
|
54
44
|
# Internally the session OWNS (and never shares):
|
|
55
45
|
#
|
|
56
46
|
# - {Rigor::Plugin::Services} bound to the per-worker Store.
|
|
57
|
-
# - {Rigor::Plugin::Registry} materialised from the blueprints
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# merges entries post-pool via {#drain_reporters}).
|
|
66
|
-
# - {Rigor::Environment} threaded with the per-worker reporters
|
|
67
|
-
# so reporter writes from inference / dispatcher accumulate
|
|
68
|
-
# into the worker's own state.
|
|
47
|
+
# - {Rigor::Plugin::Registry} materialised from the blueprints via {Rigor::Plugin::Registry.materialize};
|
|
48
|
+
# each plugin instance, with its mutable per-run accumulators (`@reachable_absurd_nodes`, `*_index`,
|
|
49
|
+
# …) lives entirely inside this session.
|
|
50
|
+
# - {Rigor::RbsExtended::Reporter} + {Rigor::Analysis::DependencySourceInference::BoundaryCrossReporter}
|
|
51
|
+
# (Mutex-bearing; intentionally per-worker — the runner merges entries post-pool via
|
|
52
|
+
# {#drain_reporters}).
|
|
53
|
+
# - {Rigor::Environment} threaded with the per-worker reporters so reporter writes from inference /
|
|
54
|
+
# dispatcher accumulate into the worker's own state.
|
|
69
55
|
#
|
|
70
|
-
# Plugin `prepare` runs ONCE at construction time so each
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# so the runner can surface them alongside the per-file
|
|
74
|
-
# diagnostic stream.
|
|
56
|
+
# Plugin `prepare` runs ONCE at construction time so each worker is "warm" by the time `#analyze` is
|
|
57
|
+
# first called. Any raise from `prepare` is captured into {#prepare_diagnostics} so the runner can
|
|
58
|
+
# surface them alongside the per-file diagnostic stream.
|
|
75
59
|
#
|
|
76
|
-
# Equivalence contract (proven by spec): given identical
|
|
77
|
-
# `
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
# corresponding subset of {Rigor::Analysis::Runner#run}'s
|
|
82
|
-
# output (modulo severity-profile re-stamping, which the
|
|
83
|
-
# session leaves to the caller because it is a per-run
|
|
84
|
-
# aggregate concern).
|
|
60
|
+
# Equivalence contract (proven by spec): given identical `(configuration, cache_store,
|
|
61
|
+
# plugin_blueprints)`, the multiset of diagnostics from `paths.flat_map { |p| session.analyze(p) }` plus
|
|
62
|
+
# {#prepare_diagnostics} plus reporter drains MUST equal the corresponding subset of
|
|
63
|
+
# {Rigor::Analysis::Runner#run}'s output (modulo severity-profile re-stamping, which the session leaves
|
|
64
|
+
# to the caller because it is a per-run aggregate concern).
|
|
85
65
|
class WorkerSession # rubocop:disable Metrics/ClassLength
|
|
86
66
|
attr_reader :configuration, :cache_store, :services, :plugin_registry,
|
|
87
67
|
:dependency_source_index, :environment,
|
|
@@ -89,16 +69,12 @@ module Rigor
|
|
|
89
69
|
:prepare_diagnostics
|
|
90
70
|
|
|
91
71
|
# @param configuration [Rigor::Configuration]
|
|
92
|
-
# @param cache_store [Rigor::Cache::Store, nil] persistent
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
# @param explain [Boolean] when true, `#analyze` additionally
|
|
99
|
-
# emits one `:info` `fallback` diagnostic per
|
|
100
|
-
# directly-unrecognised node, mirroring
|
|
101
|
-
# {Rigor::Analysis::Runner#explain_diagnostics}.
|
|
72
|
+
# @param cache_store [Rigor::Cache::Store, nil] persistent cache the session exposes to plugin-side
|
|
73
|
+
# producers and the RBS loader. Pass `nil` to disable caching.
|
|
74
|
+
# @param plugin_blueprints [Array<Rigor::Plugin::Blueprint>] replay descriptors. Empty array yields a
|
|
75
|
+
# session with no plugin contributions.
|
|
76
|
+
# @param explain [Boolean] when true, `#analyze` additionally emits one `:info` `fallback` diagnostic
|
|
77
|
+
# per directly-unrecognised node, mirroring {Rigor::Analysis::Runner#explain_diagnostics}.
|
|
102
78
|
def initialize(configuration:, cache_store: nil, # rubocop:disable Metrics/MethodLength,Metrics/ParameterLists
|
|
103
79
|
plugin_blueprints: [], explain: false, buffer: nil,
|
|
104
80
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
@@ -110,18 +86,14 @@ module Rigor
|
|
|
110
86
|
@synthetic_method_index = synthetic_method_index
|
|
111
87
|
@project_patched_methods = project_patched_methods
|
|
112
88
|
@project_scope_seed = project_scope_seed || {}
|
|
113
|
-
# ADR-32 WD4 — full project file list (frozen
|
|
114
|
-
# Array<String>) for env-build-time invocation of any
|
|
89
|
+
# ADR-32 WD4 — full project file list (frozen Array<String>) for env-build-time invocation of any
|
|
115
90
|
# loaded plugin's `source_rbs_synthesizer` callable.
|
|
116
91
|
@source_files = source_files
|
|
117
92
|
|
|
118
|
-
# NOTE: `Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths`
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# {Rigor::Analysis::Runner#run}) is responsible for
|
|
123
|
-
# setting it on the main Ractor before spawning the
|
|
124
|
-
# pool. The substrate stays Ractor-safe by construction.
|
|
93
|
+
# NOTE: `Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths` is process-global
|
|
94
|
+
# state. Writing it from a non-main Ractor would raise `Ractor::IsolationError`, so the session does
|
|
95
|
+
# NOT touch it — the CALLER (typically {Rigor::Analysis::Runner#run}) is responsible for setting it
|
|
96
|
+
# on the main Ractor before spawning the pool. The substrate stays Ractor-safe by construction.
|
|
125
97
|
@rbs_extended_reporter = RbsExtended::Reporter.new
|
|
126
98
|
@boundary_cross_reporter = DependencySourceInference::BoundaryCrossReporter.new
|
|
127
99
|
@source_rbs_synthesis_reporter = Plugin::SourceRbsSynthesisReporter.new
|
|
@@ -158,11 +130,9 @@ module Rigor
|
|
|
158
130
|
@prepare_diagnostics = run_plugin_prepare.freeze
|
|
159
131
|
end
|
|
160
132
|
|
|
161
|
-
# Equivalent of {Rigor::Analysis::Runner#analyze_file} +
|
|
162
|
-
# `
|
|
163
|
-
#
|
|
164
|
-
# profile re-stamping is intentionally NOT applied — that
|
|
165
|
-
# is a per-run aggregate concern handled by the caller.
|
|
133
|
+
# Equivalent of {Rigor::Analysis::Runner#analyze_file} + `plugin_emitted_diagnostics` +
|
|
134
|
+
# `explain_diagnostics`. Returns a flat `Array<Diagnostic>` for the file. Severity profile re-stamping
|
|
135
|
+
# is intentionally NOT applied — that is a per-run aggregate concern handled by the caller.
|
|
166
136
|
def analyze(path)
|
|
167
137
|
parse_result = parse_source(path)
|
|
168
138
|
unless parse_result.errors.empty?
|
|
@@ -192,11 +162,9 @@ module Rigor
|
|
|
192
162
|
[analyzer_error(path, "internal analyzer error: #{e.class}: #{e.message}")]
|
|
193
163
|
end
|
|
194
164
|
|
|
195
|
-
# Read-once snapshot of the per-worker reporters so the
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
# reporters dedupe at write time, so a post-hoc concat +
|
|
199
|
-
# de-dup at the entry-key level is sound.
|
|
165
|
+
# Read-once snapshot of the per-worker reporters so the caller (or the eventual Phase 4b pool
|
|
166
|
+
# aggregator) can merge into a single coordinator-side reporter. Both reporters dedupe at write time,
|
|
167
|
+
# so a post-hoc concat + de-dup at the entry-key level is sound.
|
|
200
168
|
def drain_reporters
|
|
201
169
|
{
|
|
202
170
|
rbs_extended: {
|
|
@@ -210,21 +178,18 @@ module Rigor
|
|
|
210
178
|
|
|
211
179
|
private
|
|
212
180
|
|
|
213
|
-
# Mirrors {Runner#seed_project_scope}: applies the cross-file
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
# scope, so worker-side inference resolves project-internal
|
|
217
|
-
# cross-file calls exactly like the sequential path.
|
|
181
|
+
# Mirrors {Runner#seed_project_scope}: applies the cross-file pre-pass discovery tables the
|
|
182
|
+
# constructor received (fork backend only — see the class comment) to a fresh per-file scope, so
|
|
183
|
+
# worker-side inference resolves project-internal cross-file calls exactly like the sequential path.
|
|
218
184
|
def seed_project_scope(scope)
|
|
219
185
|
return scope if @project_scope_seed.empty?
|
|
220
186
|
|
|
221
187
|
scope.with_discovery(scope.discovery.with(**@project_scope_seed))
|
|
222
188
|
end
|
|
223
189
|
|
|
224
|
-
# See {Runner#parse_source}. Same contract: if `@buffer`
|
|
225
|
-
#
|
|
226
|
-
#
|
|
227
|
-
# path so downstream diagnostics carry the logical path.
|
|
190
|
+
# See {Runner#parse_source}. Same contract: if `@buffer` binds `path` to a physical file, read the
|
|
191
|
+
# physical bytes but stamp the parse buffer's `filepath:` as the LOGICAL path so downstream
|
|
192
|
+
# diagnostics carry the logical path.
|
|
228
193
|
def parse_source(path)
|
|
229
194
|
physical = @buffer ? @buffer.resolve(path) : path
|
|
230
195
|
return Prism.parse_file(physical, version: @configuration.target_ruby) if physical == path
|
|
@@ -232,9 +197,8 @@ module Rigor
|
|
|
232
197
|
Prism.parse(File.read(physical), filepath: path, version: @configuration.target_ruby)
|
|
233
198
|
end
|
|
234
199
|
|
|
235
|
-
# Mirrors {Runner#build_trust_policy}. Deriving trust inside
|
|
236
|
-
# the
|
|
237
|
-
# coordinator; configuration is already Ractor-shareable.
|
|
200
|
+
# Mirrors {Runner#build_trust_policy}. Deriving trust inside the session keeps the substrate decoupled
|
|
201
|
+
# from the coordinator; configuration is already Ractor-shareable.
|
|
238
202
|
def build_trust_policy
|
|
239
203
|
trusted_gems = @configuration.plugins.map { |entry| trusted_gem_name(entry) }.uniq
|
|
240
204
|
roots = [Dir.pwd]
|
|
@@ -302,11 +266,10 @@ module Rigor
|
|
|
302
266
|
end
|
|
303
267
|
end
|
|
304
268
|
|
|
305
|
-
# ADR-52 WD4 + ADR-53 B4 — single engine-owned walk per file drives
|
|
306
|
-
#
|
|
307
|
-
#
|
|
308
|
-
#
|
|
309
|
-
# plugins so the collectors still get driven (converged path).
|
|
269
|
+
# ADR-52 WD4 + ADR-53 B4 — single engine-owned walk per file drives both the plugin node rules
|
|
270
|
+
# (bucketed per plugin in registry order, plugin-major emission) and the built-in node collectors
|
|
271
|
+
# (`node_collectors`, populated in place). Runs even with no node-rule plugins so the collectors still
|
|
272
|
+
# get driven (converged path).
|
|
310
273
|
def node_rule_results_by_plugin(path, root, scope, node_collectors, scope_index)
|
|
311
274
|
walk = @plugin_registry.node_rule_walk
|
|
312
275
|
driver = node_collectors && CheckRules.node_collector_driver(node_collectors)
|
|
@@ -325,9 +288,8 @@ module Rigor
|
|
|
325
288
|
|
|
326
289
|
def collect_plugin_diagnostics(plugin, path, root, scope, node_result)
|
|
327
290
|
raw = Array(plugin.diagnostics_for_file(path: path, scope: scope, root: root))
|
|
328
|
-
# A node-rule context/rule raise isolates the whole plugin's
|
|
329
|
-
#
|
|
330
|
-
# rescue (which discarded `diagnostics_for_file` output too).
|
|
291
|
+
# A node-rule context/rule raise isolates the whole plugin's node-rule contribution, matching the
|
|
292
|
+
# old combined per-plugin rescue (which discarded `diagnostics_for_file` output too).
|
|
331
293
|
raise node_result.error if node_result&.error
|
|
332
294
|
|
|
333
295
|
raw += node_result.diagnostics if node_result
|
data/lib/rigor/ast/type_node.rb
CHANGED
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module AST
|
|
5
|
-
# A virtual node that wraps a Rigor::Type. Allows callers to ask
|
|
6
|
-
#
|
|
7
|
-
# were T?" without constructing a real Prism expression.
|
|
5
|
+
# A virtual node that wraps a Rigor::Type. Allows callers to ask "what would the analyzer infer at this
|
|
6
|
+
# position if the value's type were T?" without constructing a real Prism expression.
|
|
8
7
|
#
|
|
9
|
-
# Rigor::Scope#type_of(TypeNode.new(t)) MUST return a structurally-
|
|
10
|
-
#
|
|
8
|
+
# Rigor::Scope#type_of(TypeNode.new(t)) MUST return a structurally-equal t. The engine MUST NOT modify or
|
|
9
|
+
# annotate the wrapped type.
|
|
11
10
|
#
|
|
12
|
-
# Inspired by PHPStan's TypeExpr (a synthetic Expr that returns a
|
|
13
|
-
#
|
|
14
|
-
# spelled "TypeNode" to align with Prism's "Node" suffix convention.
|
|
11
|
+
# Inspired by PHPStan's TypeExpr (a synthetic Expr that returns a specific Type from $scope->getType). The
|
|
12
|
+
# Rigor counterpart is spelled "TypeNode" to align with Prism's "Node" suffix convention.
|
|
15
13
|
class TypeNode
|
|
16
14
|
include Node
|
|
17
15
|
|
data/lib/rigor/ast.rb
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
|
-
# Synthetic AST nodes accepted by Rigor::Scope#type_of alongside real
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# node-specific data the engine needs to translate them into a
|
|
9
|
-
# Rigor::Type.
|
|
4
|
+
# Synthetic AST nodes accepted by Rigor::Scope#type_of alongside real Prism nodes. Rigor::AST::Node is a
|
|
5
|
+
# documentation-only marker module that production code uses to detect virtual-node arguments. Concrete virtual
|
|
6
|
+
# node classes include Rigor::AST::Node and provide whatever node-specific data the engine needs to translate
|
|
7
|
+
# them into a Rigor::Type.
|
|
10
8
|
#
|
|
11
|
-
# The contract for virtual nodes lives in
|
|
12
|
-
# docs/
|
|
13
|
-
# alternative of specialising type classes for operator-method dispatch
|
|
14
|
-
# live in docs/adr/4-type-inference-engine.md.
|
|
9
|
+
# The contract for virtual nodes lives in docs/internal-spec/inference-engine.md; the rationale and the rejected
|
|
10
|
+
# alternative of specialising type classes for operator-method dispatch live in docs/adr/4-type-inference-engine.md.
|
|
15
11
|
module AST
|
|
16
12
|
# Marker module included by every synthetic node. Carries no behaviour.
|
|
17
13
|
module Node
|
data/lib/rigor/bleeding_edge.rb
CHANGED
|
@@ -3,26 +3,21 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
# ADR-50 § WD2 — the bleeding-edge overlay.
|
|
5
5
|
#
|
|
6
|
-
# A Rigor-maintained set of the *next major's* queued changes —
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# user-supplied file: the inspectable counterpart to PHPStan's
|
|
12
|
-
# `bleedingEdge` include.
|
|
6
|
+
# A Rigor-maintained set of the *next major's* queued changes — severity-map promotions and
|
|
7
|
+
# new-discipline rule enablements — that a user can adopt early, before they become
|
|
8
|
+
# default-on at a major (ADR-50 § WD7). It is orthogonal to `severity_profile:` (how loud
|
|
9
|
+
# *today's* rules are) and is versioned with the gem, NOT a user-supplied file: the
|
|
10
|
+
# inspectable counterpart to PHPStan's `bleedingEdge` include.
|
|
13
11
|
#
|
|
14
|
-
# The overlay is **empty today** — no discipline has yet been queued
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# {
|
|
19
|
-
# end-to-end, so the first real feature lands as a single {FEATURES}
|
|
20
|
-
# entry with no engine plumbing.
|
|
12
|
+
# The overlay is **empty today** — no discipline has yet been queued for the next major.
|
|
13
|
+
# This module is the WD2 *foundation* (the v0.1.19 slice): the surface (`bleeding_edge:`
|
|
14
|
+
# config, the `rigor show-bleedingedge` command, the severity-composition hook in
|
|
15
|
+
# {Configuration::SeverityProfile.resolve}) exists and is wired end-to-end, so the first
|
|
16
|
+
# real feature lands as a single {FEATURES} entry with no engine plumbing.
|
|
21
17
|
#
|
|
22
|
-
# Each feature carries a **stable feature id** — part of the ADR-50
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# feature graduates to default-on at a major by being removed from
|
|
18
|
+
# Each feature carries a **stable feature id** — part of the ADR-50 WD1 contract
|
|
19
|
+
# vocabulary: the config, the `show` command, and the eventual CHANGELOG migration note all
|
|
20
|
+
# name the same id, and a feature graduates to default-on at a major by being removed from
|
|
26
21
|
# {FEATURES}.
|
|
27
22
|
module BleedingEdge
|
|
28
23
|
# One queued change.
|
|
@@ -32,10 +27,9 @@ module Rigor
|
|
|
32
27
|
# @!attribute summary
|
|
33
28
|
# @return [String] a one-line description of what it changes.
|
|
34
29
|
# @!attribute severity_overrides
|
|
35
|
-
# @return [Hash{String => Symbol}] canonical rule id → the
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# (see {Configuration::SeverityProfile.resolve}).
|
|
30
|
+
# @return [Hash{String => Symbol}] canonical rule id → the severity this feature
|
|
31
|
+
# imposes. Composed *below* the user's own `severity_overrides:` and *above* the
|
|
32
|
+
# active `severity_profile` (see {Configuration::SeverityProfile.resolve}).
|
|
39
33
|
Feature = Data.define(:id, :summary, :severity_overrides) do
|
|
40
34
|
def to_h
|
|
41
35
|
{
|
|
@@ -46,8 +40,8 @@ module Rigor
|
|
|
46
40
|
end
|
|
47
41
|
end
|
|
48
42
|
|
|
49
|
-
# The overlay. Empty until the first next-major discipline is
|
|
50
|
-
#
|
|
43
|
+
# The overlay. Empty until the first next-major discipline is queued; add a {Feature}
|
|
44
|
+
# here (with a stable id) when one is.
|
|
51
45
|
FEATURES = [].freeze
|
|
52
46
|
|
|
53
47
|
module_function
|
|
@@ -68,12 +62,11 @@ module Rigor
|
|
|
68
62
|
FEATURES.find { |f| f.id == id }
|
|
69
63
|
end
|
|
70
64
|
|
|
71
|
-
# Resolves a normalized `bleeding_edge:` selector (see
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# lands (robust across gem versions).
|
|
65
|
+
# Resolves a normalized `bleeding_edge:` selector (see {Configuration#bleeding_edge}) to
|
|
66
|
+
# the active {Feature} list. Unknown ids in a `list` / `except` selector are simply
|
|
67
|
+
# absent from the overlay and contribute nothing — symmetric with how
|
|
68
|
+
# `severity_overrides:` keeps an unknown rule id inert until it lands (robust across gem
|
|
69
|
+
# versions).
|
|
77
70
|
#
|
|
78
71
|
# @param selector [Hash] `{ "mode" => "none" }`,
|
|
79
72
|
# `{ "mode" => "all" }`, `{ "mode" => "all", "except" => [ids] }`,
|
|
@@ -92,8 +85,8 @@ module Rigor
|
|
|
92
85
|
end
|
|
93
86
|
end
|
|
94
87
|
|
|
95
|
-
# The merged severity-override map the active features impose for a
|
|
96
|
-
#
|
|
88
|
+
# The merged severity-override map the active features impose for a selector. Frozen so
|
|
89
|
+
# the result is `Ractor.shareable?`.
|
|
97
90
|
#
|
|
98
91
|
# @param selector [Hash] see {#active_features}.
|
|
99
92
|
# @return [Hash{String => Symbol}]
|
|
@@ -103,9 +96,8 @@ module Rigor
|
|
|
103
96
|
end.freeze
|
|
104
97
|
end
|
|
105
98
|
|
|
106
|
-
# Feature ids named by a selector that are NOT in the overlay
|
|
107
|
-
#
|
|
108
|
-
# `rigor show-bleedingedge` as a hint; never an error.
|
|
99
|
+
# Feature ids named by a selector that are NOT in the overlay (typo / graduated / from a
|
|
100
|
+
# newer gem). Surfaced by `rigor show-bleedingedge` as a hint; never an error.
|
|
109
101
|
#
|
|
110
102
|
# @param selector [Hash] see {#active_features}.
|
|
111
103
|
# @return [Array<String>]
|
|
@@ -6,28 +6,21 @@ require_relative "../inference/hkt_body_parser"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Builtins
|
|
9
|
-
# ADR-20 slices 2c + 3 — Rigor-bundled Lightweight HKT
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# authors register more URIs through their manifests; user
|
|
14
|
-
# `.rbs` overlays register through the
|
|
15
|
-
# `%a{rigor:v1:hkt_register}` /
|
|
16
|
-
# `%a{rigor:v1:hkt_define}` annotations Slice 1 ships.
|
|
9
|
+
# ADR-20 slices 2c + 3 — Rigor-bundled Lightweight HKT registrations that ship with every analyzer instance.
|
|
10
|
+
# The set is intentionally small at v0.1.x: only the URIs whose payoff justifies hardcoded definitions. Plugin
|
|
11
|
+
# authors register more URIs through their manifests; user `.rbs` overlays register through the
|
|
12
|
+
# `%a{rigor:v1:hkt_register}` / `%a{rigor:v1:hkt_define}` annotations Slice 1 ships.
|
|
17
13
|
#
|
|
18
14
|
# Today's contents:
|
|
19
15
|
#
|
|
20
|
-
# - `json::value[K]` — the recursive sum stdlib's
|
|
21
|
-
# `JSON.parse` returns. Body:
|
|
16
|
+
# - `json::value[K]` — the recursive sum stdlib's `JSON.parse` returns. Body:
|
|
22
17
|
#
|
|
23
18
|
# nil | true | false | Integer | Float | String
|
|
24
19
|
# | Array[App[json::value, K]]
|
|
25
20
|
# | Hash[K, App[json::value, K]]
|
|
26
21
|
#
|
|
27
|
-
# The reducer handles the self-recursive `App` nodes via
|
|
28
|
-
#
|
|
29
|
-
# matches stdlib's default key handling; `K = Symbol`
|
|
30
|
-
# matches `symbolize_names: true`.
|
|
22
|
+
# The reducer handles the self-recursive `App` nodes via lazy "tying-the-knot" (see {HktReducer}). `K = String`
|
|
23
|
+
# matches stdlib's default key handling; `K = Symbol` matches `symbolize_names: true`.
|
|
31
24
|
module HktBuiltins
|
|
32
25
|
module_function
|
|
33
26
|
|