sonicop 26.8.110 → 26.8.112

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CONFORMANCE.md +64 -31
  3. data/Cargo.lock +92 -17
  4. data/Cargo.toml +10 -5
  5. data/NOTICE +15 -3
  6. data/README.ja.md +122 -44
  7. data/README.md +118 -35
  8. data/build.rs +155 -0
  9. data/lib/sonicop/runner.rb +7 -1
  10. data/lib/sonicop/version.rb +1 -1
  11. data/src/cli.rs +312 -92
  12. data/src/config/inheritance.rs +594 -63
  13. data/src/config/mod.rs +130 -1
  14. data/src/config/paths.rs +550 -48
  15. data/src/cop_name.rs +18 -1
  16. data/src/diagnostic.rs +168 -3
  17. data/src/directives.rs +398 -77
  18. data/src/display_width.rs +82 -42
  19. data/src/display_width_table.rs +506 -0
  20. data/src/engine.rs +1689 -175
  21. data/src/formatter.rs +10 -1
  22. data/src/lib.rs +1 -0
  23. data/src/main.rs +112 -1
  24. data/src/nul_bytes.rs +243 -41
  25. data/src/profile.rs +162 -24
  26. data/src/ruby_version.rs +167 -21
  27. data/src/rules/gemspec/support.rs +25 -6
  28. data/src/rules/layout/access_modifier_indentation.rs +13 -6
  29. data/src/rules/layout/alignment.rs +1 -1
  30. data/src/rules/layout/argument_alignment.rs +19 -7
  31. data/src/rules/layout/block_alignment.rs +75 -31
  32. data/src/rules/layout/class_structure.rs +8 -1
  33. data/src/rules/layout/closing_heredoc_indentation.rs +21 -3
  34. data/src/rules/layout/closing_parenthesis_indentation.rs +2 -1
  35. data/src/rules/layout/comment_indentation.rs +3 -2
  36. data/src/rules/layout/def_end_alignment.rs +8 -4
  37. data/src/rules/layout/else_alignment.rs +24 -14
  38. data/src/rules/layout/empty_line_after_guard_clause.rs +6 -2
  39. data/src/rules/layout/empty_line_between_defs.rs +8 -6
  40. data/src/rules/layout/empty_lines.rs +1 -1
  41. data/src/rules/layout/empty_lines_around_access_modifier.rs +21 -8
  42. data/src/rules/layout/empty_lines_around_body.rs +8 -2
  43. data/src/rules/layout/empty_lines_around_method_body.rs +1 -6
  44. data/src/rules/layout/end_alignment.rs +31 -6
  45. data/src/rules/layout/end_of_line.rs +14 -1
  46. data/src/rules/layout/extra_spacing.rs +2 -5
  47. data/src/rules/layout/first_hash_element_indentation.rs +1 -1
  48. data/src/rules/layout/hash_alignment.rs +113 -19
  49. data/src/rules/layout/indentation_style.rs +2 -1
  50. data/src/rules/layout/indentation_width.rs +65 -6
  51. data/src/rules/layout/initial_indentation.rs +18 -5
  52. data/src/rules/layout/line_continuation_spacing.rs +3 -2
  53. data/src/rules/layout/line_length.rs +362 -29
  54. data/src/rules/layout/mod.rs +1 -1
  55. data/src/rules/layout/multiline_assignment_layout.rs +16 -0
  56. data/src/rules/layout/multiline_block_layout.rs +1 -1
  57. data/src/rules/layout/redundant_line_break.rs +13 -3
  58. data/src/rules/layout/rescue_ensure_alignment.rs +20 -12
  59. data/src/rules/layout/single_line_block_chain.rs +9 -1
  60. data/src/rules/layout/space_around_block_parameters.rs +15 -0
  61. data/src/rules/layout/space_around_keyword.rs +22 -4
  62. data/src/rules/layout/space_around_operators.rs +33 -0
  63. data/src/rules/layout/space_before_brackets.rs +7 -1
  64. data/src/rules/layout/space_inside_array_literal_brackets.rs +25 -10
  65. data/src/rules/layout/space_inside_array_percent_literal.rs +7 -1
  66. data/src/rules/layout/space_inside_parens.rs +170 -87
  67. data/src/rules/layout/space_inside_range_literal.rs +45 -13
  68. data/src/rules/layout/space_inside_reference_brackets.rs +65 -3
  69. data/src/rules/layout/space_inside_string_interpolation.rs +147 -48
  70. data/src/rules/layout/support.rs +163 -19
  71. data/src/rules/layout/tokens.rs +34 -3
  72. data/src/rules/layout/trailing_whitespace.rs +5 -2
  73. data/src/rules/lint/access_modifier.rs +36 -0
  74. data/src/rules/lint/ambiguity.rs +95 -5
  75. data/src/rules/lint/ambiguous_block_association.rs +22 -2
  76. data/src/rules/lint/ambiguous_operator.rs +8 -0
  77. data/src/rules/lint/ambiguous_operator_precedence.rs +18 -1
  78. data/src/rules/lint/ambiguous_range.rs +15 -1
  79. data/src/rules/lint/ambiguous_regexp_literal.rs +38 -1
  80. data/src/rules/lint/array_literal_in_regexp.rs +9 -2
  81. data/src/rules/lint/constant_reassignment.rs +7 -12
  82. data/src/rules/lint/constant_resolution.rs +8 -0
  83. data/src/rules/lint/cop_directives.rs +28 -4
  84. data/src/rules/lint/debugger.rs +59 -9
  85. data/src/rules/lint/duplicate_branch.rs +10 -1
  86. data/src/rules/lint/duplicate_hash_key.rs +4 -1
  87. data/src/rules/lint/duplicate_magic_comment.rs +1 -1
  88. data/src/rules/lint/duplicate_methods.rs +130 -52
  89. data/src/rules/lint/duplicate_set_element.rs +16 -3
  90. data/src/rules/lint/empty_conditional_body.rs +15 -0
  91. data/src/rules/lint/empty_expression.rs +16 -1
  92. data/src/rules/lint/flow.rs +8 -5
  93. data/src/rules/lint/implicit_string_concatenation.rs +30 -2
  94. data/src/rules/lint/literal_as_condition.rs +46 -28
  95. data/src/rules/lint/literal_in_interpolation.rs +65 -1
  96. data/src/rules/lint/missing_cop_enable_directive.rs +95 -18
  97. data/src/rules/lint/mod.rs +1 -0
  98. data/src/rules/lint/nested_method_definition.rs +36 -11
  99. data/src/rules/lint/nil_receiver.rs +420 -0
  100. data/src/rules/lint/non_atomic_file_operation.rs +8 -2
  101. data/src/rules/lint/non_local_exit_from_iterator.rs +20 -8
  102. data/src/rules/lint/ordered_magic_comments.rs +1 -1
  103. data/src/rules/lint/parentheses_as_grouped_expression.rs +5 -0
  104. data/src/rules/lint/redundant_cop_disable_directive.rs +1 -1
  105. data/src/rules/lint/redundant_cop_enable_directive.rs +3 -1
  106. data/src/rules/lint/redundant_safe_navigation.rs +43 -19
  107. data/src/rules/lint/redundant_type_conversion.rs +16 -4
  108. data/src/rules/lint/regexp.rs +1 -3
  109. data/src/rules/lint/regexp_tree.rs +38 -5
  110. data/src/rules/lint/return_in_void_context.rs +6 -1
  111. data/src/rules/lint/safe_navigation_chain.rs +44 -9
  112. data/src/rules/lint/self_assignment.rs +17 -0
  113. data/src/rules/lint/suppressed_exception.rs +21 -3
  114. data/src/rules/lint/symbol_conversion.rs +51 -4
  115. data/src/rules/lint/syntax.rs +194 -5
  116. data/src/rules/lint/top_level_return_with_argument.rs +11 -1
  117. data/src/rules/lint/unexpected_block_arity.rs +22 -5
  118. data/src/rules/lint/unified_integer.rs +18 -12
  119. data/src/rules/lint/unmodified_reduce_accumulator.rs +29 -1
  120. data/src/rules/lint/unreachable_code.rs +4 -4
  121. data/src/rules/lint/unreachable_loop.rs +26 -10
  122. data/src/rules/lint/unreachable_pattern_branch.rs +3 -1
  123. data/src/rules/lint/variable_force.rs +185 -3
  124. data/src/rules/lint/void.rs +27 -16
  125. data/src/rules/metrics/abc_size.rs +197 -7
  126. data/src/rules/metrics/block_length.rs +19 -10
  127. data/src/rules/metrics/class_length.rs +16 -4
  128. data/src/rules/metrics/complexity.rs +36 -3
  129. data/src/rules/metrics/locals.rs +12 -2
  130. data/src/rules/metrics/method_length.rs +14 -6
  131. data/src/rules/metrics/perceived_complexity.rs +1 -3
  132. data/src/rules/metrics/support.rs +93 -3
  133. data/src/rules/mod.rs +67 -24
  134. data/src/rules/naming/binary_operator_parameter_name.rs +5 -4
  135. data/src/rules/naming/constant_name.rs +56 -18
  136. data/src/rules/naming/file_name.rs +174 -43
  137. data/src/rules/naming/method_name.rs +8 -1
  138. data/src/rules/naming/predicate_method.rs +36 -9
  139. data/src/rules/naming/predicate_prefix.rs +64 -0
  140. data/src/rules/naming/rescued_exceptions_variable_name.rs +6 -5
  141. data/src/rules/naming/support.rs +47 -290
  142. data/src/rules/naming/variable_name.rs +17 -4
  143. data/src/rules/naming/variable_number.rs +5 -6
  144. data/src/rules/ruby_literal.rs +5 -1
  145. data/src/rules/style/access_modifier_declarations.rs +75 -21
  146. data/src/rules/style/accessor_grouping.rs +44 -6
  147. data/src/rules/style/alias.rs +3 -1
  148. data/src/rules/style/array_first_last.rs +16 -1
  149. data/src/rules/style/array_intersect.rs +25 -7
  150. data/src/rules/style/ascii_comments.rs +2 -0
  151. data/src/rules/style/block_comments.rs +11 -2
  152. data/src/rules/style/block_delimiters.rs +147 -4
  153. data/src/rules/style/case_equality.rs +4 -0
  154. data/src/rules/style/case_like_if.rs +25 -1
  155. data/src/rules/style/class_and_module_children.rs +155 -5
  156. data/src/rules/style/class_methods_definitions.rs +9 -0
  157. data/src/rules/style/combinable_loops.rs +8 -10
  158. data/src/rules/style/comment_annotation.rs +5 -1
  159. data/src/rules/style/commented_keyword.rs +1 -1
  160. data/src/rules/style/comments.rs +6 -3
  161. data/src/rules/style/conditional.rs +4 -0
  162. data/src/rules/style/conditional_assignment.rs +133 -4
  163. data/src/rules/style/copyright.rs +63 -2
  164. data/src/rules/style/document_dynamic_eval_definition.rs +50 -12
  165. data/src/rules/style/empty_heredoc.rs +13 -0
  166. data/src/rules/style/empty_literal.rs +32 -0
  167. data/src/rules/style/endless.rs +11 -3
  168. data/src/rules/style/eval_with_location.rs +6 -0
  169. data/src/rules/style/file_open.rs +5 -0
  170. data/src/rules/style/format_sequences.rs +6 -0
  171. data/src/rules/style/format_string.rs +74 -10
  172. data/src/rules/style/format_string_token.rs +55 -6
  173. data/src/rules/style/frozen_string_literal_comment.rs +62 -4
  174. data/src/rules/style/hash_lookup_method.rs +40 -0
  175. data/src/rules/style/hash_syntax.rs +607 -69
  176. data/src/rules/style/hash_transform_keys.rs +7 -0
  177. data/src/rules/style/hash_transform_values.rs +7 -0
  178. data/src/rules/style/identical_conditional_branches.rs +52 -2
  179. data/src/rules/style/if_inside_else.rs +16 -0
  180. data/src/rules/style/if_unless_modifier.rs +3 -3
  181. data/src/rules/style/if_with_semicolon.rs +6 -0
  182. data/src/rules/style/implicit_runtime_error.rs +7 -0
  183. data/src/rules/style/infinite_loop.rs +6 -0
  184. data/src/rules/style/inline_comment.rs +4 -1
  185. data/src/rules/style/inverse_methods.rs +10 -0
  186. data/src/rules/style/invertible_unless_condition.rs +9 -9
  187. data/src/rules/style/it_block_parameter.rs +4 -1
  188. data/src/rules/style/keyword_arguments_merging.rs +6 -0
  189. data/src/rules/style/line_end_concatenation.rs +1 -1
  190. data/src/rules/style/magic_comment_format.rs +11 -4
  191. data/src/rules/style/mixin_grouping.rs +5 -6
  192. data/src/rules/style/multiline_block_chain.rs +5 -7
  193. data/src/rules/style/multiline_in_pattern_then.rs +15 -2
  194. data/src/rules/style/mutable_constant.rs +28 -32
  195. data/src/rules/style/negated_if_else_condition.rs +3 -1
  196. data/src/rules/style/negative_array_index.rs +23 -1
  197. data/src/rules/style/next.rs +11 -11
  198. data/src/rules/style/non_nil_check.rs +80 -0
  199. data/src/rules/style/numbered_parameters.rs +4 -1
  200. data/src/rules/style/numeric_literals.rs +17 -1
  201. data/src/rules/style/numeric_predicate.rs +25 -6
  202. data/src/rules/style/one_line_conditional.rs +21 -4
  203. data/src/rules/style/operator_method_call.rs +5 -0
  204. data/src/rules/style/parallel_assignment.rs +12 -0
  205. data/src/rules/style/percent.rs +9 -2
  206. data/src/rules/style/percent_q_literals.rs +37 -5
  207. data/src/rules/style/quoted_symbols.rs +6 -0
  208. data/src/rules/style/raise_args.rs +26 -20
  209. data/src/rules/style/redundant_begin.rs +3 -1
  210. data/src/rules/style/redundant_condition.rs +8 -1
  211. data/src/rules/style/redundant_double_splat_hash_braces.rs +12 -2
  212. data/src/rules/style/redundant_exception.rs +3 -1
  213. data/src/rules/style/redundant_format.rs +140 -58
  214. data/src/rules/style/redundant_initialize.rs +4 -1
  215. data/src/rules/style/redundant_interpolation.rs +6 -6
  216. data/src/rules/style/redundant_interpolation_unfreeze.rs +8 -1
  217. data/src/rules/style/redundant_line_continuation.rs +5 -3
  218. data/src/rules/style/redundant_parentheses.rs +82 -6
  219. data/src/rules/style/redundant_regexp_argument.rs +1 -1
  220. data/src/rules/style/redundant_self.rs +17 -5
  221. data/src/rules/style/rescue_modifier.rs +8 -3
  222. data/src/rules/style/safe_navigation_chain_length.rs +8 -1
  223. data/src/rules/style/select_by.rs +4 -0
  224. data/src/rules/style/semicolon.rs +74 -2
  225. data/src/rules/style/signal_exception.rs +60 -3
  226. data/src/rules/style/single_argument_dig.rs +9 -1
  227. data/src/rules/style/single_line_block_params.rs +10 -1
  228. data/src/rules/style/static_class.rs +6 -0
  229. data/src/rules/style/string_concatenation.rs +3 -0
  230. data/src/rules/style/string_literals_in_interpolation.rs +3 -0
  231. data/src/rules/style/super_arguments.rs +13 -5
  232. data/src/rules/style/super_with_args_parentheses.rs +49 -12
  233. data/src/rules/style/symbol_array.rs +8 -1
  234. data/src/rules/style/ternary_parentheses.rs +26 -11
  235. data/src/rules/style/top_level_method_definition.rs +9 -4
  236. data/src/rules/style/trailing_comma.rs +206 -10
  237. data/src/rules/style/trailing_comma_in_arguments.rs +9 -10
  238. data/src/rules/style/trailing_comma_in_array_literal.rs +1 -0
  239. data/src/rules/style/trailing_comma_in_hash_literal.rs +1 -0
  240. data/src/rules/style/trailing_method_end_statement.rs +6 -1
  241. data/src/rules/style/unpack_first.rs +10 -1
  242. data/src/rules/style/while_until_modifier.rs +1 -1
  243. data/src/rules/style/word_array.rs +6 -4
  244. data/src/rules/style/zero_length_predicate.rs +5 -0
  245. data/src/rules/support.rs +118 -4
  246. data/src/source.rs +18 -15
  247. metadata +4 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a00a7d0dc817fde927c8f9a5eb24db975f85aa2f4dda36ae1f7de548aa6557f6
