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
|
@@ -8,35 +8,26 @@ require_relative "sig_parser"
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module Plugin
|
|
10
10
|
class Sorbet < Rigor::Plugin::Base
|
|
11
|
-
# Walks a parsed Prism program looking for
|
|
12
|
-
# `
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# {SigParser} and recorded in the {Catalog} under its
|
|
16
|
-
# qualified `(class_name, method_name, kind)` key.
|
|
11
|
+
# Walks a parsed Prism program looking for `sig { ... }` / `sig do ... end` calls that immediately
|
|
12
|
+
# precede a `def` (or a `def self.foo` / `class << self; def foo; end`). Each recognised pair is
|
|
13
|
+
# parsed by {SigParser} and recorded in the {Catalog} under its qualified `(class_name, method_name,
|
|
14
|
+
# kind)` key.
|
|
17
15
|
#
|
|
18
|
-
# Anything we don't recognise (a stray `sig { ... }` not
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# `plugin.sorbet.parse-error` diagnostic. Walking is
|
|
23
|
-
# otherwise infallible — a bad sig block does not abort
|
|
24
|
-
# the catalog build for the rest of the file.
|
|
16
|
+
# Anything we don't recognise (a stray `sig { ... }` not followed by a `def`, a `def` with no
|
|
17
|
+
# preceding `sig`, malformed sig blocks, etc.) is reported back to the caller through
|
|
18
|
+
# `parse_errors:` so the plugin can emit a `plugin.sorbet.parse-error` diagnostic. Walking is
|
|
19
|
+
# otherwise infallible — a bad sig block does not abort the catalog build for the rest of the file.
|
|
25
20
|
module CatalogWalker
|
|
26
|
-
# Detected error during walking. `kind` is one of:
|
|
27
|
-
# `:
|
|
28
|
-
# / `:duplicate_sig` / `:dangling_sig`.
|
|
21
|
+
# Detected error during walking. `kind` is one of: `:no_block` / `:empty_block` /
|
|
22
|
+
# `:missing_returns_or_void` / `:duplicate_sig` / `:dangling_sig`.
|
|
29
23
|
ParseError = Data.define(:kind, :node, :path)
|
|
30
24
|
|
|
31
25
|
module_function
|
|
32
26
|
|
|
33
27
|
# @param root [Prism::Node] the file's program node.
|
|
34
|
-
# @param catalog [Catalog] mutable; signatures are
|
|
35
|
-
#
|
|
36
|
-
# @
|
|
37
|
-
# provenance.
|
|
38
|
-
# @return [Array<ParseError>] errors observed during the
|
|
39
|
-
# walk; empty when the file is sig-clean.
|
|
28
|
+
# @param catalog [Catalog] mutable; signatures are recorded into it.
|
|
29
|
+
# @param path [String] file path used for diagnostic provenance.
|
|
30
|
+
# @return [Array<ParseError>] errors observed during the walk; empty when the file is sig-clean.
|
|
40
31
|
def walk(root:, catalog:, path:)
|
|
41
32
|
state = State.new(catalog: catalog, path: path)
|
|
42
33
|
walk_node(root, state, lexical_path: [], in_singleton_class: false)
|
|
@@ -64,9 +55,8 @@ module Rigor
|
|
|
64
55
|
when Prism::StatementsNode
|
|
65
56
|
walk_statements(node, state, lexical_path: lexical_path, in_singleton_class: in_singleton_class)
|
|
66
57
|
when Prism::DefNode
|
|
67
|
-
# A `def` not preceded by a `sig` is fine; we just
|
|
68
|
-
#
|
|
69
|
-
# is in `walk_statements`, which pairs sig+def.
|
|
58
|
+
# A `def` not preceded by a `sig` is fine; we just don't record anything for it. The
|
|
59
|
+
# interesting case is in `walk_statements`, which pairs sig+def.
|
|
70
60
|
else
|
|
71
61
|
node.compact_child_nodes.each do |child|
|
|
72
62
|
walk_node(child, state, lexical_path: lexical_path, in_singleton_class: in_singleton_class)
|
|
@@ -92,13 +82,10 @@ module Rigor
|
|
|
92
82
|
end
|
|
93
83
|
end
|
|
94
84
|
|
|
95
|
-
# The pair-finding loop. Walks a `StatementsNode`'s
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
# a sig and its def (a comment is fine — comments aren't
|
|
100
|
-
# AST nodes — but a method call would be a problem)
|
|
101
|
-
# leaves the sig dangling.
|
|
85
|
+
# The pair-finding loop. Walks a `StatementsNode`'s children left-to-right; when it encounters a
|
|
86
|
+
# `sig` call, it remembers it and consumes the very next `def` / `def self.foo` as the target.
|
|
87
|
+
# Anything between a sig and its def (a comment is fine — comments aren't AST nodes — but a
|
|
88
|
+
# method call would be a problem) leaves the sig dangling.
|
|
102
89
|
def walk_statements(statements, state, lexical_path:, in_singleton_class:)
|
|
103
90
|
pending_sig = nil
|
|
104
91
|
|
|
@@ -107,18 +94,15 @@ module Rigor
|
|
|
107
94
|
record_def_with_sig(child, pending_sig, state, lexical_path, in_singleton_class)
|
|
108
95
|
pending_sig = nil
|
|
109
96
|
elsif pending_sig && attr_macro_call?(child)
|
|
110
|
-
# `sig { returns(T) }` above `attr_reader :name` /
|
|
111
|
-
#
|
|
112
|
-
# accessor(s)
|
|
113
|
-
# a dangling sig — so record the accessor signature(s)
|
|
114
|
-
# instead of warning.
|
|
97
|
+
# `sig { returns(T) }` above `attr_reader :name` / `attr_accessor` / `attr_writer` types
|
|
98
|
+
# the generated accessor(s). This is a first-class Sorbet idiom — not a dangling sig — so
|
|
99
|
+
# record the accessor signature(s) instead of warning.
|
|
115
100
|
record_attr_with_sig(child, pending_sig, state, lexical_path, in_singleton_class)
|
|
116
101
|
pending_sig = nil
|
|
117
102
|
elsif pending_sig && (inner_def = visibility_wrapped_def(child))
|
|
118
|
-
# `sig { ... }` above `private def foo` /
|
|
119
|
-
# `
|
|
120
|
-
#
|
|
121
|
-
# sig types. Record the inner def, not a dangling sig.
|
|
103
|
+
# `sig { ... }` above `private def foo` / `private_class_method def self.foo` /
|
|
104
|
+
# `module_function def bar` — a visibility macro wrapping the very def the sig types.
|
|
105
|
+
# Record the inner def, not a dangling sig.
|
|
122
106
|
record_def_with_sig(inner_def, pending_sig, state, lexical_path, in_singleton_class)
|
|
123
107
|
pending_sig = nil
|
|
124
108
|
elsif sig_call?(child)
|
|
@@ -129,10 +113,8 @@ module Rigor
|
|
|
129
113
|
state.record_error(:dangling_sig, pending_sig)
|
|
130
114
|
pending_sig = nil
|
|
131
115
|
end
|
|
132
|
-
# ADR-11 slice 8 — record `include` / `extend`
|
|
133
|
-
#
|
|
134
|
-
# plugin's chain lookup can lift sigs declared
|
|
135
|
-
# on a mixed-in module to the host class.
|
|
116
|
+
# ADR-11 slice 8 — record `include` / `extend` declarations alongside the regular walk so
|
|
117
|
+
# the plugin's chain lookup can lift sigs declared on a mixed-in module to the host class.
|
|
136
118
|
record_mixin_call(child, state, lexical_path) if mixin_call?(child) && !in_singleton_class
|
|
137
119
|
walk_node(child, state, lexical_path: lexical_path, in_singleton_class: in_singleton_class)
|
|
138
120
|
end
|
|
@@ -141,12 +123,9 @@ module Rigor
|
|
|
141
123
|
state.record_error(:dangling_sig, pending_sig) if pending_sig
|
|
142
124
|
end
|
|
143
125
|
|
|
144
|
-
# `include Foo` / `extend Foo` / `include Foo, Bar` —
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
# call has no explicit receiver (top-level inside a
|
|
148
|
-
# class body) and every argument is a constant
|
|
149
|
-
# reference.
|
|
126
|
+
# `include Foo` / `extend Foo` / `include Foo, Bar` — the `include` and `extend` mixin macros that
|
|
127
|
+
# Tapioca-generated DSL RBIs depend on. Recognised when the call has no explicit receiver
|
|
128
|
+
# (top-level inside a class body) and every argument is a constant reference.
|
|
150
129
|
def mixin_call?(node)
|
|
151
130
|
return false unless node.is_a?(Prism::CallNode)
|
|
152
131
|
return false unless %i[include extend].include?(node.name)
|
|
@@ -191,12 +170,10 @@ module Rigor
|
|
|
191
170
|
private_class_method public_class_method module_function
|
|
192
171
|
].freeze
|
|
193
172
|
|
|
194
|
-
# `private def foo` / `private_class_method def self.bar` /
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
# The def's own receiver still drives instance-vs-singleton, so
|
|
199
|
-
# `private_class_method def self.bar` records as singleton.
|
|
173
|
+
# `private def foo` / `private_class_method def self.bar` / `module_function def baz` — a
|
|
174
|
+
# receiverless visibility macro whose single argument is the `def` it wraps. Returns the inner
|
|
175
|
+
# `Prism::DefNode` (so a preceding sig types it), or nil. The def's own receiver still drives
|
|
176
|
+
# instance-vs-singleton, so `private_class_method def self.bar` records as singleton.
|
|
200
177
|
def visibility_wrapped_def(node)
|
|
201
178
|
return nil unless node.is_a?(Prism::CallNode) && node.receiver.nil?
|
|
202
179
|
return nil unless VISIBILITY_MACROS.include?(node.name)
|
|
@@ -209,9 +186,8 @@ module Rigor
|
|
|
209
186
|
|
|
210
187
|
ATTR_MACROS = %i[attr_reader attr_writer attr_accessor].freeze
|
|
211
188
|
|
|
212
|
-
# `attr_reader :a, :b` / `attr_writer` / `attr_accessor` —
|
|
213
|
-
#
|
|
214
|
-
# symbol literals (the only shape a preceding `sig` types).
|
|
189
|
+
# `attr_reader :a, :b` / `attr_writer` / `attr_accessor` — a receiverless attribute macro whose
|
|
190
|
+
# arguments are all symbol literals (the only shape a preceding `sig` types).
|
|
215
191
|
def attr_macro_call?(node)
|
|
216
192
|
return false unless node.is_a?(Prism::CallNode) && node.receiver.nil?
|
|
217
193
|
return false unless ATTR_MACROS.include?(node.name)
|
|
@@ -220,11 +196,9 @@ module Rigor
|
|
|
220
196
|
!args.nil? && !args.empty? && args.all?(Prism::SymbolNode)
|
|
221
197
|
end
|
|
222
198
|
|
|
223
|
-
# Records the method signature(s) a `sig` contributes to the
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
# type. `attr_reader` emits the reader, `attr_writer` the
|
|
227
|
-
# writer, `attr_accessor` both — for every symbol argument.
|
|
199
|
+
# Records the method signature(s) a `sig` contributes to the accessor(s) it precedes: the reader
|
|
200
|
+
# `name` and/or the writer `name=`, each carrying the sig's `returns(...)` type. `attr_reader`
|
|
201
|
+
# emits the reader, `attr_writer` the writer, `attr_accessor` both — for every symbol argument.
|
|
228
202
|
def record_attr_with_sig(attr_node, sig_call, state, lexical_path, in_singleton_class)
|
|
229
203
|
parsed = SigParser.parse(sig_call)
|
|
230
204
|
if parsed.is_a?(SigParser::ParseError)
|
|
@@ -273,10 +247,8 @@ module Rigor
|
|
|
273
247
|
in_singleton_class || def_node.receiver.is_a?(Prism::SelfNode)
|
|
274
248
|
end
|
|
275
249
|
|
|
276
|
-
# Resolves a constant-path node (`Foo::Bar`,
|
|
277
|
-
#
|
|
278
|
-
# for the rare dynamic-prefix shape so the walker
|
|
279
|
-
# doesn't guess a qualified name in that case.
|
|
250
|
+
# Resolves a constant-path node (`Foo::Bar`, `::Foo::Bar`) to its dot-separated name. Returns nil
|
|
251
|
+
# for the rare dynamic-prefix shape so the walker doesn't guess a qualified name in that case.
|
|
280
252
|
def qualified_name_for(node)
|
|
281
253
|
case node
|
|
282
254
|
when Prism::ConstantReadNode then node.name.to_s
|
|
@@ -3,19 +3,15 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class Sorbet < Rigor::Plugin::Base
|
|
6
|
-
# Frozen description of one Sorbet `sig` block as parsed by
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# override-compatibility validation are deferred; only the
|
|
10
|
-
# return-type contribution is active.
|
|
6
|
+
# Frozen description of one Sorbet `sig` block as parsed by {SigParser}. Holds the return type,
|
|
7
|
+
# parameter shape, and modifier list. Call-site argument-type checking and override-compatibility
|
|
8
|
+
# validation are deferred; only the return-type contribution is active.
|
|
11
9
|
#
|
|
12
|
-
# `kind` distinguishes `def foo` (`:instance`) from
|
|
13
|
-
# `def self.foo` / `class << self; def foo; end`
|
|
10
|
+
# `kind` distinguishes `def foo` (`:instance`) from `def self.foo` / `class << self; def foo; end`
|
|
14
11
|
# (`:singleton`).
|
|
15
12
|
#
|
|
16
|
-
# `modifiers` records the `sig`-level flags observed:
|
|
17
|
-
# `:
|
|
18
|
-
# Currently stored but not acted on.
|
|
13
|
+
# `modifiers` records the `sig`-level flags observed: `:abstract`, `:override`, `:overridable`,
|
|
14
|
+
# `:final`. Currently stored but not acted on.
|
|
19
15
|
MethodSignature = Data.define(
|
|
20
16
|
:class_name, :method_name, :kind, :params, :return_type, :modifiers
|
|
21
17
|
)
|
|
@@ -7,10 +7,8 @@ require_relative "type_translator"
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Plugin
|
|
9
9
|
class Sorbet < Rigor::Plugin::Base
|
|
10
|
-
# Mini-interpreter for the chained-call expression that
|
|
11
|
-
#
|
|
12
|
-
# a single expression — Sorbet's docs (`sigs.md`) show the
|
|
13
|
-
# full grammar:
|
|
10
|
+
# Mini-interpreter for the chained-call expression that makes up a Sorbet `sig` block. The block
|
|
11
|
+
# body is always a single expression — Sorbet's docs (`sigs.md`) show the full grammar:
|
|
14
12
|
#
|
|
15
13
|
# sig { params(x: T, y: T).returns(U) }
|
|
16
14
|
# sig { void }
|
|
@@ -22,26 +20,20 @@ module Rigor
|
|
|
22
20
|
# .returns(...)
|
|
23
21
|
# end
|
|
24
22
|
#
|
|
25
|
-
# The parser walks the chain right-to-left, gathering
|
|
26
|
-
#
|
|
27
|
-
# `
|
|
28
|
-
# `type_parameters`
|
|
29
|
-
# frozen result hash stored in {MethodSignature}. Modifiers
|
|
30
|
-
# and `type_parameters` are recorded but not yet acted on.
|
|
23
|
+
# The parser walks the chain right-to-left, gathering whatever it recognises (`params` / `returns` /
|
|
24
|
+
# `void` / `abstract` / `override` / `overridable` / `final` / `type_parameters` / `checked` /
|
|
25
|
+
# `on_failure`) into a frozen result hash stored in {MethodSignature}. Modifiers and
|
|
26
|
+
# `type_parameters` are recorded but not yet acted on.
|
|
31
27
|
#
|
|
32
|
-
# The parser is intentionally tolerant — unknown chain
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# (`plugin.sorbet.parse-error`) only when the entire chain
|
|
36
|
-
# fails to yield either a `returns` or a `void`.
|
|
28
|
+
# The parser is intentionally tolerant — unknown chain nodes degrade to "the rest of the chain is
|
|
29
|
+
# opaque" rather than raising. The plugin emits a diagnostic (`plugin.sorbet.parse-error`) only when
|
|
30
|
+
# the entire chain fails to yield either a `returns` or a `void`.
|
|
37
31
|
module SigParser
|
|
38
|
-
# Modifiers we recognise at any position in the chain.
|
|
39
|
-
# Stored in `:modifiers` on the parse result.
|
|
32
|
+
# Modifiers we recognise at any position in the chain. Stored in `:modifiers` on the parse result.
|
|
40
33
|
RECOGNISED_MODIFIERS = %i[abstract override overridable final].freeze
|
|
41
34
|
|
|
42
|
-
# Sorbet runtime-only chain steps. Recognised so the
|
|
43
|
-
#
|
|
44
|
-
# but their payload is intentionally discarded.
|
|
35
|
+
# Sorbet runtime-only chain steps. Recognised so the parser doesn't degrade the whole sig when it
|
|
36
|
+
# sees them, but their payload is intentionally discarded.
|
|
45
37
|
RUNTIME_ONLY_STEPS = %i[checked on_failure].freeze
|
|
46
38
|
|
|
47
39
|
ParseResult = Data.define(:return_type, :params, :modifiers, :void) do
|
|
@@ -52,8 +44,7 @@ module Rigor
|
|
|
52
44
|
|
|
53
45
|
module_function
|
|
54
46
|
|
|
55
|
-
# @param sig_call [Prism::CallNode] the `sig { ... }` /
|
|
56
|
-
# `sig do ... end` call.
|
|
47
|
+
# @param sig_call [Prism::CallNode] the `sig { ... }` / `sig do ... end` call.
|
|
57
48
|
# @return [ParseResult, ParseError]
|
|
58
49
|
def parse(sig_call)
|
|
59
50
|
return ParseError.new(reason: :no_block, node: sig_call) if sig_call.block.nil?
|
|
@@ -72,11 +63,9 @@ module Rigor
|
|
|
72
63
|
end
|
|
73
64
|
end
|
|
74
65
|
|
|
75
|
-
# Walks the chain bottom-up. Each chain link is a
|
|
76
|
-
# `
|
|
77
|
-
#
|
|
78
|
-
# position, so we accumulate their effect into a
|
|
79
|
-
# mutable hash and freeze on the way out.
|
|
66
|
+
# Walks the chain bottom-up. Each chain link is a `Prism::CallNode` whose receiver is the next
|
|
67
|
+
# link; `params` / `returns` / `void` may appear at any position, so we accumulate their effect
|
|
68
|
+
# into a mutable hash and freeze on the way out.
|
|
80
69
|
def fold_chain(node, sig_call)
|
|
81
70
|
accumulator = { return_type: nil, params: {}, modifiers: [], void: false, terminus_kind: nil }
|
|
82
71
|
current = node
|
|
@@ -92,15 +81,13 @@ module Rigor
|
|
|
92
81
|
when :params
|
|
93
82
|
accumulator[:params].merge!(parse_params(current))
|
|
94
83
|
when :type_parameters
|
|
95
|
-
# Recognised to suppress the degraded path;
|
|
96
|
-
# payload intentionally discarded (deferred).
|
|
84
|
+
# Recognised to suppress the degraded path; payload intentionally discarded (deferred).
|
|
97
85
|
when *RECOGNISED_MODIFIERS
|
|
98
86
|
accumulator[:modifiers] << current.name
|
|
99
87
|
when *RUNTIME_ONLY_STEPS
|
|
100
88
|
# Discard payload; runtime-only.
|
|
101
89
|
else
|
|
102
|
-
# Unknown chain link — stop folding and treat
|
|
103
|
-
# whatever we accumulated so far as the result.
|
|
90
|
+
# Unknown chain link — stop folding and treat whatever we accumulated so far as the result.
|
|
104
91
|
break
|
|
105
92
|
end
|
|
106
93
|
current = current.receiver
|
|
@@ -116,20 +103,16 @@ module Rigor
|
|
|
116
103
|
)
|
|
117
104
|
end
|
|
118
105
|
|
|
119
|
-
# `void` and `returns(T)` share the slot; if both are
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# "discard the value" — when the user explicitly named
|
|
123
|
-
# `T`, that's the more informative shape.
|
|
106
|
+
# `void` and `returns(T)` share the slot; if both are present (unusual but parseable), `returns(T)`
|
|
107
|
+
# wins because Sorbet's static side treats `void` as "discard the value" — when the user
|
|
108
|
+
# explicitly named `T`, that's the more informative shape.
|
|
124
109
|
def resolve_return_type(accumulator)
|
|
125
110
|
accumulator[:return_type] || Rigor::Type::Combinator.untyped
|
|
126
111
|
end
|
|
127
112
|
|
|
128
|
-
# `params(x: Integer, y: T.nilable(String))` — extracts
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# double-splat / unrecognised keys degrade silently
|
|
132
|
-
# (slice 1 behaviour).
|
|
113
|
+
# `params(x: Integer, y: T.nilable(String))` — extracts the `KeywordHashNode` AST and translates
|
|
114
|
+
# each value. The result is `{ Symbol => Rigor::Type }`. Splat / double-splat / unrecognised keys
|
|
115
|
+
# degrade silently (slice 1 behaviour).
|
|
133
116
|
def parse_params(call_node)
|
|
134
117
|
args = call_node.arguments&.arguments || []
|
|
135
118
|
first = args.first
|
|
@@ -3,49 +3,36 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class Sorbet < Rigor::Plugin::Base
|
|
6
|
-
# Reads Sorbet's `# typed: <level>` magic comment from the
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# may appear after a few comment / blank lines (matching
|
|
12
|
-
# what Sorbet itself accepts in practice) but we stop
|
|
13
|
-
# scanning once we hit a non-comment, non-blank line.
|
|
6
|
+
# Reads Sorbet's `# typed: <level>` magic comment from the head of a file. Sorbet's own contract (per
|
|
7
|
+
# [`static.md`](https://sorbet.org/docs/static)) requires the sigil to appear at the top of the file
|
|
8
|
+
# before any Ruby code. We're slightly more lenient here — the sigil may appear after a few comment
|
|
9
|
+
# / blank lines (matching what Sorbet itself accepts in practice) but we stop scanning once we hit a
|
|
10
|
+
# non-comment, non-blank line.
|
|
14
11
|
#
|
|
15
|
-
# Recognised levels: `:ignore` / `:false` / `:true` /
|
|
16
|
-
#
|
|
17
|
-
# default) when no sigil is present, matching how Sorbet
|
|
18
|
-
# treats sigil-less files.
|
|
12
|
+
# Recognised levels: `:ignore` / `:false` / `:true` / `:strict` / `:strong`. Falls back to `:false`
|
|
13
|
+
# (Sorbet's default) when no sigil is present, matching how Sorbet treats sigil-less files.
|
|
19
14
|
#
|
|
20
|
-
# ADR-11 slice 5 uses this at catalog-harvest time:
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# `:strong` only) and per-call assertion recognition
|
|
24
|
-
# (`T.let` / `T.cast` / `T.must` / etc.) via
|
|
25
|
-
# `Sorbet#assertion_enforced_here?`.
|
|
15
|
+
# ADR-11 slice 5 uses this at catalog-harvest time: `# typed: ignore` files are skipped entirely;
|
|
16
|
+
# other levels gate both sig contributions (`:true`/`:strict`/`:strong` only) and per-call assertion
|
|
17
|
+
# recognition (`T.let` / `T.cast` / `T.must` / etc.) via `Sorbet#assertion_enforced_here?`.
|
|
26
18
|
module SigilDetector
|
|
27
|
-
# Sorbet's strictness-level names. Stored as symbols to
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# level *names* (the textual sigil values) and are
|
|
31
|
-
# intentionally distinct from the `true` / `false`
|
|
32
|
-
# boolean literals.
|
|
19
|
+
# Sorbet's strictness-level names. Stored as symbols to match the analyzer's existing convention
|
|
20
|
+
# for level identifiers; the `:true` / `:false` symbols here are level *names* (the textual sigil
|
|
21
|
+
# values) and are intentionally distinct from the `true` / `false` boolean literals.
|
|
33
22
|
VALID_LEVELS = %i[ignore false true strict strong].freeze
|
|
34
23
|
DEFAULT_LEVEL = :false # rubocop:disable Lint/BooleanSymbol
|
|
35
24
|
SIGIL_REGEX = /\A\s*#\s*typed\s*:\s*(ignore|false|true|strict|strong)\s*\z/
|
|
36
25
|
|
|
37
|
-
# Cap on how many lines we scan before giving up. Sorbet
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# generous and bounds the parse cost on enormous files.
|
|
26
|
+
# Cap on how many lines we scan before giving up. Sorbet doesn't formally specify a cap, but the
|
|
27
|
+
# sigil convention is "near the top of the file"; 10 lines is generous and bounds the parse cost
|
|
28
|
+
# on enormous files.
|
|
41
29
|
MAX_HEAD_LINES = 10
|
|
42
30
|
|
|
43
31
|
module_function
|
|
44
32
|
|
|
45
33
|
# @param contents [String] raw file contents.
|
|
46
|
-
# @return [Symbol] one of {VALID_LEVELS}; defaults to
|
|
47
|
-
#
|
|
48
|
-
# files.
|
|
34
|
+
# @return [Symbol] one of {VALID_LEVELS}; defaults to {DEFAULT_LEVEL} for sigil-less or
|
|
35
|
+
# malformed-sigil files.
|
|
49
36
|
def detect(contents)
|
|
50
37
|
return DEFAULT_LEVEL if contents.nil? || contents.empty?
|
|
51
38
|
|
|
@@ -57,9 +44,8 @@ module Rigor
|
|
|
57
44
|
|
|
58
45
|
match = SIGIL_REGEX.match(stripped)
|
|
59
46
|
return match[1].to_sym if match
|
|
60
|
-
# First non-blank line that isn't a sigil-shaped
|
|
61
|
-
#
|
|
62
|
-
# the first directive-or-code line.
|
|
47
|
+
# First non-blank line that isn't a sigil-shaped comment ends the scan: Sorbet's parser stops
|
|
48
|
+
# at the first directive-or-code line.
|
|
63
49
|
break unless stripped.start_with?("#")
|
|
64
50
|
end
|
|
65
51
|
|
|
@@ -67,27 +53,20 @@ module Rigor
|
|
|
67
53
|
end
|
|
68
54
|
|
|
69
55
|
# @param level [Symbol]
|
|
70
|
-
# @return [Boolean] true when `# typed: ignore`. The
|
|
71
|
-
# harvest pipeline calls this to short-circuit
|
|
56
|
+
# @return [Boolean] true when `# typed: ignore`. The harvest pipeline calls this to short-circuit
|
|
72
57
|
# walking the file's AST.
|
|
73
58
|
def ignored?(level)
|
|
74
59
|
level == :ignore
|
|
75
60
|
end
|
|
76
61
|
|
|
77
|
-
# @return [Boolean] true when `level` is at or above the
|
|
78
|
-
#
|
|
79
|
-
# `
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# suppressed — matching how Sorbet itself only
|
|
86
|
-
# enforces type errors at `# typed: true`+. Assertion
|
|
87
|
-
# recognisers (`T.let` / `T.cast` / `T.must` /
|
|
88
|
-
# `T.bind` / `T.assert_type!`) are NOT gated by this:
|
|
89
|
-
# the user wrote them deliberately, so the
|
|
90
|
-
# recogniser still fires regardless of sigil.
|
|
62
|
+
# @return [Boolean] true when `level` is at or above the `# typed: true` mark. Used by the
|
|
63
|
+
# `enforce_sigil` config gate (default `true`): with the gate on, only files marked `:true` /
|
|
64
|
+
# `:strict` / `:strong` contribute their sigs to the catalog. The `:false` (and sigil-less)
|
|
65
|
+
# levels still get walked (so RBI files outside the project can be loaded regardless), but their
|
|
66
|
+
# sig-derived narrowing is suppressed — matching how Sorbet itself only enforces type errors at
|
|
67
|
+
# `# typed: true`+. Assertion recognisers (`T.let` / `T.cast` / `T.must` / `T.bind` /
|
|
68
|
+
# `T.assert_type!`) are NOT gated by this: the user wrote them deliberately, so the recogniser
|
|
69
|
+
# still fires regardless of sigil.
|
|
91
70
|
def enforced?(level)
|
|
92
71
|
%i[true strict strong].include?(level)
|
|
93
72
|
end
|