rubocop 1.81.7 → 1.85.1

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 (234) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +149 -7
  5. data/config/obsoletion.yml +9 -0
  6. data/lib/rubocop/cache_config.rb +29 -0
  7. data/lib/rubocop/cli/command/lsp.rb +1 -1
  8. data/lib/rubocop/cli/command/mcp.rb +19 -0
  9. data/lib/rubocop/cli.rb +27 -4
  10. data/lib/rubocop/comment_config.rb +62 -17
  11. data/lib/rubocop/config_loader.rb +17 -20
  12. data/lib/rubocop/config_loader_resolver.rb +2 -2
  13. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  14. data/lib/rubocop/cop/autocorrect_logic.rb +4 -0
  15. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  16. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  17. data/lib/rubocop/cop/correctors/alignment_corrector.rb +21 -5
  18. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  19. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  20. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  21. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  22. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  23. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  24. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  25. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  26. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
  27. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  28. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  29. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  32. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  33. data/lib/rubocop/cop/layout/class_structure.rb +12 -5
  34. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  35. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  36. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  37. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  38. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  39. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  40. data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
  41. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  42. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  43. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  44. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  45. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  46. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  47. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  48. data/lib/rubocop/cop/layout/indentation_width.rb +111 -7
  49. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  50. data/lib/rubocop/cop/layout/line_length.rb +13 -6
  51. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  52. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  53. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  54. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  55. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +179 -39
  56. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  57. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  58. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +5 -3
  59. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  60. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  61. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  62. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  63. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +8 -8
  64. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  65. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  66. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +1 -1
  67. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  68. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  69. data/lib/rubocop/cop/lint/duplicate_methods.rb +57 -5
  70. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  71. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  72. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  73. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  74. data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
  75. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  76. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  77. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  78. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
  79. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  80. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
  81. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  82. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +7 -6
  83. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
  84. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  85. data/lib/rubocop/cop/lint/self_assignment.rb +9 -1
  86. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  87. data/lib/rubocop/cop/lint/to_json.rb +12 -16
  88. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  89. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  90. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  91. data/lib/rubocop/cop/lint/useless_assignment.rb +45 -17
  92. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  93. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +2 -2
  94. data/lib/rubocop/cop/lint/void.rb +32 -12
  95. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  96. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  97. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  98. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  99. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +3 -5
  100. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  101. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
  102. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  103. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  104. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  105. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  106. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  107. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  108. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  110. data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -4
  111. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  112. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  113. data/lib/rubocop/cop/naming/predicate_method.rb +11 -0
  114. data/lib/rubocop/cop/naming/predicate_prefix.rb +11 -11
  115. data/lib/rubocop/cop/offense.rb +9 -1
  116. data/lib/rubocop/cop/security/eval.rb +15 -2
  117. data/lib/rubocop/cop/security/json_load.rb +1 -1
  118. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -2
  119. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  120. data/lib/rubocop/cop/style/alias.rb +4 -1
  121. data/lib/rubocop/cop/style/array_join.rb +4 -2
  122. data/lib/rubocop/cop/style/ascii_comments.rb +5 -2
  123. data/lib/rubocop/cop/style/attr.rb +5 -2
  124. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  125. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  126. data/lib/rubocop/cop/style/block_delimiters.rb +4 -3
  127. data/lib/rubocop/cop/style/case_equality.rb +15 -13
  128. data/lib/rubocop/cop/style/class_and_module_children.rb +11 -2
  129. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  130. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -11
  131. data/lib/rubocop/cop/style/constant_visibility.rb +3 -3
  132. data/lib/rubocop/cop/style/copyright.rb +1 -1
  133. data/lib/rubocop/cop/style/documentation.rb +6 -6
  134. data/lib/rubocop/cop/style/documentation_method.rb +8 -8
  135. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  136. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  137. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  138. data/lib/rubocop/cop/style/empty_class_definition.rb +97 -0
  139. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  140. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  141. data/lib/rubocop/cop/style/encoding.rb +7 -1
  142. data/lib/rubocop/cop/style/end_block.rb +3 -1
  143. data/lib/rubocop/cop/style/endless_method.rb +10 -5
  144. data/lib/rubocop/cop/style/file_open.rb +84 -0
  145. data/lib/rubocop/cop/style/for.rb +3 -0
  146. data/lib/rubocop/cop/style/format_string_token.rb +49 -5
  147. data/lib/rubocop/cop/style/global_vars.rb +4 -1
  148. data/lib/rubocop/cop/style/guard_clause.rb +24 -22
  149. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  150. data/lib/rubocop/cop/style/hash_lookup_method.rb +94 -0
  151. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  152. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  153. data/lib/rubocop/cop/style/if_unless_modifier.rb +46 -17
  154. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
  155. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  156. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  157. data/lib/rubocop/cop/style/lambda_call.rb +8 -8
  158. data/lib/rubocop/cop/style/map_join.rb +123 -0
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  160. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  161. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
  162. data/lib/rubocop/cop/style/module_member_existence_check.rb +117 -0
  163. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
  164. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  165. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  166. data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
  167. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  168. data/lib/rubocop/cop/style/not.rb +2 -0
  169. data/lib/rubocop/cop/style/numeric_literals.rb +2 -1
  170. data/lib/rubocop/cop/style/one_class_per_file.rb +95 -0
  171. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
  172. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  173. data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
  174. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  175. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  176. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  177. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  178. data/lib/rubocop/cop/style/proc.rb +3 -2
  179. data/lib/rubocop/cop/style/reduce_to_hash.rb +184 -0
  180. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  181. data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
  182. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  183. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  184. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  185. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  186. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -3
  187. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  188. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +5 -0
  189. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  190. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  191. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +104 -0
  192. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  193. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  194. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  195. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  196. data/lib/rubocop/cop/style/semicolon.rb +2 -0
  197. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  198. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  199. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  200. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  201. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  202. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  203. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  204. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  205. data/lib/rubocop/cop/team.rb +4 -4
  206. data/lib/rubocop/cop/util.rb +2 -3
  207. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  208. data/lib/rubocop/directive_comment.rb +48 -4
  209. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  210. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
  211. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  212. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  213. data/lib/rubocop/formatter/tap_formatter.rb +5 -2
  214. data/lib/rubocop/formatter.rb +22 -21
  215. data/lib/rubocop/lsp/diagnostic.rb +18 -34
  216. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  217. data/lib/rubocop/lsp/routes.rb +11 -38
  218. data/lib/rubocop/lsp/runtime.rb +14 -4
  219. data/lib/rubocop/lsp/server.rb +2 -2
  220. data/lib/rubocop/lsp/stdin_runner.rb +8 -1
  221. data/lib/rubocop/magic_comment.rb +20 -0
  222. data/lib/rubocop/mcp/server.rb +174 -0
  223. data/lib/rubocop/options.rb +10 -1
  224. data/lib/rubocop/rake_task.rb +1 -1
  225. data/lib/rubocop/remote_config.rb +10 -8
  226. data/lib/rubocop/result_cache.rb +50 -36
  227. data/lib/rubocop/rspec/shared_contexts.rb +7 -3
  228. data/lib/rubocop/rspec/support.rb +2 -1
  229. data/lib/rubocop/runner.rb +4 -0
  230. data/lib/rubocop/server/cache.rb +6 -29
  231. data/lib/rubocop/target_ruby.rb +21 -13
  232. data/lib/rubocop/version.rb +1 -1
  233. data/lib/rubocop.rb +19 -0
  234. metadata +44 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8acfafa4ed4b94c367e6ef95c84d2d02f01222a1e8a813790948977476f34456