4
- data.tar.gz: 2c09e86e186f680c8f31cf5fd0e979fb974bc23ad173fa14e4f100f98dc95ce3
3
+ metadata.gz: bd4ccd5169f98c0ac8c5aedbe9dd4662344c27da16b2a4ea009a5f95b77a0cff
4
+ data.tar.gz: d516055ea9785026bda48a405d49ad97fc0e0851469bafa7d71cb341b663bda3
5
5
  SHA512:
6
- metadata.gz: 786c6eb994b2d5020f9f035623ec0f54ab95ad3f0359f747efd0bf97fd1bd4cca00d21b7a652b483861aef2af80dabb18dea4185bf9320a214307c4ea8780a8a
7
- data.tar.gz: 8c0b93e14e6e7a56f497cc55aad95ce730c681515f9e2f8d67efcfe3c8ae44d98dc8f5ab1bf9c25b60f6de0791b0ed077bc3df0b4a679d3c07416a731426c66d
6
+ metadata.gz: a28ead40c6fd72e5e79ea4c69e3d6dabeeb1a5af3004110548ae02cbad6310bbdaf6fe7f5765afc3014d77dd640dcad02821465be4d6d866808f080bc697f822
7
+ data.tar.gz: f422f7e53c4e4a7535ac1910ca2bbf50a0e7fae1851fcb94621a0dcec388bf4bdd0164962b140187085e15eabb5e31351f0e4c0a04ae6cb050fa8b1f7834e009
data/CONFORMANCE.md CHANGED
@@ -55,17 +55,18 @@ sonicop --force-default-config --format json
55
55
 
