rubocop 1.91.0 → 1.92.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +4 -1
  4. data/lib/rubocop/cached_data.rb +47 -7
  5. data/lib/rubocop/changed_files.rb +35 -13
  6. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +2 -2
  8. data/lib/rubocop/cli/command/explain.rb +34 -0
  9. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  10. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  11. data/lib/rubocop/cli.rb +3 -2
  12. data/lib/rubocop/comment_config.rb +17 -8
  13. data/lib/rubocop/config.rb +0 -4
  14. data/lib/rubocop/config_loader.rb +6 -3
  15. data/lib/rubocop/config_loader_resolver.rb +37 -12
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
  17. data/lib/rubocop/config_obsoletion.rb +9 -0
  18. data/lib/rubocop/config_validator.rb +11 -0
  19. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  20. data/lib/rubocop/cop/badge.rb +1 -1
  21. data/lib/rubocop/cop/base.rb +42 -21
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  24. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  25. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  26. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  27. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
  28. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
  30. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
  31. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  32. data/lib/rubocop/cop/documentation.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  34. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  35. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  36. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  37. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  38. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  39. data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
  40. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  41. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  42. data/lib/rubocop/cop/layout/class_structure.rb +29 -7
  43. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  44. data/lib/rubocop/cop/layout/dot_position.rb +25 -15
  45. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
  46. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  47. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
  50. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  51. data/lib/rubocop/cop/layout/end_alignment.rb +21 -25
  52. data/lib/rubocop/cop/layout/extra_spacing.rb +21 -6
  53. data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
  54. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
  55. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
  56. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  57. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  58. data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  61. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  62. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  63. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  64. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  65. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  66. data/lib/rubocop/cop/layout/line_length.rb +176 -26
  67. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  68. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  69. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +9 -0
  70. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  71. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
  72. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  73. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  74. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  75. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  76. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  77. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
  78. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  79. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
  80. data/lib/rubocop/cop/layout/space_before_block_braces.rb +16 -1
  81. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  82. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -9
  83. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
  84. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  85. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  86. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  87. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  88. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  89. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  90. data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
  91. data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
  92. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  93. data/lib/rubocop/cop/lint/loop.rb +24 -2
  94. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
  95. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  96. data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
  97. data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
  98. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
  99. data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
  100. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +39 -9
  101. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  102. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
  103. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
  104. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
  105. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  106. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  107. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  108. data/lib/rubocop/cop/lint/void.rb +8 -1
  109. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  110. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  111. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  112. data/lib/rubocop/cop/mixin/alignment.rb +4 -0
  113. data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
  114. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
  115. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  116. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  117. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  118. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
  119. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  120. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +41 -6
  121. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
  122. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  123. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  124. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  125. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  126. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  127. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
  128. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  129. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  130. data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -5
  131. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  132. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  133. data/lib/rubocop/cop/mixin.rb +2 -0
  134. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  135. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  136. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  137. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  138. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  139. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  140. data/lib/rubocop/cop/offense.rb +59 -3
  141. data/lib/rubocop/cop/registry.rb +1 -1
  142. data/lib/rubocop/cop/security/json_load.rb +16 -4
  143. data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -2
  144. data/lib/rubocop/cop/style/alias.rb +18 -5
  145. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  146. data/lib/rubocop/cop/style/and_or.rb +37 -10
  147. data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -3
  148. data/lib/rubocop/cop/style/attr.rb +3 -4
  149. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  150. data/lib/rubocop/cop/style/block_delimiters.rb +35 -3
  151. data/lib/rubocop/cop/style/case_equality.rb +14 -3
  152. data/lib/rubocop/cop/style/case_like_if.rb +6 -3
  153. data/lib/rubocop/cop/style/class_and_module_children.rb +57 -16
  154. data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
  155. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  156. data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
  157. data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
  158. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  159. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
  160. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  161. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  162. data/lib/rubocop/cop/style/empty_method.rb +3 -1
  163. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
  164. data/lib/rubocop/cop/style/endless_method.rb +104 -11
  165. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  166. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  167. data/lib/rubocop/cop/style/float_division.rb +37 -2
  168. data/lib/rubocop/cop/style/for.rb +53 -2
  169. data/lib/rubocop/cop/style/format_string.rb +28 -6
  170. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  171. data/lib/rubocop/cop/style/guard_clause.rb +31 -22
  172. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
  173. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  174. data/lib/rubocop/cop/style/hash_lookup_method.rb +42 -9
  175. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  176. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  177. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  178. data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -26
  179. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  180. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  181. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  182. data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
  183. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  184. data/lib/rubocop/cop/style/lambda.rb +34 -1
  185. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  186. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  187. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
  188. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -2
  189. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  190. data/lib/rubocop/cop/style/method_def_parentheses.rb +38 -4
  191. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  192. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  193. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  194. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  195. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  196. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  197. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  198. data/lib/rubocop/cop/style/mutable_constant.rb +52 -7
  199. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  200. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  201. data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
  202. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  203. data/lib/rubocop/cop/style/next.rb +24 -10
  204. data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
  205. data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
  206. data/lib/rubocop/cop/style/not.rb +10 -5
  207. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -5
  208. data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
  209. data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
  210. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  211. data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
  212. data/lib/rubocop/cop/style/raise_args.rb +80 -11
  213. data/lib/rubocop/cop/style/reduce_to_hash.rb +47 -33
  214. data/lib/rubocop/cop/style/redundant_begin.rb +45 -5
  215. data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
  216. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
  217. data/lib/rubocop/cop/style/redundant_exception.rb +27 -11
  218. data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
  219. data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
  220. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
  221. data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
  222. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  223. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
  224. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  225. data/lib/rubocop/cop/style/redundant_self.rb +9 -1
  226. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
  227. data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
  228. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  229. data/lib/rubocop/cop/style/require_order.rb +25 -8
  230. data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
  231. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  232. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  233. data/lib/rubocop/cop/style/sample.rb +9 -8
  234. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  235. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  236. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  237. data/lib/rubocop/cop/style/single_line_methods.rb +42 -4
  238. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  239. data/lib/rubocop/cop/style/string_concatenation.rb +21 -4
  240. data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
  241. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  242. data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
  243. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  244. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  245. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  246. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  247. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  248. data/lib/rubocop/cop/team.rb +10 -5
  249. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  250. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  251. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  252. data/lib/rubocop/formatter/formatter_set.rb +4 -0
  253. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  254. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  255. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  256. data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
  257. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  258. data/lib/rubocop/lsp/routes.rb +23 -23
  259. data/lib/rubocop/lsp/runtime.rb +47 -11
  260. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  261. data/lib/rubocop/lsp.rb +5 -2
  262. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  263. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  264. data/lib/rubocop/mcp/scope.rb +65 -0
  265. data/lib/rubocop/mcp/server.rb +184 -76
  266. data/lib/rubocop/mcp/source_files.rb +35 -0
  267. data/lib/rubocop/offense_limit.rb +30 -0
  268. data/lib/rubocop/options.rb +45 -10
  269. data/lib/rubocop/plugin/configuration_integrator.rb +36 -8
  270. data/lib/rubocop/remote_config.rb +4 -1
  271. data/lib/rubocop/result_cache.rb +20 -13
  272. data/lib/rubocop/runner.rb +110 -42
  273. data/lib/rubocop/server/cache.rb +6 -6
  274. data/lib/rubocop/target_ruby.rb +21 -9
  275. data/lib/rubocop/util.rb +69 -0
  276. data/lib/rubocop/version.rb +1 -1
  277. data/lib/rubocop.rb +5 -0
  278. metadata +16 -5
