rubocop 1.48.1 → 1.62.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (386) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +7 -5
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +217 -35
  7. data/config/obsoletion.yml +5 -0
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
  9. data/lib/rubocop/cli/command/execute_runner.rb +7 -2
  10. data/lib/rubocop/cli/command/lsp.rb +19 -0
  11. data/lib/rubocop/cli.rb +16 -8
  12. data/lib/rubocop/config.rb +9 -3
  13. data/lib/rubocop/config_finder.rb +14 -4
  14. data/lib/rubocop/config_loader.rb +8 -9
  15. data/lib/rubocop/config_loader_resolver.rb +4 -3
  16. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  17. data/lib/rubocop/config_obsoletion.rb +13 -10
  18. data/lib/rubocop/config_validator.rb +14 -7
  19. data/lib/rubocop/cop/autocorrect_logic.rb +36 -13
  20. data/lib/rubocop/cop/base.rb +23 -4
  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 +3 -3
  24. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  25. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  26. data/lib/rubocop/cop/cop.rb +2 -2
  27. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  28. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  29. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  30. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  31. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  32. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  33. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  34. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  35. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +3 -3
  36. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  37. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  38. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  39. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  40. data/lib/rubocop/cop/internal_affairs/cop_description.rb +33 -9
  41. data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
  42. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +2 -2
  43. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  44. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  45. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  46. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  47. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  48. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
  49. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  50. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  51. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +29 -2
  52. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  53. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  54. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  55. data/lib/rubocop/cop/layout/class_structure.rb +8 -0
  56. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  57. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  58. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  59. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  60. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  61. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  62. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  63. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
  64. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  65. data/lib/rubocop/cop/layout/end_alignment.rb +20 -4
  66. data/lib/rubocop/cop/layout/extra_spacing.rb +3 -4
  67. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  68. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  69. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  70. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
  71. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
  72. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  73. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  74. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +6 -6
  75. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  76. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  77. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  78. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  79. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  80. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  81. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  82. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  83. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  84. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
  85. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
  86. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  87. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
  88. data/lib/rubocop/cop/layout/redundant_line_break.rb +33 -11
  89. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  90. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  91. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  92. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  93. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  94. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  95. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  96. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  97. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  98. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  99. data/lib/rubocop/cop/layout/space_inside_parens.rb +3 -3
  100. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  101. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  102. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  103. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  104. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  105. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  106. data/lib/rubocop/cop/lint/debugger.rb +19 -5
  107. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +3 -3
  108. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  109. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  110. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  111. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  112. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  113. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  114. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  115. data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
  116. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  117. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  118. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  119. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  120. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  121. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  122. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  123. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  124. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  125. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  126. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  127. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  128. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  129. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  130. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  131. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  132. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  133. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  134. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  135. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  136. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -1
  137. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  138. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  139. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  140. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
  141. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  142. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  143. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  144. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  145. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  146. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  147. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  148. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  149. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  150. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  151. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  152. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  153. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  154. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  155. data/lib/rubocop/cop/lint/to_enum_arguments.rb +19 -6
  156. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  157. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  158. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  159. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
  160. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  161. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  162. data/lib/rubocop/cop/lint/useless_method_definition.rb +10 -2
  163. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  164. data/lib/rubocop/cop/lint/void.rb +104 -14
  165. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  166. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  167. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  168. data/lib/rubocop/cop/metrics/class_length.rb +8 -2
  169. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  170. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  171. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +31 -3
  172. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  173. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  174. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  175. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  176. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  177. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  178. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  179. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  180. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  181. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  182. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  183. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  184. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  185. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  186. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  187. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  188. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  189. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  190. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  191. data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
  192. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  193. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  194. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  195. data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
  196. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  197. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  198. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  199. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  200. data/lib/rubocop/cop/registry.rb +1 -1
  201. data/lib/rubocop/cop/security/open.rb +2 -2
  202. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  203. data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
  204. data/lib/rubocop/cop/style/alias.rb +9 -8
  205. data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
  206. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  207. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  208. data/lib/rubocop/cop/style/attr.rb +11 -1
  209. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  210. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  211. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  212. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  213. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  214. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  215. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -2
  216. data/lib/rubocop/cop/style/class_check.rb +1 -0
  217. data/lib/rubocop/cop/style/class_equality_comparison.rb +58 -40
  218. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  219. data/lib/rubocop/cop/style/collection_compact.rb +35 -12
  220. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  221. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  222. data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
  223. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  224. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  225. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
  226. data/lib/rubocop/cop/style/copyright.rb +6 -3
  227. data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
  228. data/lib/rubocop/cop/style/date_time.rb +5 -4
  229. data/lib/rubocop/cop/style/dir.rb +1 -1
  230. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  231. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  232. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +2 -2
  233. data/lib/rubocop/cop/style/documentation.rb +1 -1
  234. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  235. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  236. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  237. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  238. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  239. data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
  240. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  241. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  242. data/lib/rubocop/cop/style/file_empty.rb +3 -3
  243. data/lib/rubocop/cop/style/file_read.rb +2 -2
  244. data/lib/rubocop/cop/style/for.rb +3 -1
  245. data/lib/rubocop/cop/style/format_string.rb +24 -3
  246. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +4 -2
  247. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  248. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  249. data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
  250. data/lib/rubocop/cop/style/hash_except.rb +25 -13
  251. data/lib/rubocop/cop/style/hash_syntax.rb +9 -2
  252. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  253. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  254. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  255. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  256. data/lib/rubocop/cop/style/if_unless_modifier.rb +41 -12
  257. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  258. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  259. data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
  260. data/lib/rubocop/cop/style/lambda.rb +3 -3
  261. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  262. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  263. data/lib/rubocop/cop/style/map_to_hash.rb +19 -6
  264. data/lib/rubocop/cop/style/map_to_set.rb +4 -1
  265. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +27 -16
  266. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +45 -40
  267. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  268. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  269. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  270. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  271. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  272. data/lib/rubocop/cop/style/multiline_method_signature.rb +16 -4
  273. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  274. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  275. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  276. data/lib/rubocop/cop/style/next.rb +1 -1
  277. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  278. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  279. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  280. data/lib/rubocop/cop/style/object_then.rb +5 -3
  281. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  282. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  283. data/lib/rubocop/cop/style/parallel_assignment.rb +29 -23
  284. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  285. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
  286. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  287. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  288. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  289. data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
  290. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  291. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  292. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  293. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  294. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  295. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  296. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  297. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  298. data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -7
  299. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  300. data/lib/rubocop/cop/style/redundant_line_continuation.rb +203 -0
  301. data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
  302. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  303. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  304. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -2
  305. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  306. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +3 -2
  307. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  308. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  309. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  310. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  311. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  312. data/lib/rubocop/cop/style/redundant_string_escape.rb +5 -4
  313. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  314. data/lib/rubocop/cop/style/require_order.rb +11 -5
  315. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  316. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  317. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  318. data/lib/rubocop/cop/style/sample.rb +3 -4
  319. data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
  320. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  321. data/lib/rubocop/cop/style/semicolon.rb +20 -4
  322. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  323. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  324. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  325. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  326. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  327. data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -4
  328. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  329. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  330. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  331. data/lib/rubocop/cop/style/strip.rb +7 -4
  332. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  333. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  334. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  335. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  336. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  337. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  338. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  339. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  340. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  341. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  342. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  343. data/lib/rubocop/cop/team.rb +1 -1
  344. data/lib/rubocop/cop/util.rb +1 -1
  345. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  346. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  347. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  348. data/lib/rubocop/cop/variable_force.rb +1 -0
  349. data/lib/rubocop/cops_documentation_generator.rb +26 -7
  350. data/lib/rubocop/directive_comment.rb +10 -8
  351. data/lib/rubocop/ext/regexp_node.rb +10 -5
  352. data/lib/rubocop/ext/regexp_parser.rb +5 -2
  353. data/lib/rubocop/file_finder.rb +4 -7
  354. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  355. data/lib/rubocop/formatter/html_formatter.rb +35 -14
  356. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  357. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  358. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  359. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  360. data/lib/rubocop/formatter.rb +1 -1
  361. data/lib/rubocop/lsp/logger.rb +22 -0
  362. data/lib/rubocop/lsp/routes.rb +246 -0
  363. data/lib/rubocop/lsp/runtime.rb +99 -0
  364. data/lib/rubocop/lsp/server.rb +71 -0
  365. data/lib/rubocop/lsp/severity.rb +27 -0
  366. data/lib/rubocop/lsp.rb +29 -0
  367. data/lib/rubocop/magic_comment.rb +13 -11
  368. data/lib/rubocop/options.rb +26 -10
  369. data/lib/rubocop/path_util.rb +6 -2
  370. data/lib/rubocop/result_cache.rb +6 -3
  371. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  372. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  373. data/lib/rubocop/rspec/shared_contexts.rb +42 -18
  374. data/lib/rubocop/rspec/support.rb +2 -0
  375. data/lib/rubocop/runner.rb +15 -6
  376. data/lib/rubocop/server/cache.rb +1 -1
  377. data/lib/rubocop/server/client_command/exec.rb +3 -3
  378. data/lib/rubocop/server/helper.rb +1 -1
  379. data/lib/rubocop/server/server_command/exec.rb +1 -2
  380. data/lib/rubocop/string_interpreter.rb +3 -3
  381. data/lib/rubocop/target_finder.rb +91 -81
  382. data/lib/rubocop/target_ruby.rb +85 -78
  383. data/lib/rubocop/version.rb +27 -8
  384. data/lib/rubocop.rb +22 -0
  385. metadata +59 -14
  386. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -8,6 +8,27 @@ 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