56
56
  ## Results
57
57
 
58
- The two kinds of difference are counted separately because they mean different things. A
59
- `Lint/Syntax` difference says the two disagree about whether a file parses, and everything else in
60
- that file follows from it; a difference in any other cop says the port reads the same tree and
61
- draws a different conclusion. Only the second is a defect in a cop.
58
+ Three kinds of difference are counted separately because they mean different things. The set of
59
+ files with a fatal `Lint/Syntax` offense says whether the parsers disagree about accepting a file.
60
+ `Lint/Syntax` positions inside a file both already rejected measure diagnostic recovery, not file
61
+ acceptance. A difference in any other cop says the port reads the same tree and draws a different
62
+ conclusion. Only the last category is a defect in a cop.
62
63
 
63
64
  | Corpus | Excess | Missing | of which `Lint/Syntax` | Other cops | Field differences | Measured |
64
65
  |---|---:|---:|---|---:|---|---|
65
66
  | rubocop/rubocop | 0 | 0 | — | 0 | correctable ×1 | 2026-08-17 |
66
67
  | rails/rails | 0 | 0 | — | 0 | none | 2026-08-17 |
67
68
  | mastodon/mastodon | 0 | 0 | — | 0 | none | 2026-08-17 |
68
- | Homebrew/brew | 263 | 997 | **all of them** | **0** | none | 2026-08-17 |
69
+ | Homebrew/brew | 263 | 997 | **all of them** | **0** | none | 2026-08-18 |
69
70
  | ruby/ruby | 142 | 585 | 117 missing, 44 excess | 92 | 5 | 2026-08-16 |
