rubocop 1.89.0 → 1.91.0

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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +309 -14
  3. data/config/obsoletion.yml +9 -0
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/cached_data.rb +7 -2
  6. data/lib/rubocop/changed_files.rb +112 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +52 -1
  8. data/lib/rubocop/cli.rb +11 -7
  9. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  10. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  11. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  12. data/lib/rubocop/comment_config.rb +50 -64
  13. data/lib/rubocop/config.rb +33 -5
  14. data/lib/rubocop/config_loader.rb +13 -6
  15. data/lib/rubocop/config_loader_resolver.rb +50 -9
  16. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  17. data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
  18. data/lib/rubocop/config_obsoletion.rb +1 -1
  19. data/lib/rubocop/config_validator.rb +19 -5
  20. data/lib/rubocop/cop/autocorrect_logic.rb +8 -0
  21. data/lib/rubocop/cop/badge.rb +1 -1
  22. data/lib/rubocop/cop/base.rb +49 -5
  23. data/lib/rubocop/cop/corrector.rb +3 -3
  24. data/lib/rubocop/cop/correctors.rb +2 -2
  25. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  26. data/lib/rubocop/cop/generator.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -2
  28. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  29. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
  31. data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
  32. data/lib/rubocop/cop/layout/class_structure.rb +102 -26
  33. data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
  34. data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
  35. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -2
  36. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  37. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  38. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  39. data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
  40. data/lib/rubocop/cop/layout/first_argument_indentation.rb +21 -1
  41. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
  42. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  43. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -5
  44. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  45. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -2
  46. data/lib/rubocop/cop/layout/line_length.rb +20 -3
  47. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -2
  48. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -5
  49. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -2
  50. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
  51. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  52. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +2 -4
  53. data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
  54. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  55. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
  56. data/lib/rubocop/cop/lint/constant_reassignment.rb +17 -11
  57. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
  58. data/lib/rubocop/cop/lint/deprecated_reference.rb +11 -2
  59. data/lib/rubocop/cop/lint/duplicate_methods.rb +113 -15
  60. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  61. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  62. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  63. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -2
  64. data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -8
  65. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -6
  66. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
  67. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +25 -12
  68. data/lib/rubocop/cop/lint/name_typo.rb +53 -6
  69. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  70. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  71. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -0
  72. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
  73. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +122 -29
  74. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +47 -7
  75. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -2
  76. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -2
  77. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -2
  78. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +1 -2
  79. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -2
  80. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -2
  81. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -4
  82. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  83. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +1 -2
  84. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -2
  85. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -2
  86. data/lib/rubocop/cop/lint/unused_private_method.rb +94 -17
  87. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
  88. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -2
  89. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +36 -0
  90. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  91. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
  92. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +61 -7
  93. data/lib/rubocop/cop/lint/void.rb +1 -2
  94. data/lib/rubocop/cop/lint.rb +3 -0
  95. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
  96. data/lib/rubocop/cop/migration/department_name.rb +1 -2
  97. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  98. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  99. data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
  100. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  101. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +11 -1
  102. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +7 -4
  103. data/lib/rubocop/cop/mixin/hash_subset.rb +1 -2
  104. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  105. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  106. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -1
  107. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
  108. data/lib/rubocop/cop/mixin/range_help.rb +1 -2
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +13 -7
  110. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
  111. data/lib/rubocop/cop/mixin.rb +6 -2
  112. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +16 -0
  113. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  114. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -4
  116. data/lib/rubocop/cop/naming/method_name.rb +5 -2
  117. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -2
  118. data/lib/rubocop/cop/offense.rb +27 -4
  119. data/lib/rubocop/cop/registry.rb +43 -11
  120. data/lib/rubocop/cop/severity.rb +12 -0
  121. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -2
  122. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -2
  123. data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -8
  124. data/lib/rubocop/cop/style/array_first_last.rb +1 -2
  125. data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -2
  126. data/lib/rubocop/cop/style/block_delimiters.rb +3 -6
  127. data/lib/rubocop/cop/style/case_like_if.rb +5 -7
  128. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -2
  129. data/lib/rubocop/cop/style/combinable_loops.rb +1 -2
  130. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -2
  131. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -2
  132. data/lib/rubocop/cop/style/constant_visibility.rb +6 -3
  133. data/lib/rubocop/cop/style/copyright.rb +1 -2
  134. data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
  135. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  136. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +83 -13
  137. data/lib/rubocop/cop/style/documentation_method.rb +1 -9
  138. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  139. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  140. data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
  141. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  142. data/lib/rubocop/cop/style/empty_method.rb +12 -2
  143. data/lib/rubocop/cop/style/endless_method.rb +31 -12
  144. data/lib/rubocop/cop/style/file_null.rb +2 -2
  145. data/lib/rubocop/cop/style/float_division.rb +10 -16
  146. data/lib/rubocop/cop/style/for.rb +5 -0
  147. data/lib/rubocop/cop/style/format_string_token.rb +1 -2
  148. data/lib/rubocop/cop/style/guard_clause.rb +5 -2
  149. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
  150. data/lib/rubocop/cop/style/hash_lookup_method.rb +3 -0
  151. data/lib/rubocop/cop/style/hash_syntax.rb +1 -2
  152. data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -4
  153. data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
  154. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -2
  155. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -2
  156. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  157. data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
  158. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  160. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -2
  161. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -2
  162. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
  163. data/lib/rubocop/cop/style/negative_array_index.rb +2 -4
  164. data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
  165. data/lib/rubocop/cop/style/nil_comparison.rb +36 -9
  166. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  167. data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
  168. data/lib/rubocop/cop/style/not.rb +3 -1
  169. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  170. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  171. data/lib/rubocop/cop/style/operator_method_call.rb +1 -2
  172. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -2
  173. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  174. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -2
  175. data/lib/rubocop/cop/style/redundant_condition.rb +6 -8
  176. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
  177. data/lib/rubocop/cop/style/redundant_each.rb +1 -2
  178. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  179. data/lib/rubocop/cop/style/redundant_format.rb +2 -4
  180. data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -5
  181. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -2
  182. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  183. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +6 -6
  184. data/lib/rubocop/cop/style/redundant_return.rb +1 -2
  185. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
  186. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  187. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -2
  188. data/lib/rubocop/cop/style/safe_navigation.rb +1 -2
  189. data/lib/rubocop/cop/style/sample.rb +11 -6
  190. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -2
  191. data/lib/rubocop/cop/style/semicolon.rb +2 -4
  192. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  193. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  194. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -2
  195. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  196. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -0
  197. data/lib/rubocop/cop/style/string_concatenation.rb +18 -5
  198. data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
  199. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  200. data/lib/rubocop/cop/style/symbol_proc.rb +1 -2
  201. data/lib/rubocop/cop/style/time_now.rb +41 -0
  202. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  203. data/lib/rubocop/cop/style/yoda_condition.rb +1 -2
  204. data/lib/rubocop/cop/style.rb +2 -1
  205. data/lib/rubocop/cop/team.rb +11 -3
  206. data/lib/rubocop/cop/util.rb +3 -5
  207. data/lib/rubocop/cop/variable_force/variable.rb +1 -2
  208. data/lib/rubocop/cops_documentation_generator.rb +26 -8
  209. data/lib/rubocop/directive_comment.rb +73 -10
  210. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
  211. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  212. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  213. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  214. data/lib/rubocop/formatter/html_formatter.rb +2 -4
  215. data/lib/rubocop/formatter/json_formatter.rb +11 -6
  216. data/lib/rubocop/formatter/junit_formatter.rb +26 -9
  217. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -2
  218. data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
  219. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -3
  220. data/lib/rubocop/formatter/tap_formatter.rb +3 -1
  221. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -2
  222. data/lib/rubocop/formatter.rb +1 -0
  223. data/lib/rubocop/lockfile.rb +18 -0
  224. data/lib/rubocop/lsp/diagnostic.rb +4 -8
  225. data/lib/rubocop/lsp/routes.rb +48 -19
  226. data/lib/rubocop/magic_comment.rb +27 -0
  227. data/lib/rubocop/mcp/server.rb +1 -2
  228. data/lib/rubocop/options.rb +69 -7
  229. data/lib/rubocop/path_util.rb +2 -3
  230. data/lib/rubocop/plugin/configuration_integrator.rb +6 -3
  231. data/lib/rubocop/plugin/loader.rb +1 -1
  232. data/lib/rubocop/rake_task.rb +1 -2
  233. data/lib/rubocop/remote_config.rb +4 -4
  234. data/lib/rubocop/result_cache.rb +16 -5
  235. data/lib/rubocop/rspec/expect_offense.rb +2 -4
  236. data/lib/rubocop/rspec/shared_contexts.rb +4 -2
  237. data/lib/rubocop/runner.rb +90 -44
  238. data/lib/rubocop/server/cache.rb +1 -2
  239. data/lib/rubocop/server/cli.rb +2 -4
  240. data/lib/rubocop/server.rb +14 -0
  241. data/lib/rubocop/target_finder.rb +4 -1
  242. data/lib/rubocop/todo_audit.rb +111 -0
  243. data/lib/rubocop/unified_diff.rb +257 -0
  244. data/lib/rubocop/version.rb +3 -5
  245. data/lib/rubocop.rb +7 -1
  246. data/lib/ruby_lsp/rubocop/addon.rb +1 -2
  247. metadata +18 -6
  248. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -107,7 +107,7 @@ module RuboCop