+ #
11
32
  # @example
12
33
  # # bad
13
34
  # def foo(*args, &block)
@@ -24,7 +45,30 @@ module RuboCop
24
45
  # bar(...)
25
46
  # end
26
47
  #
27
- # @example AllowOnlyRestArgument: true (default)
48
+ # @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
49
+ # # bad
50
+ # def foo(*args, **kwargs, &block)
51
+ # args_only(*args)
52
+ # kwargs_only(**kwargs)
53
+ # block_only(&block)
54
+ # end
55
+ #
56
+ # # good
57
+ # def foo(*, **, &)
58
+ # args_only(*)
59
+ # kwargs_only(**)
60
+ # block_only(&)
61
+ # end
62
+ #
63
+ # @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
64
+ # # good
65
+ # def foo(*args, **kwargs, &block)
66
+ # args_only(*args)
67
+ # kwargs_only(**kwargs)
68
+ # block_only(&block)
69
+ # end
70
+ #
71
+ # @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
28
72
  # # good
29
73
  # def foo(*args)
30
74
  # bar(*args)
@@ -34,7 +78,7 @@ module RuboCop
34
78
  # bar(**kwargs)
35
79
  # end
36
80
  #
37
- # @example AllowOnlyRestArgument: false
81
+ # @example AllowOnlyRestArgument: false (only relevant for Ruby < 3.2)
38
82
  # # bad