70
71
 
71
72
  The last column is per row on purpose. A single date at the top of the file would say the five were
@@ -85,14 +86,19 @@ run starts from, and `TargetRubyVersion` is only inferred from the working direc
85
86
  tools therefore fall back to the default of 2.7 (RuboCop says so itself: `Using Ruby 2.7 parser`) and
86
87
  both call `dry_run:,` — a hash value omission, valid since 3.1 — a syntax error. **Run the same corpus
87
88
  at 3.1 and both report zero `Lint/Syntax`.** What is left is not disagreement about which files parse:
88
- the file sets are identical, 569 on each side, and the first diagnostic in each file lands at the same
89
- position. Only the second and later diagnostics diverge, because the two parsers recover from the
90
- error differently — which is what puts offenses on both sides of the ledger rather than only on
91
- RuboCop's. Those are not chased; see *Known divergences*.
92
-
93
- What is checked here is that every one of the 1,260 is a `Lint/Syntax` offense, in both directions.
94
- What is not checked is which recovery produced which diagnostic: the 263 Sonicop reports and RuboCop
95
- does not have not been read one by one. They are accounted for as a class, not individually.
89
+ the file sets are identical, 569 on each side, with no file unique to either parser. The two parsers
90
+ recover differently after encountering invalid syntax, which puts diagnostic positions on both sides
91
+ of the ledger rather than only on RuboCop's.
92
+
93
+ All 263 Sonicop-only positions were classified mechanically, not inferred from their cop name. They
94
+ occur in 135 of those shared syntax-error files, and every one follows a `Lint/Syntax` position that
95
+ both tools reported in the same file. Their messages are 113 end-of-input (`$end`), 86 right
96
+ parentheses (`tRPAREN`), 53 commas (`tCOMMA`), seven `end` keywords (`kEND`), two equals signs
97
+ (`tEQL`), one `when` (`kWHEN`) and one identifier (`tIDENTIFIER`). Thus the former “excess” is not a
98
+ set of valid files rejected only by Sonicop; it is the other direction of the same diagnostic-recovery
99
+ divergence as the 997 RuboCop-only positions. Suppressing every diagnostic after Sonicop's first one
100
+ would make the excess zero, but would also discard 1,998 positions that already match and increase the
101
+ missing side from 997 to 2,995. That is not a conformance fix. See *Known divergences*.
96
102
 