107
107
  remove_to_f_method(corrector, node.receiver)
108
108
  add_to_f_method(corrector, node.first_argument)
109
109
  when :fdiv
110
- correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
110
+ correct_from_slash_to_fdiv(corrector, node.receiver, node.first_argument)
111
111
  end
112
112
  end
113
113
  end
@@ -145,23 +145,17 @@ module RuboCop
145
145
  corrector.remove(send_node.loc.selector)
146
146
  end
147
147
 
148
- def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
149
- receiver_source = extract_receiver_source(receiver)
150
- argument_source = extract_receiver_source(argument)
148
+ def correct_from_slash_to_fdiv(corrector, receiver, argument)
149
+ remove_to_f_method(corrector, receiver) if to_f_method?(receiver)
151
150
 
152
- if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
153
- argument_source = "(#{argument_source})"
154
- end
155
-
156
- corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
157
- end
151
+ argument_parenthesized = argument.begin_type?
152
+ corrector.replace(
153
+ receiver.source_range.end.join(argument.source_range.begin),
154
+ argument_parenthesized ? '.fdiv' : '.fdiv('
155
+ )
158
156
 
159
- def extract_receiver_source(node)
160
- if node.send_type? && node.method?(:to_f)
161
- node.receiver.source
162
- else
163
- node.source
164
- end
157
+ remove_to_f_method(corrector, argument) if to_f_method?(argument)
158
+ corrector.insert_after(argument, ')') unless argument_parenthesized
165
159
  end
