rubocop 1.50.2 → 1.68.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 (494) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +73 -72
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +316 -38
  7. data/config/internal_affairs.yml +11 -0
  8. data/config/obsoletion.yml +5 -0
  9. data/exe/rubocop +4 -3
  10. data/lib/rubocop/cached_data.rb +21 -5
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +28 -15
  12. data/lib/rubocop/cli/command/execute_runner.rb +1 -1
  13. data/lib/rubocop/cli/command/lsp.rb +19 -0
  14. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  15. data/lib/rubocop/cli/command/version.rb +2 -2
  16. data/lib/rubocop/cli.rb +14 -2
  17. data/lib/rubocop/comment_config.rb +1 -1
  18. data/lib/rubocop/config.rb +45 -13
  19. data/lib/rubocop/config_finder.rb +14 -4
  20. data/lib/rubocop/config_loader.rb +15 -10
  21. data/lib/rubocop/config_loader_resolver.rb +17 -11
  22. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  23. data/lib/rubocop/config_obsoletion.rb +13 -10
  24. data/lib/rubocop/config_validator.rb +17 -9
  25. data/lib/rubocop/cop/autocorrect_logic.rb +30 -3
  26. data/lib/rubocop/cop/base.rb +78 -19
  27. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  28. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  29. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  30. data/lib/rubocop/cop/bundler/gem_version.rb +6 -7
  31. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  32. data/lib/rubocop/cop/cop.rb +30 -4
  33. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -13
  34. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  35. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  36. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  37. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  38. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  39. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  40. data/lib/rubocop/cop/documentation.rb +32 -5
  41. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  42. data/lib/rubocop/cop/force.rb +12 -0
  43. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  44. data/lib/rubocop/cop/gemspec/dependency_version.rb +5 -7
  45. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  46. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  47. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  48. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  49. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  50. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  51. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  52. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -12
  53. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  54. data/lib/rubocop/cop/internal_affairs/example_description.rb +46 -24
  55. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  56. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  57. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  58. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  59. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +128 -34
  60. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  61. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  62. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  63. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
  64. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
  65. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -5
  66. data/lib/rubocop/cop/internal_affairs.rb +18 -0
  67. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
  68. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  69. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  70. data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
  71. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  72. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  73. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  74. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  75. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  76. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  77. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  78. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  79. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +43 -10
  80. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  81. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  82. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +29 -5
  83. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +10 -3
  84. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  85. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  86. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  87. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +24 -10
  88. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  89. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  90. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  91. data/lib/rubocop/cop/layout/heredoc_indentation.rb +5 -2
  92. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  93. data/lib/rubocop/cop/layout/indentation_width.rb +8 -9
  94. data/lib/rubocop/cop/layout/leading_comment_space.rb +57 -2
  95. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  96. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  97. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  98. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  99. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  100. data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
  101. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  102. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  103. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  104. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  105. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  106. data/lib/rubocop/cop/layout/space_around_operators.rb +56 -21
  107. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  108. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  109. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +6 -0
  110. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  111. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  112. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  113. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  114. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  115. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  116. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -3
  117. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  118. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  119. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  120. data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -6
  121. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  122. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  123. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -3
  124. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  125. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  126. data/lib/rubocop/cop/lint/debugger.rb +45 -10
  127. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  128. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  129. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  130. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  131. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -5
  132. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -11
  133. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  134. data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
  135. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  136. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  137. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  138. data/lib/rubocop/cop/lint/empty_conditional_body.rb +29 -8
  139. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  140. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  141. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  142. data/lib/rubocop/cop/lint/ensure_return.rb +1 -9
  143. data/lib/rubocop/cop/lint/erb_new_arguments.rb +27 -21
  144. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  145. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  146. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  147. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  148. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  149. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  150. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +23 -12
  151. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  152. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  153. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  154. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  155. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +47 -0
  156. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  157. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  158. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  159. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +26 -7
  160. data/lib/rubocop/cop/lint/loop.rb +6 -12
  161. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  162. data/lib/rubocop/cop/lint/mixed_case_range.rb +116 -0
  163. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -7
  164. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -25
  165. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  166. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +17 -7
  167. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  168. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  169. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  170. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  171. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  172. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
  173. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  174. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  175. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  176. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  177. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  178. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  179. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  180. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  181. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -5
  182. data/lib/rubocop/cop/lint/redundant_with_index.rb +6 -2
  183. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  184. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  185. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  186. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  187. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  188. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +23 -12
  189. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +107 -41
  190. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  191. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  192. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  193. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  194. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  195. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -11
  196. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  197. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  198. data/lib/rubocop/cop/lint/symbol_conversion.rb +9 -4
  199. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  200. data/lib/rubocop/cop/lint/to_enum_arguments.rb +6 -6
  201. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  202. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  203. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  204. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  205. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +3 -2
  206. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -7
  207. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  208. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  209. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  210. data/lib/rubocop/cop/lint/useless_assignment.rb +102 -15
  211. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  212. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
  213. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  214. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  215. data/lib/rubocop/cop/lint/void.rb +128 -15
  216. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  217. data/lib/rubocop/cop/metrics/block_length.rb +7 -6
  218. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  219. data/lib/rubocop/cop/metrics/class_length.rb +14 -8
  220. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
  221. data/lib/rubocop/cop/metrics/method_length.rb +7 -6
  222. data/lib/rubocop/cop/metrics/module_length.rb +6 -5
  223. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  224. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +37 -9
  225. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  226. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  227. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  228. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  229. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  230. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  231. data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -1
  232. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  233. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  234. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  235. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  236. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  237. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  238. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  239. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +22 -10
  240. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +23 -13
  241. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  242. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
  243. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  244. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  245. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  246. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  247. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  248. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  249. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  250. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  251. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  252. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
  253. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  254. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  255. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  256. data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
  257. data/lib/rubocop/cop/naming/block_forwarding.rb +35 -8
  258. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  259. data/lib/rubocop/cop/naming/file_name.rb +3 -3
  260. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  261. data/lib/rubocop/cop/naming/inclusive_language.rb +13 -5
  262. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  263. data/lib/rubocop/cop/naming/predicate_name.rb +55 -29
  264. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +21 -4
  265. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  266. data/lib/rubocop/cop/offense.rb +4 -5
  267. data/lib/rubocop/cop/registry.rb +1 -1
  268. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  269. data/lib/rubocop/cop/security/open.rb +2 -2
  270. data/lib/rubocop/cop/style/access_modifier_declarations.rb +63 -3
  271. data/lib/rubocop/cop/style/accessor_grouping.rb +14 -2
  272. data/lib/rubocop/cop/style/alias.rb +11 -9
  273. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  274. data/lib/rubocop/cop/style/arguments_forwarding.rb +459 -63
  275. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  276. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  277. data/lib/rubocop/cop/style/attr.rb +11 -1
  278. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  279. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  280. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  281. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  282. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  283. data/lib/rubocop/cop/style/block_delimiters.rb +36 -7
  284. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  285. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  286. data/lib/rubocop/cop/style/class_check.rb +1 -0
  287. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  288. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  289. data/lib/rubocop/cop/style/collection_compact.rb +31 -11
  290. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  291. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  292. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  293. data/lib/rubocop/cop/style/combinable_loops.rb +43 -8
  294. data/lib/rubocop/cop/style/commented_keyword.rb +12 -3
  295. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  296. data/lib/rubocop/cop/style/conditional_assignment.rb +13 -12
  297. data/lib/rubocop/cop/style/copyright.rb +36 -23
  298. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  299. data/lib/rubocop/cop/style/date_time.rb +5 -4
  300. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  301. data/lib/rubocop/cop/style/dir.rb +1 -1
  302. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  303. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  304. data/lib/rubocop/cop/style/documentation.rb +25 -25
  305. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  306. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -8
  307. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  308. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  309. data/lib/rubocop/cop/style/empty_else.rb +6 -5
  310. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  311. data/lib/rubocop/cop/style/empty_literal.rb +32 -23
  312. data/lib/rubocop/cop/style/endless_method.rb +1 -14
  313. data/lib/rubocop/cop/style/eval_with_location.rb +24 -32
  314. data/lib/rubocop/cop/style/exact_regexp_match.rb +70 -0
  315. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  316. data/lib/rubocop/cop/style/file_read.rb +4 -7
  317. data/lib/rubocop/cop/style/file_write.rb +2 -5
  318. data/lib/rubocop/cop/style/for.rb +3 -1
  319. data/lib/rubocop/cop/style/format_string.rb +33 -12
  320. data/lib/rubocop/cop/style/format_string_token.rb +2 -2
  321. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  322. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  323. data/lib/rubocop/cop/style/guard_clause.rb +45 -2
  324. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  325. data/lib/rubocop/cop/style/hash_each_methods.rb +112 -33
  326. data/lib/rubocop/cop/style/hash_except.rb +29 -14
  327. data/lib/rubocop/cop/style/hash_syntax.rb +26 -4
  328. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  329. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  330. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  331. data/lib/rubocop/cop/style/if_inside_else.rb +7 -1
  332. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  333. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -4
  334. data/lib/rubocop/cop/style/if_with_semicolon.rb +51 -8
  335. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  336. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  337. data/lib/rubocop/cop/style/invertible_unless_condition.rb +56 -10
  338. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  339. data/lib/rubocop/cop/style/lambda.rb +4 -4
  340. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  341. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  342. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +82 -50
  343. data/lib/rubocop/cop/style/map_into_array.rb +233 -0
  344. data/lib/rubocop/cop/style/map_to_hash.rb +18 -8
  345. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  346. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +40 -15
  347. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -5
  348. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +22 -2
  349. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  350. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  351. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  352. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  353. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  354. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  355. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  356. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  357. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  358. data/lib/rubocop/cop/style/multiple_comparison.rb +41 -46
  359. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  360. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  361. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  362. data/lib/rubocop/cop/style/next.rb +1 -1
  363. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  364. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  365. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  366. data/lib/rubocop/cop/style/numeric_predicate.rb +12 -4
  367. data/lib/rubocop/cop/style/object_then.rb +5 -3
  368. data/lib/rubocop/cop/style/one_line_conditional.rb +6 -2
  369. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  370. data/lib/rubocop/cop/style/operator_method_call.rb +32 -7
  371. data/lib/rubocop/cop/style/parallel_assignment.rb +8 -9
  372. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  373. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  374. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  375. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -3
  376. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  377. data/lib/rubocop/cop/style/redundant_argument.rb +33 -4
  378. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  379. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  380. data/lib/rubocop/cop/style/redundant_begin.rb +15 -3
  381. data/lib/rubocop/cop/style/redundant_condition.rb +4 -4
  382. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  383. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  384. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  385. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  386. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  387. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  388. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  389. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  390. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  391. data/lib/rubocop/cop/style/redundant_line_continuation.rb +48 -9
  392. data/lib/rubocop/cop/style/redundant_parentheses.rb +80 -33
  393. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  394. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +103 -0
  395. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  396. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -24
  397. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  398. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  399. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  400. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  401. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  402. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  403. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  404. data/lib/rubocop/cop/style/require_order.rb +13 -7
  405. data/lib/rubocop/cop/style/rescue_modifier.rb +14 -4
  406. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  407. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +137 -0
  408. data/lib/rubocop/cop/style/safe_navigation.rb +106 -52
  409. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  410. data/lib/rubocop/cop/style/sample.rb +3 -4
  411. data/lib/rubocop/cop/style/select_by_regexp.rb +29 -15
  412. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  413. data/lib/rubocop/cop/style/semicolon.rb +21 -5
  414. data/lib/rubocop/cop/style/send.rb +4 -4
  415. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  416. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  417. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  418. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  419. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  420. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  421. data/lib/rubocop/cop/style/sole_nested_conditional.rb +27 -4
  422. data/lib/rubocop/cop/style/special_global_vars.rb +4 -6
  423. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  424. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  425. data/lib/rubocop/cop/style/strip.rb +7 -4
  426. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  427. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  428. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  429. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  430. data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
  431. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  432. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  433. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  434. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  435. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  436. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  437. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  438. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  439. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  440. data/lib/rubocop/cop/style/zero_length_predicate.rb +32 -24
  441. data/lib/rubocop/cop/team.rb +27 -3
  442. data/lib/rubocop/cop/util.rb +9 -3
  443. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  444. data/lib/rubocop/cop/variable_force/assignment.rb +62 -6
  445. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  446. data/lib/rubocop/cop/variable_force/variable.rb +5 -1
  447. data/lib/rubocop/cop/variable_force/variable_table.rb +4 -4
  448. data/lib/rubocop/cop/variable_force.rb +14 -1
  449. data/lib/rubocop/cops_documentation_generator.rb +97 -44
  450. data/lib/rubocop/core_ext/string.rb +2 -6
  451. data/lib/rubocop/directive_comment.rb +10 -8
  452. data/lib/rubocop/ext/regexp_node.rb +18 -35
  453. data/lib/rubocop/ext/regexp_parser.rb +7 -21
  454. data/lib/rubocop/file_finder.rb +11 -9
  455. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  456. data/lib/rubocop/formatter/disabled_config_formatter.rb +24 -9
  457. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  458. data/lib/rubocop/formatter/html_formatter.rb +37 -14
  459. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  460. data/lib/rubocop/formatter/junit_formatter.rb +71 -24
  461. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  462. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  463. data/lib/rubocop/formatter.rb +1 -1
  464. data/lib/rubocop/lockfile.rb +58 -7
  465. data/lib/rubocop/lsp/logger.rb +22 -0
  466. data/lib/rubocop/lsp/routes.rb +243 -0
  467. data/lib/rubocop/lsp/runtime.rb +101 -0
  468. data/lib/rubocop/lsp/server.rb +72 -0
  469. data/lib/rubocop/lsp/severity.rb +27 -0
  470. data/lib/rubocop/lsp.rb +36 -0
  471. data/lib/rubocop/magic_comment.rb +13 -11
  472. data/lib/rubocop/options.rb +28 -13
  473. data/lib/rubocop/path_util.rb +6 -2
  474. data/lib/rubocop/rake_task.rb +1 -1
  475. data/lib/rubocop/remote_config.rb +5 -1
  476. data/lib/rubocop/result_cache.rb +7 -10
  477. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  478. data/lib/rubocop/rspec/expect_offense.rb +17 -8
  479. data/lib/rubocop/rspec/shared_contexts.rb +77 -21
  480. data/lib/rubocop/rspec/support.rb +3 -0
  481. data/lib/rubocop/runner.rb +36 -12
  482. data/lib/rubocop/server/cache.rb +16 -1
  483. data/lib/rubocop/server/client_command/exec.rb +5 -5
  484. data/lib/rubocop/server/client_command/start.rb +1 -1
  485. data/lib/rubocop/server/core.rb +5 -0
  486. data/lib/rubocop/server/server_command/exec.rb +0 -1
  487. data/lib/rubocop/string_interpreter.rb +3 -3
  488. data/lib/rubocop/target_finder.rb +91 -81
  489. data/lib/rubocop/target_ruby.rb +90 -79
  490. data/lib/rubocop/version.rb +53 -13
  491. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  492. data/lib/rubocop.rb +40 -1
  493. metadata +73 -36
  494. /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,420 @@ 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, :yield).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', '&')