97
103
  Much of ruby/ruby's difference is the same shape,
98
104
  with 117 of the 585 missing and 44 of the 142 excess being `Lint/Syntax` itself,
@@ -181,10 +187,10 @@ but no longer reproduces fails the test, and so does one that appears without be
181
187
  ### Error recovery after a syntax error
182
188
 
183
189
  RuboCop parses with `parser`, an LALR parser that recovers from an error and keeps going, emitting
184
- further diagnostics from the recovered state. Sonicop parses with tree-sitter, which does not model
185
- that recovery, so the follow-on diagnostics cannot be reproduced. On Homebrew this accounts for the
186
- 997 missing `Lint/Syntax` offenses: `class definition in method body`, `dynamic constant assignment`,
187
- `cannot assign to a keyword`, and repeated `unexpected token` inside one multi-line hash.
190
+ further diagnostics from the recovered state. Sonicop parses with tree-sitter and reaches different
191
+ recovery states. On Homebrew this produces 997 RuboCop-only and 263 Sonicop-only `Lint/Syntax`
192
+ positions: examples on the RuboCop side include `class definition in method body`, `dynamic constant
193
+ assignment`, `cannot assign to a keyword`, and repeated `unexpected token` inside one multi-line hash.
188
194
 
189
195
  What the divergence does not change is **which** files are held to be unparseable, and that is what
190
196
  decides whether a file is inspected at all: RuboCop runs no cop other than `Lint/Syntax` on a file
@@ -198,9 +204,10 @@ programs, one of which is English prose that happens to parse as Ruby — where
198
204
  error and `parser` does not. Those five hold 465 of that corpus's 773 differences.
199
205
 
200
206
  Within Homebrew's 569 files the agreement is partial, as recovery cannot be reproduced: 499 report the
201
- same first diagnostic (position and message), and 222 report an identical list end to end. The 277
202
- files in between are the divergence in its purest form the two agree on where the file first goes
203
- wrong and part company on what follows. The 70
207
+ same first diagnostic (position and message), and 222 report an identical list end to end. In all 569,
208
+ Sonicop's earliest source-position diagnostic is also present in RuboCop's output. The 277 files in
209
+ between are the divergence in its purest form — the two agree on at least one error position and part
210
+ company as recovery proceeds. The 70
204
211
  files whose first diagnostic differs follow one shape — an endless method definition (`def to_s =
205
212
  to_str`, valid from Ruby 3.0, rejected by the default `TargetRubyVersion: 2.7`) leaves `parser`'s
206
213
  method context open, so the enclosing `class` emits `class definition in method body` when it is
@@ -299,17 +306,43 @@ defect, so the difference stands as it is.
299
306
  ## Limits
300
307
 
301
308
  A clean run is a property of the corpora, not a general claim. `known_divergences.yml` carries the