166
160
  end
167
161
  end
@@ -69,6 +69,7 @@ module RuboCop
69
69
 
70
70
  if style == :for
71
71
  return unless node.receiver
72
+ return if rescue_or_ensure_body?(node)
72
73
 
73
74
  add_offense(node, message: PREFER_FOR) do |corrector|
74
75
  EachToForCorrector.new(node).call(corrector)
@@ -87,6 +88,10 @@ module RuboCop
87
88
  def suspect_enumerable?(node)
88
89
  node.multiline? && node.method?(:each) && !node.send_node.arguments?
89
90
  end
91
+
92
+ def rescue_or_ensure_body?(node)
93
+ node.body&.type?(:rescue, :ensure)
94
+ end
90
95
  end
91
96
  end
92
97
  end
@@ -228,7 +228,7 @@ module RuboCop
228
228
  "Prefer #{message_text(style)} over #{message_text(detected_style)}."
229
229
  end
230
230
 
231
- # rubocop:disable Style/FormatStringToken
231
+ # rubocop:disable-next Style/FormatStringToken -- the cop needs the token style it is matching
232
232
  def message_text(style)
233
233
  {
234
234
  annotated: 'annotated tokens (like `%<foo>s`)',
@@ -236,7 +236,6 @@ module RuboCop
236
236
  unannotated: 'unannotated tokens (like `%s`)'
237
237
  }[style]
238
238
  end
239
- # rubocop:enable Style/FormatStringToken
240
239
 
241
240
  def tokens(str_node, &block)
242
241
  return if str_node.source == '__FILE__'
@@ -109,6 +109,10 @@ module RuboCop
109
109
  MSG = 'Use a guard clause (`%<example>s`) instead of wrapping the ' \
110
110
  'code inside a conditional expression.'
111
111
 
112
+ def self.autocorrect_incompatible_with
113
+ [Style::MissingElse]
114
+ end
115
+
112
116
  def on_def(node)
113
117
  body = node.body
114
118
 
@@ -196,7 +200,7 @@ module RuboCop
196
200
  end
197
201
  end
198
202
 
199
- # rubocop:disable Metrics/AbcSize
203
+ # rubocop:disable-next Metrics/AbcSize
200
204
  def autocorrect(corrector, node, condition, replacement, guard)
201
205
  corrector.replace(node.loc.keyword.join(condition.source_range), replacement)