112
178
 
113
- forwarding_method_arguments?(node, rest_arg, block_arg, kwargs)
179
+ [restarg_node, kwrestarg_node, blockarg_node]
114
180
  end
115
181
 
116
- def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method)
117
- lvars = def_node.body.each_descendant(:lvar, :lvasgn)
182
+ def only_forwards_all?(send_classifications)
183
+ all_classifications = %i[all all_anonymous].freeze
184
+ send_classifications.all? { |_, c, _, _| all_classifications.include?(c) }
185
+ end
186
+
187
+ # rubocop:disable Metrics/MethodLength
188
+ def add_forward_all_offenses(node, send_classifications, forwardable_args)
189
+ _rest_arg, _kwrest_arg, block_arg = *forwardable_args
190
+ registered_block_arg_offense = false
118
191
 
119
- begin_pos = forwarding_method.source_range.begin_pos
120
- end_pos = forwarding_method.source_range.end_pos
192
+ send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
193
+ if !forward_rest && !forward_kwrest && c != :all_anonymous
194
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
195
+ # in Ruby 3.3.0.
196
+ if outside_block?(forward_block_arg)
197
+ register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
198
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
199
+ end
200
+ registered_block_arg_offense = true
201
+ break
202
+ else
203
+ register_forward_all_offense(send_node, send_node, forward_rest)
204
+ end
205
+ end
121
206
 
