rigortype 0.4.1 → 0.4.2
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/data/builtins/ruby_core/io.yml +1 -0
- data/data/builtins/ruby_core/proc.yml +4 -0
- data/data/builtins/ruby_core/random.yml +4 -0
- data/data/builtins/ruby_core/struct.yml +3 -0
- data/data/core_overlay/env.rbs +34 -0
- data/data/core_overlay/gc.rbs +50 -0
- data/data/core_overlay/hash.rbs +45 -0
- data/data/core_overlay/integer.rbs +31 -0
- data/data/core_overlay/io_buffer.rbs +27 -0
- data/data/core_overlay/kernel.rbs +40 -0
- data/data/core_overlay/match_data.rbs +28 -0
- data/data/core_overlay/module.rbs +51 -0
- data/data/core_overlay/object_space.rbs +29 -0
- data/data/core_overlay/proc.rbs +45 -0
- data/data/core_overlay/range.rbs +40 -0
- data/data/core_overlay/source_range.rbs +78 -0
- data/data/core_overlay/string.rbs +86 -0
- data/data/vendored_gem_sigs/prime/integer-extension.rbs +41 -0
- data/data/vendored_gem_sigs/prime/prime.rbs +372 -0
- data/docs/handbook/01-getting-started.md +3 -3
- data/docs/handbook/06-classes.md +3 -1
- data/docs/handbook/11-sig-gen.md +6 -0
- data/docs/handbook/appendix-liskov.md +5 -0
- data/docs/manual/03-configuration.md +1 -1
- data/docs/manual/04-diagnostics.md +2 -1
- data/docs/manual/06-baseline.md +2 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/18-removing-dead-code.md +32 -2
- data/docs/manual/plugins/README.md +6 -1
- data/docs/manual/plugins/rigor-activerecord.md +21 -0
- data/docs/manual/plugins/rigor-alba.md +60 -0
- data/docs/manual/plugins/rigor-minitest.md +22 -4
- data/docs/manual/plugins/rigor-typelizer.md +71 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +27 -3
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +21 -92
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +275 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +4 -0
- data/lib/rigor/analysis/check_rules/source_arity.rb +21 -2
- data/lib/rigor/analysis/check_rules.rb +289 -57
- data/lib/rigor/analysis/dependency_recorder.rb +15 -0
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +8 -1
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +21 -0
- data/lib/rigor/analysis/dependency_source_inference/index.rb +36 -11
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +196 -27
- data/lib/rigor/analysis/erb_template_detector.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +29 -9
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +30 -5
- data/lib/rigor/analysis/incremental_run_slot.rb +3 -1
- data/lib/rigor/analysis/incremental_session.rb +14 -1
- data/lib/rigor/analysis/reachability/graph.rb +123 -23
- data/lib/rigor/analysis/reachability/scan.rb +290 -36
- data/lib/rigor/analysis/rule_catalog.rb +43 -0
- data/lib/rigor/analysis/run_cache_key.rb +16 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +87 -5
- data/lib/rigor/analysis/runner/pool_coordinator.rb +50 -11
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +34 -3
- data/lib/rigor/analysis/worker_session.rb +7 -4
- data/lib/rigor/cache/incremental_snapshot.rb +22 -0
- data/lib/rigor/cli/annotate_command.rb +5 -0
- data/lib/rigor/cli/baseline_command.rb +7 -18
- data/lib/rigor/cli/check_command.rb +2 -1
- data/lib/rigor/cli/trace_command.rb +5 -0
- data/lib/rigor/cli/type_of_command.rb +5 -3
- data/lib/rigor/cli/unused_command.rb +13 -7
- data/lib/rigor/cli.rb +10 -2
- data/lib/rigor/configuration/severity_profile.rb +6 -0
- data/lib/rigor/configuration.rb +46 -2
- data/lib/rigor/environment/gated_signature_guard.rb +43 -0
- data/lib/rigor/environment/gated_signature_plan.rb +339 -0
- data/lib/rigor/environment/rbs_coverage_report.rb +1 -1
- data/lib/rigor/environment/rbs_loader.rb +283 -14
- data/lib/rigor/environment/required_features.rb +206 -0
- data/lib/rigor/environment.rb +21 -3
- data/lib/rigor/inference/acceptance.rb +28 -3
- data/lib/rigor/inference/builtins/cruby_definers.rb +61 -0
- data/lib/rigor/inference/builtins/method_catalog.rb +3 -0
- data/lib/rigor/inference/def_node_resolver.rb +23 -1
- data/lib/rigor/inference/expression_typer.rb +215 -16
- data/lib/rigor/inference/global_write_census.rb +7 -4
- data/lib/rigor/inference/guard_rebinding.rb +1 -1
- data/lib/rigor/inference/in_effect_refinements/proc_literals.rb +83 -0
- data/lib/rigor/inference/in_effect_refinements/refine_defs.rb +54 -0
- data/lib/rigor/inference/in_effect_refinements/scope_reads.rb +282 -0
- data/lib/rigor/inference/in_effect_refinements/walk.rb +276 -0
- data/lib/rigor/inference/in_effect_refinements.rb +256 -0
- data/lib/rigor/inference/key_presence_guard/scan.rb +281 -0
- data/lib/rigor/inference/key_presence_guard.rb +303 -0
- data/lib/rigor/inference/macro_block_self_type.rb +59 -12
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/arithmetic_sequence_elements.rb +73 -0
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +68 -0
- data/lib/rigor/inference/method_dispatcher/integer_step_block_params.rb +81 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -0
- data/lib/rigor/inference/method_dispatcher/keyword_arguments.rb +267 -0
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -1
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +122 -105
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +259 -28
- data/lib/rigor/inference/method_dispatcher/splat_arity.rb +71 -0
- data/lib/rigor/inference/method_dispatcher.rb +44 -11
- data/lib/rigor/inference/module_function_state.rb +2 -1
- data/lib/rigor/inference/narrowing.rb +20 -6
- data/lib/rigor/inference/object_mixins.rb +180 -0
- data/lib/rigor/inference/project_patched_methods.rb +10 -5
- data/lib/rigor/inference/project_patched_scanner.rb +71 -3
- data/lib/rigor/inference/refine_census.rb +239 -0
- data/lib/rigor/inference/refine_self.rb +317 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +403 -0
- data/lib/rigor/inference/refined_dispatch.rb +272 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +13 -0
- data/lib/rigor/inference/scope_indexer.rb +687 -60
- data/lib/rigor/inference/statement_evaluator.rb +71 -20
- data/lib/rigor/inference/string_mutation.rb +9 -3
- data/lib/rigor/inference/synthetic_method_scanner.rb +2 -1
- data/lib/rigor/inference/version_guard.rb +19 -10
- data/lib/rigor/language_server/project_context.rb +31 -0
- data/lib/rigor/language_server/server.rb +18 -0
- data/lib/rigor/plugin/inflector.rb +1 -1
- data/lib/rigor/plugin/io_boundary.rb +42 -3
- data/lib/rigor/plugin/macro/block_as_method.rb +51 -8
- data/lib/rigor/project_environment.rb +29 -6
- data/lib/rigor/protection/mutation_cache.rb +1 -1
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/reflection/constant_ancestors.rb +127 -11
- data/lib/rigor/reflection/constant_path.rb +13 -2
- data/lib/rigor/reflection.rb +40 -8
- data/lib/rigor/scope/discovery_index.rb +40 -1
- data/lib/rigor/scope/resolution_chain.rb +159 -11
- data/lib/rigor/scope.rb +189 -10
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/generator.rb +55 -5
- data/lib/rigor/sig_gen/method_candidate.rb +2 -2
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +12 -0
- data/lib/rigor/source/alias_names.rb +52 -0
- data/lib/rigor/source/literals.rb +3 -2
- data/lib/rigor/source/symbol_name.rb +20 -0
- data/lib/rigor/type/combinator.rb +34 -2
- data/lib/rigor/type/float_range.rb +4 -1
- data/lib/rigor/type/nominal.rb +6 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-ac-library-rb/lib/rigor/plugin/ac_library_rb.rb +28 -0
- data/plugins/rigor-ac-library-rb/lib/rigor-ac-library-rb.rb +3 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/convolution.rbs +7 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/data_structures.rbs +160 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/graph.rbs +94 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/math.rbs +42 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/modint.rbs +71 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/object.rbs +37 -0
- data/plugins/rigor-ac-library-rb/sig/ac_library_rb/segtree.rbs +83 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +100 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +94 -10
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +43 -2
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +3 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +149 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +74 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +104 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba.rb +85 -0
- data/plugins/rigor-alba/lib/rigor-alba.rb +3 -0
- data/plugins/rigor-alba/sig/alba.rbs +4 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +2 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +29 -12
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +7 -6
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +130 -21
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +6 -4
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +4 -4
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +31 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +102 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +87 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +76 -0
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +73 -0
- data/plugins/rigor-typelizer/lib/rigor-typelizer.rb +3 -0
- data/sig/rigor/analysis/dependency_source_inference/index.rbs +1 -1
- data/sig/rigor/plugin/io_boundary.rbs +3 -0
- data/sig/rigor/scope.rbs +27 -4
- data/sig/rigor/source.rbs +4 -0
- data/sig/rigor.rbs +3 -1
- metadata +66 -1
|
@@ -36,6 +36,8 @@ module Rigor
|
|
|
36
36
|
# that stood down against a colliding generic arity (#610), as
|
|
37
37
|
# `[path, class_name, existing_arity, incoming_arity, existing_file]` tuples. Defaults to none so
|
|
38
38
|
# a caller that snapshots nothing of the kind need not say so.
|
|
39
|
+
# @param vendored_standdowns_snapshot — issue #1713 — reader returning what each required-feature-gated
|
|
40
|
+
# vendored directory left out (`Environment::RbsLoader#vendored_standdowns`). Defaults to none.
|
|
39
41
|
# @param env_build_failure_snapshot — reader returning the total RBS env-build failure tuple
|
|
40
42
|
# (`[error_class, first_error_line, conflicting_buffer_names]`) or nil when the env built.
|
|
41
43
|
# @param definition_build_failures_snapshot — issue #696 — reader returning the per-class
|
|
@@ -55,7 +57,7 @@ module Rigor
|
|
|
55
57
|
quarantined_signatures_snapshot:, env_build_failure_snapshot:,
|
|
56
58
|
definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
|
|
57
59
|
conformance_results_snapshot:, signature_standdowns_snapshot: -> { [] },
|
|
58
|
-
pooled_run_disclosures: -> { [] })
|
|
60
|
+
vendored_standdowns_snapshot: -> { [] }, pooled_run_disclosures: -> { [] })
|
|
59
61
|
@configuration = configuration
|
|
60
62
|
@rbs_extended_reporter = rbs_extended_reporter
|
|
61
63
|
@boundary_cross_reporter = boundary_cross_reporter
|
|
@@ -68,6 +70,7 @@ module Rigor
|
|
|
68
70
|
@synthesized_namespaces_snapshot_reader = synthesized_namespaces_snapshot
|
|
69
71
|
@quarantined_signatures_snapshot_reader = quarantined_signatures_snapshot
|
|
70
72
|
@signature_standdowns_snapshot_reader = signature_standdowns_snapshot
|
|
73
|
+
@vendored_standdowns_snapshot_reader = vendored_standdowns_snapshot
|
|
71
74
|
@env_build_failure_snapshot_reader = env_build_failure_snapshot
|
|
72
75
|
@definition_build_failures_snapshot_reader = definition_build_failures_snapshot
|
|
73
76
|
@hkt_scan_failure_snapshot_reader = hkt_scan_failure_snapshot
|
|
@@ -437,11 +440,23 @@ module Rigor
|
|
|
437
440
|
standdowns.map { |entry| build_rbs_plugin_signature_stood_down_diagnostic(entry) }
|
|
438
441
|
end
|
|
439
442
|
|
|
440
|
-
#
|
|
441
|
-
#
|
|
442
|
-
#
|
|
443
|
+
# Issue #1713 — the other outcome that avoided a definition-build failure: a required-feature-gated
|
|
444
|
+
# vendored directory (`data/vendored_gem_sigs/prime/`) left out what another signature source already
|
|
445
|
+
# declares — a member, a whole type, or, when nothing narrower built, the directory. One `:info` per
|
|
446
|
+
# directory, naming the declarations that stood down and the files that displaced them.
|
|
447
|
+
def rbs_vendored_signature_stood_down_diagnostics
|
|
448
|
+
standdowns = vendored_standdowns_snapshot
|
|
449
|
+
return [] if standdowns.nil? || standdowns.empty?
|
|
450
|
+
|
|
451
|
+
standdowns.map { |entry| build_rbs_vendored_signature_stood_down_diagnostic(entry) }
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# The `:info` notices that close the `rbs.coverage.*` ladder, in this order: the namespace synthesis
|
|
455
|
+
# first, then the stand-downs (#610, #1713) — the outcomes that AVOIDED a definition-build failure and so
|
|
456
|
+
# the quietest rows on it. One method so the runner's assembly reads them as one slot.
|
|
443
457
|
def rbs_coverage_notice_diagnostics
|
|
444
|
-
rbs_synthesized_namespace_diagnostics + rbs_plugin_signature_stood_down_diagnostics
|
|
458
|
+
rbs_synthesized_namespace_diagnostics + rbs_plugin_signature_stood_down_diagnostics +
|
|
459
|
+
rbs_vendored_signature_stood_down_diagnostics
|
|
445
460
|
end
|
|
446
461
|
|
|
447
462
|
# Maps the per-run `rigor:v1:conforms-to` scan results into diagnostics (spec: `rbs-extended.md` §
|
|
@@ -769,6 +784,69 @@ module Rigor
|
|
|
769
784
|
)
|
|
770
785
|
end
|
|
771
786
|
|
|
787
|
+
def build_rbs_vendored_signature_stood_down_diagnostic(entry)
|
|
788
|
+
dir, declarations, whole = entry
|
|
789
|
+
Diagnostic.new(
|
|
790
|
+
path: ".rigor.yml",
|
|
791
|
+
line: 1,
|
|
792
|
+
column: 1,
|
|
793
|
+
message: vendored_standdown_message(dir, declarations, whole),
|
|
794
|
+
severity: :info,
|
|
795
|
+
rule: "rbs.coverage.vendored-signature-stood-down",
|
|
796
|
+
source_family: :builtin
|
|
797
|
+
)
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
def vendored_standdown_message(dir, declarations, whole)
|
|
801
|
+
subject = "Rigor's vendored `#{dir}` signatures (loaded because the project requires `#{dir}` or lists " \
|
|
802
|
+
"it under `libraries:`)"
|
|
803
|
+
return vendored_whole_standdown_message(subject, dir, declarations) if whole
|
|
804
|
+
|
|
805
|
+
vendored_partial_standdown_message(subject, declarations)
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
# One sentence per kind of stand-down present ({Environment::GatedSignaturePlan.standdowns}' reasons).
|
|
809
|
+
VENDORED_STANDDOWN_SENTENCES = {
|
|
810
|
+
"member" => "left out %<count>d method declaration(s) another signature source also makes, since two " \
|
|
811
|
+
"declarations of one method fail the class's definition build, and uses the other " \
|
|
812
|
+
"source's: %<list>s.",
|
|
813
|
+
"type" => "stood %<count>d type(s) down whole, keeping only the types nested in them, because another " \
|
|
814
|
+
"source declares each with a different kind (class or module) or generic arity, or the type " \
|
|
815
|
+
"failed to build beside that source's declaration: %<list>s.",
|
|
816
|
+
"open" => "kept %<count>d type(s) without their superclass, because each failed to build beside the " \
|
|
817
|
+
"other signatures although no other source declares it; calls they no longer answer read " \
|
|
818
|
+
"untyped rather than undefined: %<list>s."
|
|
819
|
+
}.freeze
|
|
820
|
+
private_constant :VENDORED_STANDDOWN_SENTENCES
|
|
821
|
+
|
|
822
|
+
def vendored_partial_standdown_message(subject, declarations)
|
|
823
|
+
sentences = VENDORED_STANDDOWN_SENTENCES.filter_map do |reason, template|
|
|
824
|
+
group = declarations.select { |entry| (entry[2] || "member") == reason }
|
|
825
|
+
next if group.empty?
|
|
826
|
+
|
|
827
|
+
format(template, count: group.size, list: sampled(vendored_standdown_labels(group), 5))
|
|
828
|
+
end
|
|
829
|
+
"#{subject} loaded without some of their declarations. Rigor #{sentences.join(' Rigor ')} The rest of the " \
|
|
830
|
+
"vendored signatures still load. Nothing to fix unless the other declaration is an outdated copy; " \
|
|
831
|
+
"removing it brings the vendored one back."
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
def vendored_whole_standdown_message(subject, dir, declarations)
|
|
835
|
+
labels = vendored_standdown_labels(declarations)
|
|
836
|
+
clashes = labels.empty? ? "" : " Declarations it clashed with: #{sampled(labels, 5)}."
|
|
837
|
+
"#{subject} stood down " \
|
|
838
|
+
"entirely: a type they declare failed to build beside the other signature sources even with the " \
|
|
839
|
+
"clashing declarations left out, so calls into `#{dir}`'s API resolve only against what those " \
|
|
840
|
+
"sources declare.#{clashes}"
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
def vendored_standdown_labels(declarations)
|
|
844
|
+
declarations.map do |declaration, cause_file|
|
|
845
|
+
cause = cause_file.nil? ? "" : " (#{relative_signature_path(cause_file.to_s)})"
|
|
846
|
+
"`#{declaration}`#{cause}"
|
|
847
|
+
end
|
|
848
|
+
end
|
|
849
|
+
|
|
772
850
|
def displacing_source_phrase(existing_file)
|
|
773
851
|
return "another loaded signature source" if existing_file.nil?
|
|
774
852
|
|
|
@@ -1196,6 +1274,10 @@ module Rigor
|
|
|
1196
1274
|
@signature_standdowns_snapshot_reader.call
|
|
1197
1275
|
end
|
|
1198
1276
|
|
|
1277
|
+
def vendored_standdowns_snapshot
|
|
1278
|
+
@vendored_standdowns_snapshot_reader.call
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1199
1281
|
def env_build_failure_snapshot
|
|
1200
1282
|
@env_build_failure_snapshot_reader.call
|
|
1201
1283
|
end
|
|
@@ -45,7 +45,8 @@ module Rigor
|
|
|
45
45
|
snapshots:, plugin_registry:, dependency_source_index:,
|
|
46
46
|
synthetic_method_index:, project_patched_methods:,
|
|
47
47
|
analyze_file:, project_scope_seed: -> { {} }, record_dependencies: false,
|
|
48
|
-
restored_run_level_rows: nil, template_units: -> { TemplateUnits.empty }
|
|
48
|
+
restored_run_level_rows: nil, template_units: -> { TemplateUnits.empty },
|
|
49
|
+
feature_sources: -> { {} })
|
|
49
50
|
@configuration = configuration
|
|
50
51
|
@cache_store = cache_store
|
|
51
52
|
@explain = explain
|
|
@@ -67,6 +68,7 @@ module Rigor
|
|
|
67
68
|
@collected_run_disclosures = {}
|
|
68
69
|
@collect_stats = collect_stats
|
|
69
70
|
@buffer = buffer
|
|
71
|
+
@feature_sources = feature_sources
|
|
70
72
|
@environment_override = environment_override
|
|
71
73
|
@rbs_extended_reporter = rbs_extended_reporter
|
|
72
74
|
@boundary_cross_reporter = boundary_cross_reporter
|
|
@@ -208,7 +210,7 @@ module Rigor
|
|
|
208
210
|
|
|
209
211
|
env = resolve_sequential_environment(source_files: project_files)
|
|
210
212
|
end
|
|
211
|
-
snapshot_project_signature_state(signature_state_environment(resolve))
|
|
213
|
+
snapshot_project_signature_state(signature_state_environment(resolve, project_files))
|
|
212
214
|
snapshot_effect_annotation_carrier(
|
|
213
215
|
annotation_carrier_environment(resolve, in_hand: !env.nil?)&.rbs_loader
|
|
214
216
|
)
|
|
@@ -220,11 +222,21 @@ module Rigor
|
|
|
220
222
|
record_hkt_scan_failure(hkt_scan_outcome(resolve.call))
|
|
221
223
|
end
|
|
222
224
|
|
|
223
|
-
# Issue #794 — the signature-state snapshot's own gates, asked BEFORE an environment exists.
|
|
224
|
-
#
|
|
225
|
-
# {#snapshot_project_signature_state} writes the same empty state a nil
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
# Issue #794 — the signature-state snapshot's own gates, asked BEFORE an environment exists. Every
|
|
226
|
+
# answer is loader-free (the configuration, the plugin registry and, issue #1713, the required-feature
|
|
227
|
+
# scan), and with no gate open {#snapshot_project_signature_state} writes the same empty state a nil
|
|
228
|
+
# environment gives it.
|
|
229
|
+
def signature_state_environment(resolve, project_files)
|
|
230
|
+
gated = plugin_signature_paths? || project_signature_paths? || vendored_features_requested?(project_files)
|
|
231
|
+
gated ? resolve.call : nil
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Issue #1713 — whether this run activates a required-feature-gated vendored directory, whose stand-down
|
|
235
|
+
# {#snapshot_project_signature_state} reports: the scan every build of this run gates on, or the
|
|
236
|
+
# feature named under `libraries:`.
|
|
237
|
+
def vendored_features_requested?(project_files)
|
|
238
|
+
features = project_files.nil? || project_files.empty? ? [] : required_features_for(project_files)
|
|
239
|
+
!Environment::RequiredFeatures.tokens(features, @configuration.libraries).empty?
|
|
228
240
|
end
|
|
229
241
|
|
|
230
242
|
# Issue #794 — the same, for the #441 carrier. The carrier is a filter over the loader's
|
|
@@ -344,6 +356,10 @@ module Rigor
|
|
|
344
356
|
# no such plugin reads nothing off its loader here, as before.
|
|
345
357
|
@snapshots.signature_standdowns =
|
|
346
358
|
plugin_signature_paths? ? signature_standdowns_for(environment&.rbs_loader) : []
|
|
359
|
+
# Issue #1713 — NOT behind the `signature_paths:` gate either: what displaces a vendored declaration may
|
|
360
|
+
# be a gem's or a collection's copy. The loader answers without building its env when no gated
|
|
361
|
+
# directory is active.
|
|
362
|
+
@snapshots.vendored_standdowns = vendored_standdowns_for(environment&.rbs_loader)
|
|
347
363
|
unless project_signature_paths?
|
|
348
364
|
@snapshots.synthesized_namespaces = []
|
|
349
365
|
@snapshots.quarantined_signatures = []
|
|
@@ -459,7 +475,22 @@ module Rigor
|
|
|
459
475
|
**ProjectEnvironment.dependency_discovery_options(@configuration),
|
|
460
476
|
synthetic_method_index: synthetic_method_index,
|
|
461
477
|
project_patched_methods: project_patched_methods,
|
|
462
|
-
source_files: source_files
|
|
478
|
+
source_files: source_files,
|
|
479
|
+
required_features: required_features_for(source_files)
|
|
480
|
+
)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Issue #1700 — the {Environment::RequiredFeatures} this run's environments gate on: the configured paths
|
|
484
|
+
# plus `source_files`, whichever files the run checks, with an editor buffer or an in-memory source read
|
|
485
|
+
# in place of its file. Taken once per file list and handed to every build (the sequential one, the
|
|
486
|
+
# pool's prewarm and each worker), so they agree and a pool does not re-read the project per worker.
|
|
487
|
+
def required_features_for(source_files)
|
|
488
|
+
key = source_files.map(&:to_s)
|
|
489
|
+
return @required_features if @required_features_key == key
|
|
490
|
+
|
|
491
|
+
@required_features_key = key
|
|
492
|
+
@required_features = Ractor.make_shareable(
|
|
493
|
+
Environment::RequiredFeatures.for_configuration(@configuration, key, sources: @feature_sources.call)
|
|
463
494
|
)
|
|
464
495
|
end
|
|
465
496
|
|
|
@@ -575,9 +606,10 @@ module Rigor
|
|
|
575
606
|
# a frozen Array<String>; cheaply shareable. Issue #793 — it IS the full project now
|
|
576
607
|
# (`source_files`), not the analyzed subset this comment always described.
|
|
577
608
|
shareable_source_files = source_files.map { |path| path.to_s.dup.freeze }.freeze
|
|
609
|
+
features = required_features_for(source_files)
|
|
578
610
|
|
|
579
611
|
pool = Array.new(@workers) do
|
|
580
|
-
Ractor.new(configuration, cache_root, blueprints, explain, shareable_source_files, locked_gems) do |configuration, cache_root, blueprints, explain, shareable_source_files, locked_gems| # rubocop:disable Layout/LineLength
|
|
612
|
+
Ractor.new(configuration, cache_root, blueprints, explain, shareable_source_files, locked_gems, features) do |configuration, cache_root, blueprints, explain, shareable_source_files, locked_gems, features| # rubocop:disable Layout/LineLength
|
|
581
613
|
cache_store = cache_root ? Rigor::Cache::Store.new(root: cache_root) : nil
|
|
582
614
|
session = Rigor::Analysis::WorkerSession.new(
|
|
583
615
|
configuration: configuration,
|
|
@@ -585,7 +617,8 @@ module Rigor
|
|
|
585
617
|
plugin_blueprints: blueprints,
|
|
586
618
|
explain: explain,
|
|
587
619
|
source_files: shareable_source_files,
|
|
588
|
-
locked_gems: locked_gems
|
|
620
|
+
locked_gems: locked_gems,
|
|
621
|
+
required_features: features
|
|
589
622
|
)
|
|
590
623
|
main = Ractor.main
|
|
591
624
|
main.send([:prepare, session.prepare_diagnostics])
|
|
@@ -713,7 +746,8 @@ module Rigor
|
|
|
713
746
|
project_scope_seed: project_scope_seed,
|
|
714
747
|
source_files: source_files,
|
|
715
748
|
record_dependencies: @record_dependencies,
|
|
716
|
-
template_units: template_units
|
|
749
|
+
template_units: template_units,
|
|
750
|
+
required_features: required_features_for(source_files)
|
|
717
751
|
)
|
|
718
752
|
# Force the full RBS load on the parent so children copy-on-write inherit a warm Environment
|
|
719
753
|
# rather than each rebuilding it after the fork.
|
|
@@ -890,6 +924,7 @@ module Rigor
|
|
|
890
924
|
plugin_registry: plugin_registry,
|
|
891
925
|
source_files: source_files,
|
|
892
926
|
locked_gems: locked_gems,
|
|
927
|
+
required_features: required_features_for(source_files),
|
|
893
928
|
**ProjectEnvironment.dependency_discovery_options(@configuration)
|
|
894
929
|
)
|
|
895
930
|
warm_env.rbs_loader&.prewarm
|
|
@@ -1094,6 +1129,10 @@ module Rigor
|
|
|
1094
1129
|
loader.signature_standdowns
|
|
1095
1130
|
end
|
|
1096
1131
|
|
|
1132
|
+
def vendored_standdowns_for(loader)
|
|
1133
|
+
loader.respond_to?(:vendored_standdowns) ? loader.vendored_standdowns : []
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1097
1136
|
def plugin_registry
|
|
1098
1137
|
@plugin_registry_reader.call
|
|
1099
1138
|
end
|
|
@@ -16,7 +16,8 @@ module Rigor
|
|
|
16
16
|
# back-reference cycle.
|
|
17
17
|
class RunSnapshots
|
|
18
18
|
attr_accessor :class_decl_paths, :signature_paths,
|
|
19
|
-
:synthesized_namespaces, :quarantined_signatures, :signature_standdowns, :
|
|
19
|
+
:synthesized_namespaces, :quarantined_signatures, :signature_standdowns, :vendored_standdowns,
|
|
20
|
+
:conformance_results,
|
|
20
21
|
:env_build_failure, :definition_build_failures, :hkt_scan_failure,
|
|
21
22
|
:effect_annotation_carrier
|
|
22
23
|
|
|
@@ -32,12 +33,15 @@ module Rigor
|
|
|
32
33
|
# `signature_standdowns` (#610) is the quarantine slot's twin for the plugin-contributed files that
|
|
33
34
|
# stood down against a colliding generic arity: a list, assigned once from the loader as
|
|
34
35
|
# `quarantined_signatures` is, and derived from the final env so a cache HIT carries it too.
|
|
36
|
+
# `vendored_standdowns` (#1713) is the same shape of slot for what a required-feature-gated vendored
|
|
37
|
+
# directory left out because another signature source declares it.
|
|
35
38
|
def initialize
|
|
36
39
|
@class_decl_paths = {}.freeze
|
|
37
40
|
@signature_paths = [].freeze
|
|
38
41
|
@synthesized_namespaces = [].freeze
|
|
39
42
|
@quarantined_signatures = [].freeze
|
|
40
43
|
@signature_standdowns = [].freeze
|
|
44
|
+
@vendored_standdowns = [].freeze
|
|
41
45
|
@conformance_results = [].freeze
|
|
42
46
|
@env_build_failure = nil
|
|
43
47
|
@definition_build_failures = [].freeze
|
|
@@ -53,6 +57,7 @@ module Rigor
|
|
|
53
57
|
@synthesized_namespaces = []
|
|
54
58
|
@quarantined_signatures = []
|
|
55
59
|
@signature_standdowns = []
|
|
60
|
+
@vendored_standdowns = []
|
|
56
61
|
@conformance_results = []
|
|
57
62
|
@env_build_failure = nil
|
|
58
63
|
@definition_build_failures = []
|
|
@@ -575,6 +575,12 @@ module Rigor
|
|
|
575
575
|
@in_memory_sources = nil
|
|
576
576
|
end
|
|
577
577
|
|
|
578
|
+
# Issue #1700 — the sources the required-feature scan reads in place of a file on disk: an in-memory
|
|
579
|
+
# source ({#run_source}) and an editor buffer (`--tmp-file` read for its `--instead-of` path).
|
|
580
|
+
def required_feature_sources
|
|
581
|
+
(@in_memory_sources || {}).merge(ProjectEnvironment.buffer_sources(@buffer))
|
|
582
|
+
end
|
|
583
|
+
|
|
578
584
|
# ADR-46 — the project file set that a run over `paths` would analyze, computed by globbing only (no
|
|
579
585
|
# RBS environment build), so the incremental fingerprint can be derived cheaply on the warm path
|
|
580
586
|
# before deciding whether to build the env at all.
|
|
@@ -636,11 +642,16 @@ module Rigor
|
|
|
636
642
|
# detect a class that *appeared* in an edit so a subclass whose ancestor was previously undefined
|
|
637
643
|
# (and so recorded a negative class edge) is re-checked. Inverts the project class-source attribution
|
|
638
644
|
# (class → declaring files).
|
|
645
|
+
#
|
|
646
|
+
# Issue #1820 — each file's set also holds a `[class, superclass as written]` pair for every class it declares
|
|
647
|
+
# with a superclass, so a subclass appearing or vanishing re-checks the consumers that enumerated the parent's
|
|
648
|
+
# subclasses (`subclass_of:<last segment>`).
|
|
639
649
|
def class_declarations
|
|
640
650
|
result = Hash.new { |hash, key| hash[key] = Set.new }
|
|
641
651
|
@project_discovered_class_sources.each do |class_name, files|
|
|
642
652
|
files.each { |file| result[file] << class_name }
|
|
643
653
|
end
|
|
654
|
+
Incremental.add_superclass_edges(result, @project_discovered_class_sources, @project_discovered_superclasses)
|
|
644
655
|
result.transform_values(&:freeze).freeze
|
|
645
656
|
end
|
|
646
657
|
|
|
@@ -2005,7 +2016,8 @@ module Rigor
|
|
|
2005
2016
|
project_scope_seed: -> { project_scope_seed_tables },
|
|
2006
2017
|
template_units: -> { template_units },
|
|
2007
2018
|
analyze_file: ->(path, environment) { analyze_file(path, environment) },
|
|
2008
|
-
restored_run_level_rows: @restored_run_level_rows
|
|
2019
|
+
restored_run_level_rows: @restored_run_level_rows,
|
|
2020
|
+
feature_sources: -> { required_feature_sources }
|
|
2009
2021
|
)
|
|
2010
2022
|
@diagnostic_aggregator = DiagnosticAggregator.new(
|
|
2011
2023
|
configuration: @configuration,
|
|
@@ -2020,6 +2032,7 @@ module Rigor
|
|
|
2020
2032
|
synthesized_namespaces_snapshot: -> { @snapshots.synthesized_namespaces },
|
|
2021
2033
|
quarantined_signatures_snapshot: -> { @snapshots.quarantined_signatures },
|
|
2022
2034
|
signature_standdowns_snapshot: -> { @snapshots.signature_standdowns },
|
|
2035
|
+
vendored_standdowns_snapshot: -> { @snapshots.vendored_standdowns },
|
|
2023
2036
|
env_build_failure_snapshot: -> { @snapshots.env_build_failure },
|
|
2024
2037
|
definition_build_failures_snapshot: -> { @snapshots.definition_build_failures },
|
|
2025
2038
|
hkt_scan_failure_snapshot: -> { @snapshots.hkt_scan_failure },
|
|
@@ -2295,13 +2308,30 @@ module Rigor
|
|
|
2295
2308
|
# global-write census (the `global.*` write rules); the issue #992 envelopes ride {#seed_paired_tables}. Split
|
|
2296
2309
|
# out of {#project_scope_seed_tables} to keep it under the complexity budget.
|
|
2297
2310
|
def seed_call_surface_tables(tables)
|
|
2298
|
-
|
|
2311
|
+
refinements = seed_refinements(tables)
|
|
2312
|
+
tables[:discovered_refinements] = refinements unless refinements.nil? || refinements.empty?
|
|
2299
2313
|
# Issue #1367 — read by the `global.*` write rules.
|
|
2300
2314
|
return if @project_discovered_global_write_census.empty?
|
|
2301
2315
|
|
|
2302
2316
|
tables[:discovered_global_write_census] = @project_discovered_global_write_census
|
|
2303
2317
|
end
|
|
2304
2318
|
|
|
2319
|
+
# Issue #1672 — the project's refinements (this run's discovery, else an opt-in `discovery_seed:` base's)
|
|
2320
|
+
# unioned with the opt-in gems' ({DependencySourceInference::Index#refinements}). The gem half comes from
|
|
2321
|
+
# the pre-passes every run takes, warm or cold, so a file re-analysed warm is seeded what a cold run seeds.
|
|
2322
|
+
# The seed is rebuilt per file, so the union is kept while its two inputs are the same objects.
|
|
2323
|
+
def seed_refinements(tables)
|
|
2324
|
+
project = @project_discovered_refinements
|
|
2325
|
+
project = tables[:discovered_refinements] if project.empty?
|
|
2326
|
+
gems = @dependency_source_index.refinements
|
|
2327
|
+
memo = @seed_refinements
|
|
2328
|
+
return memo[2] if memo && memo[0].equal?(project) && memo[1].equal?(gems)
|
|
2329
|
+
|
|
2330
|
+
merged = Inference::ScopeIndexer.merge_refinement_tables(project, gems)
|
|
2331
|
+
@seed_refinements = [project, gems, merged]
|
|
2332
|
+
merged
|
|
2333
|
+
end
|
|
2334
|
+
|
|
2305
2335
|
# The three mixin tables: the ADR-24 instance-side `include` map, its issue #1123 `prepend` twin
|
|
2306
2336
|
# (which carries the instance-ancestor order the include table's set-shaped value cannot), and the
|
|
2307
2337
|
# #898 singleton-side `extend` table. Grouped here because they are read as one picture of a class's
|
|
@@ -2603,7 +2633,8 @@ module Rigor
|
|
|
2603
2633
|
self_call_misses: self_call_misses,
|
|
2604
2634
|
comments: parse_result.comments,
|
|
2605
2635
|
disabled_rules: @configuration.disabled_rules,
|
|
2606
|
-
node_collectors: node_collectors
|
|
2636
|
+
node_collectors: node_collectors,
|
|
2637
|
+
stated_runtime_ruby: @configuration.stated_runtime_ruby
|
|
2607
2638
|
)
|
|
2608
2639
|
diagnostics + plugin_emitted_diagnostics(path, root, scope, node_results)
|
|
2609
2640
|
end
|
|
@@ -86,7 +86,7 @@ module Rigor
|
|
|
86
86
|
plugin_blueprints: [], explain: false, buffer: nil,
|
|
87
87
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
88
88
|
project_scope_seed: {}, source_files: [], record_dependencies: false,
|
|
89
|
-
template_units: nil, locked_gems: nil)
|
|
89
|
+
template_units: nil, locked_gems: nil, required_features: nil)
|
|
90
90
|
@configuration = configuration
|
|
91
91
|
@cache_store = cache_store
|
|
92
92
|
@explain = explain
|
|
@@ -119,7 +119,9 @@ module Rigor
|
|
|
119
119
|
# RubyGems module state a non-main Ractor may not touch, so a Ractor worker that resolved it here got
|
|
120
120
|
# `Ractor::IsolationError` and an empty map — no gem `sig/` directories, no ADR-72 overlays. nil (the
|
|
121
121
|
# fork backend and every other caller) resolves inside `Environment.for_project` exactly as before.
|
|
122
|
-
|
|
122
|
+
# Issue #1700 — `required_features` is the coordinator's scan ({Runner::PoolCoordinator#required_features_for});
|
|
123
|
+
# nil scans `source_files` inside `Environment.for_project`.
|
|
124
|
+
@environment_inputs = { locked_gems: locked_gems, required_features: required_features }.freeze
|
|
123
125
|
|
|
124
126
|
# NOTE: `Inference::MethodDispatcher::FileFolding.fold_platform_specific_paths` is process-global
|
|
125
127
|
# state. Writing it from a non-main Ractor would raise `Ractor::IsolationError`, so the session does
|
|
@@ -153,7 +155,7 @@ module Rigor
|
|
|
153
155
|
synthetic_method_index: @synthetic_method_index,
|
|
154
156
|
project_patched_methods: @project_patched_methods,
|
|
155
157
|
source_files: @source_files,
|
|
156
|
-
|
|
158
|
+
**@environment_inputs
|
|
157
159
|
)
|
|
158
160
|
@prepare_diagnostics = run_plugin_prepare.freeze
|
|
159
161
|
end
|
|
@@ -236,7 +238,8 @@ module Rigor
|
|
|
236
238
|
scope_index: index,
|
|
237
239
|
comments: parse_result.comments,
|
|
238
240
|
disabled_rules: @configuration.disabled_rules,
|
|
239
|
-
node_collectors: node_collectors
|
|
241
|
+
node_collectors: node_collectors,
|
|
242
|
+
stated_runtime_ruby: @configuration.stated_runtime_ruby
|
|
240
243
|
)
|
|
241
244
|
diagnostics += plugin_emitted_diagnostics(path, root, scope, node_results)
|
|
242
245
|
diagnostics + explain_diagnostics(path, parse_result.value, scope)
|
|
@@ -9,6 +9,7 @@ require_relative "store"
|
|
|
9
9
|
require_relative "../analysis/shadow_harness"
|
|
10
10
|
require_relative "../analysis/run_cache_key"
|
|
11
11
|
require_relative "../environment"
|
|
12
|
+
require_relative "../analysis/path_expansion"
|
|
12
13
|
|
|
13
14
|
module Rigor
|
|
14
15
|
module Cache
|
|
@@ -270,8 +271,18 @@ module Rigor
|
|
|
270
271
|
"sig:#{digest_signature_paths(project_sig_roots(configuration))}",
|
|
271
272
|
"pre_eval:#{digest_pre_eval(configuration.pre_eval)}"
|
|
272
273
|
]
|
|
274
|
+
parts.concat(dependency_source_parts(configuration))
|
|
273
275
|
identity = EngineSource.process_identity
|
|
274
276
|
parts << "engine-source:#{identity}" if identity
|
|
277
|
+
# Issue #1700 — the gated vendored signatures the run's source activates. A file that gains or drops a
|
|
278
|
+
# `require "prime"` changes the environment every other file was analysed against, which no per-file
|
|
279
|
+
# dependency edge records, so the whole snapshot goes. Scanned over the configured paths plus the roots'
|
|
280
|
+
# files, the set the run's environment scans; no part when nothing is required, so every other
|
|
281
|
+
# project's fingerprint is as it was.
|
|
282
|
+
features = Environment::RequiredFeatures.for_configuration(
|
|
283
|
+
configuration, Analysis::PathExpansion.ruby_files(roots, configuration.exclude_patterns)
|
|
284
|
+
)
|
|
285
|
+
parts << "required-features:#{features.join(',')}" unless features.empty?
|
|
275
286
|
# ADR-116 WD5 — the snapshot's per-file rows and seed bundles are only as checked as the run that
|
|
276
287
|
# wrote them ({Inference::DeclarationWalk::Shadow}); nil with the harness off adds no part.
|
|
277
288
|
shadow = Analysis::ShadowHarness.cache_identity
|
|
@@ -286,6 +297,17 @@ module Rigor
|
|
|
286
297
|
nil
|
|
287
298
|
end
|
|
288
299
|
|
|
300
|
+
# ADR-10 slice 3, issue #1814 — the walked gems' versions: their method catalogue, their refinement table and the
|
|
301
|
+
# constants they bind reach every file's checks, and the lockfile digest above does not cover a project with none.
|
|
302
|
+
# No part for a project that lists no gem, so its fingerprint is what it was.
|
|
303
|
+
def self.dependency_source_parts(configuration)
|
|
304
|
+
rows = Analysis::RunCacheKey.dependency_source_entries(configuration).map do |row|
|
|
305
|
+
[row.gem_name, row.gem_version, row.mode]
|
|
306
|
+
end
|
|
307
|
+
rows.empty? ? [] : ["dependency-source:#{rows.sort.inspect}"]
|
|
308
|
+
end
|
|
309
|
+
private_class_method :dependency_source_parts
|
|
310
|
+
|
|
289
311
|
def self.digest_file_if_present(path)
|
|
290
312
|
path = path&.to_s
|
|
291
313
|
path && File.file?(path) ? Digest::SHA256.file(path).hexdigest : "absent"
|
|
@@ -100,7 +100,12 @@ module Rigor
|
|
|
100
100
|
# in `#annotate` raise `invalid byte sequence in US-ASCII`. Ruby source is UTF-8 by convention (the parser's own
|
|
101
101
|
# assumption absent a magic comment).
|
|
102
102
|
source = File.read(file, mode: "r:bom|utf-8")
|
|
103
|
+
# Prism parses the ORIGINAL bytes, so a `# -*- coding: -*-` file is read in its own encoding. Only the text the
|
|
104
|
+
# line-wise regexps below see is scrubbed: a byte invalid in UTF-8 (a comment, `__END__` data, a non-UTF-8
|
|
105
|
+
# file) would make them raise.
|
|
106
|
+
# Scrubbing is byte-for-byte (`?` per bad byte), so Prism's positions still address it.
|
|
103
107
|
parse_result = Prism.parse(source, filepath: file, version: configuration.target_ruby)
|
|
108
|
+
source = source.scrub { |bytes| "?" * bytes.bytesize } unless source.valid_encoding?
|
|
104
109
|
return 1 if parse_errors?(parse_result, file)
|
|
105
110
|
|
|
106
111
|
# `converged_loop_recording` re-records fixpoint-tracked loop bodies from their converged (post-writeback)
|
|
@@ -126,8 +126,10 @@ module Rigor
|
|
|
126
126
|
|
|
127
127
|
def collect_diagnostics(configuration, _options)
|
|
128
128
|
cache_store = Cache::Store.new(root: configuration.cache_path)
|
|
129
|
-
#
|
|
130
|
-
#
|
|
129
|
+
# The generating run is the loaded configuration with `baseline:` off (#1777): every other key shapes the
|
|
130
|
+
# diagnostic set `rigor check` reports, so it must shape the recorded one too. The baseline filter itself is
|
|
131
|
+
# applied CLI-side by `check` (`CheckCommand#apply_baseline_filter`), never by the runner; clearing it here is
|
|
132
|
+
# defensive.
|
|
131
133
|
configuration_for_generation = override_configuration_baseline_off(configuration)
|
|
132
134
|
runner = Analysis::Runner.new(
|
|
133
135
|
configuration: configuration_for_generation,
|
|
@@ -137,23 +139,10 @@ module Rigor
|
|
|
137
139
|
runner.run(configuration_for_generation.paths).diagnostics
|
|
138
140
|
end
|
|
139
141
|
|
|
142
|
+
# The loaded configuration with only `baseline` disabled (#1777): any other key can change the
|
|
143
|
+
# diagnostic set, and the baseline must record the set `rigor check` will then report.
|
|
140
144
|
def override_configuration_baseline_off(configuration)
|
|
141
|
-
|
|
142
|
-
# so we round-trip through the constructor with an override hash.
|
|
143
|
-
defaults = Configuration::DEFAULTS.merge(
|
|
144
|
-
"paths" => configuration.paths,
|
|
145
|
-
"exclude" => configuration.exclude_patterns,
|
|
146
|
-
"plugins" => configuration.plugins,
|
|
147
|
-
"disable" => configuration.disabled_rules,
|
|
148
|
-
"libraries" => configuration.libraries,
|
|
149
|
-
"signature_paths" => configuration.signature_paths,
|
|
150
|
-
"pre_eval" => configuration.pre_eval,
|
|
151
|
-
"severity_profile" => configuration.severity_profile.to_s,
|
|
152
|
-
"severity_overrides" => configuration.severity_overrides,
|
|
153
|
-
"baseline" => false,
|
|
154
|
-
"cache" => { "path" => configuration.cache_path }
|
|
155
|
-
)
|
|
156
|
-
Configuration.new(defaults)
|
|
145
|
+
configuration.without_baseline
|
|
157
146
|
end
|
|
158
147
|
|
|
159
148
|
# ---- dump --------------------------------------------------
|
|
@@ -685,9 +685,10 @@ module Rigor
|
|
|
685
685
|
# ADR-103 WD15 — captured before `DEFAULTS.merge` below folds "no `effects:` key" and "`effects:
|
|
686
686
|
# false`" into the same value; see `Configuration.load`'s identical capture.
|
|
687
687
|
effects_key_present = data.key?("effects")
|
|
688
|
+
target_ruby_key_present = data.key?("target_ruby")
|
|
688
689
|
data = data.dup
|
|
689
690
|
data["plugins"] = inject_treat_all_as_inline_rbs(Array(data["plugins"]))
|
|
690
|
-
Configuration.new(Configuration::DEFAULTS.merge(data), effects_key_present)
|
|
691
|
+
Configuration.new(Configuration::DEFAULTS.merge(data), effects_key_present, target_ruby_key_present)
|
|
691
692
|
end
|
|
692
693
|
|
|
693
694
|
# ADR-50 § WD2 — applies the `--bleeding-edge[=ids]` / `--no-bleeding-edge` CLI selection over the configured
|
|
@@ -69,7 +69,12 @@ module Rigor
|
|
|
69
69
|
def execute(file:, options:)
|
|
70
70
|
configuration = Configuration.load(options.fetch(:config))
|
|
71
71
|
source = File.read(file, encoding: Encoding::UTF_8)
|
|
72
|
+
# Prism parses the ORIGINAL bytes, so a `# -*- coding: -*-` file is read in its own encoding. Only the text the
|
|
73
|
+
# renderer sees is scrubbed: the colouriser and line splitter raise on a byte invalid in UTF-8 (a comment,
|
|
74
|
+
# `__END__` data, a non-UTF-8 file).
|
|
75
|
+
# Scrubbing is byte-for-byte (`?` per bad byte), so Prism's positions still address it.
|
|
72
76
|
parse_result = Prism.parse(source, filepath: file, version: configuration.target_ruby)
|
|
77
|
+
source = source.scrub { |bytes| "?" * bytes.bytesize } unless source.valid_encoding?
|
|
73
78
|
return 1 if parse_errors?(parse_result, file)
|
|
74
79
|
|
|
75
80
|
events = record_events(parse_result.value, file, configuration)
|
|
@@ -87,7 +87,7 @@ module Rigor
|
|
|
87
87
|
# file is parsed and scope-indexed once, however many positions land in it.
|
|
88
88
|
def execute(targets:, options:, buffer: nil)
|
|
89
89
|
configuration = Configuration.load(options.fetch(:config))
|
|
90
|
-
environment = project_environment(targets.map(&:file).uniq, configuration)
|
|
90
|
+
environment = project_environment(targets.map(&:file).uniq, configuration, buffer)
|
|
91
91
|
base_scope = Scope.empty(environment: environment)
|
|
92
92
|
|
|
93
93
|
results_by_target = Array.new(targets.length)
|
|
@@ -218,8 +218,10 @@ module Rigor
|
|
|
218
218
|
# closes). The probed file is threaded as the synthesizer's `source_files:`. Project-RBS auto-detection
|
|
219
219
|
# roots at CWD today; future work will walk parent directories to find the enclosing `Gemfile`/`*.gemspec`
|
|
220
220
|
# so probes against files outside the current process's CWD still see the right `sig/` tree.
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
# Issue #1700 — an editor buffer is scanned for required features in place of the file it stands for.
|
|
222
|
+
def project_environment(files, configuration, buffer = nil)
|
|
223
|
+
ProjectEnvironment.build(configuration: configuration, source_files: files,
|
|
224
|
+
feature_sources: ProjectEnvironment.buffer_sources(buffer))
|
|
223
225
|
end
|
|
224
226
|
|
|
225
227
|
def file_exists?(file)
|