rigortype 0.1.17 → 0.1.19

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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +159 -222
  3. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +24 -1
  4. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +25 -0
  5. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +29 -0
  6. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +54 -0
  7. data/lib/rigor/analysis/check_rules/rule_walk.rb +213 -0
  8. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +24 -1
  9. data/lib/rigor/analysis/check_rules.rb +275 -44
  10. data/lib/rigor/analysis/diagnostic.rb +8 -0
  11. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +581 -0
  12. data/lib/rigor/analysis/runner/pool_coordinator.rb +569 -0
  13. data/lib/rigor/analysis/runner/project_pre_passes.rb +321 -0
  14. data/lib/rigor/analysis/runner/run_snapshots.rb +46 -0
  15. data/lib/rigor/analysis/runner.rb +207 -1200
  16. data/lib/rigor/analysis/worker_session.rb +60 -11
  17. data/lib/rigor/bleeding_edge.rb +123 -0
  18. data/lib/rigor/cache/descriptor.rb +86 -8
  19. data/lib/rigor/cache/incremental_snapshot.rb +10 -4
  20. data/lib/rigor/cache/rbs_cache_producer.rb +5 -1
  21. data/lib/rigor/cache/rbs_descriptor.rb +2 -1
  22. data/lib/rigor/cache/store.rb +46 -13
  23. data/lib/rigor/cli/annotate_command.rb +100 -15
  24. data/lib/rigor/cli/check_command.rb +708 -0
  25. data/lib/rigor/cli/ci_detector.rb +94 -0
  26. data/lib/rigor/cli/diagnostic_formats.rb +345 -0
  27. data/lib/rigor/cli/plugins_command.rb +2 -4
  28. data/lib/rigor/cli/plugins_renderer.rb +0 -2
  29. data/lib/rigor/cli/prism_colorizer.rb +10 -3
  30. data/lib/rigor/cli/show_bleedingedge_command.rb +114 -0
  31. data/lib/rigor/cli/trace_command.rb +143 -0
  32. data/lib/rigor/cli/trace_renderer.rb +310 -0
  33. data/lib/rigor/cli/triage_command.rb +6 -3
  34. data/lib/rigor/cli/triage_renderer.rb +15 -1
  35. data/lib/rigor/cli.rb +21 -612
  36. data/lib/rigor/configuration/severity_profile.rb +13 -1
  37. data/lib/rigor/configuration.rb +66 -7
  38. data/lib/rigor/environment/rbs_loader.rb +78 -68
  39. data/lib/rigor/environment.rb +1 -1
  40. data/lib/rigor/inference/acceptance.rb +10 -0
  41. data/lib/rigor/inference/body_fixpoint.rb +89 -0
  42. data/lib/rigor/inference/budget_trace.rb +29 -2
  43. data/lib/rigor/inference/expression_typer.rb +1080 -105
  44. data/lib/rigor/inference/flow_tracer.rb +180 -0
  45. data/lib/rigor/inference/macro_block_self_type.rb +11 -12
  46. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +60 -0
  47. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +54 -14
  48. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +33 -1
  49. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +281 -0
  50. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +71 -0
  51. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +148 -10
  52. data/lib/rigor/inference/method_dispatcher.rb +187 -55
  53. data/lib/rigor/inference/method_parameter_binder.rb +56 -2
  54. data/lib/rigor/inference/multi_target_binder.rb +46 -3
  55. data/lib/rigor/inference/mutation_widening.rb +142 -0
  56. data/lib/rigor/inference/narrowing.rb +330 -37
  57. data/lib/rigor/inference/scope_indexer.rb +770 -39
  58. data/lib/rigor/inference/statement_evaluator.rb +998 -68
  59. data/lib/rigor/inference/synthetic_method_scanner.rb +1 -1
  60. data/lib/rigor/plugin/additional_initializer.rb +61 -38
  61. data/lib/rigor/plugin/base.rb +517 -120
  62. data/lib/rigor/plugin/macro/block_as_method.rb +22 -21
  63. data/lib/rigor/plugin/macro/nested_class_template.rb +9 -7
  64. data/lib/rigor/plugin/macro.rb +2 -3
  65. data/lib/rigor/plugin/manifest.rb +4 -24
  66. data/lib/rigor/plugin/node_rule_walk.rb +192 -0
  67. data/lib/rigor/plugin/registry.rb +264 -35
  68. data/lib/rigor/plugin.rb +1 -0
  69. data/lib/rigor/rbs_extended/conformance_checker.rb +86 -1
  70. data/lib/rigor/scope/discovery_index.rb +60 -0
  71. data/lib/rigor/scope.rb +199 -204
  72. data/lib/rigor/sig_gen/generator.rb +8 -0
  73. data/lib/rigor/sig_gen/observation_collector.rb +6 -6
  74. data/lib/rigor/source/literals.rb +14 -0
  75. data/lib/rigor/triage/catalogue.rb +4 -19
  76. data/lib/rigor/triage.rb +69 -1
  77. data/lib/rigor/type/combinator.rb +34 -0
  78. data/lib/rigor/version.rb +1 -1
  79. data/lib/rigor.rb +0 -1
  80. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +13 -29
  81. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -32
  82. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -2
  83. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +27 -90
  84. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +13 -30
  85. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +2 -4
  86. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +90 -51
  87. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +3 -3
  88. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -29
  89. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +1 -1
  90. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -2
  91. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +11 -40
  92. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +2 -2
  93. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +1 -1
  94. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +10 -21
  95. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +21 -34
  96. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +11 -18
  97. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +0 -1
  98. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +12 -2
  99. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
  100. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +37 -31
  101. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +3 -23
  102. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +8 -21
  103. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -1
  104. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +8 -29
  105. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +17 -1
  106. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +2 -2
  107. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +108 -36
  108. data/sig/rigor/analysis/fact_store.rbs +3 -0
  109. data/sig/rigor/environment.rbs +0 -2
  110. data/sig/rigor/inference/builtins/method_catalog.rbs +1 -1
  111. data/sig/rigor/inference.rbs +5 -0
  112. data/sig/rigor/plugin/base.rbs +6 -4
  113. data/sig/rigor/plugin/manifest.rbs +1 -2
  114. data/sig/rigor/scope.rbs +50 -29
  115. data/sig/rigor/source.rbs +1 -0
  116. data/sig/rigor/type.rbs +1 -0
  117. data/sig/rigor.rbs +1 -1
  118. data/skills/rigor-baseline-reduce/references/01-classify.md +27 -0
  119. data/skills/rigor-ci-setup/SKILL.md +319 -0
  120. data/skills/rigor-plugin-author/SKILL.md +6 -4
  121. data/skills/rigor-plugin-author/references/02-walker-and-types.md +22 -17
  122. data/skills/rigor-project-init/references/03-baseline-and-bugs.md +18 -1
  123. metadata +21 -3
  124. data/lib/rigor/cache/rbs_instance_definitions.rb +0 -66
  125. data/lib/rigor/plugin/macro/external_file.rb +0 -143
