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
|
@@ -7,17 +7,13 @@ require_relative "buffer_resolution"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module LanguageServer
|
|
10
|
-
# Answers `textDocument/foldingRange` requests. Walks the Prism
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# block (`do…end` or `{…}`). Skips single-line constructs
|
|
14
|
-
# (start_line == end_line) since there's nothing to fold.
|
|
10
|
+
# Answers `textDocument/foldingRange` requests. Walks the Prism AST and emits one `FoldingRange` per
|
|
11
|
+
# foldable construct: `class` / `module` / `def` / `singleton class << self` / block (`do…end` or `{…}`).
|
|
12
|
+
# Skips single-line constructs (start_line == end_line) since there's nothing to fold.
|
|
15
13
|
#
|
|
16
|
-
# Ranges are LSP 0-based. `startLine` is the line containing
|
|
17
|
-
# the
|
|
18
|
-
#
|
|
19
|
-
# collapsed view shows the opener intact and hides the body
|
|
20
|
-
# only.
|
|
14
|
+
# Ranges are LSP 0-based. `startLine` is the line containing the opening keyword (`class`, `def`); `endLine`
|
|
15
|
+
# is the last line OF the body — one line before the `end` keyword — so collapsed view shows the opener
|
|
16
|
+
# intact and hides the body only.
|
|
21
17
|
class FoldingRangeProvider
|
|
22
18
|
include BufferResolution
|
|
23
19
|
|
|
@@ -34,9 +30,8 @@ module Rigor
|
|
|
34
30
|
|
|
35
31
|
parse_result = Prism.parse(entry.bytes, filepath: path,
|
|
36
32
|
version: @project_context.configuration.target_ruby)
|
|
37
|
-
# Tolerate partial parse errors — fold whatever AST Prism
|
|
38
|
-
#
|
|
39
|
-
# over none.
|
|
33
|
+
# Tolerate partial parse errors — fold whatever AST Prism produced. Editors prefer a stale outline /
|
|
34
|
+
# fold map over none.
|
|
40
35
|
ranges = []
|
|
41
36
|
walk(parse_result.value, ranges)
|
|
42
37
|
ranges
|
|
@@ -59,12 +54,9 @@ module Rigor
|
|
|
59
54
|
def add_range(node, ranges)
|
|
60
55
|
loc = node.location
|
|
61
56
|
start_line = loc.start_line - 1
|
|
62
|
-
# `end_line` includes the line of the `end` keyword.
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# before `end`. When the body is a single line, that
|
|
66
|
-
# makes start == end (one-line fold), which most editors
|
|
67
|
-
# skip; we filter those out.
|
|
57
|
+
# `end_line` includes the line of the `end` keyword. Folding should hide the body and leave both the
|
|
58
|
+
# opener AND the `end` keyword visible — so endLine is one line before `end`. When the body is a single
|
|
59
|
+
# line, that makes start == end (one-line fold), which most editors skip; we filter those out.
|
|
68
60
|
end_line = loc.end_line - 2
|
|
69
61
|
return if end_line <= start_line
|
|
70
62
|
|
|
@@ -12,16 +12,14 @@ require_relative "../inference/scope_indexer"
|
|
|
12
12
|
|
|
13
13
|
module Rigor
|
|
14
14
|
module LanguageServer
|
|
15
|
-
# Answers `textDocument/hover` requests by running the same
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# `Hover` payload with markdown contents.
|
|
15
|
+
# Answers `textDocument/hover` requests by running the same NodeLocator + ScopeIndexer + `Scope#type_of`
|
|
16
|
+
# chain that `rigor type-of` already drives. The LSP wraps the result in a `Hover` payload with markdown
|
|
17
|
+
# contents.
|
|
19
18
|
#
|
|
20
19
|
# Per LSP spec § "Position":
|
|
21
20
|
# - `line` and `character` are 0-based.
|
|
22
|
-
# - `character` counts UTF-16 code units; v1 emits byte counts
|
|
23
|
-
#
|
|
24
|
-
# doc § "Open questions").
|
|
21
|
+
# - `character` counts UTF-16 code units; v1 emits byte counts for ASCII source (UTF-16 conversion is
|
|
22
|
+
# queued, see design doc § "Open questions").
|
|
25
23
|
class HoverProvider
|
|
26
24
|
include BufferResolution
|
|
27
25
|
|
|
@@ -42,8 +40,7 @@ module Rigor
|
|
|
42
40
|
parse_result = Prism.parse(entry.bytes, filepath: path, version: @project_context.configuration.target_ruby)
|
|
43
41
|
return nil unless parse_result.errors.empty?
|
|
44
42
|
|
|
45
|
-
# Rigor's NodeLocator uses 1-based line / column; LSP uses
|
|
46
|
-
# 0-based. Translate at the boundary.
|
|
43
|
+
# Rigor's NodeLocator uses 1-based line / column; LSP uses 0-based. Translate at the boundary.
|
|
47
44
|
node = locate_node(source: entry.bytes, root: parse_result.value, line: line + 1, character: character + 1)
|
|
48
45
|
return nil if node.nil?
|
|
49
46
|
|
|
@@ -64,8 +61,8 @@ module Rigor
|
|
|
64
61
|
end
|
|
65
62
|
|
|
66
63
|
def base_scope(_path)
|
|
67
|
-
# Pulls the Environment from the cached ProjectContext so
|
|
68
|
-
#
|
|
64
|
+
# Pulls the Environment from the cached ProjectContext so each hover avoids repeating the RBS-load
|
|
65
|
+
# build.
|
|
69
66
|
Scope.empty(environment: @project_context.environment)
|
|
70
67
|
end
|
|
71
68
|
end
|
|
@@ -9,18 +9,14 @@ require_relative "../type/difference"
|
|
|
9
9
|
|
|
10
10
|
module Rigor
|
|
11
11
|
module LanguageServer
|
|
12
|
-
# Builds the LSP `Hover.contents` markdown body. Dispatches on
|
|
13
|
-
#
|
|
14
|
-
# constant, local, ivar, literal) gets the most relevant
|
|
15
|
-
# type-aware presentation per
|
|
12
|
+
# Builds the LSP `Hover.contents` markdown body. Dispatches on the hovered Prism node class so each shape
|
|
13
|
+
# (method call, constant, local, ivar, literal) gets the most relevant type-aware presentation per
|
|
16
14
|
# `docs/design/20260517-lsp-hover-completion.md`.
|
|
17
15
|
class HoverRenderer
|
|
18
|
-
# @param node_scope_lookup [#[]] node-to-scope table built
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# Hash carries `default_scope` as its default value), so
|
|
23
|
-
# the renderer trusts the lookup result.
|
|
16
|
+
# @param node_scope_lookup [#[]] node-to-scope table built by `ScopeIndexer.index`. The renderer indexes
|
|
17
|
+
# into it to retrieve the receiver's narrow scope when specialising on `CallNode`. The lookup never
|
|
18
|
+
# returns nil (the indexer's Hash carries `default_scope` as its default value), so the renderer trusts
|
|
19
|
+
# the lookup result.
|
|
24
20
|
def render(node:, type:, node_scope_lookup:)
|
|
25
21
|
body = render_body(node, type, node_scope_lookup)
|
|
26
22
|
result = { contents: { kind: "markdown", value: body } }
|
|
@@ -30,11 +26,9 @@ module Rigor
|
|
|
30
26
|
|
|
31
27
|
private
|
|
32
28
|
|
|
33
|
-
# Converts a Prism `Location` to an LSP `Range` (0-based
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# ASCII source; non-ASCII falls back gracefully because
|
|
37
|
-
# clients clamp out-of-range columns to the end of line.
|
|
29
|
+
# Converts a Prism `Location` to an LSP `Range` (0-based line, 0-based UTF-16-character column). UTF-16
|
|
30
|
+
# conversion is queued — slice E1 emits byte columns which match for ASCII source; non-ASCII falls back
|
|
31
|
+
# gracefully because clients clamp out-of-range columns to the end of line.
|
|
38
32
|
def lsp_range_for(node)
|
|
39
33
|
loc = node.location
|
|
40
34
|
{
|
|
@@ -65,12 +59,10 @@ module Rigor
|
|
|
65
59
|
end
|
|
66
60
|
end
|
|
67
61
|
|
|
68
|
-
# Renders a `CallNode` hover when the receiver's type can be
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# — those land in slices A2-A4 and slice 7); the caller falls
|
|
73
|
-
# back to the default body.
|
|
62
|
+
# Renders a `CallNode` hover when the receiver's type can be mapped to a known RBS class and the method
|
|
63
|
+
# is declared there. Returns nil for shapes the slice-A1 floor doesn't handle (implicit `self`, Union /
|
|
64
|
+
# Refined / Shape receivers — those land in slices A2-A4 and slice 7); the caller falls back to the
|
|
65
|
+
# default body.
|
|
74
66
|
def render_call(call_node, return_type, node_scope_lookup)
|
|
75
67
|
receiver_node = call_node.receiver
|
|
76
68
|
return nil if receiver_node.nil?
|
|
@@ -91,11 +83,9 @@ module Rigor
|
|
|
91
83
|
)
|
|
92
84
|
end
|
|
93
85
|
|
|
94
|
-
# @return [[RBS::Definition::Method, String, Symbol], nil]
|
|
95
|
-
# the
|
|
96
|
-
#
|
|
97
|
-
# when the receiver shape isn't yet supported or the
|
|
98
|
-
# method doesn't resolve through the RBS env.
|
|
86
|
+
# @return [[RBS::Definition::Method, String, Symbol], nil] the resolved method definition, the receiver
|
|
87
|
+
# class name, and the dispatch kind (`:instance` or `:singleton`); nil when the receiver shape isn't
|
|
88
|
+
# yet supported or the method doesn't resolve through the RBS env.
|
|
99
89
|
def lookup_method(receiver_type, method_name, scope)
|
|
100
90
|
case receiver_type
|
|
101
91
|
when Type::Singleton
|
|
@@ -114,13 +104,10 @@ module Rigor
|
|
|
114
104
|
end
|
|
115
105
|
end
|
|
116
106
|
|
|
117
|
-
# Maps a receiver carrier to the underlying RBS class name
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# where the value's runtime class is the receiver). Other
|
|
122
|
-
# carriers fall through to the default hover; slice 7 of the
|
|
123
|
-
# design adds Union / Refined / Shape handling.
|
|
107
|
+
# Maps a receiver carrier to the underlying RBS class name for method lookup. v1 handles the two carriers
|
|
108
|
+
# that produce well-defined ".methods to enumerate" semantics: `Nominal[C]` (the canonical case) and
|
|
109
|
+
# `Constant<v>` (literal scalars, where the value's runtime class is the receiver). Other carriers fall
|
|
110
|
+
# through to the default hover; slice 7 of the design adds Union / Refined / Shape handling.
|
|
124
111
|
def nominal_class_name(type)
|
|
125
112
|
case type
|
|
126
113
|
when Type::Nominal then type.class_name
|
|
@@ -128,12 +115,9 @@ module Rigor
|
|
|
128
115
|
end
|
|
129
116
|
end
|
|
130
117
|
|
|
131
|
-
# `Type::Constant<value>`'s `value` is the literal Ruby
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
# dispatcher already widens a literal to its nominal class
|
|
135
|
-
# at the call site — keep these in sync if a new literal
|
|
136
|
-
# carrier lands.
|
|
118
|
+
# `Type::Constant<value>`'s `value` is the literal Ruby object; map it to the RBS-canonical class name
|
|
119
|
+
# through `Object#class`. The cross-runtime mapping mirrors how the dispatcher already widens a literal
|
|
120
|
+
# to its nominal class at the call site — keep these in sync if a new literal carrier lands.
|
|
137
121
|
def constant_to_class_name(value)
|
|
138
122
|
value.class.name
|
|
139
123
|
end
|
|
@@ -149,21 +133,17 @@ module Rigor
|
|
|
149
133
|
body << "#{return_type.describe}\n"
|
|
150
134
|
body << "```"
|
|
151
135
|
if (doc = rbs_documentation(definition))
|
|
152
|
-
# Close the code fence first so the comment text renders
|
|
153
|
-
#
|
|
154
|
-
# plain markdown below the code reads better in clients.
|
|
136
|
+
# Close the code fence first so the comment text renders as prose, then a fresh fenced block isn't
|
|
137
|
+
# necessary — plain markdown below the code reads better in clients.
|
|
155
138
|
body << "\n\n---\n\n#{doc}"
|
|
156
139
|
end
|
|
157
140
|
body
|
|
158
141
|
end
|
|
159
142
|
|
|
160
|
-
# Returns the concatenated text of every RBS comment attached
|
|
161
|
-
#
|
|
162
|
-
# `
|
|
163
|
-
#
|
|
164
|
-
# terminated `# foo` lines). Multiple comments are joined
|
|
165
|
-
# with a blank line so each upstream `# Foo bar` paragraph
|
|
166
|
-
# is preserved.
|
|
143
|
+
# Returns the concatenated text of every RBS comment attached to the method definition, or nil when no
|
|
144
|
+
# comments exist. `RBS::Definition::Method#comments` is an Array<AST::Comment> with each entry's
|
|
145
|
+
# `.string` carrying the raw text (newline-terminated `# foo` lines). Multiple comments are joined with a
|
|
146
|
+
# blank line so each upstream `# Foo bar` paragraph is preserved.
|
|
167
147
|
def rbs_documentation(definition)
|
|
168
148
|
comments = definition.respond_to?(:comments) ? definition.comments : nil
|
|
169
149
|
return nil if comments.nil? || comments.empty?
|
|
@@ -172,9 +152,8 @@ module Rigor
|
|
|
172
152
|
text.empty? ? nil : text
|
|
173
153
|
end
|
|
174
154
|
|
|
175
|
-
# v1 surfaces the FIRST overload only. Multi-overload
|
|
176
|
-
#
|
|
177
|
-
# — multi-overload signature display).
|
|
155
|
+
# v1 surfaces the FIRST overload only. Multi-overload presentation is queued (design doc § "Out of scope
|
|
156
|
+
# for v2" — multi-overload signature display).
|
|
178
157
|
def first_method_type(definition)
|
|
179
158
|
method_type = definition.method_types.first
|
|
180
159
|
return "(unknown)" if method_type.nil?
|
|
@@ -182,11 +161,9 @@ module Rigor
|
|
|
182
161
|
method_type.to_s
|
|
183
162
|
end
|
|
184
163
|
|
|
185
|
-
# Specialises `ConstantReadNode` (`Foo`) and `ConstantPathNode`
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
# for constants pointing at values (`FOO = 42`); those fall
|
|
189
|
-
# through to the literal-polish slice (A4).
|
|
164
|
+
# Specialises `ConstantReadNode` (`Foo`) and `ConstantPathNode` (`Foo::Bar`) when the inferred type is a
|
|
165
|
+
# `Type::Singleton` — i.e., the constant refers to a class / module. Returns nil for constants pointing
|
|
166
|
+
# at values (`FOO = 42`); those fall through to the literal-polish slice (A4).
|
|
190
167
|
def render_constant(node, type, node_scope_lookup)
|
|
191
168
|
return nil unless type.is_a?(Type::Singleton)
|
|
192
169
|
|
|
@@ -202,10 +179,9 @@ module Rigor
|
|
|
202
179
|
body
|
|
203
180
|
end
|
|
204
181
|
|
|
205
|
-
# Resolves the source-file location for a class FQN by reading
|
|
206
|
-
# the
|
|
207
|
-
#
|
|
208
|
-
# it with a sentinel, see `RunStats.attribution_available?`).
|
|
182
|
+
# Resolves the source-file location for a class FQN by reading the RBS loader's `class_decl_paths` table.
|
|
183
|
+
# Returns nil when the table doesn't carry attribution (cache-hit paths replace it with a sentinel, see
|
|
184
|
+
# `RunStats.attribution_available?`).
|
|
209
185
|
def defined_in(fqn, scope)
|
|
210
186
|
loader = scope&.environment&.rbs_loader
|
|
211
187
|
return nil if loader.nil?
|
|
@@ -216,12 +192,9 @@ module Rigor
|
|
|
216
192
|
path
|
|
217
193
|
end
|
|
218
194
|
|
|
219
|
-
# Specialises local-variable reads / writes / target nodes.
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
# {name => Type} but not the binding location); when the
|
|
223
|
-
# ScopeIndexer grows a side-table for it, slice A3 follow-up
|
|
224
|
-
# can fill the row in.
|
|
195
|
+
# Specialises local-variable reads / writes / target nodes. Surfaces the variable name + narrowed type.
|
|
196
|
+
# "Bound at" source-line attribution is queued (Scope#locals tracks {name => Type} but not the binding
|
|
197
|
+
# location); when the ScopeIndexer grows a side-table for it, slice A3 follow-up can fill the row in.
|
|
225
198
|
def render_local(node, type)
|
|
226
199
|
body = +"```ruby\n"
|
|
227
200
|
body << "# Local\n#{node.name}\n\n"
|
|
@@ -230,11 +203,9 @@ module Rigor
|
|
|
230
203
|
body
|
|
231
204
|
end
|
|
232
205
|
|
|
233
|
-
# Specialises instance-variable reads / writes / targets.
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
-
# the self_type isn't a Nominal (e.g., top-level main) the
|
|
237
|
-
# enclosing-class row is omitted.
|
|
206
|
+
# Specialises instance-variable reads / writes / targets. Surfaces the ivar name + narrowed type + the
|
|
207
|
+
# enclosing class context derived from the scope's `self_type`. When the self_type isn't a Nominal (e.g.,
|
|
208
|
+
# top-level main) the enclosing-class row is omitted.
|
|
238
209
|
def render_ivar(node, type, node_scope_lookup)
|
|
239
210
|
scope = node_scope_lookup[node]
|
|
240
211
|
body = +"```ruby\n"
|
|
@@ -249,20 +220,16 @@ module Rigor
|
|
|
249
220
|
|
|
250
221
|
def enclosing_class_for(scope)
|
|
251
222
|
self_type = scope.self_type
|
|
252
|
-
# Both `Nominal[C]` and `Singleton[C]` carry `class_name`;
|
|
253
|
-
#
|
|
254
|
-
# keeps the slice-A3 contract simple.
|
|
223
|
+
# Both `Nominal[C]` and `Singleton[C]` carry `class_name`; we want the class label either way. Combined
|
|
224
|
+
# branch keeps the slice-A3 contract simple.
|
|
255
225
|
self_type.class_name if self_type.is_a?(Type::Nominal) || self_type.is_a?(Type::Singleton)
|
|
256
226
|
end
|
|
257
227
|
|
|
258
|
-
# Specialises literal-bearing nodes (Integer / Float / String /
|
|
259
|
-
#
|
|
260
|
-
# the
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
# the shape carriers (`Tuple<...>` / `HashShape<...>`) already
|
|
264
|
-
# describe element types, so the framing is identical to
|
|
265
|
-
# primitive literals.
|
|
228
|
+
# Specialises literal-bearing nodes (Integer / Float / String / Symbol / Regex / true / false / nil /
|
|
229
|
+
# Array / Hash). Drops the slice-A1 `node:` debug row in favour of a cleaner `# Type` + `# Erased`
|
|
230
|
+
# framing, and surfaces the refinement / difference name when one is present. For Array / Hash the shape
|
|
231
|
+
# carriers (`Tuple<...>` / `HashShape<...>`) already describe element types, so the framing is identical
|
|
232
|
+
# to primitive literals.
|
|
266
233
|
def render_literal(_node, type)
|
|
267
234
|
body = +"```ruby\n"
|
|
268
235
|
body << "# Type\n#{type.describe}\n"
|
|
@@ -274,16 +241,12 @@ module Rigor
|
|
|
274
241
|
body
|
|
275
242
|
end
|
|
276
243
|
|
|
277
|
-
# Surfaces the canonical kebab-case refinement name when the
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
#
|
|
283
|
-
# display-level metadata. Returns nil for unrefined carriers
|
|
284
|
-
# and for refinements that don't have a canonical name (those
|
|
285
|
-
# are presented through the predicate-id operator form by
|
|
286
|
-
# `describe`).
|
|
244
|
+
# Surfaces the canonical kebab-case refinement name when the type is a `Refined` or `Difference` carrier
|
|
245
|
+
# with a registered canonical_name (e.g. `non-empty-string` / `positive-int`). `canonical_name` is
|
|
246
|
+
# private on both carriers; the LSP layer is a trusted internal consumer and `send` is the documented
|
|
247
|
+
# escape hatch for surfacing display-level metadata. Returns nil for unrefined carriers and for
|
|
248
|
+
# refinements that don't have a canonical name (those are presented through the predicate-id operator
|
|
249
|
+
# form by `describe`).
|
|
287
250
|
def refinement_name_for(type)
|
|
288
251
|
return nil unless type.is_a?(Type::Refined) || type.is_a?(Type::Difference)
|
|
289
252
|
|
|
@@ -5,24 +5,20 @@ require "language_server-protocol"
|
|
|
5
5
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module LanguageServer
|
|
8
|
-
# JSON-RPC dispatch loop. Drains messages from `reader`, routes
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# its end of the pipe) or the server transitions to `:exited`.
|
|
8
|
+
# JSON-RPC dispatch loop. Drains messages from `reader`, routes each to `server.dispatch`, and writes
|
|
9
|
+
# responses back through `writer`. Stops when either the reader hits EOF (client closed its end of the
|
|
10
|
+
# pipe) or the server transitions to `:exited`.
|
|
12
11
|
#
|
|
13
|
-
# The Loop knows the request / notification distinction from the
|
|
14
|
-
#
|
|
12
|
+
# The Loop knows the request / notification distinction from the presence of the `id` field on the inbound
|
|
13
|
+
# JSON-RPC envelope:
|
|
15
14
|
#
|
|
16
|
-
# - Request (`id` present) → ALWAYS gets a response (success or
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# - Notification (`id` absent) → NEVER gets a response. The
|
|
20
|
-
# dispatcher's return value is discarded.
|
|
15
|
+
# - Request (`id` present) → ALWAYS gets a response (success or error). `Server#dispatch` returning nil
|
|
16
|
+
# for a request maps to `result: null` per the LSP shutdown contract.
|
|
17
|
+
# - Notification (`id` absent) → NEVER gets a response. The dispatcher's return value is discarded.
|
|
21
18
|
#
|
|
22
|
-
# JSON parse errors at the framing boundary surface as an LSP
|
|
23
|
-
# `
|
|
24
|
-
#
|
|
25
|
-
# poison the rest of the session.
|
|
19
|
+
# JSON parse errors at the framing boundary surface as an LSP `ParseError` (-32700) response with
|
|
20
|
+
# `id: null` per JSON-RPC spec § 5.1; the loop continues so a corrupt frame doesn't poison the rest of the
|
|
21
|
+
# session.
|
|
26
22
|
class Loop
|
|
27
23
|
def initialize(reader:, writer:, server:)
|
|
28
24
|
@reader = reader
|
|
@@ -52,13 +48,12 @@ module Rigor
|
|
|
52
48
|
write_response(id, result)
|
|
53
49
|
end
|
|
54
50
|
|
|
55
|
-
# Maps the dispatcher's return value to a JSON-RPC response
|
|
56
|
-
#
|
|
51
|
+
# Maps the dispatcher's return value to a JSON-RPC response envelope. `Server#dispatch` returns one of
|
|
52
|
+
# three shapes:
|
|
57
53
|
#
|
|
58
54
|
# - `{ error: {...} }` — surfaced as `{ id, error: {...} }`.
|
|
59
55
|
# - any other Hash — surfaced as `{ id, result: hash }`.
|
|
60
|
-
# - `nil` — surfaced as `{ id, result: null }` (the LSP
|
|
61
|
-
# `shutdown` contract).
|
|
56
|
+
# - `nil` — surfaced as `{ id, result: null }` (the LSP `shutdown` contract).
|
|
62
57
|
def write_response(id, result)
|
|
63
58
|
if result.is_a?(Hash) && result.key?(:error)
|
|
64
59
|
@writer.write(id: id, error: result[:error])
|
|
@@ -6,49 +6,33 @@ require_relative "../analysis/runner"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module LanguageServer
|
|
9
|
-
# Per-session cache of the project-wide analyzer state the LSP
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# {Rigor::Analysis::ProjectScan} snapshot covering the
|
|
15
|
-
# plugin registry, dependency-source index, and pre-pass
|
|
16
|
-
# scanner outputs.
|
|
9
|
+
# Per-session cache of the project-wide analyzer state the LSP reads on every request — chiefly the
|
|
10
|
+
# `Environment` (with its ~100-300ms RBS env build), a read-only `Cache::Store` that lets the runner hit
|
|
11
|
+
# the on-disk RBS cache without writing back, and (since the pre-pass cache slice) a frozen
|
|
12
|
+
# {Rigor::Analysis::ProjectScan} snapshot covering the plugin registry, dependency-source index, and
|
|
13
|
+
# pre-pass scanner outputs.
|
|
17
14
|
#
|
|
18
|
-
# The pre-pass scan lets `DiagnosticPublisher#run_analysis`
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# source / sizeable `pre_eval:` configuration this cuts
|
|
24
|
-
# publish wall time substantially — for the trivial case
|
|
25
|
-
# the savings are small (the per-publish path is already
|
|
26
|
-
# ≈2ms once Environment is warm).
|
|
15
|
+
# The pre-pass scan lets `DiagnosticPublisher#run_analysis` build a `Runner` with `prebuilt:` so per-buffer
|
|
16
|
+
# publishes skip plugin `#prepare`, the synthetic-method scanner, the project-patched scanner, and the
|
|
17
|
+
# dependency-source walker. For projects with substrate plugins / opt-in dependency source / sizeable
|
|
18
|
+
# `pre_eval:` configuration this cuts publish wall time substantially — for the trivial case the savings
|
|
19
|
+
# are small (the per-publish path is already ≈2ms once Environment is warm).
|
|
27
20
|
#
|
|
28
21
|
# Invalidation:
|
|
29
|
-
# - `#invalidate!` drops the cached environment AND project
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# - The cache store is NOT invalidated on file change — it's
|
|
37
|
-
# content-addressed (digests over file contents), so stale
|
|
38
|
-
# entries naturally lose their key match. We DO keep a single
|
|
39
|
-
# Store instance across the session so the in-process memo
|
|
40
|
-
# serves repeat reads cheaply.
|
|
22
|
+
# - `#invalidate!` drops the cached environment AND project scan + bumps the generation counter; the next
|
|
23
|
+
# reader rebuilds. Watched-file changes (`workspace/didChangeWatchedFiles`) and configuration refreshes
|
|
24
|
+
# (`workspace/didChangeConfiguration`) both trigger this — the next publish observes the new project
|
|
25
|
+
# state.
|
|
26
|
+
# - The cache store is NOT invalidated on file change — it's content-addressed (digests over file
|
|
27
|
+
# contents), so stale entries naturally lose their key match. We DO keep a single Store instance across
|
|
28
|
+
# the session so the in-process memo serves repeat reads cheaply.
|
|
41
29
|
#
|
|
42
|
-
# Editor-mode trade-off: the cached `project_scan` was built
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# watched-file change triggers `invalidate!`. The common
|
|
49
|
-
# editor flow (save → file watch fires → publish) refreshes
|
|
50
|
-
# automatically; the rare in-flight edit to a substrate-DSL
|
|
51
|
-
# file is the documented edge case.
|
|
30
|
+
# Editor-mode trade-off: the cached `project_scan` was built without any `buffer:` binding so scanners
|
|
31
|
+
# observed on-disk bytes for every project file (including the file the user is editing right now). Edits
|
|
32
|
+
# to a file that itself declares `Plugin::Macro::HeredocTemplate` consumers or `pre_eval:`-listed methods
|
|
33
|
+
# are not visible until a watched-file change triggers `invalidate!`. The common editor flow (save → file
|
|
34
|
+
# watch fires → publish) refreshes automatically; the rare in-flight edit to a substrate-DSL file is the
|
|
35
|
+
# documented edge case.
|
|
52
36
|
class ProjectContext
|
|
53
37
|
attr_reader :configuration, :generation
|
|
54
38
|
|
|
@@ -60,27 +44,20 @@ module Rigor
|
|
|
60
44
|
@project_scan = nil
|
|
61
45
|
end
|
|
62
46
|
|
|
63
|
-
# Returns the cached `Rigor::Environment` for this session,
|
|
64
|
-
#
|
|
65
|
-
# project
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# axis the runner consults at build time, so the resulting
|
|
69
|
-
# env is bit-for-bit equivalent to what `Runner.run` would
|
|
70
|
-
# have built on its own.
|
|
47
|
+
# Returns the cached `Rigor::Environment` for this session, building it on first access. The build
|
|
48
|
+
# includes the project's full scan state (plugin registry, dependency-source index, synthetic-method /
|
|
49
|
+
# project-patched indexes — drawn from {#project_scan}) AND every Bundler / RBS-collection axis the
|
|
50
|
+
# runner consults at build time, so the resulting env is bit-for-bit equivalent to what `Runner.run`
|
|
51
|
+
# would have built on its own.
|
|
71
52
|
#
|
|
72
|
-
# `DiagnosticPublisher` passes this env through
|
|
73
|
-
# `
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# discovery, RbsLoader construction, signature_paths
|
|
77
|
-
# composition). Subsequent calls return the same instance
|
|
78
|
-
# until `#invalidate!` drops the cache.
|
|
53
|
+
# `DiagnosticPublisher` passes this env through `Runner.new(environment: …)` so per-buffer publishes
|
|
54
|
+
# share one instance instead of repeating the `Environment.for_project` build per call (bundler
|
|
55
|
+
# discovery, RbsLoader construction, signature_paths composition). Subsequent calls return the same
|
|
56
|
+
# instance until `#invalidate!` drops the cache.
|
|
79
57
|
#
|
|
80
|
-
# The runner attaches its own per-call reporter pair onto
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# single publish and do NOT accumulate across publishes.
|
|
58
|
+
# The runner attaches its own per-call reporter pair onto the shared env's `Reporters` slot at the start
|
|
59
|
+
# of each `#analyze_files` — so diagnostic events stay scoped to a single publish and do NOT accumulate
|
|
60
|
+
# across publishes.
|
|
84
61
|
def environment
|
|
85
62
|
@environment ||= Environment.for_project(
|
|
86
63
|
libraries: @configuration.libraries,
|
|
@@ -98,35 +75,30 @@ module Rigor
|
|
|
98
75
|
)
|
|
99
76
|
end
|
|
100
77
|
|
|
101
|
-
# Returns the per-session read-only `Cache::Store`. Read-only
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
# uses for the CLI `--tmp-file` path.
|
|
78
|
+
# Returns the per-session read-only `Cache::Store`. Read-only so multiple LSP sessions against the same
|
|
79
|
+
# project don't race on cache writes — same contract editor mode v1 already uses for the CLI
|
|
80
|
+
# `--tmp-file` path.
|
|
105
81
|
def cache_store
|
|
106
82
|
@cache_store ||= Cache::Store.new(root: @configuration.cache_path, read_only: true)
|
|
107
83
|
end
|
|
108
84
|
|
|
109
|
-
# Returns the cached {Rigor::Analysis::ProjectScan} for this
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
# calling `#prepare_project_scan`. The cold build pays the
|
|
113
|
-
# full pre-pass cost once per generation; every subsequent
|
|
85
|
+
# Returns the cached {Rigor::Analysis::ProjectScan} for this session, building it lazily by spinning up a
|
|
86
|
+
# project-only `Runner` (no buffer binding, no `paths` override) and calling `#prepare_project_scan`. The
|
|
87
|
+
# cold build pays the full pre-pass cost once per generation; every subsequent
|
|
114
88
|
# `Runner.new(prebuilt: project_scan)` skips it.
|
|
115
89
|
def project_scan
|
|
116
90
|
@project_scan ||= build_project_scan
|
|
117
91
|
end
|
|
118
92
|
|
|
119
|
-
# Drops every cached collaborator and bumps the generation.
|
|
120
|
-
#
|
|
121
|
-
# `workspace/
|
|
122
|
-
# and by `workspace/didChangeConfiguration`.
|
|
93
|
+
# Drops every cached collaborator and bumps the generation. The next reader rebuilds from scratch.
|
|
94
|
+
# Triggered by `workspace/didChangeWatchedFiles` for project source files and by
|
|
95
|
+
# `workspace/didChangeConfiguration`.
|
|
123
96
|
def invalidate!
|
|
124
97
|
@generation += 1
|
|
125
98
|
@environment = nil
|
|
126
99
|
@project_scan = nil
|
|
127
|
-
# Cache store stays — it's content-addressed; a stale env
|
|
128
|
-
#
|
|
129
|
-
# the cache key has changed.
|
|
100
|
+
# Cache store stays — it's content-addressed; a stale env build won't be served because the file
|
|
101
|
+
# digest mixed into the cache key has changed.
|
|
130
102
|
nil
|
|
131
103
|
end
|
|
132
104
|
|
|
@@ -7,12 +7,10 @@ require_relative "buffer_resolution"
|
|
|
7
7
|
|
|
8
8
|
module Rigor
|
|
9
9
|
module LanguageServer
|
|
10
|
-
# Answers `textDocument/selectionRange` requests. For each
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# one keystroke moves up the chain, another moves further out,
|
|
15
|
-
# all the way to the root.
|
|
10
|
+
# Answers `textDocument/selectionRange` requests. For each position, returns a linked list of
|
|
11
|
+
# SelectionRange entries — innermost first, each pointing at its `parent` (the next-wider expression).
|
|
12
|
+
# Editors use this for "expand selection": one keystroke moves up the chain, another moves further out, all
|
|
13
|
+
# the way to the root.
|
|
16
14
|
class SelectionRangeProvider
|
|
17
15
|
include BufferResolution
|
|
18
16
|
|
|
@@ -43,8 +41,8 @@ module Rigor
|
|
|
43
41
|
|
|
44
42
|
private
|
|
45
43
|
|
|
46
|
-
# Walks the AST top-down; each node whose location encloses
|
|
47
|
-
#
|
|
44
|
+
# Walks the AST top-down; each node whose location encloses `offset` gets appended to the chain. Returns
|
|
45
|
+
# root→innermost.
|
|
48
46
|
def ancestor_chain(node, offset, chain = [])
|
|
49
47
|
return chain unless node.is_a?(Prism::Node)
|
|
50
48
|
return chain unless node.location && offset_in?(node.location, offset)
|
|
@@ -58,10 +56,9 @@ module Rigor
|
|
|
58
56
|
offset.between?(location.start_offset, location.end_offset)
|
|
59
57
|
end
|
|
60
58
|
|
|
61
|
-
# Folds the root→innermost chain into the LSP `SelectionRange`
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
# selection" follows `.parent` one step per invocation.
|
|
59
|
+
# Folds the root→innermost chain into the LSP `SelectionRange` linked-list shape — innermost on the
|
|
60
|
+
# outside (the request's return value) with `parent` chained outward. Editor "expand selection" follows
|
|
61
|
+
# `.parent` one step per invocation.
|
|
65
62
|
def build_chain(root, offset)
|
|
66
63
|
chain = ancestor_chain(root, offset)
|
|
67
64
|
return nil if chain.empty?
|