202
206
 
@@ -217,7 +221,6 @@ module RuboCop
217
221
  corrector.remove(range_of_branch_to_remove(node, guard))
218
222
  end
219
223
  end
220
- # rubocop:enable Metrics/AbcSize
221
224
 
222
225
  def heredoc?(argument)
223
226
  argument.respond_to?(:heredoc?) && argument.heredoc?
@@ -76,7 +76,7 @@ module RuboCop
76
76
  alias on_numblock on_block
77
77
  alias on_itblock on_block
78
78
 
79
- # rubocop:disable Metrics/AbcSize
79
+ # rubocop:disable-next Metrics/AbcSize
80
80
  def check_unused_block_args(node, key, value)
81
81
  return if node.body.nil?
82
82
 
@@ -96,7 +96,6 @@ module RuboCop
96
96
  register_each_args_offense(node, message, 'each_value', unused_range)
97
97
  end
98
98
  end
99
- # rubocop:enable Metrics/AbcSize
100
99
 
101
100
  def on_block_pass(node)
102
101
  kv_each_with_block_pass(node.parent) do |target, method|
@@ -57,12 +57,15 @@ module RuboCop
57
57
 
58
58
  def on_send(node)
59
59
  return if (receiver = node.receiver) && allowed_receiver?(receiver)
60
+ return if part_of_ignored_node?(node)
60
61
 
61
62
  if offense_for_brackets?(node)
63
+ ignore_node(node.first_argument)
62
64
  add_offense(node.loc.selector, message: BRACKET_MSG) do |corrector|
63
65
  correct_fetch_to_brackets(corrector, node)
64
66
  end
65
67
  elsif offense_for_fetch?(node)
68
+ ignore_node(node.first_argument)
66
69
  add_offense(node, message: FETCH_MSG) do |corrector|
67
70
  correct_brackets_to_fetch(corrector, node)
68
71
  end
@@ -217,7 +217,7 @@ module RuboCop
217
217
  acceptable_19_syntax_symbol?(pair.key.source)
218
218
  end
219
219
 
220
- # rubocop:disable Metrics/CyclomaticComplexity
220
+ # rubocop:disable-next Metrics/CyclomaticComplexity
221
221
  def acceptable_19_syntax_symbol?(sym_name)
222
222
  sym_name.delete_prefix!(':')
223
223
 
@@ -237,7 +237,6 @@ module RuboCop
237
237
  (sym_name.start_with?("'") && sym_name.end_with?("'")) ||
238
238
  (sym_name.start_with?('"') && sym_name.end_with?('"'))
239
239
  end
240
- # rubocop:enable Metrics/CyclomaticComplexity
241
240
 
242
241
  def check(pairs, delim, msg)
243
242
  pairs.each do |pair|
@@ -136,7 +136,7 @@ module RuboCop
136
136
 
137
137
  private
138
138
 
139
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
139
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
140
140
  def check_branches(node, branches)
141
141
  # return if any branch is empty. An empty branch can be an `if`
142
142
  # without an `else` or a branch that contains only comments.
@@ -168,7 +168,6 @@ module RuboCop
168
168
 
169
169
  check_expressions(node, heads, :before_condition)
170
170
  end
171
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
172
171
 
173
172
  def duplicated_expressions?(node, expressions)
174
173
  unique_expressions = expressions.uniq
@@ -189,7 +188,7 @@ module RuboCop
189
188
  end
190
189
  end
191
190
 
192
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
191
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
193
192
  def check_expressions(node, expressions, insert_position)
194
193
  return if expressions.any?(&:nil?)
195
194
 
@@ -213,7 +212,6 @@ module RuboCop
213
212
  end
214
213
  end
215
214
  end
216
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
217
215
 
218
216
  def correct_assignment(corrector, node, expression, insert_position)
219
217
  indentation = indentation_of(node.parent)
@@ -64,7 +64,7 @@ module RuboCop
64
64
 
65
65
  MSG = 'Convert `if` nested inside `else` to `elsif`.'
66
66
 
67
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
+ # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
68
68
  def on_if(node)
69
69
  return if node.ternary? || node.unless?
70
70
 
@@ -81,7 +81,6 @@ module RuboCop
81
81
  ignore_node(node)
82
82
  end
83
83
  end
84
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
85
84
 
86
85
  private
87
86
 
@@ -91,7 +91,7 @@ module RuboCop
91
91
  [Style::Next, Style::SoleNestedConditional]
92
92
  end
93
93
 
