rubocop 1.54.1 → 1.64.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 (297) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +5 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +155 -26
  7. data/config/obsoletion.yml +5 -0
  8. data/lib/rubocop/cached_data.rb +11 -3
  9. data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
  10. data/lib/rubocop/cli/command/lsp.rb +2 -2
  11. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  12. data/lib/rubocop/cli.rb +11 -2
  13. data/lib/rubocop/config.rb +36 -12
  14. data/lib/rubocop/config_finder.rb +14 -4
  15. data/lib/rubocop/config_loader.rb +0 -1
  16. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  17. data/lib/rubocop/config_obsoletion.rb +11 -8
  18. data/lib/rubocop/config_validator.rb +14 -7
  19. data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
  20. data/lib/rubocop/cop/base.rb +64 -17
  21. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  22. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  23. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  24. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  25. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  26. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  28. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  29. data/lib/rubocop/cop/documentation.rb +16 -6
  30. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  31. data/lib/rubocop/cop/force.rb +12 -0
  32. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  33. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  34. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  35. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  36. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  37. data/lib/rubocop/cop/internal_affairs/example_description.rb +46 -24
  38. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  39. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  40. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  41. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +123 -29
  42. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  43. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  44. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  45. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  46. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  47. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  48. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  49. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  50. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  51. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  52. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  53. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  54. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +24 -7
  55. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  56. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  57. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  58. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  59. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  60. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  61. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  62. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  63. data/lib/rubocop/cop/layout/redundant_line_break.rb +29 -6
  64. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  65. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  66. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  67. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  68. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  69. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  70. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  71. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  72. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  73. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  74. data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -6
  75. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  76. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  77. data/lib/rubocop/cop/lint/debugger.rb +38 -3
  78. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  79. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  80. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  81. data/lib/rubocop/cop/lint/empty_conditional_body.rb +2 -2
  82. data/lib/rubocop/cop/lint/erb_new_arguments.rb +24 -17
  83. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  84. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  85. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  86. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  87. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  88. data/lib/rubocop/cop/lint/mixed_case_range.rb +10 -5
  89. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  90. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  91. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  92. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  93. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
  94. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  95. data/lib/rubocop/cop/lint/redundant_with_index.rb +6 -2
  96. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  97. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  98. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  99. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  100. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  101. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  102. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  103. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  104. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  105. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  106. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  107. data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
  108. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  109. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  110. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  111. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  112. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  113. data/lib/rubocop/cop/lint/useless_assignment.rb +38 -12
  114. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  115. data/lib/rubocop/cop/lint/void.rb +48 -12
  116. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  117. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  118. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  119. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  120. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +7 -7
  121. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  122. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  123. data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
  124. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  125. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  126. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +23 -13
  127. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  128. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  129. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  130. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  131. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  132. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  133. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  134. data/lib/rubocop/cop/naming/block_forwarding.rb +34 -7
  135. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  136. data/lib/rubocop/cop/naming/file_name.rb +3 -3
  137. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  138. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  139. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  140. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  141. data/lib/rubocop/cop/registry.rb +1 -1
  142. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  143. data/lib/rubocop/cop/security/open.rb +2 -2
  144. data/lib/rubocop/cop/style/access_modifier_declarations.rb +52 -2
  145. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  146. data/lib/rubocop/cop/style/alias.rb +10 -8
  147. data/lib/rubocop/cop/style/arguments_forwarding.rb +414 -63
  148. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  149. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  150. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  151. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  152. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  153. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  154. data/lib/rubocop/cop/style/class_check.rb +1 -0
  155. data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -0
  156. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  157. data/lib/rubocop/cop/style/collection_compact.rb +21 -11
  158. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  159. data/lib/rubocop/cop/style/combinable_loops.rb +17 -9
  160. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  161. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  162. data/lib/rubocop/cop/style/conditional_assignment.rb +7 -8
  163. data/lib/rubocop/cop/style/copyright.rb +31 -21
  164. data/lib/rubocop/cop/style/date_time.rb +5 -4
  165. data/lib/rubocop/cop/style/documentation.rb +24 -24
  166. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  167. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  168. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  169. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  170. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  171. data/lib/rubocop/cop/style/eval_with_location.rb +6 -15
  172. data/lib/rubocop/cop/style/exact_regexp_match.rb +4 -2
  173. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  174. data/lib/rubocop/cop/style/for.rb +3 -1
  175. data/lib/rubocop/cop/style/format_string.rb +33 -12
  176. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  177. data/lib/rubocop/cop/style/guard_clause.rb +26 -0
  178. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  179. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  180. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  181. data/lib/rubocop/cop/style/hash_syntax.rb +24 -2
  182. data/lib/rubocop/cop/style/identical_conditional_branches.rb +28 -3
  183. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  184. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  185. data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
  186. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  187. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  188. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  189. data/lib/rubocop/cop/style/map_to_hash.rb +18 -8
  190. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  191. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +22 -6
  192. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  193. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  194. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  195. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  196. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  197. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  198. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  199. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  200. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  201. data/lib/rubocop/cop/style/next.rb +1 -1
  202. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  203. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  204. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  205. data/lib/rubocop/cop/style/object_then.rb +5 -3
  206. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  207. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  208. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  209. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  210. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  211. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  212. data/lib/rubocop/cop/style/redundant_argument.rb +33 -4
  213. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  214. data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
  215. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -9
  216. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
  217. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  218. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  219. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  220. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  221. data/lib/rubocop/cop/style/redundant_filter_chain.rb +23 -6
  222. data/lib/rubocop/cop/style/redundant_line_continuation.rb +19 -2
  223. data/lib/rubocop/cop/style/redundant_parentheses.rb +71 -22
  224. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  225. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  226. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  227. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +5 -0
  228. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  229. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  230. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  231. data/lib/rubocop/cop/style/require_order.rb +1 -1
  232. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  233. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +23 -9
  234. data/lib/rubocop/cop/style/sample.rb +3 -4
  235. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  236. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  237. data/lib/rubocop/cop/style/semicolon.rb +8 -3
  238. data/lib/rubocop/cop/style/send.rb +4 -4
  239. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +90 -0
  240. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  241. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  242. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  243. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  244. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  245. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  246. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  247. data/lib/rubocop/cop/style/strip.rb +7 -4
  248. data/lib/rubocop/cop/style/super_arguments.rb +156 -0
  249. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  250. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  251. data/lib/rubocop/cop/style/symbol_proc.rb +68 -5
  252. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  253. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  254. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  255. data/lib/rubocop/cop/team.rb +5 -0
  256. data/lib/rubocop/cop/utils/regexp_ranges.rb +27 -14
  257. data/lib/rubocop/cop/variable_force/assignment.rb +1 -3
  258. data/lib/rubocop/cops_documentation_generator.rb +15 -3
  259. data/lib/rubocop/directive_comment.rb +10 -8
  260. data/lib/rubocop/ext/regexp_node.rb +9 -4
  261. data/lib/rubocop/file_finder.rb +4 -7
  262. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  263. data/lib/rubocop/formatter/disabled_config_formatter.rb +23 -8
  264. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  265. data/lib/rubocop/formatter/html_formatter.rb +35 -14
  266. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  267. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  268. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  269. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  270. data/lib/rubocop/formatter.rb +1 -1
  271. data/lib/rubocop/lockfile.rb +56 -7
  272. data/lib/rubocop/lsp/logger.rb +1 -1
  273. data/lib/rubocop/lsp/routes.rb +43 -31
  274. data/lib/rubocop/lsp/runtime.rb +21 -4
  275. data/lib/rubocop/lsp/server.rb +13 -6
  276. data/lib/rubocop/lsp/severity.rb +1 -1
  277. data/lib/rubocop/lsp.rb +36 -0
  278. data/lib/rubocop/magic_comment.rb +13 -11
  279. data/lib/rubocop/options.rb +14 -11
  280. data/lib/rubocop/path_util.rb +6 -2
  281. data/lib/rubocop/rake_task.rb +1 -1
  282. data/lib/rubocop/result_cache.rb +4 -1
  283. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  284. data/lib/rubocop/rspec/expect_offense.rb +16 -8
  285. data/lib/rubocop/rspec/shared_contexts.rb +55 -19
  286. data/lib/rubocop/rspec/support.rb +2 -0
  287. data/lib/rubocop/runner.rb +19 -6
  288. data/lib/rubocop/server/cache.rb +1 -1
  289. data/lib/rubocop/server/client_command/exec.rb +1 -2
  290. data/lib/rubocop/server/server_command/exec.rb +0 -1
  291. data/lib/rubocop/string_interpreter.rb +3 -3
  292. data/lib/rubocop/target_finder.rb +91 -81
  293. data/lib/rubocop/target_ruby.rb +82 -76
  294. data/lib/rubocop/version.rb +19 -4
  295. data/lib/rubocop.rb +9 -0
  296. metadata +29 -16
  297. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -8,6 +8,29 @@ module RuboCop