4
- data.tar.gz: 0d2ad56c4a81da58046a098351606bfb8314f09f9e5f946ad1dd825aa70fe0f7
3
+ metadata.gz: d0878d77ab8d3571eaa4e50ac6d4c89bac50ba7b36a740b944293dff7e60e3c5
4
+ data.tar.gz: 21f33042b5a670b5da1b58cbdee49a6250f537326881e34b2766c40a4d9a9f3b
5
5
  SHA512:
6
- metadata.gz: ae4edea22ca7511df39ec99591df3d537bfd3fa8974d5bb461d2b1c674b48f15296f22c81b1cd9329719a68b0d3f8d36442eaa5742cbf8e0974c6e3e2e56e29c
7
- data.tar.gz: ffce467cec50d2ed0ef7b312a15dd17e9b7fd1622b70528d12f0cfe16056ae3b5111f2d360b4e855ea5811befd092a306ff56ad091b89a6050f3354f3db205a4
6
+ metadata.gz: 87cec420dd37c3c60d6112b9e6ced643ee22fb5b4c95148d714876fb0bfc8171634dd9b39ac6a0f7be7373e59c960a6bdbc74c01489daad3e9fcc7dbddb78e0d
7
+ data.tar.gz: 3f7c8637950adec215950b600ef61565b8847f1ba90f82f0ec9720ea6e7d4215f9d0312247324ea0976e4829b1bd3de3b11a4662d0a2a865433825d42779e7be
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-25 Bozhidar Batsov
1
+ Copyright (c) 2012-26 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -51,7 +51,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
51
51
  in your `Gemfile`:
52
52
 
53
53
  ```rb
54
- gem 'rubocop', '~> 1.81', require: false
54
+ gem 'rubocop', '~> 1.82', require: false
55
55
  ```
56
56
 
57
57
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -251,5 +251,5 @@ RuboCop's release notes are available [here](https://github.com/rubocop/rubocop/
251
251
 
252
252
  ## Copyright
253
253
 
254
- Copyright (c) 2012-2025 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
254
+ Copyright (c) 2012-2026 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
255
255
  further details.
data/config/default.yml CHANGED
@@ -835,6 +835,7 @@ Layout/FirstArrayElementLineBreak:
835
835
  multi-line array.