39
83
  # # The following code can replace the arguments with `...`,
40
84
  # # but it will change the behavior. Because `...` forwards block also.
@@ -46,6 +90,38 @@ module RuboCop
46
90
  # bar(**kwargs)
47
91
  # end
48
92
  #
93
+ # @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
94
+ # # bad
95
+ # def foo(*args)
96
+ # bar(*args)
97
+ # end
98
+ #
99
+ # # good
100
+ # def foo(*)
101
+ # bar(*)
102
+ # end
103
+ #
104
+ # @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
105
+ # # bad
106
+ # def foo(**kwargs)
107
+ # bar(**kwargs)
108
+ # end
109
+ #
110
+ # # good
111
+ # def foo(**)
112
+ # bar(**)
113
+ # end
114
+ #
115
+ # @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
116
+ # # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
117
+ # def foo(&block)
118
+ # bar(&block)
119
+ # end
120
+ #
121
+ # # good
122
+ # def foo(&)
123
+ # bar(&)
124
+ # end
49
125
  class ArgumentsForwarding < Base
50
126
  include RangeHelp
51
127
  extend AutoCorrector
@@ -53,102 +129,374 @@ module RuboCop
53
129
 
54
130
  minimum_target_ruby_version 2.7
55
131
 
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
132
+ FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
133
+ ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
134
+
135
+ FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
136
+ ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
137
+ KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
138
+ BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
139
+
140
+ def self.autocorrect_incompatible_with
141
+ [Naming::BlockForwarding]
142
+ end
83
143
 
84
144
  def on_def(node)
85
145
  return unless node.body
86
- return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
87
- return if args.any?(&:default?)
88
146
 