8
8
  # This cop identifies places where `do_something(*args, &block)`
9
9
  # can be replaced by `do_something(...)`.
10
10
  #
11
+ # In Ruby 3.1, anonymous block forwarding has been added.
12
+ #
13
+ # This cop identifies places where `do_something(&block)` can be replaced
14
+ # by `do_something(&)`; if desired, this functionality can be disabled
15
+ # by setting `UseAnonymousForwarding: false`.
16
+ #
17
+ # In Ruby 3.2, anonymous args/kwargs forwarding has been added.
18
+ #
19
+ # This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
20
+ # replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
21
+ # by setting `UseAnonymousForwarding: false`.
22
+ #
23
+ # And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
24
+ # and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
25
+ # that are sufficient for anonymizing meaningless naming.
26
+ #
27
+ # Meaningless names that are commonly used can be anonymized by default:
28
+ # e.g., `*args`, `**options`, `&block`, and so on.
29
+ #
30
+ # Names not on this list are likely to be meaningful and are allowed by default.
31
+ #
32
+ # This cop handles not only method forwarding but also forwarding to `super`.
33
+ #
11
34
  # @example
12
35
  # # bad
13
36
  # def foo(*args, &block)
@@ -24,7 +47,30 @@ module RuboCop
24
47
  # bar(...)