836
836
  Enabled: false
837
837
  VersionAdded: '0.49'
838
+ AllowImplicitArrayLiterals: false
838
839
  AllowMultilineFinalElement: false
839
840
 
840
841
  Layout/FirstHashElementIndentation:
@@ -1037,6 +1038,15 @@ Layout/IndentationWidth:
1037
1038
  VersionAdded: '0.49'
1038
1039
  # Number of spaces for each indentation level.
1039
1040
  Width: 2
1041
+ # Block body indentation for method chain blocks.
1042
+ # The value `start_of_line` means that block bodies are indented
1043
+ # relative to the start of the line where the block starts.
1044
+ # The value `relative_to_receiver` means that block bodies are indented
1045
+ # relative to the method call position in the chain.
1046
+ EnforcedStyleAlignWith: start_of_line
1047
+ SupportedStylesAlignWith:
1048
+ - start_of_line
1049
+ - relative_to_receiver
1040
1050
  AllowedPatterns: []
1041
1051
 
1042
1052
  Layout/InitialIndentation:
@@ -1102,7 +1112,7 @@ Layout/LineLength:
1102
1112
  StyleGuide: '#max-line-length'
1103
1113
  Enabled: true
1104
1114
  VersionAdded: '0.25'
1105
- VersionChanged: '1.69'
1115
+ VersionChanged: '1.82'
1106
1116
  Max: 120
1107
1117
  AllowHeredoc: true
1108
1118
  # To make it possible to copy or click on URIs in the code, we allow lines
@@ -1112,9 +1122,12 @@ Layout/LineLength:
1112
1122
  URISchemes:
1113
1123
  - http
1114
1124
  - https
1115
- # The IgnoreCopDirectives option causes the LineLength rule to ignore cop
1125
+ # The AllowRBSInlineAnnotation option makes LineLength allow RBS::Inline annotations
1126
+ # such as `#: (?date: Date) -> Foo` when calculating line length.
1127
+ AllowRBSInlineAnnotation: false
1128
+ # The AllowCopDirectives option causes the LineLength rule to ignore cop
1116
1129
  # directives like '# rubocop: enable ...' when calculating a line's length.
1117
- IgnoreCopDirectives: true
1130
+ AllowCopDirectives: true
1118
1131
  # The AllowedPatterns option is a list of !ruby/regexp and/or string
1119
1132
  # elements. Strings will be converted to Regexp objects. A line that matches
1120
1133
  # any regular expression listed in this option will be ignored by LineLength.
@@ -1707,6 +1720,11 @@ Lint/CopDirectiveSyntax:
1707
1720
  Enabled: pending
1708
1721
  VersionAdded: '1.72'
1709
1722
 
1723
+ Lint/DataDefineOverride:
1724
+ Description: 'Disallow overriding the `Data` built-in methods via `Data.define`.'
1725
+ Enabled: pending
1726
+ VersionAdded: '1.85'
1727
+
1710
1728
  Lint/Debugger:
1711
1729
  Description: 'Checks for debugger calls.'
1712
1730
  Enabled: true
@@ -2396,8 +2414,9 @@ Lint/SafeNavigationConsistency:
2396
2414
  consistent and appropriate safe navigation, without excess or deficiency,
2397
2415
  is used for all method calls on the same object.
2398
2416
  Enabled: true
2417
+ SafeAutoCorrect: false
2399
2418
  VersionAdded: '0.55'
2400
- VersionChanged: '0.77'
2419
+ VersionChanged: '1.85'
2401
2420
  AllowedMethods:
2402
2421
  - present?
2403
2422
  - blank?
@@ -2574,6 +2593,11 @@ Lint/UnreachableLoop:
2574
2593
  # eg. `exactly(2).times`
2575
2594
  - !ruby/regexp /(exactly|at_least|at_most)\(\d+\)\.times/
2576
2595
 
2596
+ Lint/UnreachablePatternBranch:
2597
+ Description: 'Checks for unreachable `in` pattern branches after an unconditional catch-all pattern.'
2598
+ Enabled: pending
2599
+ VersionAdded: '1.85'
2600
+
2577
2601
  Lint/UnusedBlockArgument:
2578
2602
  Description: 'Checks for unused block arguments.'
2579
2603
  StyleGuide: '#underscore-unused-vars'
@@ -2669,7 +2693,10 @@ Lint/UselessNumericOperation:
2669
2693
  Lint/UselessOr:
2670
2694
  Description: 'Checks for useless OR expressions.'
2671
2695
  Enabled: pending
2696
+ SafeAutoCorrect: false
2697
+ AutoCorrect: contextual
2672
2698
  VersionAdded: '1.76'
2699
+ VersionChanged: '1.82'
2673
2700
 
2674
2701
  Lint/UselessRescue:
2675
2702
  Description: 'Checks for useless `rescue`s.'
@@ -3097,6 +3124,7 @@ Naming/PredicateMethod:
3097
3124
  AllowBangMethods: false