122
- lvars.all? { |lvar| lvar.source_range.begin_pos.between?(begin_pos, end_pos) }
207
+ return if registered_block_arg_offense
208
+
209
+ rest_arg, _kwrest_arg, _block_arg = *forwardable_args
210
+ register_forward_all_offense(node, node.arguments, rest_arg)
123
211
  end
212
+ # rubocop:enable Metrics/MethodLength
213
+
214
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
215
+ def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
216
+ return unless use_anonymous_forwarding?
217
+ return if send_inside_block?(send_classifications)
218
+
219
+ rest_arg, kwrest_arg, block_arg = *forwardable_args
124
220
 
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)
221
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
222
+ if outside_block?(forward_rest)
223
+ register_forward_args_offense(def_node.arguments, rest_arg)
224
+ register_forward_args_offense(send_node, forward_rest)
225
+ end
129
226
 
130
- corrector.replace(range, '(...)')
227
+ if outside_block?(forward_kwrest)
228
+ register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
229
+ register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
230
+ end
231
+
232
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
233
+ # in Ruby 3.3.0.
234
+ if outside_block?(forward_block_arg)
235
+ register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
236
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
237
+ end
131
238
  end
132
239
  end
240
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
241
+
242
+ def non_splat_or_block_pass_lvar_references(body)
243
+ body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
244
+ parent = lvar.parent
133
245
 
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
246
+ next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
247
+
248
+ lvar.children.first
249
+ end.uniq
250
+ end
251
+
252
+ def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
253
+ send_nodes.filter_map do |send_node|
254
+ classification_and_forwards = classification_and_forwards(
255
+ def_node,
256
+ send_node,
257
+ referenced_lvars,
258
+ forwardable_args
138
259
  )