25
48
  # end
26
49
  #
27
- # @example AllowOnlyRestArgument: true (default)
50
+ # @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
51
+ # # bad
52
+ # def foo(*args, **kwargs, &block)
53
+ # args_only(*args)
54
+ # kwargs_only(**kwargs)
55
+ # block_only(&block)
56
+ # end
57
+ #
58
+ # # good
59
+ # def foo(*, **, &)
60
+ # args_only(*)
61
+ # kwargs_only(**)
62
+ # block_only(&)
63
+ # end
64
+ #
65
+ # @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
66
+ # # good
67
+ # def foo(*args, **kwargs, &block)
68
+ # args_only(*args)
69
+ # kwargs_only(**kwargs)
70
+ # block_only(&block)
71
+ # end
72
+ #
73
+ # @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
28
74
  # # good
29
75
  # def foo(*args)
30
76
  # bar(*args)
@@ -34,7 +80,7 @@ module RuboCop
34
80
  # bar(**kwargs)
35
81
  # end
36
82
  #
37
- # @example AllowOnlyRestArgument: false
83
+ # @example AllowOnlyRestArgument: false (only relevant for Ruby < 3.2)
38
84
  # # bad
39
85
  # # The following code can replace the arguments with `...`,
40
86
  # # but it will change the behavior. Because `...` forwards block also.
@@ -46,6 +92,38 @@ module RuboCop
46
92
  # bar(**kwargs)
47
93
  # end
48
94
  #
95
+ # @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
96
+ # # bad
97
+ # def foo(*args)
98
+ # bar(*args)
99
+ # end
100
+ #
101
+ # # good
102
+ # def foo(*)
103
+ # bar(*)
104
+ # end
105
+ #
106
+ # @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
107
+ # # bad
108
+ # def foo(**kwargs)
109
+ # bar(**kwargs)
110
+ # end
111
+ #
112
+ # # good
113
+ # def foo(**)
114
+ # bar(**)
115
+ # end
116
+ #
117
+ # @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
118
+ # # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
119
+ # def foo(&block)
120
+ # bar(&block)
121
+ # end
122
+ #
123
+ # # good
124
+ # def foo(&)
125
+ # bar(&)
126
+ # end
49
127
  class ArgumentsForwarding < Base
50
128
  include RangeHelp
51
129
  extend AutoCorrector
@@ -53,102 +131,375 @@ module RuboCop
53
131
 
54
132
  minimum_target_ruby_version 2.7
55
133
 