3098
3125
  # Methods that are known to not return a boolean value, despite ending in `?`.
3099
3126
  WaywardPredicates:
3127
+ - infinite?
3100
3128
  - nonzero?
3101
3129
 
3102
3130
  Naming/PredicatePrefix:
@@ -3281,7 +3309,7 @@ Style/Alias:
3281
3309
 
3282
3310
  Style/AmbiguousEndlessMethodDefinition:
3283
3311
  Description: 'Checks for endless methods inside operators of lower precedence.'
3284
- StyleGuide: '#ambiguous-endless-method-defintions'
3312
+ StyleGuide: '#ambiguous-endless-method-definitions'
3285
3313
  Enabled: pending
3286
3314
  VersionAdded: '1.68'
3287
3315
 
@@ -3525,9 +3553,11 @@ Style/BlockDelimiters:
3525
3553
  BracesRequiredMethods: []
3526
3554
 
3527
3555
  Style/CaseEquality:
3528
- Description: 'Avoid explicit use of the case equality operator(===).'
3556
+ Description: 'Avoid explicit use of the case equality operator (`===`).'
3529
3557
  StyleGuide: '#no-case-equality'
3530
3558
  Enabled: true
3559
+ References:
3560
+ - 'https://docs.rubocop.org/rubocop-performance/cops_performance.html#performanceregexpmatch'
3531
3561
  VersionAdded: '0.9'
3532
3562
  VersionChanged: '0.89'
3533
3563
  # If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
@@ -3959,6 +3989,16 @@ Style/EmptyCaseCondition:
3959
3989
  Enabled: true
3960
3990
  VersionAdded: '0.40'
3961
3991
 
3992
+ Style/EmptyClassDefinition:
3993
+ Description: 'Enforces consistent style for empty class definitions.'
3994
+ Enabled: pending
3995
+ VersionAdded: '1.84'
3996
+ EnforcedStyle: class_keyword
3997
+ SupportedStyles:
3998
+ - class_keyword
3999
+ - class_new
4000
+ - class_definition # Deprecated.
4001
+
3962
4002
  Style/EmptyElse:
3963
4003
  Description: 'Avoid empty else-clauses.'
3964
4004
  Enabled: true
@@ -4117,6 +4157,12 @@ Style/FileNull:
4117
4157
  SafeAutoCorrect: false
4118
4158
  VersionAdded: '1.69'
4119
4159
 
4160
+ Style/FileOpen:
4161
+ Description: 'Checks for `File.open` without a block, which can leak file descriptors.'
4162
+ Enabled: pending
4163
+ Safe: false
4164
+ VersionAdded: '1.85'
4165
+
4120
4166
  Style/FileRead:
4121
4167
  Description: 'Favor `File.(bin)read` convenience methods.'
4122
4168
  StyleGuide: '#file-read'
@@ -4310,6 +4356,16 @@ Style/HashLikeCase:
4310
4356
  # to trigger this cop
4311
4357
  MinBranchesCount: 3
4312
4358
 
4359
+ Style/HashLookupMethod:
4360
+ Description: 'Enforces the use of either `Hash#[]` or `Hash#fetch` for hash lookup.'
4361
+ Enabled: false
4362
+ Safe: false
4363
+ VersionAdded: '1.84'
4364
+ EnforcedStyle: brackets
4365
+ SupportedStyles:
4366
+ - brackets
4367
+ - fetch
4368
+
4313
4369
  Style/HashSlice:
4314
4370
  Description: >-
4315
4371
  Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
@@ -4407,6 +4463,7 @@ Style/IfWithBooleanLiteralBranches:
4407
4463
  VersionAdded: '1.9'
4408
4464
  SafeAutoCorrect: false
4409
4465
  AllowedMethods:
4466
+ - infinite?
4410
4467
  - nonzero?
4411
4468
 
4412
4469
  Style/IfWithSemicolon:
@@ -4603,6 +4660,12 @@ Style/MapIntoArray:
4603
4660
  VersionChanged: '1.67'
4604
4661
  Safe: false
4605
4662
 
4663
+ Style/MapJoin:
4664
+ Description: 'Checks for redundant `map(&:to_s)` before `join`.'
4665
+ Enabled: pending
4666
+ Safe: false
4667
+ VersionAdded: '1.85'
4668
+
4606
4669
  Style/MapToHash:
4607
4670
  Description: 'Prefer `to_h` with a block over `map.to_h`.'
4608
4671
  Enabled: pending
@@ -4625,6 +4688,7 @@ Style/MethodCallWithArgsParentheses:
4625
4688
  AllowedMethods: []
4626
4689
  AllowedPatterns: []
4627
4690
  IncludedMacros: []
4691
+ IncludedMacroPatterns: []
4628
4692
  AllowParenthesesInMultilineCall: false
4629
4693
  AllowParenthesesInChaining: false
4630
4694
  AllowParenthesesInCamelCaseMethod: false