94
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
94
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
95
95
  def on_if(node)
96
96
  return if endless_method?(node.body) || node.each_ancestor(:dstr).any?
97
97
 
@@ -109,7 +109,6 @@ module RuboCop
109
109
  ignore_node(node)
110
110
  end
111
111
  end
112
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
113
112
 
114
113
  private
115
114
 
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  MSG = 'Avoid modifier `%<keyword>s` after another conditional.'
30
30
 
31
- # rubocop:disable Metrics/AbcSize
31
+ # rubocop:disable-next Metrics/AbcSize
32
32
  def on_if(node)
33
33
  return unless node.modifier_form? && node.body.if_type?
34
34
 
@@ -37,7 +37,6 @@ module RuboCop
37
37
  corrector.remove(node.if_branch.source_range.end.join(node.condition.source_range.end))
38
38
  end
39
39
  end
40
- # rubocop:enable Metrics/AbcSize
41
40
  end
42
41
  end
43
42
  end
@@ -187,7 +187,7 @@ module RuboCop
187
187
  issues[:directives] << directive if directive_offends?(directive)
188
188
  end
189
189
 
190
- comment.values.each do |value| # rubocop:disable Style/HashEachMethods
190
+ comment.values.each do |value| # rubocop:disable Style/HashEachMethods -- the receiver is a magic comment, not a Hash
191
191
  issues[:values] << value if wrong_capitalization?(value.source, value_capitalization)
192
192
  end
193
193
 
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  private
69
69
 
70
- # rubocop:disable Metrics/AbcSize
70
+ # rubocop:disable-next Metrics/AbcSize
71
71
  def autocorrect(corrector, to_h, map)
72
72
  removal_range = range_between(to_h.loc.dot.begin_pos, to_h.loc.selector.end_pos)
73
73
 
@@ -83,7 +83,6 @@ module RuboCop
83
83
  corrector.replace(argument, argument.source[1..-2])
84
84
  end
85
85
  end
86
- # rubocop:enable Metrics/AbcSize
87
86
  end
88
87
  end
89
88
  end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  class MethodCallWithArgsParentheses
7
7
  # Style omit_parentheses
8
- # rubocop:disable Metrics/ModuleLength, Metrics/CyclomaticComplexity
8
+ # rubocop:disable-next Metrics/ModuleLength, Metrics/CyclomaticComplexity
9
9
  module OmitParentheses
10
10
  include RangeHelp
11
11
  include ReparsedEquivalence
@@ -150,7 +150,7 @@ module RuboCop
150
150
  node.parent&.class_type? && node.parent.single_line?
151
151
  end
152
152
 
153
- # rubocop:disable Metrics/PerceivedComplexity
153
+ # rubocop:disable-next Metrics/PerceivedComplexity
154
154
  def call_with_ambiguous_arguments?(node)
155
155
  call_with_braced_block?(node) ||
156
156
  call_in_argument_with_block?(node) ||
@@ -163,7 +163,6 @@ module RuboCop
163
163
  ambiguous_literal?(n) || logical_operator?(n)
164
164
  end
165
165
  end
166
- # rubocop:enable Metrics/PerceivedComplexity
167
166
 
168
167
  def call_with_braced_block?(node)
169
168
  node.type?(:call, :super) && node.block_node&.braces?
@@ -269,7 +268,6 @@ module RuboCop
269
268
  last_argument.hash_type? && last_argument.children.any?(&:forwarded_kwrestarg_type?)
270
269
  end
271
270
  end
272
- # rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
273
271
  end
274
272
  end
275
273
  end
@@ -242,7 +242,7 @@ module RuboCop
242
242
  extend AutoCorrector
243
243
 
244
244
  def self.autocorrect_incompatible_with
245
- [Style::NestedParenthesizedCalls, Style::RescueModifier]
245
+ [Style::NestedParenthesizedCalls, Style::RescueModifier, Style::TrailingCommaInArguments]
246
246
  end
247
247
 
248
248
  def on_send(node)
@@ -33,7 +33,7 @@ module RuboCop
33
33
 
34
34
  MSG = 'Do not use parentheses for method calls with no arguments.'
35
35
 
36
- # rubocop:disable Metrics/CyclomaticComplexity
36
+ # rubocop:disable-next Metrics/CyclomaticComplexity
37
37
  def on_send(node)
38
38
  return unless !node.arguments? && node.parenthesized?
39
39
  return if ineligible_node?(node)
@@ -44,7 +44,6 @@ module RuboCop
44
44
 