@@ -98,22 +98,23 @@ module RuboCop
98
98
  second.int_type? ? second.to_a.first : :unknown
99
99
  end
100
100
 
101
- # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
102
101
  def range_size(range_node)
103
- vals = range_node.to_a
104
- return :unknown unless vals.all? { |val| val.nil? || val.int_type? }
105
-
106
- low, high = vals.map { |val| val.nil? ? 0 : val.children[0] }
107
- return :unknown unless low.zero? && high >= 0
102
+ low, high = range_node.to_a
103
+ # An endless range takes the rest of the collection, whatever its size.
104
+ return :unknown unless zero_or_beginless?(low) && high&.int_type? && high.value >= 0
108
105
 
109
106
  case range_node.type
110
107
  when :erange
111
- (low...high).size
108
+ high.value
112
109
  when :irange
113
- (low..high).size
110
+ high.value + 1
114
111
  end
115
112
  end
116
113
 
114
+ def zero_or_beginless?(low)
115
+ low.nil? || (low.int_type? && low.value.zero?)
116
+ end
117
+
117
118
  def source_range(shuffle_node, node)
118
119
  shuffle_node.loc.selector.join(node.source_range.end)
119
120
  end
@@ -37,15 +37,20 @@ module RuboCop
37
37
  private
38
38
 