@@ -4735,6 +4799,12 @@ Style/ModuleFunction:
4735
4799
  Autocorrect: false
4736
4800
  SafeAutoCorrect: false
4737
4801
 
4802
+ Style/ModuleMemberExistenceCheck:
4803
+ Description: 'Checks for usage of `Module` methods returning arrays that can be replaced with equivalent predicates.'
4804
+ Enabled: pending
4805
+ VersionAdded: '1.82'
4806
+ AllowedMethods: []
4807
+
4738
4808
  Style/MultilineBlockChain:
4739
4809
  Description: 'Avoid multi-line chains of blocks.'
4740
4810
  StyleGuide: '#single-line-blocks'
@@ -4862,6 +4932,14 @@ Style/NegatedWhile:
4862
4932
  Enabled: true
4863
4933
  VersionAdded: '0.20'
4864
4934
 
4935
+ Style/NegativeArrayIndex:
4936
+ Description: >-
4937
+ Use negative array indices instead of calculating array length minus a value.
4938
+ Also handles range patterns with length calculations. Recognizes preserving methods
4939
+ and their combinations, allowing safe replacement when the receiver matches.
4940
+ Enabled: pending
4941
+ VersionAdded: '1.84'
4942
+
4865
4943
  Style/NestedFileDirname:
4866
4944
  Description: 'Checks for nested `File.dirname`.'
4867
4945
  Enabled: pending
@@ -5037,6 +5115,12 @@ Style/ObjectThen:
5037
5115
  - then
5038
5116
  - yield_self
5039
5117
 
5118
+ Style/OneClassPerFile:
5119
+ Description: 'Checks that each source file defines at most one top-level class or module.'
5120
+ Enabled: pending
5121
+ VersionAdded: '1.85'
5122
+ AllowedClasses: []
5123
+
5040
5124
  Style/OneLineConditional:
5041
5125
  Description: >-
5042
5126
  Favor the ternary operator (?:) or multi-line constructs over
@@ -5125,6 +5209,14 @@ Style/ParenthesesAroundCondition:
5125
5209
  AllowSafeAssignment: true
5126
5210
  AllowInMultilineConditions: false
5127
5211
 
5212
+ Style/PartitionInsteadOfDoubleSelect:
5213
+ Description: >-
5214
+ Checks for consecutive `select`/`filter`/`find_all` and `reject` calls
5215
+ on the same receiver with the same block body.
5216
+ Enabled: pending
5217
+ Safe: false
5218
+ VersionAdded: '1.85'
5219
+
5128
5220
  Style/PercentLiteralDelimiters:
5129
5221
  Description: 'Use `%`-literal delimiters consistently.'
5130
5222
  StyleGuide: '#percent-literal-braces'
@@ -5157,6 +5249,12 @@ Style/PerlBackrefs:
5157
5249
  Enabled: true
5158
5250
  VersionAdded: '0.13'
5159
5251
 
5252
+ Style/PredicateWithKind:
5253
+ Description: 'Prefer `any?(Klass)` to `any? { |x| x.is_a?(Klass) }`.'
5254
+ Enabled: pending
5255
+ SafeAutoCorrect: false
5256
+ VersionAdded: '1.85'
5257
+
5160
5258
  Style/PreferredHashMethods:
5161
5259
  Description: 'Checks use of `has_key?` and `has_value?` Hash methods.'
5162
5260
  StyleGuide: '#hash-key'
@@ -5207,6 +5305,12 @@ Style/RandomWithOffset:
5207
5305
  Enabled: true
5208
5306
  VersionAdded: '0.52'
5209
5307
 
5308
+ Style/ReduceToHash:
5309
+ Description: 'Use `to_h { ... }` instead of `each_with_object`, `inject`, or `reduce` to build a hash.'
5310
+ Enabled: pending
5311
+ Safe: false
5312
+ VersionAdded: '1.85'
5313
+
5210
5314
  Style/RedundantArgument:
5211
5315
  Description: 'Checks for a redundant argument passed to certain methods.'
5212
5316
  Enabled: pending
@@ -5222,6 +5326,8 @@ Style/RedundantArgument:
5222
5326
  exit: true
5223
5327
  # Kernel.#exit!
5224
5328
  exit!: false
5329
+ # String#to_i
5330
+ to_i: 10
5225
5331
  # String#split
5226
5332
  split: ' '
5227
5333
  # String#chomp
@@ -5263,6 +5369,7 @@ Style/RedundantCondition:
5263
5369
  VersionAdded: '0.76'
5264
5370
  VersionChanged: '1.73'
5265
5371
  AllowedMethods:
5372
+ - infinite?
5266
5373
  - nonzero?
5267
5374
 
5268
5375
  Style/RedundantConditional:
@@ -5373,6 +5480,11 @@ Style/RedundantLineContinuation:
5373
5480
  Enabled: pending
5374
5481
  VersionAdded: '1.49'
5375
5482
 