139
- corrector.replace(arguments_range, '(...)')
260
+
261
+ next unless classification_and_forwards
262
+
263
+ [send_node, *classification_and_forwards]
264
+ end
265
+ end
266
+
267
+ def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
268
+ classifier = SendNodeClassifier.new(
269
+ def_node, send_node, referenced_lvars, forwardable_args,
270
+ target_ruby_version: target_ruby_version,
271
+ allow_only_rest_arguments: allow_only_rest_arguments?
272
+ )
273
+
274
+ classification = classifier.classification
275
+
276
+ return unless classification
277
+
278
+ [
279
+ classification,
280
+ classifier.forwarded_rest_arg,
281
+ classifier.forwarded_kwrest_arg,
282
+ classifier.forwarded_block_arg
283
+ ]
284
+ end
285
+
286
+ def redundant_named_arg(arg, config_name, keyword)
287
+ return nil unless arg
288
+
289
+ redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
290
+ "#{keyword}#{redundant_arg_name}"
291
+ end << keyword
292
+
293
+ redundant_arg_names.include?(arg.source) ? arg : nil
294
+ end
295
+
296
+ def outside_block?(node)
297
+ return false unless node
298
+
299
+ node.each_ancestor(:block, :numblock).none?
300
+ end
301
+
302
+ def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
303
+ add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
304
+ add_parens_if_missing(def_arguments_or_send, corrector)
305
+
306
+ corrector.replace(rest_arg_or_splat, '*')
307
+ end
308
+ end
309
+
310
+ def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
311
+ add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
312
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
313
+
314
+ corrector.replace(kwrest_arg_or_splat, '**')
315
+ end
316
+ end
317
+
318
+ def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
319
+ return if target_ruby_version <= 3.0 ||
320
+ block_arg.nil? || block_arg.source == '&' || explicit_block_name?
321
+
322
+ add_offense(block_arg, message: BLOCK_MSG) do |corrector|
323
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
324
+
325
+ corrector.replace(block_arg, '&')
326
+ end
327
+ end
328
+
329
+ def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
330
+ arg_range = arguments_range(def_or_send, rest_or_splat)
331
+
332
+ add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
333
+ add_parens_if_missing(send_or_arguments, corrector)
334
+
335
+ corrector.replace(arg_range, '...')
140
336
  end