39
39
  def check(node, var_type)
40
- return unless (rhs = node.expression)
40
+ return unless (rhs = unparenthesized(node.expression))
41
41
 
42
42
  if rhs.send_type? && rhs.arguments.one?
43
43
  check_send_node(node, rhs, node.name, var_type)
44
- elsif rhs.operator_keyword?
44
+ elsif rhs.operator_keyword? && rhs.logical_operator?
45
45
  check_boolean_node(node, rhs, node.name, var_type)
46
46
  end
47
47
  end
48
48
 
49
+ def unparenthesized(node)
50
+ node = node.children.first while node&.begin_type? && node.children.one?
51
+ node
52
+ end
53
+
49
54
  def check_send_node(node, rhs, var_name, var_type)
50
55
  return unless OPS.include?(rhs.method_name)
51
56
 
@@ -68,26 +73,18 @@ module RuboCop
68
73
  end
69
74
 
70
75
  def autocorrect(corrector, node)
71
- rhs = node.expression
76
+ rhs = unparenthesized(node.expression)
72
77
 
73
78
  if rhs.send_type?
74
- autocorrect_send_node(corrector, node, rhs)
79
+ apply_autocorrect(corrector, node, rhs.method_name, rhs.first_argument)
75
80
  elsif rhs.operator_keyword?
76
- autocorrect_boolean_node(corrector, node, rhs)
81
+ apply_autocorrect(corrector, node, rhs.loc.operator.source, rhs.rhs)
77
82
  end
78
83
  end
79
84
 
80
- def autocorrect_send_node(corrector, node, rhs)
81
- apply_autocorrect(corrector, node, rhs, rhs.method_name, rhs.first_argument)
82
- end
83
-
84
- def autocorrect_boolean_node(corrector, node, rhs)
85
- apply_autocorrect(corrector, node, rhs, rhs.loc.operator.source, rhs.rhs)
86
- end
87
-
88
- def apply_autocorrect(corrector, node, rhs, operator, new_rhs)
85
+ def apply_autocorrect(corrector, node, operator, new_rhs)
89
86
  corrector.insert_before(node.loc.operator, operator)
90
- corrector.replace(rhs, new_rhs.source)
87
+ corrector.replace(node.expression, new_rhs.source)
91
88
  end
92
89
  end
93
90
  end
@@ -121,7 +121,6 @@ module RuboCop
121
121
  tokens[1]&.type == :tSTRING_DBEG && tokens[2]&.semicolon?
122
122
  end
123
123
 
124
- # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
125
124
  def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
126
125
  range = source_range(processed_source.buffer, line, column)
127
126
 
@@ -134,13 +133,11 @@ module RuboCop
134
133
  # See: https://github.com/rubocop/rubocop/issues/10791
135
134
  if token_before_semicolon&.regexp_dots?
136
135
  node = find_node(range_nodes, token_before_semicolon)
136
+ corrector.wrap(node, '(', ')') if node
137
137
  elsif token_before_semicolon&.type == :tLABEL
138
- node = find_node(value_omission_pair_nodes, token_before_semicolon).parent
139
- space = node.parent.loc.selector.end.join(node.source_range.begin)
140
- corrector.remove(space)
138
+ parenthesize_arguments(corrector, value_omission_hash(token_before_semicolon))
141
139
  end
142
140
 
143
- corrector.wrap(node, '(', ')') if node
144
141
  corrector.remove(range)
145
142
  end
146
143
  end
@@ -161,6 +158,20 @@ module RuboCop
161
158
  end
162
159
  end
163
160
 
161
+ def value_omission_hash(token_before_semicolon)
162
+ find_node(value_omission_pair_nodes, token_before_semicolon)&.parent
163
+ end
164
+
165
+ def parenthesize_arguments(corrector, hash_node)
166
+ return unless hash_node
167
+
168
+ call = hash_node.parent
169
+ before_arguments = args_begin(call).begin.join(call.first_argument.source_range.begin)
170
+
171
+ corrector.replace(before_arguments, '(')
172
+ corrector.insert_after(call.last_argument, ')')
173
+ end
174
+
164
175
  def expressions_per_line(exprs)
165
176
  # create a map matching lines to the number of expressions on them
166
177
  exprs_lines = exprs.map(&:last_line)
@@ -64,6 +64,10 @@ module RuboCop
64
64
  undef unless until when while yield