56
- MSG = 'Use arguments forwarding.'
57
-
58
- # @!method use_rest_arguments?(node)
59
- def_node_matcher :use_rest_arguments?, <<~PATTERN
60
- (args ({restarg kwrestarg} $_) $...)
61
- PATTERN
62
-
63
- # @!method only_rest_arguments?(node, name)
64
- def_node_matcher :only_rest_arguments?, <<~PATTERN
65
- {
66
- (send _ _ (splat (lvar %1)))
67
- (send _ _ (hash (kwsplat (lvar %1))))
68
- }
69
- PATTERN
70
-
71
- # @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
72
- def_node_matcher :forwarding_method_arguments?, <<~PATTERN
73
- {
74
- (send _ _
75
- (splat (lvar %1))
76
- (block-pass {(lvar %2) nil?}))
77
- (send _ _
78
- (splat (lvar %1))
79
- (hash (kwsplat (lvar %3)))
80
- (block-pass {(lvar %2) nil?}))
81
- }
82
- PATTERN
134
+ FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
135
+ ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
136
+
137
+ FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
138
+ ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
139
+ KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
140
+ BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
141
+
142
+ def self.autocorrect_incompatible_with
143
+ [Naming::BlockForwarding]
144
+ end
83
145
 
84
146
  def on_def(node)
85
147
  return unless node.body
86
- return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
87
- return if args.any?(&:default?)
88
148
 
89
- node.each_descendant(:send) do |send_node|
90
- kwargs_name, block_name = extract_argument_names_from(args)
149
+ restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
150
+ forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
151
+ send_nodes = node.each_descendant(:send, :csend, :super).to_a
91
152
 
92
- next unless forwarding_method?(send_node, rest_args_name, kwargs_name, block_name) &&
93
- all_lvars_as_forwarding_method_arguments?(node, send_node)
153
+ send_classifications = classify_send_nodes(
154
+ node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
155
+ )
94
156
 
95
- register_offense_to_forwarding_method_arguments(send_node)
96
- register_offense_to_method_definition_arguments(node)
157
+ return if send_classifications.empty?
158
+
159
+ if only_forwards_all?(send_classifications)
160
+ add_forward_all_offenses(node, send_classifications, forwardable_args)
161
+ elsif target_ruby_version >= 3.2
162
+ add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
97
163
  end
98
164
  end
165
+
99
166
  alias on_defs on_def
100
167
 
101
168
  private
102
169
 
103
- def extract_argument_names_from(args)
104
- kwargs_name = args.first.source.delete('**') if args.first&.kwrestarg_type?
105
- block_arg_name = args.last.source.delete('&') if args.last&.blockarg_type?
106
-
107
- [kwargs_name, block_arg_name].map { |name| name&.to_sym }
170
+ def extract_forwardable_args(args)
171
+ [args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
108
172
  end
109
173
 
110
- def forwarding_method?(node, rest_arg, kwargs, block_arg)
111
- return only_rest_arguments?(node, rest_arg) unless allow_only_rest_arguments?
174
+ def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
175
+ restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
176
+ kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
177
+ blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
178
+
179
+ [restarg_node, kwrestarg_node, blockarg_node]
180
+ end
112
181
 
113
- forwarding_method_arguments?(node, rest_arg, block_arg, kwargs)
182
+ def only_forwards_all?(send_classifications)
183
+ send_classifications.all? { |_, c, _, _| c == :all }
114
184
  end
115
185
 
116
- def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method)
117
- lvars = def_node.body.each_descendant(:lvar, :lvasgn)
186
+ # rubocop:disable Metrics/MethodLength
187
+ def add_forward_all_offenses(node, send_classifications, forwardable_args)
188
+ _rest_arg, _kwrest_arg, block_arg = *forwardable_args
189
+ registered_block_arg_offense = false
190
+
191
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
192
+ if !forward_rest && !forward_kwrest
193
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
194
+ # in Ruby 3.3.0.
195
+ if outside_block?(forward_block_arg)
196
+ register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
197
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
198
+ end
199
+ registered_block_arg_offense = true
200
+ break
201
+ else
202
+ register_forward_all_offense(send_node, send_node, forward_rest)
203
+ end
204
+ end
118
205
 
119
- begin_pos = forwarding_method.source_range.begin_pos
120
- end_pos = forwarding_method.source_range.end_pos
206
+ return if registered_block_arg_offense
121
207
 