141
337
  end
142
338
 
143
- def arguments_range(node)
144
- arguments = node.arguments
339
+ # rubocop:disable Metrics/AbcSize
340
+ def arguments_range(node, first_node)
341
+ arguments = node.arguments.reject do |arg|
342
+ next true if ADDITIONAL_ARG_TYPES.include?(arg.type) || arg.variable? || arg.call_type?
343
+
344
+ arg.literal? && arg.each_descendant(:kwsplat).none?
345
+ end
145
346
 
146
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
347
+ start_node = first_node || arguments.first
348
+ start_node.source_range.begin.join(arguments.last.source_range.end)
147
349
  end
350
+ # rubocop:enable Metrics/AbcSize
148
351
 
149
352
  def allow_only_rest_arguments?
150
353
  cop_config.fetch('AllowOnlyRestArgument', true)
151
354
  end
355
+
356
+ def use_anonymous_forwarding?
357
+ cop_config.fetch('UseAnonymousForwarding', false)
358
+ end
359
+
360
+ def send_inside_block?(send_classifications)
361
+ send_classifications.any? do |send_node, *|
362
+ send_node.each_ancestor(:block, :numblock).any?
363
+ end
364
+ end
365
+
366
+ def add_parens_if_missing(node, corrector)
367
+ return if parentheses?(node)
368
+ return if node.send_type? && node.method?(:[])
369
+
370
+ add_parentheses(node, corrector)
371
+ end
372
+
373
+ # Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
374
+ class SendNodeClassifier
375
+ extend NodePattern::Macros
376
+
377
+ # @!method forwarded_rest_arg?(node, rest_name)
378
+ def_node_matcher :forwarded_rest_arg?, '(splat (lvar %1))'
379
+
380
+ # @!method extract_forwarded_kwrest_arg(node, kwrest_name)
381
+ def_node_matcher :extract_forwarded_kwrest_arg, '(hash <$(kwsplat (lvar %1)) ...>)'
382
+
383
+ # @!method forwarded_block_arg?(node, block_name)
384
+ def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
385
+
386
+ # @!method def_all_anonymous_args?(node)
387
+ def_node_matcher :def_all_anonymous_args?, <<~PATTERN
388
+ (
389
+ def _
390
+ (args ... (restarg) (kwrestarg) (blockarg nil?))
391
+ _
392
+ )
393
+ PATTERN
394
+
395
+ # @!method send_all_anonymous_args?(node)
396
+ def_node_matcher :send_all_anonymous_args?, <<~PATTERN
397
+ (
398
+ send _ _
399
+ ... (forwarded_restarg) (hash (forwarded_kwrestarg)) (block_pass nil?)
400
+ )
401
+ PATTERN
402
+
403
+ def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
404
+ @def_node = def_node
405
+ @send_node = send_node
406
+ @referenced_lvars = referenced_lvars
407
+ @rest_arg, @kwrest_arg, @block_arg = *forwardable_args
408
+ @rest_arg_name, @kwrest_arg_name, @block_arg_name =
409
+ *forwardable_args.map { |a| a&.name }
410
+ @config = config
411
+ end
412
+
413
+ def forwarded_rest_arg
414
+ return nil if referenced_rest_arg?
415
+
416
+ arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
417
+ end
418
+
419
+ def forwarded_kwrest_arg
420
+ return nil if referenced_kwrest_arg?
421
+
422
+ arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
423
+ end
424
+
425
+ def forwarded_block_arg
426
+ return nil if referenced_block_arg?
427
+
428
+ arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
429
+ end
430
+
431
+ def classification
432
+ return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
433
+
434
+ if ruby_32_only_anonymous_forwarding?
435
+ :all_anonymous
436
+ elsif can_forward_all?
437
+ :all
438
+ else
439
+ :rest_or_kwrest
440
+ end
441
+ end
442
+
443
+ private
444
+
445
+ # rubocop:disable Metrics/CyclomaticComplexity
446
+ def can_forward_all?
447
+ return false if any_arg_referenced?
448
+ return false if ruby_30_or_lower_optarg?
449
+ return false if ruby_32_or_higher_missing_rest_or_kwest?
450
+ return false unless offensive_block_forwarding?
451
+ return false if additional_kwargs_or_forwarded_kwargs?
452
+
453
+ no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
454
+ end
455
+ # rubocop:enable Metrics/CyclomaticComplexity
456
+
457
+ # def foo(a = 41, ...) is a syntax error in 3.0.
458
+ def ruby_30_or_lower_optarg?
459
+ target_ruby_version <= 3.0 && @def_node.arguments.any?(&:optarg_type?)
460
+ end
461
+
462
+ def ruby_32_only_anonymous_forwarding?
463
+ def_all_anonymous_args?(@def_node) && send_all_anonymous_args?(@send_node)
464
+ end
465
+
466
+ def ruby_32_or_higher_missing_rest_or_kwest?
467
+ target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
468
+ end
469
+
470
+ def offensive_block_forwarding?
471
+ @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
472
+ end
473
+
474
+ def forwarded_rest_and_kwrest_args
475
+ forwarded_rest_arg && forwarded_kwrest_arg
476
+ end
477
+
478
+ def arguments
479
+ @send_node.arguments
480
+ end
481
+
482
+ def referenced_rest_arg?
483
+ @referenced_lvars.include?(@rest_arg_name)
484
+ end
485
+
486
+ def referenced_kwrest_arg?
487
+ @referenced_lvars.include?(@kwrest_arg_name)
488
+ end
489
+
490
+ def referenced_block_arg?
491
+ @referenced_lvars.include?(@block_arg_name)
492
+ end
493
+
494
+ def any_arg_referenced?
495
+ referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
496
+ end
497
+
498
+ def target_ruby_version
499
+ @config.fetch(:target_ruby_version)
500
+ end
501
+
502
+ def no_post_splat_args?
503
+ return true unless (splat_index = arguments.index(forwarded_rest_arg))
504
+
505
+ arg_after_splat = arguments[splat_index + 1]
506
+ [nil, :hash, :block_pass].include?(arg_after_splat&.type)
507
+ end
508
+
509
+ def additional_kwargs_or_forwarded_kwargs?
510
+ additional_kwargs? || forward_additional_kwargs?
511
+ end
512
+
513
+ def additional_kwargs?
514
+ @def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
515
+ end
516
+
517
+ def forward_additional_kwargs?
518
+ return false unless forwarded_kwrest_arg
519
+
520
+ !forwarded_kwrest_arg.parent.children.one?
521
+ end
522
+
523
+ def allow_offense_for_no_block?
524
+ !@config.fetch(:allow_only_rest_arguments)
525
+ end
526
+
527
+ def no_additional_args?
528
+ forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
529
+
530
+ return false if missing_rest_arg_or_kwrest_arg?
531
+
532
+ @def_node.arguments.size == forwardable_count &&
533
+ @send_node.arguments.size == forwardable_count
534
+ end
535
+
536
+ def missing_rest_arg_or_kwrest_arg?
537
+ (@rest_arg_name && !forwarded_rest_arg) ||
538
+ (@kwrest_arg_name && !forwarded_kwrest_arg)
539
+ end
540
+ end
541
+
542
+ def explicit_block_name?
543
+ block_forwarding_config = config.for_cop('Naming/BlockForwarding')
544
+ return false unless block_forwarding_config['Enabled']
545
+
546
+ block_forwarding_config['EnforcedStyle'] == 'explicit'
547
+ end
152
548
  end
153
549
  end
154
550
  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