45
45
  register_offense(node)
46
46
  end
47
- # rubocop:enable Metrics/CyclomaticComplexity
48
47
  alias on_csend on_send
49
48
 
50
49
  private
@@ -38,7 +38,7 @@ module RuboCop
38
38
 
39
39
  private
40
40
 
41
- # rubocop:disable Metrics/AbcSize
41
+ # rubocop:disable-next Metrics/AbcSize
42
42
  def autocorrect(corrector, node, begin_of_arguments)
43
43
  arguments = node.arguments
44
44
  joined_arguments = arguments.map(&:source).join(', ')
@@ -62,7 +62,6 @@ module RuboCop
62
62
  corrector.remove(arguments_range)
63
63
  corrector.insert_after(begin_of_arguments, joined_arguments)
64
64
  end
65
- # rubocop:enable Metrics/AbcSize
66
65
 
67
66
  def last_line_source_of_arguments(arguments)
68
67
  processed_source[arguments.last_line - 1].strip
@@ -46,7 +46,7 @@ module RuboCop
46
46
  @corrected_nodes = nil
47
47
  end
48
48
 
49
- # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
49
+ # rubocop:disable-next Metrics/AbcSize,Metrics/CyclomaticComplexity
50
50
  def on_if(node)
51
51
  return unless if_else?(node)
52
52
  return unless (condition = unwrap_begin_nodes(node.condition))
@@ -64,7 +64,6 @@ module RuboCop
64
64
  end
65
65
  end
66
66
  end
67
- # rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity
68
67
 
69
68
  private
70
69
 
@@ -91,7 +91,7 @@ module RuboCop
91
91
  end
92
92
  end
93
93
 
94
- # rubocop:disable Metrics/CyclomaticComplexity
94
+ # rubocop:disable-next Metrics/CyclomaticComplexity
95
95
  def range_with_length_subtraction?(range_node, array_receiver)
96
96
  return false unless range_node&.range_type?
97
97
 
@@ -108,7 +108,6 @@ module RuboCop
108
108
 
109
109
  receivers_match_strict?(length_receiver, array_receiver)
110
110
  end
111
- # rubocop:enable Metrics/CyclomaticComplexity
112
111
 
113
112
  def handle_range_pattern(receiver, range_node, index_arg)
114
113
  range_end = range_node.end
@@ -124,7 +123,7 @@ module RuboCop
124
123
  end
125
124
  end
126
125
 
127
- # rubocop:disable Metrics/ParameterLists
126
+ # rubocop:disable-next Metrics/ParameterLists
128
127
  def build_range_offense_data(receiver, range_node, range_end, inner_end, negative_index,
129
128
  index_arg)
130
129
  range_op = range_node.erange_type? ? '...' : '..'
@@ -140,7 +139,6 @@ module RuboCop
140
139
 
141
140
  [message, replacement]
142
141
  end
143
- # rubocop:enable Metrics/ParameterLists
144
142
 
145
143
  def format_range_message_parts(range_start, negative_index, index_arg)
146
144
  has_parentheses = index_arg.begin_type?
@@ -70,6 +70,7 @@ module RuboCop
70
70
 
71
71
  def right_hand_operand(node, left_hand_keyword)
72
72
  condition = node.condition
73
+ negated = left_hand_keyword != node.keyword
73
74
 
74
75
  expr = if condition.send_type? && !condition.arguments.empty? &&
75
76
  !condition.operator_method?
@@ -77,8 +78,8 @@ module RuboCop
77
78
  else
78
79
  condition.source
79
80
  end
80
- expr = "(#{expr})" if requires_parens?(condition)
81
- expr = "!#{expr}" unless left_hand_keyword == node.keyword
81
+ expr = "(#{expr})" if requires_parens?(condition, negated)
82
+ expr = "!#{expr}" if negated
82
83
  expr
83
84
  end
84
85
 
@@ -91,8 +92,12 @@ module RuboCop
91
92
  expr
92
93
  end
93
94
 
94
- def requires_parens?(node)
95
- node.or_type? || !(RuboCop::AST::Node::COMPARISON_OPERATORS & node.children).empty?
95
+ def requires_parens?(node, negated)
96
+ # A negated `&&`/`||` operand must be wrapped so the `!` applies to the
97
+ # whole expression (e.g. `!(a && b)`, not `!a && b`).
98
+ (negated && node.operator_keyword?) ||
99
+ node.or_type? ||
100
+ !(RuboCop::AST::Node::COMPARISON_OPERATORS & node.children).empty?
96
101
  end