65
65
  ].freeze
66
66
 
67
+ def self.autocorrect_incompatible_with
68
+ [Layout::MultilineMethodArgumentLineBreaks]
69
+ end
70
+
67
71
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
68
72
  def on_send(node)
69
73
  return if allow_send? && !node.method?(:public_send)
@@ -35,6 +35,7 @@ module RuboCop
35
35
  #
36
36
  class SingleLineMethods < Base
37
37
  include Alignment
38
+ include EndlessMethodBodyHelp
38
39
  extend AutoCorrector
39
40
 
40
41
  MSG = 'Avoid single-line method definitions.'
@@ -67,10 +68,40 @@ module RuboCop
67
68
  return false if target_ruby_version < 3.0
68
69
  return false if disallow_endless_method_style?
69
70
  return false unless body_node
70
- return false if body_node.basic_conditional? || body_node.parent.assignment_method? ||
71
- NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
71
+ return false if body_node.parent.assignment_method?
72
+ return false if captures_following_code?(body_node.parent)
72
73
 
73
- !body_node.type?(:begin, :kwbegin)
74
+ !unsupported_endless_method_body?(body_node) && endless_method_body?(body_node)
75
+ end
76
+
77
+ # `def foo; bar; end && baz` would become `def foo() = bar && baz`. The same goes for a def
78
+ # that ends an operand, as in `a && def foo; bar; end || baz`.
79
+ def captures_following_code?(node)
80
+ return false unless (parent = node.parent)
81
+
82
+ node_end = node.source_range.end_pos
83
+ return captures_following_code?(parent) if parent.source_range.end_pos == node_end
84
+
85
+ parent.children.first.equal?(node) && extends_endless_body?(parent, node)
86
+ end
87
+
88
+ def extends_endless_body?(parent, node)
89
+ case parent.type
90
+ when :and, :or then parent.logical_operator?
91
+ when :if then parent.ternary?
92
+ when :rescue then same_line?(node, parent.resbody_branches.first) # the modifier form
93
+ else parent.type?(:call, :range)
94
+ end
95
+ end
96
+
97
+ def unsupported_endless_method_body?(body_node)
98
+ body_node.basic_conditional? ||
99
+ NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
100
+ end
101
+
102
+ # The body gets parenthesized when it becomes endless, so it is no longer a command.
103
+ def command_body_in_argument?(body)
104
+ !require_parentheses?(body) && super
74
105
  end
75
106
 
76
107
  def correct_to_multiline(corrector, node)
@@ -89,8 +120,8 @@ module RuboCop
89
120
 
90
121
  def correct_to_endless(corrector, node)
91
122
  receiver = "#{node.receiver.source}." if node.receiver
92
- arguments = node.arguments.any? ? node.arguments.source : '()'
93
123
  body_source = method_body_source(node.body)
124
+ arguments = endless_arguments(node)
94
125
  replacement = "def #{receiver}#{node.method_name}#{arguments} = #{body_source}"
95
126
 
96
127
  corrector.replace(node, replacement)
@@ -138,6 +169,13 @@ module RuboCop
138
169
  !method_body.arguments.empty? && !method_body.comparison_method?
139
170
  end
140
171
 
172
+ def endless_arguments(node)
173
+ arguments = node.arguments
174
+ return '()' if arguments.none?
175
+
176
+ arguments.loc.begin ? arguments.source : "(#{arguments.source})"
177
+ end
178
+
141
179
  def disallow_endless_method_style?
142
180
  return true unless config.cop_enabled?('Style/EndlessMethod')
143
181
 
@@ -50,7 +50,33 @@ module RuboCop
50
50
  end
51
51
 
52
52
  def redundant_parentheses?(node)
53
- style == :require_no_parentheses && parentheses?(node)
53
+ return false unless style == :require_no_parentheses && parentheses?(node)
54
+
55
+ arguments = node.block_node.arguments
56
+ !arguments_require_parentheses?(arguments) && !comment_inside_parentheses?(arguments)
57
+ end
58
+
59
+ def arguments_require_parentheses?(arguments)
60
+ arguments.each_descendant(:any_block, :hash).any? do |node|
61
+ !node.hash_type? || node.braces?
62
+ end
63
+ end
64
+
65
+ def comment_inside_parentheses?(arguments)
66
+ !leading_padding(arguments).source.strip.empty? ||
67
+ !trailing_padding(arguments).source.strip.empty?
68
+ end
69
+
70
+ def leading_padding(arguments)
71
+ first_argument = arguments.children.first
72
+
73
+ arguments.loc.begin.end.join(first_argument.source_range.begin)
74
+ end
75
+
76
+ def trailing_padding(arguments)
77
+ last_argument = arguments.children.last
78
+
79
+ last_argument.source_range.end.join(arguments.loc.end.begin)
54
80
  end