122
- lvars.all? { |lvar| lvar.source_range.begin_pos.between?(begin_pos, end_pos) }
208
+ rest_arg, _kwrest_arg, _block_arg = *forwardable_args
209
+ register_forward_all_offense(node, node.arguments, rest_arg)
123
210
  end
211
+ # rubocop:enable Metrics/MethodLength
124
212
 
125
- def register_offense_to_forwarding_method_arguments(forwarding_method)
126
- add_offense(arguments_range(forwarding_method)) do |corrector|
127
- begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos
128
- range = range_between(begin_pos, forwarding_method.source_range.end_pos)
213
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
214
+ def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
215
+ return unless use_anonymous_forwarding?
129
216
 
130
- corrector.replace(range, '(...)')
217
+ rest_arg, kwrest_arg, block_arg = *forwardable_args
218
+
219
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
220
+ if outside_block?(forward_rest)
221
+ register_forward_args_offense(def_node.arguments, rest_arg)
222
+ register_forward_args_offense(send_node, forward_rest)
223
+ end
224
+
225
+ if outside_block?(forward_kwrest)
226
+ register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
227
+ register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
228
+ end
229
+
230
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
231
+ # in Ruby 3.3.0.
232
+ if outside_block?(forward_block_arg)
233
+ register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
234
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
235
+ end
131
236
  end
132
237
  end
238
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
239
+
240
+ def non_splat_or_block_pass_lvar_references(body)
241
+ body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
242
+ parent = lvar.parent
243
+
244
+ next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
245
+
246
+ lvar.children.first
247
+ end.uniq
248
+ end
133
249
 