5483
+ Style/RedundantMinMaxBy:
5484
+ Description: 'Identifies places where `max_by`/`min_by` can be replaced by `max`/`min`.'
5485
+ Enabled: pending
5486
+ VersionAdded: '1.85'
5487
+
5376
5488
  Style/RedundantParentheses:
5377
5489
  Description: "Checks for parentheses that seem not to serve any purpose."
5378
5490
  Enabled: true
@@ -5450,6 +5562,12 @@ Style/RedundantStringEscape:
5450
5562
  Enabled: pending
5451
5563
  VersionAdded: '1.37'
5452
5564
 
5565
+ Style/RedundantStructKeywordInit:
5566
+ Description: 'Checks for redundant `keyword_init` option for `Struct.new`.'
5567
+ Enabled: pending
5568
+ SafeAutoCorrect: false
5569
+ VersionAdded: '1.85'
5570
+
5453
5571
  Style/RegexpLiteral:
5454
5572
  Description: 'Use / or %r around regular expressions.'
5455
5573
  StyleGuide: '#percent-r'
@@ -5511,6 +5629,12 @@ Style/ReturnNilInPredicateMethodDefinition:
5511
5629
  VersionAdded: '1.53'
5512
5630
  VersionChanged: '1.67'
5513
5631
 
5632
+ Style/ReverseFind:
5633
+ Description: 'Use `array.rfind` instead of `array.reverse.find`.'
5634
+ Enabled: pending
5635
+ Safe: false
5636
+ VersionAdded: '1.84'
5637
+
5514
5638
  Style/SafeNavigation:
5515
5639
  Description: >-
5516
5640
  Transforms usages of a method call safeguarded by
@@ -5550,8 +5674,20 @@ Style/Sample:
5550
5674
  Enabled: true
5551
5675
  VersionAdded: '0.30'
5552
5676
 
5677
+ Style/SelectByKind:
5678
+ Description: 'Prefer grep/grep_v to select/reject/find/detect with a kind check.'
5679
+ Enabled: pending
5680
+ SafeAutoCorrect: false
5681
+ VersionAdded: '1.85'
5682
+
5683
+ Style/SelectByRange:
5684
+ Description: 'Prefer grep/grep_v to select/reject/find/detect with a range check.'
5685
+ Enabled: pending
5686
+ SafeAutoCorrect: false
5687
+ VersionAdded: '1.85'
5688
+
5553
5689
  Style/SelectByRegexp:
5554
- Description: 'Prefer grep/grep_v to select/reject with a regexp match.'
5690
+ Description: 'Prefer grep/grep_v to select/reject/find/detect with a regexp match.'
5555
5691
  Enabled: pending
5556
5692
  SafeAutoCorrect: false
5557
5693
  VersionAdded: '1.22'
@@ -5810,6 +5946,12 @@ Style/SymbolProc:
5810
5946
  AllowedPatterns: []
5811
5947
  AllowComments: false
5812
5948
 
5949
+ Style/TallyMethod:
5950
+ Description: 'Prefer `Enumerable#tally` over manual counting patterns.'
5951
+ Enabled: pending
5952
+ Safe: false
5953
+ VersionAdded: '1.85'
5954
+
5813
5955
  Style/TernaryParentheses:
5814
5956
  Description: 'Checks for use of parentheses around ternary conditions.'
5815
5957
  Enabled: true
@@ -145,6 +145,10 @@ changed_parameters:
145
145
  - cops: Layout/CaseIndentation
146
146
  parameters: IndentWhenRelativeTo
147
147
  alternative: EnforcedStyle
148
+ - cops: Layout/LineLength
149
+ parameters: IgnoreCopDirectives
150
+ alternative: AllowCopDirectives
151
+ severity: warning
148
152
  - cops:
149
153
  - Lint/BlockAlignment
150
154
  - Layout/BlockAlignment
@@ -241,3 +245,8 @@ changed_enforced_styles:
241
245
  parameters: EnforcedStyle
242
246
  value: rails
243
247
  alternative: indented_internal_methods
248
+ - cops: Style/EmptyClassDefinition
249
+ parameters: EnforcedStyle
250
+ value: class_definition
251
+ alternative: class_keyword
252
+ severity: warning
@@ -25,5 +25,34 @@ module RuboCop
25
25
 
26
26
  File.join(root, 'rubocop_cache')
27
27
  end