89
- node.each_descendant(:send) do |send_node|
90
- kwargs_name, block_name = extract_argument_names_from(args)
147
+ restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
148
+ forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
149
+ send_nodes = node.each_descendant(:send).to_a
150
+
151
+ send_classifications = classify_send_nodes(
152
+ node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
153
+ )
91
154
 
92
- next unless forwarding_method?(send_node, rest_args_name, kwargs_name, block_name) &&
93
- all_lvars_as_forwarding_method_arguments?(node, send_node)
155
+ return if send_classifications.empty?
94
156
 
95
- register_offense_to_forwarding_method_arguments(send_node)
96
- register_offense_to_method_definition_arguments(node)
157
+ if only_forwards_all?(send_classifications)
158
+ add_forward_all_offenses(node, send_classifications, forwardable_args)
159
+ elsif target_ruby_version >= 3.2
160
+ add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
97
161
  end
98
162
  end
163
+
99
164
  alias on_defs on_def
100
165
 
101
166
  private
102
167
 
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 }
168
+ def extract_forwardable_args(args)
169
+ [args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
108
170
  end
109
171
 
110
- def forwarding_method?(node, rest_arg, kwargs, block_arg)
111
- return only_rest_arguments?(node, rest_arg) unless allow_only_rest_arguments?
172
+ def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
173
+ restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
174
+ kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
175
+ blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
112
176
 
113
- forwarding_method_arguments?(node, rest_arg, block_arg, kwargs)
177
+ [restarg_node, kwrestarg_node, blockarg_node]
114
178
  end
115
179
 
116
- def all_lvars_as_forwarding_method_arguments?(def_node, forwarding_method)
117
- lvars = def_node.body.each_descendant(:lvar, :lvasgn)
180
+ def only_forwards_all?(send_classifications)
181
+ send_classifications.all? { |_, c, _, _| c == :all }
182
+ end
183
+
184
+ # rubocop:disable Metrics/MethodLength
185
+ def add_forward_all_offenses(node, send_classifications, forwardable_args)
186
+ _rest_arg, _kwrest_arg, block_arg = *forwardable_args
187
+ registered_block_arg_offense = false
118
188
 
119
- begin_pos = forwarding_method.source_range.begin_pos
120
- end_pos = forwarding_method.source_range.end_pos
189
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
190
+ if !forward_rest && !forward_kwrest
191
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
192
+ # in Ruby 3.3.0.
193
+ if outside_block?(forward_block_arg)
194
+ register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
195
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
196
+ end
197
+ registered_block_arg_offense = true
198
+ break
199
+ else
200
+ register_forward_all_offense(send_node, send_node, forward_rest)
201
+ end
202
+ end
121
203
 
122
- lvars.all? { |lvar| lvar.source_range.begin_pos.between?(begin_pos, end_pos) }
204
+ return if registered_block_arg_offense
205
+
206
+ rest_arg, _kwrest_arg, _block_arg = *forwardable_args
207
+ register_forward_all_offense(node, node.arguments, rest_arg)
123
208
  end
209
+ # rubocop:enable Metrics/MethodLength
210
+
211
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
212
+ def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
213
+ return unless use_anonymous_forwarding?
124
214
 
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)
215
+ rest_arg, kwrest_arg, block_arg = *forwardable_args
129
216
 
130
- corrector.replace(range, '(...)')
217
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
218
+ if outside_block?(forward_rest)
219
+ register_forward_args_offense(def_node.arguments, rest_arg)
220
+ register_forward_args_offense(send_node, forward_rest)
221
+ end
222
+
223
+ if outside_block?(forward_kwrest)
224
+ register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
225
+ register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
226
+ end
227
+
228
+ # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
229
+ # in Ruby 3.3.0.
230
+ if outside_block?(forward_block_arg)
231
+ register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
232
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
233
+ end
131
234
  end
132
235
  end
236
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
237
+
238
+ def non_splat_or_block_pass_lvar_references(body)
239
+ body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
240
+ parent = lvar.parent
241
+
242
+ next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
243
+
244
+ lvar.children.first
245
+ end.uniq
246
+ end
133
247
 
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
248
+ def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
249
+ send_nodes.filter_map do |send_node|
250
+ classification_and_forwards = classification_and_forwards(
251
+ def_node,
252
+ send_node,
253
+ referenced_lvars,
254
+ forwardable_args
138
255
  )