302
- current list of what these corpora never exercise; the main ones are non-default configuration
303
- values, extension plugins, and Windows line endings. Cops that never fire contribute nothing to a
304
- match count, and their silence is indistinguishable from agreement.
305
-
306
- That limit is not hypothetical, and one instance is now measured. `Style/HashSyntax` defaults
307
- `EnforcedShorthandSyntax` to `either`, under which neither tool reports anything; the port
308
- implements none of the other four values, so half the cop is missing. Both the corpus runs and a
309
- sweep of RuboCop's own specs report agreement for it, because both run at the default. A cop can be
310
- half absent and still match everywhere the default reaches. Where a cop's behaviour is selected by
311
- configuration, this document covers the default branch only — the others are neither measured nor
312
- claimed.
309
+ current list of what these corpora never exercise; the main ones are extension plugins and Windows
310
+ line endings. Cops that never fire contribute nothing to a match count, and their silence is
311
+ indistinguishable from agreement.
312
+
313
+ Non-default configuration values used to be the largest of those gaps, and are now measured. Every
314
+ one of the 111 cops carrying an `Enforced*` setting was switched to a non-default value at once —
315
+ `Layout/SpaceInsideParens` to `space`, `Style/HashSyntax` to `hash_rockets` with
316
+ `EnforcedShorthandSyntax: always`, and so on and rubocop/rubocop re-run against RuboCop under the
317
+ same file. Of 622,317 reference offenses, **99.99% match**, and 84 of the 96 cops that fired match
318
+ exactly.
319
+
320
+ | Cop | Offenses differing | |
321
+ |---|---:|---|
322
+ | `Layout/HashAlignment` | 35 | **RuboCop's own bug**, see below |
323
+ | `Style/BlockDelimiters` | 17 | |
324
+ | `Style/ConditionalAssignment` | 12 | |
325
+ | `Style/MixinGrouping` | 8 | |
326
+ | `Layout/SpaceInsideStringInterpolation` | 6 | |
327
+ | `Style/NumericPredicate` | 5 | |
328
+ | `Style/PercentQLiterals` | 4 | |
329
+ | `Naming/VariableName` | 3 | |
330
+ | `Lint/SymbolConversion` | 3 | |
331
+ | `Layout/SpaceInsideParens` | 1 | |
332
+
333
+ `Layout/HashAlignment`'s 35 are not a defect here. Under `EnforcedHashRocketStyle: separator`
334
+ RuboCop raises `Parser::ClobberingError` on `spec/rubocop/config_loader_spec.rb` — three times, at
335
+ `1111:35`, `1130:38` and `1217:35` — and reports nothing for the hashes it crashed on. Sonicop
336
+ inspects them and reports. Every one of the 35 sits in that file between lines 1114 and 1234.
337
+ Reproduce with:
338
+
339
+ ```bash
340
+ rubocop -c <variants.yml> --only Layout/HashAlignment -d spec/rubocop/config_loader_spec.rb
341
+ ```
342
+
343
+ One value per cop is not the whole configuration space — a cop with four supported styles is
344
+ measured at two of them — so this is a floor, not a ceiling. It does settle the shape of the old
345
+ limit: a cop is no longer allowed to be half absent and still count as matching.
313
346
 
314
347
  The 215 cops RuboCop ships switched off are a limit of a different kind. They are implemented, but a
315
348
  default run never reaches them, so the corpus numbers above say nothing about them. What stands
data/Cargo.lock CHANGED
@@ -4,9 +4,9 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "aho-corasick"
7
- version = "1.1.4"
7
+ version = "1.1.5"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
9
+ checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
10
10
  dependencies = [
11
11
  "memchr",
12
12
  ]
@@ -67,6 +67,18 @@ version = "1.0.104"
67
67
  source = "registry+https://github.com/rust-lang/crates.io-index"
68
68
  checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
69
69
 
70
+ [[package]]
71
+ name = "arrayref"
72
+ version = "0.3.9"
73
+ source = "registry+https://github.com/rust-lang/crates.io-index"
74
+ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
75
+
76
+ [[package]]
77
+ name = "arrayvec"
78
+ version = "0.7.8"
79
+ source = "registry+https://github.com/rust-lang/crates.io-index"
80
+ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
81
+
70
82
  [[package]]
71
83
  name = "assert_cmd"
72
84
  version = "2.2.2"
@@ -100,6 +112,20 @@ version = "2.13.1"
100
112
  source = "registry+https://github.com/rust-lang/crates.io-index"
101
113
  checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
102
114
 
115
+ [[package]]
116
+ name = "blake3"
117
+ version = "1.8.6"
118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
119
+ checksum = "76ae7bad254120e9e4c63bafc385310756f90c484eac0e36b8317cf09cb92a77"
120
+ dependencies = [
121
+ "arrayref",
122
+ "arrayvec",
123
+ "cc",
124
+ "cfg-if",
125
+ "constant_time_eq",
126
+ "cpufeatures",
127
+ ]
128
+
103
129
  [[package]]
104
130
  name = "bstr"
105
131
  version = "1.13.0"
@@ -135,9 +161,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
135
161
 
136
162
  [[package]]
137
163
  name = "clap"
138
- version = "4.6.4"
164
+ version = "4.6.6"
139
165
  source = "registry+https://github.com/rust-lang/crates.io-index"