97
102
  end
98
103
  end
@@ -42,29 +42,56 @@ module RuboCop
42
42
  # @!method nil_check?(node)
43
43
  def_node_matcher :nil_check?, '(send _ :nil?)'
44
44
 
45
- # rubocop:disable Metrics/AbcSize
46
45
  def on_send(node)
47
46
  return unless node.receiver
48
47
 
49
48
  style_check?(node) do
50
49
  add_offense(node.loc.selector) do |corrector|
51
50
  if prefer_comparison?
52
- range = node.loc.dot.join(node.loc.selector.end)
53
- corrector.replace(range, ' == nil')
51
+ autocorrect_to_comparison(corrector, node)
54
52
  else
55
- range = node.receiver.source_range.end.join(node.source_range.end)
56
- corrector.replace(range, '.nil?')
53
+ autocorrect_to_predicate(corrector, node)
57
54
  end
58
-
59
- parent = node.parent
60
- corrector.wrap(node, '(', ')') if parent.respond_to?(:method?) && parent.method?(:!)
61
55
  end
62
56
  end
63
57
  end
64
- # rubocop:enable Metrics/AbcSize
65
58
 
66
59
  private
67
60
 
61
+ def autocorrect_to_comparison(corrector, node)
62
+ range = node.loc.dot.join(node.loc.selector.end)
63
+ corrector.replace(range, ' == nil')
64
+ # The new `== nil` binds looser than an enclosing operator (e.g. `<<`,
65
+ # `!`), so wrap it to keep the original precedence.
66
+ corrector.wrap(node, '(', ')') if operator_expression?(node.parent)
67
+ end
68
+
69
+ def autocorrect_to_predicate(corrector, node)
70
+ receiver = node.receiver
71
+ if operator_expression?(receiver)
72
+ # A looser-binding receiver (e.g. `!x`, `a + b`) must be parenthesized
73
+ # so the appended `.nil?` applies to the whole expression.
74
+ corrector.replace(node, "(#{receiver.source}).nil?")
75
+ else
76
+ range = receiver.source_range.end.join(node.source_range.end)
77
+ corrector.replace(range, '.nil?')
78
+ end
79
+ end
80
+
81
+ def operator_expression?(node)
82
+ return false unless node
83
+
84
+ operator_send?(node) ||
85
+ node.operator_keyword? ||
86
+ (node.if_type? && node.ternary?) ||
87
+ node.type?(:range, :iflipflop, :eflipflop) ||
88
+ node.assignment?
89
+ end
90
+
91
+ def operator_send?(node)
92
+ node.send_type? && node.operator_method? && !node.method?(:[]) && !node.method?(:[]=)
93
+ end
94
+
68
95
  def message(_node)
69
96
  prefer_comparison? ? EXPLICIT_MSG : PREDICATE_MSG
70
97
  end
@@ -48,7 +48,7 @@ module RuboCop
48
48
  { ({return next break} nil) (nil) }
49
49
  PATTERN
50
50
 
51
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
51
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- a lambda whose body is `nil` uses no parameters
52
52
  return unless node.lambda_or_proc?
53
53
  return unless nil_return?(node.body)
54
54
  # `return` inside a non-lambda proc returns from the enclosing method,
@@ -109,7 +109,7 @@ module RuboCop
109
109
 
110
110
  def message(node)
111
111
  if node.method?(:!=) && !include_semantic_changes?
112
- prefer = "!#{node.receiver.source}.nil?"
112
+ prefer = non_nil_check_replacement(node)
113
113
  format(MSG_FOR_REPLACEMENT, prefer: prefer, current: node.source)
114
114
  else
115
115
  MSG_FOR_REDUNDANCY
@@ -120,11 +120,27 @@ module RuboCop
120
120
  cop_config['IncludeSemanticChanges']
121
121
  end
122
122
 
123
+ # An operator-expression receiver (e.g. `a + b`) binds looser than the
124
+ # appended `.nil?`, so it must be parenthesized: `!(a + b).nil?`.
125
+ def non_nil_check_replacement(node)
126
+ receiver = node.receiver
127
+ source = operator_expression?(receiver) ? "(#{receiver.source})" : receiver.source
128
+ "!#{source}.nil?"
129
+ end
130
+
131
+ def operator_expression?(node)
132
+ node.operator_keyword? ||
133
+ (node.send_type? && node.binary_operation?) ||
134
+ (node.if_type? && node.ternary?) ||
135
+ node.type?(:range, :iflipflop, :eflipflop) ||
136
+ node.assignment?
137
+ end
138
+
123
139
  def autocorrect_comparison(corrector, node)