55
81
 
56
82
  def message(_node)
@@ -62,10 +88,8 @@ module RuboCop
62
88
  end
63
89
 
64
90
  def unwanted_parentheses_corrector(corrector, node)
65
- args_loc = node.loc
66
-
67
- corrector.replace(args_loc.begin, '')
68
- corrector.remove(args_loc.end)
91
+ corrector.remove(node.loc.begin.join(leading_padding(node)))
92
+ corrector.remove(trailing_padding(node).join(node.loc.end))
69
93
  end
70
94
 
71
95
  def stabby_lambda_with_args?(node)
@@ -143,7 +143,18 @@ module RuboCop
143
143
  def replacement(parts)
144
144
  interpolated_parts = parts.map { |part| adjust_str(part) }
145
145
 
146
- "\"#{handle_quotes(interpolated_parts).join}\""
146
+ "\"#{join_parts(handle_quotes(interpolated_parts))}\""
147
+ end
148
+
149
+ def join_parts(parts)
150
+ parts.each_with_object(+'') do |part, result|
151
+ result.insert(-2, '\\') if interpolation_formed?(result, part)
152
+ result << part
153
+ end
154
+ end
155
+
156
+ def interpolation_formed?(preceding, part)
157
+ part.start_with?('{', '@', '$') && preceding.match?(/(?<!\\)(?:\\\\)*#\z/)
147
158
  end
148
159
 
149
160
  def adjust_str(part)
@@ -160,7 +171,9 @@ module RuboCop
160
171
  end
161
172
 
162
173
  def adjust_str_literal(part)
163
- if single_quoted?(part)
174
+ if file_keyword?(part)
175
+ "\#{#{part.source}}"
176
+ elsif single_quoted?(part)
164
177
  part.value.gsub(/(\\|"|#\{|#@|#\$)/, '\\\\\&')
165
178
  elsif double_quoted?(part)
166
179
  # Reuse the source as written - rebuilding it from the value via
@@ -178,12 +191,16 @@ module RuboCop
178
191
  end
179
192
  end
180
193
 
194
+ def file_keyword?(str_node)
195
+ str_node.source == '__FILE__' && !str_node.parent.dstr_type?
196
+ end
197
+
181
198
  def single_quoted?(str_node)
182
- str_node.source.start_with?("'")
199
+ str_node.loc.begin && str_node.source.start_with?("'")
183
200
  end
184
201
 
185
202
  def double_quoted?(str_node)
186
- str_node.source.start_with?('"')
203
+ str_node.loc.begin && str_node.source.start_with?('"')
187
204
  end
188
205
 
189
206
  def mode
@@ -41,6 +41,12 @@ module RuboCop
41
41
  MSG = "Don't extend an instance initialized by `Struct.new`. " \
42
42
  'Use a block to customize the struct.'
43
43
 
44
+ # When the closing parenthesis of `Struct.new` is on its own line, omitting the
45
+ # parentheses in the same pass leaves a line break before the appended `do`.
46
+ def self.autocorrect_incompatible_with
47
+ [Style::MethodCallWithArgsParentheses]
48
+ end
49
+
44
50
  def on_class(node)
45
51
  return unless struct_constructor?(node.parent_class)
46
52
  return if defines_constants?(node.body)
@@ -76,6 +76,9 @@ module RuboCop
76
76
 
77
77
  def on_super(super_node)
78
78
  return unless (def_node = find_def_node(super_node))
79
+ # Zsuper passes a destructured argument as the original value, while
80
+ # `argument_list` flattens it into its parts.
81
+ return if def_node.arguments.any?(&:mlhs_type?)
79
82
 
80
83
  def_node_args = def_node.arguments.argument_list
81
84
  super_args = preprocess_super_args(super_node.arguments)
@@ -142,9 +142,11 @@ module RuboCop
142
142
  include RangeHelp
143
143
  include AllowedMethods
144
144
  include AllowedPattern
145
+ include PatternMatchingHelp
145
146
  extend AutoCorrector
146
147
 
147
148
  MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` instead of a block.'
149
+ MSG_LAMBDA_LITERAL = 'Use `lambda(&:%<method>s)` instead of %<original>s.'
148
150
  SUPER_TYPES = %i[super zsuper].freeze
149
151
  LAMBDA_OR_PROC = %i[lambda proc].freeze
150
152
 
@@ -164,7 +166,7 @@ module RuboCop
164
166
  PATTERN
165
167
 
166
168
  def self.autocorrect_incompatible_with
167
- [Layout::SpaceBeforeBlockBraces]
169
+ [Layout::SpaceBeforeBlockBraces, Style::TrailingCommaInArguments]
168
170
  end
169
171
 
170
172
  # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -174,6 +176,8 @@ module RuboCop
174
176
  return if proc_node?(dispatch_node)
175
177
  return if LAMBDA_OR_PROC.include?(dispatch_node.method_name)
176
178
  end
179
+ # A pattern accepts a lambda literal, but not `lambda(&:foo)`.
180
+ return if in_pattern?(node)
177
181
  return if unsafe_hash_usage?(dispatch_node)
178
182
  return if unsafe_array_usage?(dispatch_node)
179
183
  return if allowed_method_name?(dispatch_node.method_name)
@@ -207,12 +211,26 @@ module RuboCop
207
211
  end
208
212
 
209
213
  def register_offense(node, method_name, block_method_name)
210
- block_start = node.loc.begin.begin_pos
211
- block_end = node.loc.end.end_pos
212
- range = range_between(block_start, block_end)
213
- message = format(MSG, method: method_name, block_method: block_method_name)
214
+ range = if node.send_node.lambda_literal?
215
+ node.source_range
216
+ else
217
+ node.loc.begin.begin.join(node.loc.end.end)
218
+ end
219
+ message = message(node, method_name, block_method_name)
214
220
 
215
- add_offense(range, message: message) { |corrector| autocorrect(corrector, node) }
221
+ add_offense(range, message: message) do |corrector|
222
+ autocorrect(corrector, node)
223
+ end
224
+ end
225
+
226
+ def message(node, method_name, block_method_name)
227
+ if node.send_node.lambda_literal?
228
+ original = node.single_line? ? "`#{node.source}`" : 'a lambda literal with a block'
229
+
230
+ format(MSG_LAMBDA_LITERAL, method: method_name, original: original)
231
+ else
232
+ format(MSG, method: method_name, block_method: block_method_name)
233
+ end
216
234
  end
217
235
 
218
236
  def autocorrect(corrector, node)
@@ -58,6 +58,7 @@ module RuboCop
58
58
  include SafeAssignment
59
59
  include ConfigurableEnforcedStyle
60
60
  include SurroundingSpace
61
+ include ReparsedEquivalence
61
62
  extend AutoCorrector
62
63
 
63
64
  VARIABLE_TYPES = AST::Node::VARIABLES
@@ -101,7 +102,8 @@ module RuboCop
101
102
  condition = node.condition
102
103
 
103
104
  return nil if parenthesized?(condition) &&
104
- (safe_assignment?(condition) || unsafe_autocorrect?(condition))
105
+ (safe_assignment?(condition) || unsafe_autocorrect?(condition) ||
106
+ verified_by_reparse([condition]).empty?)
105
107
 
106
108
  if parenthesized?(condition)
107
109
  correct_parenthesized(corrector, condition)
@@ -218,6 +220,26 @@ module RuboCop
218
220
  end
219
221
  end
220
222
 
223
+ # Whatever binds looser than the ternary operator (`n += 1`, `a rescue b`,
224
+ # a nested ternary, `yield a`, several statements, ...) changes
225
+ # meaning without the parentheses, so their removal is verified by
226
+ # reparsing.
227
+ def apply_reparse_correction(corrector, condition)
228
+ correct_parenthesized(corrector, condition)
229
+ end
230
+
231
+ # The removed parentheses are the only expected difference.
232
+ def normalize_reparsed_ast(node)
233
+ return node unless node.is_a?(::Parser::AST::Node)
234
+
235
+ children = node.children.map { |child| normalize_reparsed_ast(child) }
236
+ if node.begin_type? && children.one? && children.first.is_a?(::Parser::AST::Node)
237
+ children.first
238
+ else
239
+ node.updated(nil, children)
240
+ end
241
+ end
242
+
221
243
  def correct_unparenthesized(corrector, condition)
222
244
  corrector.wrap(condition, '(', ')')
223
245
  end
@@ -35,19 +35,20 @@ module RuboCop
35
35
 
36
36
  MSG = 'Do not use trailing `_`s in parallel assignment. Prefer `%<code>s`.'
37
37
  UNDERSCORE = '_'
38
+ ARRAY_OPENING = '['
38
39
  DISALLOW = %i[lvasgn splat].freeze
39
40
  private_constant :DISALLOW
40
41
 
41
42
  def on_masgn(node)
42
- ranges = unneeded_ranges(node)
43
-
44
- ranges.each do |range|
43
+ unneeded_ranges(node).each do |range, replacement|
44
+ closing = replacement == ARRAY_OPENING ? ']' : ''
45
45
  good_code = node.source
46
46
  offset = range.begin_pos - node.source_range.begin_pos
47
- good_code[offset, range.size] = ''
47
+ good_code[offset, range.size] = replacement
48
48
 
49
- add_offense(range, message: format(MSG, code: good_code)) do |corrector|
50
- corrector.remove(range)
49
+ add_offense(range, message: format(MSG, code: "#{good_code}#{closing}")) do |corrector|
50
+ corrector.replace(range, replacement)
51
+ corrector.insert_after(node, closing) unless closing.empty?
51
52
  end
52
53
  end
53
54
  end
@@ -115,9 +116,12 @@ module RuboCop
115
116
 
116
117
  return unused_range(node, mlhs_node) if unused_variables_only?(first_offense, variables)
117
118
 
118
- return range_for_parentheses(first_offense, mlhs_node) if Util.parentheses?(mlhs_node)
119
-
120
- range_between(first_offense.source_range.begin_pos, node.loc.operator.begin_pos)
119
+ range = if Util.parentheses?(mlhs_node)
120
+ range_for_parentheses(first_offense, mlhs_node)
121
+ else
122
+ range_between(first_offense.source_range.begin_pos, node.loc.operator.begin_pos)
123
+ end
124
+ [range, '']
121
125
  end
122
126
 
123
127
  def children_offenses(variables)
@@ -129,17 +133,17 @@ module RuboCop
129
133
  end
130
134
 
131
135
  def unused_range(node, mlhs_node)
132
- start_range = mlhs_node.source_range.begin_pos
133
-
134
136
  # `node` can be an `mlhs` when recursing into a nested destructuring
135
- # group; only a `masgn` has a right-hand side to anchor against.
136
- end_range = if node.masgn_type?
137
- node.rhs.source_range.begin_pos
138
- else
139
- mlhs_node.source_range.end_pos
140
- end
141
-
142
- range_between(start_range, end_range)
137
+ # group. Removing the group could leave a dangling comma or put
138
+ # something after a splat, so it is collapsed into a single `_`,
139
+ # which the parent group handles in turn.
140
+ return [mlhs_node.source_range, UNDERSCORE] unless node.masgn_type?
141
+
142
+ rhs = node.rhs
143
+ range = range_between(mlhs_node.source_range.begin_pos, rhs.source_range.begin_pos)
144
+
145
+ # `_, _ = 1, 2` cannot become `1, 2`, so the values become an array literal.
146
+ [range, rhs.array_type? && !rhs.bracketed? ? ARRAY_OPENING : '']
143
147
  end
144
148
 
145
149
  def range_for_parentheses(offense, left)
@@ -59,7 +59,7 @@ module RuboCop
59
59
  private
60
60
 
61
61
  def non_eligible_body?(body)
62
- body&.conditional? || super
62
+ body&.conditional? || body&.kwbegin_type? || super
63
63
  end
64
64
  end
65
65
  end
@@ -104,7 +104,7 @@ module RuboCop
104
104
  valid_yoda?(node)
105
105
 
106
106
  add_offense(node) do |corrector|
107
- corrector.replace(actual_code_range(node), corrected_code(node))
107
+ autocorrect(corrector, node)
108
108
  end
109
109
  end
110
110
 
@@ -138,22 +138,37 @@ module RuboCop
138
138
  format(MSG, source: node.source)
139
139
  end
140
140
 
141
- def corrected_code(node)
142
- lhs = node.receiver
143
- rhs = node.first_argument
144
-
145
- "#{rhs.source} #{reverse_comparison(node.method_name)} #{lhs.source}"
141
+ def autocorrect(corrector, node)
142
+ if constant_portion?(node.first_argument)
143
+ move_argument_to_front(corrector, node)
144
+ else
145
+ move_receiver_to_back(corrector, node)
146
+ end
146
147
  end
147
148
 
148
149
  def constant_portion?(node)
149
150
  node.recursive_literal? || node.const_type?
150
151
  end
151
152
 
152
- def actual_code_range(node)
153
- range_between(node.source_range.begin_pos, node.source_range.end_pos)
153
+ def move_argument_to_front(corrector, node)
154
+ receiver = node.receiver
155
+
156
+ replacement = "#{node.first_argument.source} #{reverse_comparison(node)} "
157
+
158
+ corrector.insert_before(receiver, replacement)
159
+ corrector.remove(receiver.source_range.end.join(node.source_range.end))
154
160
  end
155
161
 
156
- def reverse_comparison(operator)
162
+ def move_receiver_to_back(corrector, node)
163
+ argument = node.first_argument
164
+
165
+ corrector.remove(node.source_range.begin.join(argument.source_range.begin))
166
+ corrector.insert_after(argument, " #{reverse_comparison(node)} #{node.receiver.source}")
167
+ end
168
+
169
+ def reverse_comparison(node)
170
+ operator = node.method_name
171
+
157
172
  REVERSE_COMPARISON.fetch(operator.to_s, operator)
158
173
  end
159
174
 
@@ -43,6 +43,9 @@ module RuboCop
43
43
  MSG = 'Non-literal operand (`%<source>s`) should be first.'
44
44
 
45
45
  RESTRICT_ON_SEND = %i[* + & | ^].freeze
46
+ ARGUMENT_ONLY_TYPES = %i[
47
+ splat block_pass forwarded_args forwarded_restarg forwarded_kwrestarg
48
+ ].freeze
46
49
 
47
50
  def on_new_investigation
48
51
  @offended_nodes = nil
@@ -68,13 +71,19 @@ module RuboCop
68
71
  private
69
72
 
70
73
  def yoda_expression_constant?(lhs, rhs)
71
- constant_portion?(lhs) && !constant_portion?(rhs)
74
+ constant_portion?(lhs) && !constant_portion?(rhs) && operand?(rhs)
72
75
  end
73
76
 
74
77
  def constant_portion?(node)
75
78
  node.type?(:numeric, :const)
76
79
  end
77
80
 
81
+ def operand?(node)
82
+ return false if node.hash_type? && !node.braces?
83
+
84
+ !node.type?(*ARGUMENT_ONLY_TYPES)
85
+ end
86
+
78
87
  def supported_operators
79
88
  @supported_operators ||= Array(cop_config['SupportedOperators']).freeze
80
89
  end
@@ -178,7 +178,7 @@ module RuboCop
178
178
  elsif defer_corrections
179
179
  @updated_source = new_source
180
180
  else
181
- File.write(processed_source.file_path, new_source)
181
+ RuboCop::Util.replace_file_contents(processed_source.file_path, new_source)
182
182
  end
183
183
  end
184
184
 
@@ -342,20 +342,25 @@ module RuboCop
342
342
  end
343
343
 
344
344
  def each_corrector(report)
345
- skips = Set.new
345
+ applied = []
346
346
  report.cop_reports.each do |cop_report|
347
- cop = cop_report.cop
347
+ cop_class = cop_report.cop.class
348
348
  corrector = cop_report.corrector
349
349
 
350
350
  next if corrector.nil? || corrector.empty?
351
- next if skips.include?(cop.class)
351
+ next if applied.any? { |other| autocorrect_incompatible?(cop_class, other) }
352
352
 
353
353
  yield corrector
354
354
 
355
- skips.merge(cop.class.autocorrect_incompatible_with)
355
+ applied << cop_class
356
356
  end
357
357
  end
358
358
 
359
+ def autocorrect_incompatible?(cop_class, other)
360
+ cop_class.autocorrect_incompatible_with.include?(other) ||
361
+ other.autocorrect_incompatible_with.include?(cop_class)
362
+ end
363
+
359
364
  def suppress_clobbering
360
365
  yield
361
366
  rescue ::Parser::ClobberingError
@@ -48,7 +48,7 @@ module RuboCop
48
48
  end
49
49
 
50
50
  def used?
51
- (!reassigned? && @variable.captured_by_block?) || @referenced
51
+ (!reassigned? && @variable.captured_by_block? && @variable.referenced?) || @referenced
52
52
  end
53
53
 
54
54
  def regexp_named_capture?