140
- checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7"
166
+ checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
141
167
  dependencies = [
142
168
  "clap_builder",
143
169
  "clap_derive",
@@ -145,9 +171,9 @@ dependencies = [
145
171
 
146
172
  [[package]]
147
173
  name = "clap_builder"
148
- version = "4.6.2"
174
+ version = "4.6.6"
149
175
  source = "registry+https://github.com/rust-lang/crates.io-index"
150
- checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
176
+ checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
151
177
  dependencies = [
152
178
  "anstream",
153
179
  "anstyle",
@@ -180,6 +206,12 @@ version = "1.0.5"
180
206
  source = "registry+https://github.com/rust-lang/crates.io-index"
181
207
  checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
182
208
 
209
+ [[package]]
210
+ name = "constant_time_eq"
211
+ version = "0.4.2"
212
+ source = "registry+https://github.com/rust-lang/crates.io-index"
213
+ checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
214
+
183
215
  [[package]]
184
216
  name = "core-foundation"
185
217
  version = "0.10.1"
@@ -196,6 +228,15 @@ version = "0.8.7"
196
228
  source = "registry+https://github.com/rust-lang/crates.io-index"
197
229
  checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
198
230
 
231
+ [[package]]
232
+ name = "cpufeatures"
233
+ version = "0.3.0"
234
+ source = "registry+https://github.com/rust-lang/crates.io-index"
235
+ checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
236
+ dependencies = [
237
+ "libc",
238
+ ]
239
+
199
240
  [[package]]
200
241
  name = "crossbeam-deque"
201
242
  version = "0.8.7"
@@ -276,9 +317,9 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
276
317
 
277
318
  [[package]]
278
319
  name = "find-msvc-tools"
279
- version = "0.1.10"
320
+ version = "0.1.9"
280
321
  source = "registry+https://github.com/rust-lang/crates.io-index"
281
- checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
322
+ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
282
323
 
283
324
  [[package]]
284
325
  name = "foreign-types"
@@ -295,6 +336,16 @@ version = "0.1.1"
295
336
  source = "registry+https://github.com/rust-lang/crates.io-index"
296
337
  checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
297
338
 
339
+ [[package]]
340
+ name = "fs2"
341
+ version = "0.4.3"
342
+ source = "registry+https://github.com/rust-lang/crates.io-index"
343
+ checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
344
+ dependencies = [
345
+ "libc",
346
+ "winapi",
347
+ ]
348
+
298
349
  [[package]]
299
350
  name = "getrandom"
300
351
  version = "0.4.3"
@@ -308,9 +359,9 @@ dependencies = [
308
359
 
309
360
  [[package]]
310
361
  name = "globset"
311
- version = "0.4.19"
362
+ version = "0.4.20"
312
363
  source = "registry+https://github.com/rust-lang/crates.io-index"
313
- checksum = "e47d37d2ae4464254884b60ab7071be2b876a9c35b696bd018ddcc76847309cd"
364
+ checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988"
314
365
  dependencies = [
315
366
  "aho-corasick",
316
367
  "bstr",
@@ -349,9 +400,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
349
400
 
350
401
  [[package]]
351
402
  name = "ignore"
352
- version = "0.4.31"
403
+ version = "0.4.33"
353
404
  source = "registry+https://github.com/rust-lang/crates.io-index"
354
- checksum = "7f8a7b8211e695a1d0cd91cace480d4d0bd57667ab10277cc412c5f7f4884f83"
405
+ checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f"
355
406
  dependencies = [
356
407
  "crossbeam-deque",
357
408
  "globset",
@@ -587,9 +638,9 @@ dependencies = [
587
638
 
588
639
  [[package]]
589
640
  name = "regex-automata"
590
- version = "0.4.16"
641
+ version = "0.4.18"
591
642
  source = "registry+https://github.com/rust-lang/crates.io-index"
592
- checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad"
643
+ checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
593
644
  dependencies = [
594
645
  "aho-corasick",
595
646
  "memchr",
@@ -742,12 +793,14 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
742
793
 
743
794
  [[package]]
744
795
  name = "sonicop"
745
- version = "26.8.110"
796
+ version = "26.8.112"
746
797
  dependencies = [
747
798
  "anyhow",
748
799
  "assert_cmd",
800
+ "blake3",
749
801
  "clap",
750
802
  "encoding_rs",
803
+ "fs2",
751
804
  "globset",
752
805
  "ignore",
753
806
  "rayon",
@@ -847,8 +900,8 @@ checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782"
847
900
 
848
901
  [[package]]
849
902
  name = "tree-sitter-ruby"
850
- version = "26.8.101"
851
- source = "git+https://github.com/owayo/tree-sitter-ruby.git?rev=f1a19bb27ba64300d1032b813c51437a5a76ea33#f1a19bb27ba64300d1032b813c51437a5a76ea33"
903
+ version = "26.8.103"
904
+ source = "git+https://github.com/owayo/tree-sitter-ruby.git?tag=v26.8.103#e3b414485ce2b0a154334f02576ec79c27154326"
852
905
  dependencies = [
853
906
  "cc",
854
907
  "tree-sitter-language",
@@ -941,6 +994,22 @@ dependencies = [
941
994
  "rustls-pki-types",
942
995
  ]
943
996
 
997
+ [[package]]
998
+ name = "winapi"
999
+ version = "0.3.9"
1000
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1001
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1002
+ dependencies = [
1003
+ "winapi-i686-pc-windows-gnu",
1004
+ "winapi-x86_64-pc-windows-gnu",
1005
+ ]
1006
+
1007
+ [[package]]
1008
+ name = "winapi-i686-pc-windows-gnu"
1009
+ version = "0.4.0"
1010
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1011
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1012
+
944
1013
  [[package]]
945
1014
  name = "winapi-util"
946
1015
  version = "0.1.11"
@@ -950,6 +1019,12 @@ dependencies = [
950
1019
  "windows-sys",
951
1020
  ]
952
1021
 
1022
+ [[package]]
1023
+ name = "winapi-x86_64-pc-windows-gnu"
1024
+ version = "0.4.0"
1025
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1026
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1027
+
953
1028
  [[package]]
954
1029
  name = "windows-link"
955
1030
  version = "0.2.1"
data/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sonicop"
3
- version = "26.8.110"
3
+ version = "26.8.112"
4
4
  edition = "2024"
5
5
  rust-version = "1.85"
6
6
  description = "A fast, native RuboCop-compatible Ruby linter and formatter"
@@ -16,10 +16,12 @@ path = "src/main.rs"
16
16
 
17
17
  [dependencies]
18
18
  anyhow = "1.0.104"
19
- clap = { version = "4.6.4", features = ["derive", "wrap_help"] }
19
+ blake3 = "1.8.6"
20
+ clap = { version = "4.6.6", features = ["derive", "wrap_help"] }
20
21
  encoding_rs = "0.8.35"
21
- globset = "0.4.19"
22
- ignore = "0.4.31"
22
+ fs2 = "0.4.3"
23
+ globset = "0.4.20"
24
+ ignore = "0.4.33"
23
25
  rayon = "1.12.0"
24
26
  regex = "1.13.1"
25
27
  serde = { version = "1.0.229", features = ["derive"] }
@@ -28,12 +30,15 @@ serde_yaml_ng = "0.10"
28
30
  shell-words = "1.1.1"
29
31
  tempfile = "3.27.0"
30
32
  tree-sitter = "0.26.11"
31
- tree-sitter-ruby = { git = "https://github.com/owayo/tree-sitter-ruby.git", rev = "f1a19bb27ba64300d1032b813c51437a5a76ea33" }
33
+ tree-sitter-ruby = { git = "https://github.com/owayo/tree-sitter-ruby.git", tag = "v26.8.103" }
32
34
  ureq = { version = "3.4", default-features = false, features = ["native-tls"] }
33
35
 
34
36
  [dev-dependencies]
35
37
  assert_cmd = "2.2.2"
36
38
 
39
+ [build-dependencies]
40
+ blake3 = "1.8.6"
41
+
37
42
  [profile.release]
38
43
  lto = "thin"
39
44
  codegen-units = 1
data/NOTICE CHANGED
@@ -15,9 +15,9 @@ licence position checkable rather than remembered.
15
15
  not the attribution. An entry that is added late is an entry that was, for a
16
16
  while, undocumented in a public repository.
17
17
 
18
- Known to be coming: tests/fixtures/upstream_spec_cases.jsonl, which will hold
19
- input text from RuboCop's specs. It is deliberately **not** listed yet -- this
20
- file describes what is here now, not what is planned.
18
+ That inventory is now complete for what is here. The entry that used to be
19
+ listed as "coming" -- the spec-derived fixtures -- has landed and is recorded
20
+ below with the rest.
21
21
 
22
22
  ================================================================================
23
23
  WHAT IS TAKEN
@@ -32,6 +32,18 @@ RuboCop -- https://github.com/rubocop/rubocop -- MIT
32
32
  Regenerate: scripts/sync_default_yml.sh 1.89.0
33
33
  Full text also kept at licenses/RUBOCOP.txt
34
34
 
35
+ tests/fixtures/upstream_spec_cases.jsonl
36
+ tests/fixtures/upstream_spec_divergences.jsonl
37
+ Input text taken out of RuboCop's own cop specs, each paired with what
38
+ RuboCop 1.89.0 actually reports for it. The spec text is upstream's; the
39
+ expectation beside it is not -- upstream was run once and its output
40
+ recorded, because upstream does not always behave the way its own specs
41
+ say. The second file holds the cases whose `-A` output does not parse as
42
+ Ruby, kept apart so that nothing demands this port reproduce them.
43
+ Regenerate: make spec-fixtures (runs upstream once per cop; needs the
44
+ rubocop gem, which the test run itself does not)
45
+ Read by tests/spec_fixtures.rs
46
+
35
47
  Ruby on Rails -- https://github.com/rails/rails -- MIT
36
48
  Copyright (c) David Heinemeier Hansson
37
49