28
+
29
+ # Lightweight cache root computation that reads CacheRootDirectory from
30
+ # the toplevel config file and environment variables without going through
31
+ # the full ConfigStore/ConfigLoader. This method can be used, for example,
32
+ # before loading configuration files. Please note that this method doesn't
33
+ # take into account any `inherit_from` dependencies.
34
+ def self.root_dir_from_toplevel_config(cache_root_override = nil)
35
+ root_dir do
36
+ next cache_root_override if cache_root_override
37
+
38
+ config_path = ConfigFinder.find_config_path(Dir.pwd)
39
+ file_contents = File.read(config_path)
40
+
41
+ # Returns early if `CacheRootDirectory` is not used before requiring `erb` or `yaml`.
42
+ next unless file_contents.include?('CacheRootDirectory')
43
+
44
+ require 'erb'
45
+ require 'yaml'
46
+ yaml_code = ERB.new(file_contents).result
47
+ config_yaml = YAML.safe_load(yaml_code, permitted_classes: [Regexp, Symbol], aliases: true)
48
+
49
+ # For compatibility with Ruby 3.0 or lower.
50
+ if Gem::Version.new(Psych::VERSION) < Gem::Version.new('4.0.0')
51
+ config_yaml == false ? nil : config_yaml
52
+ end
53
+
54
+ config_yaml&.dig('AllCops', 'CacheRootDirectory')
55
+ end
56
+ end
28
57
  end
29
58
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  self.command_name = :lsp
10
10
 
11
11
  def run
12
- # Load on demand, `languge-server-protocol` is heavy to require.
12
+ # Load on demand, `language-server-protocol` is heavy to require.
13
13
  require_relative '../../lsp/server'
14
14
  RuboCop::LSP::Server.new(@config_store).start
15
15
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class CLI
5
+ module Command
6
+ # Start Model Context Protocol of RuboCop.
7
+ # @api private
8
+ class MCP < Base
9
+ self.command_name = :mcp
10
+
11
+ def run
12
+ require_relative '../../mcp/server'
13
+
14
+ RuboCop::MCP::Server.new(@config_store).start
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/rubocop/cli.rb CHANGED
@@ -66,7 +66,7 @@ module RuboCop
66
66
  STATUS_INTERRUPTED
67
67
  rescue Finished
68
68
  STATUS_SUCCESS
69
- rescue OptionParser::InvalidOption => e
69
+ rescue OptionParser::ParseError => e
70
70
  warn e.message
71
71
  warn 'For usage information, use --help'
72
72
  STATUS_ERROR
@@ -76,7 +76,9 @@ module RuboCop
76
76
  STATUS_ERROR
77
77
  ensure
78
78
  elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
79
- puts "Finished in #{elapsed_time} seconds" if @options[:debug] || @options[:display_time]
79
+ if @options[:debug] || @options[:display_time]
80
+ puts "Finished in #{elapsed_time.round(5)} seconds"
81
+ end
80
82
  end
81
83
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
82
84
 
@@ -165,6 +167,10 @@ module RuboCop
165
167
  handle_editor_mode
166
168
 
167
169
  @config_store.apply_options!(@options)
170
+ # Set cache root after apply_options! to ensure force_default_config is applied first.
171
+ early_cache_root = ConfigLoader.cache_root(@options[:cache_root])
172
+ ConfigLoader.cache_root = ResultCache.cache_root(@config_store, @options[:cache_root])
173
+ warn_if_cache_root_changed(early_cache_root, ConfigLoader.cache_root)
168
174
 
169
175
  handle_exiting_options
170
176
 
@@ -194,7 +200,7 @@ module RuboCop
194
200
  RuboCop::LSP.enable if @options[:editor_mode]
195
201
  end
196
202
 
197
- # rubocop:disable Metrics/CyclomaticComplexity
203
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
198
204
  def handle_exiting_options
199
205
  return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
200
206
 
@@ -202,9 +208,10 @@ module RuboCop
202
208
  run_command(:show_cops) if @options[:show_cops]
203
209
  run_command(:show_docs_url) if @options[:show_docs_url]
204
210
  run_command(:lsp) if @options[:lsp]
211
+ run_command(:mcp) if @options[:mcp]
205
212
  raise Finished
206
213
  end
207
- # rubocop:enable Metrics/CyclomaticComplexity
214
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
208
215
 
209
216
  def apply_default_formatter
210
217
  # This must be done after the options have already been processed,
@@ -223,5 +230,21 @@ module RuboCop
223
230
  def report_pending_cops
224
231
  PendingCopsReporter.warn_if_needed(@config_store.for_pwd)
225
232
  end
233
+
234
+ def warn_if_cache_root_changed(early, desired)
235
+ return if early == desired
236
+ # Normalize paths to avoid false positives from symlink resolution differences
237
+ if File.exist?(early) && File.exist?(desired) &&
238
+ File.realpath(early) == File.realpath(desired)
239
+ return
240
+ end
241
+
242
+ warn Rainbow(
243
+ "Warning: Remote configuration cache files were stored in `#{early}` " \
244
+ "because a desired cache root (`#{desired}`) was not set at the top level. " \
245
+ 'Consider setting `AllCops: CacheRootDirectory` in your toplevel configuration file, ' \
246
+ 'using the `RUBOCOP_CACHE_ROOT` environment variable, or using CLI options.'
247
+ ).yellow
248
+ end
226
249
  end
227
250
  end
@@ -34,6 +34,7 @@ module RuboCop
34
34
  def initialize(processed_source)
35
35
  @processed_source = processed_source
36
36
  @no_directives = !processed_source.raw_source.include?('rubocop')