139
- corrector.replace(arguments_range, '(...)')
256
+
257
+ next unless classification_and_forwards
258
+
259
+ [send_node, *classification_and_forwards]
140
260
  end
141
261
  end
142
262
 
143
- def arguments_range(node)
144
- arguments = node.arguments
263
+ def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
264
+ classifier = SendNodeClassifier.new(
265
+ def_node, send_node, referenced_lvars, forwardable_args,
266
+ target_ruby_version: target_ruby_version,
267
+ allow_only_rest_arguments: allow_only_rest_arguments?
268
+ )
269
+
270
+ classification = classifier.classification
271
+
272
+ return unless classification
145
273
 
146
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
274
+ [
275
+ classification,
276
+ classifier.forwarded_rest_arg,
277
+ classifier.forwarded_kwrest_arg,
278
+ classifier.forwarded_block_arg
279
+ ]
280
+ end
281
+
282
+ def redundant_named_arg(arg, config_name, keyword)
283
+ return nil unless arg
284
+
285
+ redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
286
+ "#{keyword}#{redundant_arg_name}"
287
+ end << keyword
288
+
289
+ redundant_arg_names.include?(arg.source) ? arg : nil
290
+ end
291
+
292
+ def outside_block?(node)
293
+ return false unless node
294
+
295
+ node.each_ancestor(:block, :numblock).none?
296
+ end
297
+
298
+ def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
299
+ add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
300
+ add_parens_if_missing(def_arguments_or_send, corrector)
301
+
302
+ corrector.replace(rest_arg_or_splat, '*')
303
+ end
304
+ end
305
+
306
+ def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
307
+ add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
308
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
309
+
310
+ corrector.replace(kwrest_arg_or_splat, '**')
311
+ end
312
+ end
313
+
314
+ def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
315
+ return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
316
+
317
+ add_offense(block_arg, message: BLOCK_MSG) do |corrector|
318
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
319
+
320
+ corrector.replace(block_arg, '&')
321
+ end
322
+ end
323
+
324
+ def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
325
+ arg_range = arguments_range(def_or_send, rest_or_splat)
326
+
327
+ add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
328
+ add_parens_if_missing(send_or_arguments, corrector)
329
+
330
+ corrector.replace(arg_range, '...')
331
+ end
332
+ end
333
+
334
+ def arguments_range(node, first_node)
335
+ arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
336
+
337
+ start_node = first_node || arguments.first
338
+
339
+ range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
147
340
  end
148
341
 
149
342
  def allow_only_rest_arguments?
150
343
  cop_config.fetch('AllowOnlyRestArgument', true)
151
344
  end
