rubocop 1.50.2 → 1.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) 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 +196 -28
  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/lsp.rb +19 -0
  10. data/lib/rubocop/cli.rb +10 -2
  11. data/lib/rubocop/config.rb +8 -2
  12. data/lib/rubocop/config_finder.rb +14 -4
  13. data/lib/rubocop/config_loader.rb +0 -1
  14. data/lib/rubocop/config_loader_resolver.rb +4 -3
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  16. data/lib/rubocop/config_obsoletion.rb +13 -10
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
  19. data/lib/rubocop/cop/base.rb +23 -4
  20. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  21. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  23. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  24. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  25. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  28. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  29. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  31. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  32. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  34. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  35. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  37. data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
  38. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  40. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  41. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
  43. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  45. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  46. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  49. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  50. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  51. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  52. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  53. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  54. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  55. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  56. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  57. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  58. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  61. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  62. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  63. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  64. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  65. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  66. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  67. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  68. data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
  69. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  70. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  71. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  72. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  73. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  74. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  75. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  76. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  77. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  78. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  79. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  80. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  81. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  82. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  83. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  84. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  85. data/lib/rubocop/cop/lint/debugger.rb +19 -5
  86. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  87. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  88. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  89. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  90. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  91. data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
  92. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  93. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  94. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  95. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  96. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  97. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  98. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  99. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  100. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  102. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  103. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  104. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  105. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  107. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  108. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  109. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  110. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  111. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  112. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  113. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  114. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  115. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  116. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  117. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  118. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  119. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  120. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  121. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  122. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  123. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  124. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  125. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  126. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  127. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  128. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  129. data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
  130. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  131. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  132. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  133. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  134. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  135. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  136. data/lib/rubocop/cop/lint/void.rb +97 -11
  137. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  138. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  139. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  140. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  141. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  142. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  143. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  144. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  145. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  146. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  147. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  148. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  149. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  150. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  151. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  152. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  153. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  154. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  155. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  156. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  157. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  158. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  159. data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
  160. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  161. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  162. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  163. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  164. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  165. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  166. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  167. data/lib/rubocop/cop/registry.rb +1 -1
  168. data/lib/rubocop/cop/security/open.rb +2 -2
  169. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  170. data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
  171. data/lib/rubocop/cop/style/alias.rb +9 -8
  172. data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
  173. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  174. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  175. data/lib/rubocop/cop/style/attr.rb +11 -1
  176. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  177. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  178. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  179. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  180. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  181. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  182. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  183. data/lib/rubocop/cop/style/class_check.rb +1 -0
  184. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  185. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  186. data/lib/rubocop/cop/style/collection_compact.rb +32 -12
  187. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  188. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  189. data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
  190. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  191. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  192. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
  193. data/lib/rubocop/cop/style/copyright.rb +5 -2
  194. data/lib/rubocop/cop/style/date_time.rb +5 -4
  195. data/lib/rubocop/cop/style/dir.rb +1 -1
  196. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  197. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  198. data/lib/rubocop/cop/style/documentation.rb +1 -1
  199. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  200. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  201. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  202. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  203. data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
  204. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  205. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  206. data/lib/rubocop/cop/style/file_read.rb +2 -2
  207. data/lib/rubocop/cop/style/for.rb +3 -1
  208. data/lib/rubocop/cop/style/format_string.rb +24 -3
  209. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  210. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  211. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  212. data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
  213. data/lib/rubocop/cop/style/hash_except.rb +21 -9
  214. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  215. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  216. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  217. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  218. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  219. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  220. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  221. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  222. data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
  223. data/lib/rubocop/cop/style/lambda.rb +3 -3
  224. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  225. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  226. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  227. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +24 -9
  228. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  229. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  230. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  231. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  232. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  233. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  234. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  235. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  236. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  237. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  238. data/lib/rubocop/cop/style/next.rb +1 -1
  239. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  240. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  241. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  242. data/lib/rubocop/cop/style/object_then.rb +5 -3
  243. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  244. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  245. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  246. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  247. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  248. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  249. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  250. data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
  251. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  252. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  253. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  254. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  255. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  256. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  257. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  258. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  259. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  260. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  261. data/lib/rubocop/cop/style/redundant_line_continuation.rb +32 -8
  262. data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
  263. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  264. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  265. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  266. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  267. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  268. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  269. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  270. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  271. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  272. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  273. data/lib/rubocop/cop/style/require_order.rb +11 -5
  274. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  275. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  276. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  277. data/lib/rubocop/cop/style/sample.rb +3 -4
  278. data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
  279. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  280. data/lib/rubocop/cop/style/semicolon.rb +20 -4
  281. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  282. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  283. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  284. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  285. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  286. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
  287. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  288. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  289. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  290. data/lib/rubocop/cop/style/strip.rb +7 -4
  291. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  292. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  293. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  294. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  295. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  296. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  297. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  298. data/lib/rubocop/cop/team.rb +1 -1
  299. data/lib/rubocop/cop/util.rb +1 -1
  300. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  301. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  302. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  303. data/lib/rubocop/cop/variable_force.rb +1 -0
  304. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  305. data/lib/rubocop/directive_comment.rb +10 -8
  306. data/lib/rubocop/ext/regexp_node.rb +9 -4
  307. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  308. data/lib/rubocop/file_finder.rb +4 -7
  309. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  310. data/lib/rubocop/formatter/html_formatter.rb +35 -14
  311. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  312. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  313. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  314. data/lib/rubocop/formatter.rb +1 -1
  315. data/lib/rubocop/lsp/logger.rb +22 -0
  316. data/lib/rubocop/lsp/routes.rb +246 -0
  317. data/lib/rubocop/lsp/runtime.rb +99 -0
  318. data/lib/rubocop/lsp/server.rb +71 -0
  319. data/lib/rubocop/lsp/severity.rb +27 -0
  320. data/lib/rubocop/lsp.rb +29 -0
  321. data/lib/rubocop/magic_comment.rb +13 -11
  322. data/lib/rubocop/options.rb +22 -9
  323. data/lib/rubocop/path_util.rb +6 -2
  324. data/lib/rubocop/result_cache.rb +5 -2
  325. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  326. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  327. data/lib/rubocop/rspec/shared_contexts.rb +42 -18
  328. data/lib/rubocop/rspec/support.rb +2 -0
  329. data/lib/rubocop/runner.rb +15 -6
  330. data/lib/rubocop/server/cache.rb +1 -1
  331. data/lib/rubocop/server/client_command/exec.rb +3 -3
  332. data/lib/rubocop/server/server_command/exec.rb +0 -1
  333. data/lib/rubocop/string_interpreter.rb +3 -3
  334. data/lib/rubocop/target_finder.rb +91 -81
  335. data/lib/rubocop/target_ruby.rb +85 -78
  336. data/lib/rubocop/version.rb +27 -8
  337. data/lib/rubocop.rb +19 -0
  338. metadata +56 -14
  339. /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