124
140
  if include_semantic_changes?
125
141
  corrector.replace(node, node.receiver.source)
126
142
  else
127
- corrector.replace(node, "!#{node.receiver.source}.nil?")
143
+ corrector.replace(node, non_nil_check_replacement(node))
128
144
  end
129
145
  end
130
146
 
@@ -56,7 +56,9 @@ module RuboCop
56
56
  def requires_parens?(child)
57
57
  child.operator_keyword? ||
58
58
  (child.send_type? && child.binary_operation?) ||
59
- (child.if_type? && child.ternary?)
59
+ (child.if_type? && child.ternary?) ||
60
+ child.type?(:range, :iflipflop, :eflipflop) ||
61
+ child.assignment?
60
62
  end
61
63
 
62
64
  def correct_opposite_method(corrector, range, child)
@@ -55,7 +55,11 @@ module RuboCop
55
55
  return unless type
56
56
 
57
57
  add_offense(node) do |corrector|
58
- corrector.replace(node, send(:"format_#{type}", node.source))
58
+ # The prefix patterns below are anchored, so correct only the digits
59
+ # and leave any sign the literal's source carries in place.
60
+ range = unsigned_range(node)
61
+
62
+ corrector.replace(range, send(:"format_#{type}", range.source))
59
63
  end
60
64
  end
61
65
 
@@ -71,6 +75,12 @@ module RuboCop
71
75
  octal_literal_type(literal) || hex_bin_dec_literal_type(literal)
72
76
  end
73
77
 
78
+ def unsigned_range(node)
79
+ range = node.source_range
80
+
81
+ node.source.start_with?('+', '-') ? range.adjust(begin_pos: 1) : range
82
+ end
83
+
74
84
  def octal_literal_type(literal)
75
85
  if OCTAL_ZERO_ONLY_REGEX.match?(literal) && octal_zero_only?
76
86
  :octal_zero_only
@@ -117,7 +117,7 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def ternary_replacement(node)
120
- condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
120
+ condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring -- takes all three branches in one step
121
121
 
122
122
  "#{expr_replacement(condition)} ? " \
123
123
  "#{expr_replacement(if_branch)} : " \
@@ -26,7 +26,7 @@ module RuboCop
26
26
  splat kwsplat forwarded_args forwarded_restarg forwarded_kwrestarg block_pass
27
27
  ].freeze
28
28
 
29
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
29
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
30
30
  def on_send(node)
31
31
  return unless (dot = node.loc.dot)
32
32
  return if unary_method_no_operator?(node)
@@ -44,7 +44,6 @@ module RuboCop
44
44
  corrector.insert_after(selector, ' ') if insert_space_after?(node)
45
45
  end
46
46
  end
47
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
48
47
 
49
48
  private
50
49
 
@@ -184,9 +184,8 @@ module RuboCop
184
184
  def accesses?(rhs, lhs)
185
185
  if lhs.method?(:[]=)
186
186
  # FIXME: Workaround `rubocop:disable` comment for JRuby.
187
- # rubocop:disable Performance/RedundantEqualityComparisonBlock
187
+ # rubocop:disable-next Performance/RedundantEqualityComparisonBlock -- a JRuby workaround, as the comment above says
188
188
  matching_calls(rhs, lhs.receiver, :[]).any? { |args| args == lhs.arguments }
189
- # rubocop:enable Performance/RedundantEqualityComparisonBlock
190
189
  else
191
190
  access_method = lhs.method_name.to_s.chop.to_sym
192
191
  matching_calls(rhs, lhs.receiver, access_method).any?
@@ -123,10 +123,15 @@ module RuboCop
123
123
 
124
124
  def parens_allowed?(node)
125
125
  parens_required?(node) ||
126
- (safe_assignment?(node) && safe_assignment_allowed?) ||
126
+ (safe_assignment?(node) && safe_assignment_kept?) ||
127
127
  (node.multiline? && allow_multiline_conditions?)
128
128
  end
129
129
 
130
+ def safe_assignment_kept?
131
+ safe_assignment_allowed? ||
132
+ config.for_enabled_cop('Lint/AssignmentInCondition')['AllowSafeAssignment']
133
+ end
134
+
130
135
  def allow_multiline_conditions?
131
136
  cop_config['AllowInMultilineConditions']
132
137
  end