134
- def register_offense_to_method_definition_arguments(method_definition)
135
- add_offense(arguments_range(method_definition)) do |corrector|
136
- arguments_range = range_with_surrounding_space(
137
- method_definition.arguments.source_range, side: :left
250
+ def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
251
+ send_nodes.filter_map do |send_node|
252
+ classification_and_forwards = classification_and_forwards(
253
+ def_node,
254
+ send_node,
255
+ referenced_lvars,
256
+ forwardable_args
138
257
  )
139
- corrector.replace(arguments_range, '(...)')
258
+
259
+ next unless classification_and_forwards
260
+
261
+ [send_node, *classification_and_forwards]
262
+ end
263
+ end
264
+
265
+ def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
266
+ classifier = SendNodeClassifier.new(
267
+ def_node, send_node, referenced_lvars, forwardable_args,
268
+ target_ruby_version: target_ruby_version,
269
+ allow_only_rest_arguments: allow_only_rest_arguments?
270
+ )
271
+
272
+ classification = classifier.classification
273
+
274
+ return unless classification
275
+
276
+ [
277
+ classification,
278
+ classifier.forwarded_rest_arg,
279
+ classifier.forwarded_kwrest_arg,
280
+ classifier.forwarded_block_arg
281
+ ]
282
+ end
283
+
284
+ def redundant_named_arg(arg, config_name, keyword)
285
+ return nil unless arg
286
+
287
+ redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
288
+ "#{keyword}#{redundant_arg_name}"
289
+ end << keyword
290
+
291
+ redundant_arg_names.include?(arg.source) ? arg : nil
292
+ end
293
+
294
+ def outside_block?(node)
295
+ return false unless node
296
+
297
+ node.each_ancestor(:block, :numblock).none?
298
+ end
299
+
300
+ def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
301
+ add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
302
+ add_parens_if_missing(def_arguments_or_send, corrector)
303
+
304
+ corrector.replace(rest_arg_or_splat, '*')
305
+ end
306
+ end
307
+
308
+ def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
309
+ add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
310
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
311
+
312
+ corrector.replace(kwrest_arg_or_splat, '**')
140
313
  end
141
314
  end
142
315
 
143
- def arguments_range(node)
144
- arguments = node.arguments
316
+ def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
317
+ return if target_ruby_version <= 3.0 ||
318
+ block_arg.nil? || block_arg.source == '&' || explicit_block_name?
145
319
 
146
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
320
+ add_offense(block_arg, message: BLOCK_MSG) do |corrector|
321
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
322
+
323
+ corrector.replace(block_arg, '&')
324
+ end
325
+ end
326
+
327
+ def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
328
+ arg_range = arguments_range(def_or_send, rest_or_splat)
329
+
330
+ add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
331
+ add_parens_if_missing(send_or_arguments, corrector)
332
+
333
+ corrector.replace(arg_range, '...')
334
+ end
335
+ end
336
+
337
+ def arguments_range(node, first_node)
338
+ arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
339
+
340
+ start_node = first_node || arguments.first
341
+
342
+ range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
147
343
  end
148
344
 
149
345
  def allow_only_rest_arguments?
150
346
  cop_config.fetch('AllowOnlyRestArgument', true)
151
347
  end
348
+
349
+ def use_anonymous_forwarding?
350
+ cop_config.fetch('UseAnonymousForwarding', false)
351
+ end
352
+
353
+ def add_parens_if_missing(node, corrector)
354
+ return if parentheses?(node)
355
+
356
+ add_parentheses(node, corrector)
357
+ end
358
+
359
+ # Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
360
+ class SendNodeClassifier
361
+ extend NodePattern::Macros
362
+
363
+ # @!method forwarded_rest_arg?(node, rest_name)
364
+ def_node_matcher :forwarded_rest_arg?, '(splat (lvar %1))'
365
+
366
+ # @!method extract_forwarded_kwrest_arg(node, kwrest_name)
367
+ def_node_matcher :extract_forwarded_kwrest_arg, '(hash <$(kwsplat (lvar %1)) ...>)'
368
+
369
+ # @!method forwarded_block_arg?(node, block_name)
370
+ def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
371
+
372
+ def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
373
+ @def_node = def_node
374
+ @send_node = send_node
375
+ @referenced_lvars = referenced_lvars
376
+ @rest_arg, @kwrest_arg, @block_arg = *forwardable_args
377
+ @rest_arg_name, @kwrest_arg_name, @block_arg_name =
378
+ *forwardable_args.map { |a| a&.name }
379
+ @config = config
380
+ end
381
+
382
+ def forwarded_rest_arg
383
+ return nil if referenced_rest_arg?
384
+
385
+ arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
386
+ end
387
+
388
+ def forwarded_kwrest_arg
389
+ return nil if referenced_kwrest_arg?
390
+
391
+ arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
392
+ end
393
+
394
+ def forwarded_block_arg
395
+ return nil if referenced_block_arg?
396
+
397
+ arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
398
+ end
399
+
400
+ def classification
401
+ return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
402
+
403
+ if can_forward_all?
404
+ :all
405
+ else
406
+ :rest_or_kwrest
407
+ end
408
+ end
409
+
410
+ private
411
+
412
+ def can_forward_all?
413
+ return false if any_arg_referenced?
414
+ return false if ruby_32_missing_rest_or_kwest?
415
+ return false unless offensive_block_forwarding?
416
+ return false if additional_kwargs_or_forwarded_kwargs?
417
+
418
+ no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
419
+ end
420
+
421
+ def ruby_32_missing_rest_or_kwest?
422
+ target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
423
+ end
424
+
425
+ def offensive_block_forwarding?
426
+ @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
427
+ end
428
+
429
+ def forwarded_rest_and_kwrest_args
430
+ forwarded_rest_arg && forwarded_kwrest_arg
431
+ end
432
+
433
+ def arguments
434
+ @send_node.arguments
435
+ end
436
+
437
+ def referenced_rest_arg?
438
+ @referenced_lvars.include?(@rest_arg_name)
439
+ end
440
+
441
+ def referenced_kwrest_arg?
442
+ @referenced_lvars.include?(@kwrest_arg_name)
443
+ end
444
+
445
+ def referenced_block_arg?
446
+ @referenced_lvars.include?(@block_arg_name)
447
+ end
448
+
449
+ def any_arg_referenced?
450
+ referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
451
+ end
452
+
453
+ def target_ruby_version
454
+ @config.fetch(:target_ruby_version)
455
+ end
456
+
457
+ def no_post_splat_args?
458
+ return true unless (splat_index = arguments.index(forwarded_rest_arg))
459
+
460
+ arg_after_splat = arguments[splat_index + 1]
461
+ [nil, :hash, :block_pass].include?(arg_after_splat&.type)
462
+ end
463
+
464
+ def additional_kwargs_or_forwarded_kwargs?
465
+ additional_kwargs? || forward_additional_kwargs?
466
+ end
467
+
468
+ def additional_kwargs?
469
+ @def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
470
+ end
471
+
472
+ def forward_additional_kwargs?
473
+ return false unless forwarded_kwrest_arg
474
+
475
+ !forwarded_kwrest_arg.parent.children.one?
476
+ end
477
+
478
+ def allow_offense_for_no_block?
479
+ !@config.fetch(:allow_only_rest_arguments)
480
+ end
481
+
482
+ def no_additional_args?
483
+ forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
484
+
485
+ return false if missing_rest_arg_or_kwrest_arg?
486
+
487
+ @def_node.arguments.size == forwardable_count &&
488
+ @send_node.arguments.size == forwardable_count
489
+ end
490
+
491
+ def missing_rest_arg_or_kwrest_arg?
492
+ (@rest_arg_name && !forwarded_rest_arg) ||
493
+ (@kwrest_arg_name && !forwarded_kwrest_arg)
494
+ end
495
+ end
496
+
497
+ def explicit_block_name?
498
+ block_forwarding_config = config.for_cop('Naming/BlockForwarding')
499
+ return false unless block_forwarding_config['Enabled']
500
+
501
+ block_forwarding_config['EnforcedStyle'] == 'explicit'
502
+ end
152
503
  end
153
504
  end
154
505
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
7
+ # them to use `arr.first` and `arr.last` instead.
8
+ #
9
+ # The cop is disabled by default due to safety concerns.
10
+ #
11
+ # @safety
12
+ # This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
13
+ # which returns a value for `0` or `-1` key, but changing these to use
14
+ # `.first` or `.last` will return first/last tuple instead. Also, String
15
+ # does not implement `first`/`last` methods.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # arr[0]
20
+ # arr[-1]
21
+ #
22
+ # # good
23
+ # arr.first
24
+ # arr.last
25
+ # arr[0] = 2
26
+ # arr[0][-2]
27
+ #
28
+ class ArrayFirstLast < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<preferred>s`.'
32
+ RESTRICT_ON_SEND = %i[[]].freeze
33
+
34
+ # rubocop:disable Metrics/AbcSize
35
+ def on_send(node)
36
+ return unless node.arguments.size == 1 && node.first_argument.int_type?
37
+
38
+ value = node.first_argument.value
39
+ return unless [0, -1].include?(value)
40
+
41
+ node = innermost_braces_node(node)
42
+ return if node.parent && brace_method?(node.parent)
43
+
44
+ preferred = (value.zero? ? 'first' : 'last')
45
+ add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
46
+ corrector.replace(node.loc.selector, ".#{preferred}")
47
+ end
48
+ end
49
+ # rubocop:enable Metrics/AbcSize
50
+
51
+ private
52
+
53
+ def innermost_braces_node(node)
54
+ node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
55
+ node
56
+ end
57
+
58
+ def brace_method?(node)
59
+ node.send_type? && (node.method?(:[]) || node.method?(:[]=))
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -11,6 +11,15 @@ module RuboCop
11
11
  # The `array1.intersect?(array2)` method is faster than
12
12
  # `(array1 & array2).any?` and is more readable.
13
13
  #
14
+ # In cases like the following, compatibility is not ensured,
15
+ # so it will not be detected when using block argument.
16
+ #
17
+ # [source,ruby]
18
+ # ----
19
+ # ([1] & [1,2]).any? { |x| false } # => false
20
+ # [1].intersect?([1,2]) { |x| false } # => true
21
+ # ----
22
+ #
14
23
  # @safety
15
24
  # This cop cannot guarantee that `array1` and `array2` are
16
25
  # actually arrays while method `intersect?` is for arrays only.
@@ -68,16 +77,15 @@ module RuboCop
68
77
  RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
69
78
 
70
79
  def on_send(node)
80
+ return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
71
81
  return unless (receiver, argument, method_name = bad_intersection_check?(node))
72
82
 
73
83
  message = message(receiver.source, argument.source, method_name)
74
84
 
75
85
  add_offense(node, message: message) do |corrector|
76
- if straight?(method_name)
77
- corrector.replace(node, "#{receiver.source}.intersect?(#{argument.source})")
78
- else
79
- corrector.replace(node, "!#{receiver.source}.intersect?(#{argument.source})")
80
- end
86
+ bang = straight?(method_name) ? '' : '!'
87
+
88
+ corrector.replace(node, "#{bang}#{receiver.source}.intersect?(#{argument.source})")
81
89
  end
82
90
  end
83
91