@@ -1,143 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rigor
4
- module Plugin
5
- module Macro
6
- # ADR-16 Tier D declaration: "files matching `glob` are
7
- # analysed as if their body were pasted at a call site whose
8
- # `self` is an instance of `receiver_type` (and whose `@ivar`
9
- # facts come from `bound_ivars`)."
10
- #
11
- # Worked motivating cases (per the per-library survey):
12
- #
13
- # - Redmine's `WebhookPayload#instance_eval(File.read(path), path, 1)`
14
- # at `app/models/webhook_payload.rb:71`. The payload templates
15
- # under `config/webhooks/*.rb` run with `self` typed as
16
- # `Redmine::WebhookPayload` and ivars like `@event` / `@issue`
17
- # / `@user` pre-bound by the caller.
18
- # - tDiary Core's plugin loader pattern — `misc/plugin/*.rb`
19
- # files loaded under `instance_eval` with the tDiary plugin
20
- # instance as `self`.
21
- #
22
- # ## Authoring shape
23
- #
24
- # manifest(
25
- # id: "redmine-webhook-payloads",
26
- # version: "0.1.0",
27
- # external_files: [
28
- # Rigor::Plugin::Macro::ExternalFile.new(
29
- # glob: "config/webhooks/*.rb",
30
- # receiver_type: "Redmine::WebhookPayload",
31
- # bound_ivars: {
32
- # "@event" => "Symbol",
33
- # "@issue" => "Issue?",
34
- # "@user" => "User"
35
- # }
36
- # )
37
- # ]
38
- # )
39
- #
40
- # ## Fields
41
- #
42
- # - `glob` — non-empty String pattern. Interpreted relative
43
- # to the project root (the directory containing `.rigor.yml`)
44
- # at scan time. Slice 5a accepts any non-empty glob
45
- # pattern syntactically; the engine integration (slice 5b)
46
- # pins the resolution rule.
47
- # - `receiver_type` — non-empty String. The class name `self`
48
- # inside the loaded file binds to. Engine integration (slice
49
- # 5b) narrows the file-entry scope's `self_type` to
50
- # `Nominal[receiver_type]`.
51
- # - `bound_ivars` — Hash<String, String>. Each key MUST start
52
- # with `@`; each value is a non-empty type-name String. The
53
- # engine pre-binds these as ivar facts in the file-entry
54
- # scope (slice 5b).
55
- #
56
- # ## Slice 5a scope
57
- #
58
- # **This file ships the value class + manifest hook ONLY.**
59
- # The engine integration that (a) adds matched files to the
60
- # analysis set, (b) narrows the file-entry `self_type`, and
61
- # (c) pre-binds `bound_ivars` as ivar facts is **queued for
62
- # slice 5b**, gated on demonstrated demand. The survey
63
- # identifies only Redmine + tDiary as concrete consumers;
64
- # premature engine work is deferred until those cases (or
65
- # equivalents) materialise as committed plugin targets.
66
- #
67
- # With only this slice landed, plugin authors CAN declare a
68
- # Tier D manifest entry today — the declaration round-trips
69
- # through `Manifest#to_h` (cache-key stable) and is exposed
70
- # on `Manifest#external_files` — but the substrate does not
71
- # yet act on it. The contract is forward-compatible: when
72
- # slice 5b lands, the engine reads the same declarations and
73
- # plugin gems do not need to change.
74
- class ExternalFile
75
- attr_reader :glob, :receiver_type, :bound_ivars
76
-
77
- def initialize(glob:, receiver_type:, bound_ivars: {})
78
- validate_glob!(glob)
79
- validate_receiver_type!(receiver_type)
80
- validate_bound_ivars!(bound_ivars)
81
-
82
- @glob = glob.dup.freeze
83
- @receiver_type = receiver_type.dup.freeze
84
- @bound_ivars = bound_ivars.to_h { |k, v| [k.dup.freeze, v.dup.freeze] }.freeze
85
- freeze
86
- end
87
-
88
- def to_h
89
- {
90
- "glob" => glob,
91
- "receiver_type" => receiver_type,
92
- "bound_ivars" => bound_ivars
93
- }
94
- end
95
-
96
- def ==(other)
97
- other.is_a?(ExternalFile) && to_h == other.to_h
98
- end
99
- alias eql? ==
100
-
101
- def hash
102
- to_h.hash
103
- end
104
-
105
- private
106
-
107
- def validate_glob!(value)
108
- return if value.is_a?(String) && !value.empty?
109
-
110
- raise ArgumentError,
111
- "Plugin::Macro::ExternalFile#glob must be a non-empty String, got #{value.inspect}"
112
- end
113
-
114
- def validate_receiver_type!(value)
115
- return if value.is_a?(String) && !value.empty?
116
-
117
- raise ArgumentError,
118
- "Plugin::Macro::ExternalFile#receiver_type must be a non-empty String, got #{value.inspect}"
119
- end
120
-
121
- def validate_bound_ivars!(value)
122
- unless value.is_a?(Hash)
123
- raise ArgumentError,
124
- "Plugin::Macro::ExternalFile#bound_ivars must be a Hash, got #{value.inspect}"
125
- end
126
-
127
- value.each do |k, v|
128
- unless k.is_a?(String) && k.start_with?("@") && k.length > 1
129
- raise ArgumentError,
130
- "Plugin::Macro::ExternalFile#bound_ivars key must be a String starting with `@`, " \
131
- "got #{k.inspect}"
132
- end
133
- next if v.is_a?(String) && !v.empty?
134
-
135
- raise ArgumentError,
136
- "Plugin::Macro::ExternalFile#bound_ivars value must be a non-empty String, " \
137
- "got #{v.inspect}"
138
- end
139
- end
140
- end
141
- end
142
- end
143
- end