37
+ @stack = []
37
38
  end
38
39
 
39
40
  def cop_enabled_at_line?(cop, line_number)
@@ -69,6 +70,7 @@ module RuboCop
69
70
  def extra_enabled_comments_with_names(extras:, names:)
70
71
  each_directive do |directive|
71
72
  next unless comment_only_line?(directive.line_number)
73
+ next if directive.push? || directive.pop?
72
74
 
73
75
  if directive.enabled_all?
74
76
  handle_enable_all(directive, names, extras)
@@ -93,16 +95,24 @@ module RuboCop
93
95
  end
94
96
  end
95
97
 
96
- def analyze # rubocop:todo Metrics/AbcSize
98
+ def analyze # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
97
99
  return {} if @no_directives
98
100
 
99
101
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
100
102
  inject_disabled_cops_directives(analyses)
101
103
 
102
104
  each_directive do |directive|
103
- directive.cop_names.each do |cop_name|
104
- cop_name = qualified_cop_name(cop_name)
105
- analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
105
+ if directive.push?
106
+ resolved = resolve_push_cops(directive)
107
+ @stack.push(snapshot_cops(analyses, resolved.values.flatten))
108
+ apply_push(analyses, resolved, directive.line_number)
109
+ elsif directive.pop?
110
+ pop_state(analyses, directive.line_number) if @stack.any?
111
+ else
112
+ directive.cop_names.each do |cop_name|
113
+ cop_name = qualified_cop_name(cop_name)
114
+ analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
115
+ end
106
116
  end
107
117
  end
108
118
 
@@ -112,6 +122,49 @@ module RuboCop
112
122
  end
113
123
  end
114
124
 
125
+ def snapshot_cops(analyses, cop_names)
126
+ cop_names.to_h { |name| [name, analyses[name].dup] }
127
+ end
128
+
129
+ def resolve_push_cops(directive)
130
+ directive.push_args.transform_values do |names|
131
+ names.flat_map { |name| expand_cop_name(name) }
132
+ end
133
+ end
134
+
135
+ def expand_cop_name(name)
136
+ registry = Cop::Registry.global
137
+ cops = registry.department?(name) ? registry.names_for_department(name) : [name]
138
+ cops.map { |c| qualified_cop_name(c) }
139
+ end
140
+
141
+ def apply_push(analyses, resolved_cops, line)
142
+ resolved_cops.each do |op, cops|
143
+ cops.each { |cop| apply_cop_op(analyses, op, cop, line) }
144
+ end
145
+ end
146
+
147
+ def apply_cop_op(analyses, operation, cop, line)
148
+ analysis = analyses[cop]
149
+ if operation == '-' && !analysis.start_line_number
150
+ analyses[cop] = CopAnalysis.new(analysis.line_ranges, line)
151
+ elsif operation == '+' && analysis.start_line_number
152
+ analyses[cop] =
153
+ CopAnalysis.new(analysis.line_ranges + [analysis.start_line_number..line], nil)
154
+ end
155
+ end
156
+
157
+ def pop_state(analyses, line)
158
+ saved = @stack.pop
159
+ saved.each do |cop, old|
160
+ cur = analyses[cop]
161
+ new_range = cur.start_line_number ? [cur.start_line_number..(line - 1)] : []
162
+ ranges = cur.line_ranges + new_range
163
+ new_start = old.start_line_number ? line : nil
164
+ analyses[cop] = CopAnalysis.new(ranges, new_start)
165
+ end
166
+ end
167
+
115
168
  def inject_disabled_cops_directives(analyses)
116
169
  registry.disabled(config).each do |cop|
117
170
  analyses[cop.cop_name] = analyze_cop(
@@ -136,29 +189,21 @@ module RuboCop
136
189
  return analysis unless directive.disabled?
137
190
 
138
191
  line = directive.line_number
139
- start_line = analysis.start_line_number
140
-
141
- CopAnalysis.new(analysis.line_ranges + [(line..line)], start_line)
192
+ CopAnalysis.new(analysis.line_ranges + [(line..line)], analysis.start_line_number)
142
193
  end
143
194
 
144
195
  def analyze_disabled(analysis, directive)
145
196
  line = directive.line_number
146
197
  start_line = analysis.start_line_number
147
-
148
- # Cop already disabled on this line, so we end the current disabled
149
- # range before we start a new range.
150
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], line) if start_line
151
-
152
- CopAnalysis.new(analysis.line_ranges, line)
198
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
199
+ CopAnalysis.new(new_ranges, line)
153
200
  end
154
201
 
155
202
  def analyze_rest(analysis, directive)
156
203
  line = directive.line_number
157
204
  start_line = analysis.start_line_number
158
-
159
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], nil) if start_line
160
-
161
- CopAnalysis.new(analysis.line_ranges, nil)
205
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
206
+ CopAnalysis.new(new_ranges, nil)
162
207
  end
163
208
 
164
209
  def cop_line_ranges(analysis)