345
+
346
+ def use_anonymous_forwarding?
347
+ cop_config.fetch('UseAnonymousForwarding', false)
348
+ end
349
+
350
+ def add_parens_if_missing(node, corrector)
351
+ return if parentheses?(node)
352
+
353
+ add_parentheses(node, corrector)
354
+ end
355
+
356
+ # Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
357
+ class SendNodeClassifier
358
+ extend NodePattern::Macros
359
+
360
+ # @!method forwarded_rest_arg?(node, rest_name)
361
+ def_node_matcher :forwarded_rest_arg?, '(splat (lvar %1))'
362
+
363
+ # @!method extract_forwarded_kwrest_arg(node, kwrest_name)
364
+ def_node_matcher :extract_forwarded_kwrest_arg, '(hash <$(kwsplat (lvar %1)) ...>)'
365
+
366
+ # @!method forwarded_block_arg?(node, block_name)
367
+ def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
368
+
369
+ def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
370
+ @def_node = def_node
371
+ @send_node = send_node
372
+ @referenced_lvars = referenced_lvars
373
+ @rest_arg, @kwrest_arg, @block_arg = *forwardable_args
374
+ @rest_arg_name, @kwrest_arg_name, @block_arg_name =
375
+ *forwardable_args.map { |a| a&.name }
376
+ @config = config
377
+ end
378
+
379
+ def forwarded_rest_arg
380
+ return nil if referenced_rest_arg?
381
+
382
+ arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
383
+ end
384
+
385
+ def forwarded_kwrest_arg
386
+ return nil if referenced_kwrest_arg?
387
+
388
+ arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
389
+ end
390
+
391
+ def forwarded_block_arg
392
+ return nil if referenced_block_arg?
393
+
394
+ arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
395
+ end
396
+
397
+ def classification
398
+ return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
399
+
400
+ if can_forward_all?
401
+ :all
402
+ else
403
+ :rest_or_kwrest
404
+ end
405
+ end
406
+
407
+ private
408
+
409
+ def can_forward_all?
410
+ return false if any_arg_referenced?
411
+ return false if ruby_32_missing_rest_or_kwest?
412
+ return false unless offensive_block_forwarding?
413
+ return false if additional_kwargs_or_forwarded_kwargs?
414
+
415
+ no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
416
+ end
417
+
418
+ def ruby_32_missing_rest_or_kwest?
419
+ target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
420
+ end
421
+
422
+ def offensive_block_forwarding?
423
+ @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
424
+ end
425
+
426
+ def forwarded_rest_and_kwrest_args
427
+ forwarded_rest_arg && forwarded_kwrest_arg
428
+ end
429
+
430
+ def arguments
431
+ @send_node.arguments
432
+ end
433
+
434
+ def referenced_rest_arg?
435
+ @referenced_lvars.include?(@rest_arg_name)
436
+ end
437
+
438
+ def referenced_kwrest_arg?
439
+ @referenced_lvars.include?(@kwrest_arg_name)
440
+ end
441
+
442
+ def referenced_block_arg?
443
+ @referenced_lvars.include?(@block_arg_name)
444
+ end
445
+
446
+ def any_arg_referenced?
447
+ referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
448
+ end
449
+
450
+ def target_ruby_version
451
+ @config.fetch(:target_ruby_version)
452
+ end
453
+
454
+ def no_post_splat_args?
455
+ return true unless (splat_index = arguments.index(forwarded_rest_arg))
456
+
457
+ arg_after_splat = arguments[splat_index + 1]
458
+ [nil, :hash, :block_pass].include?(arg_after_splat&.type)
459
+ end
460
+
461
+ def additional_kwargs_or_forwarded_kwargs?
462
+ additional_kwargs? || forward_additional_kwargs?
463
+ end
464
+
465
+ def additional_kwargs?
466
+ @def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
467
+ end
468
+
469
+ def forward_additional_kwargs?
470
+ return false unless forwarded_kwrest_arg
471
+
472
+ !forwarded_kwrest_arg.parent.children.one?
473
+ end
474
+
475
+ def allow_offense_for_no_block?
476
+ !@config.fetch(:allow_only_rest_arguments)
477
+ end
478
+
479
+ def no_additional_args?
480
+ forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
481
+
482
+ return false if missing_rest_arg_or_kwrest_arg?
483
+
484
+ @def_node.arguments.size == forwardable_count &&
485
+ @send_node.arguments.size == forwardable_count
486
+ end
487
+
488
+ def missing_rest_arg_or_kwrest_arg?
489
+ (@rest_arg_name && !forwarded_rest_arg) ||
490
+ (@kwrest_arg_name && !forwarded_kwrest_arg)
491
+ end
492
+ end
493
+
494
+ def explicit_block_name?
495
+ block_forwarding_config = config.for_cop('Naming/BlockForwarding')
496
+ return false unless block_forwarding_config['Enabled']
497
+
498
+ block_forwarding_config['EnforcedStyle'] == 'explicit'
499
+ end
152
500
  end
153
501
  end
154
502
  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
 
@@ -24,7 +24,7 @@ module RuboCop
24
24
  def on_send(node)
25
25
  return unless node.command?(:attr) && node.arguments?
26
26
  # check only for method definitions in class/module body
27
- return if node.parent && !node.parent.class_type? && !class_eval?(node.parent)
27
+ return if allowed_context?(node)
28
28
 
29
29
  message = message(node)
30
30
  add_offense(node.loc.selector, message: message) do |corrector|
@@ -34,6 +34,16 @@ module RuboCop
34
34
 
35
35
  private
36
36
 
37
+ def allowed_context?(node)
38
+ return false unless (class_node = node.each_ancestor(:class, :block).first)
39
+
40
+ (!class_node.class_type? && !class_eval?(class_node)) || define_attr_method?(class_node)
41
+ end
42
+
43
+ def define_attr_method?(node)
44
+ node.each_descendant(:def).any? { |def_node| def_node.method?(:attr) }
45
+ end
46
+
37
47
  def autocorrect(corrector, node)
38
48
  attr_name, setter = *node.arguments
39
49