rubocop 1.67.0 → 1.75.5

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 (465) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +264 -47
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +3 -1
  7. data/lib/rubocop/cached_data.rb +12 -4
  8. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  9. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  10. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  11. data/lib/rubocop/cli/command/version.rb +2 -2
  12. data/lib/rubocop/cli.rb +1 -1
  13. data/lib/rubocop/comment_config.rb +2 -2
  14. data/lib/rubocop/config.rb +52 -10
  15. data/lib/rubocop/config_loader.rb +52 -9
  16. data/lib/rubocop/config_loader_resolver.rb +36 -10
  17. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  18. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  19. data/lib/rubocop/config_obsoletion.rb +46 -2
  20. data/lib/rubocop/config_validator.rb +25 -14
  21. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  22. data/lib/rubocop/cop/base.rb +7 -1
  23. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  24. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  25. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  26. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  27. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  28. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  30. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  31. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  32. data/lib/rubocop/cop/generator.rb +6 -0
  33. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  34. data/lib/rubocop/cop/internal_affairs/example_description.rb +8 -4
  35. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  36. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  37. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  38. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  39. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  40. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  41. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  42. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +230 -0
  43. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  44. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  45. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  46. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  47. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  48. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  49. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  50. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  51. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  52. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  53. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  54. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  55. data/lib/rubocop/cop/internal_affairs.rb +7 -16
  56. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  57. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  58. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  59. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  60. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  61. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  62. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  63. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  64. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  65. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  66. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  67. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -3
  68. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  69. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +30 -4
  70. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  71. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  72. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  73. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  74. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  75. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  76. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  77. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  78. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  79. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  80. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  81. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -6
  82. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  83. data/lib/rubocop/cop/layout/indentation_width.rb +8 -7
  84. data/lib/rubocop/cop/layout/leading_comment_space.rb +57 -2
  85. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  86. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  87. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  88. data/lib/rubocop/cop/layout/line_length.rb +123 -4
  89. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  90. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  91. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  92. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  93. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  94. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  95. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  96. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -4
  97. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  98. data/lib/rubocop/cop/layout/redundant_line_break.rb +19 -46
  99. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +6 -7
  100. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  101. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  102. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  103. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  104. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  105. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  106. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  107. data/lib/rubocop/cop/layout/space_around_operators.rb +23 -21
  108. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  109. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  110. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  111. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  112. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +10 -1
  113. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +5 -0
  114. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +7 -0
  115. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  116. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  117. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  118. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +118 -0
  119. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  120. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  121. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  122. data/lib/rubocop/cop/lint/circular_argument_reference.rb +4 -1
  123. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  124. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  125. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  126. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  127. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +3 -2
  128. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  129. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  130. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
  131. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  132. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  133. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  134. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  135. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  136. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  137. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  138. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  139. data/lib/rubocop/cop/lint/float_comparison.rb +20 -14
  140. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  141. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  142. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  143. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  144. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  145. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  146. data/lib/rubocop/cop/lint/literal_as_condition.rb +118 -9
  147. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  148. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  149. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  150. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  151. data/lib/rubocop/cop/lint/mixed_case_range.rb +5 -8
  152. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  153. data/lib/rubocop/cop/lint/nested_method_definition.rb +10 -6
  154. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  155. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  156. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  157. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  158. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  159. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  160. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  161. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  162. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -3
  163. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  164. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  165. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  166. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  167. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  168. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  169. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
  170. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  171. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  172. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  173. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  174. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  175. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  176. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  177. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  178. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  179. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  180. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  181. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  182. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  183. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  184. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  185. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  186. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  187. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  188. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  189. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  190. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  191. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  192. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  193. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  194. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  195. data/lib/rubocop/cop/lint/unreachable_code.rb +52 -2
  196. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  197. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  198. data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
  199. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  200. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  201. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  202. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  203. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  204. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  205. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -2
  206. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  207. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  208. data/lib/rubocop/cop/lint/void.rb +16 -12
  209. data/lib/rubocop/cop/message_annotator.rb +7 -3
  210. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  211. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  212. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  213. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  214. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  215. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  216. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  217. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  218. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  219. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -4
  220. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  221. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  222. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  223. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  224. data/lib/rubocop/cop/mixin/check_line_breakable.rb +22 -12
  225. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  226. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  227. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  228. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  229. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  230. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  231. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  232. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  233. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -2
  234. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  235. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  236. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  237. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  238. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  239. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  240. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -9
  241. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  242. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  243. data/lib/rubocop/cop/mixin/range_help.rb +15 -4
  244. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  245. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  246. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  247. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  248. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  249. data/lib/rubocop/cop/mixin/trailing_comma.rb +21 -5
  250. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  251. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  252. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  253. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  254. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -13
  255. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  256. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  257. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  258. data/lib/rubocop/cop/naming/variable_name.rb +50 -6
  259. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  260. data/lib/rubocop/cop/offense.rb +2 -3
  261. data/lib/rubocop/cop/registry.rb +9 -6
  262. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  263. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  264. data/lib/rubocop/cop/style/access_modifier_declarations.rb +86 -28
  265. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  266. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  267. data/lib/rubocop/cop/style/and_or.rb +1 -1
  268. data/lib/rubocop/cop/style/arguments_forwarding.rb +47 -28
  269. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  270. data/lib/rubocop/cop/style/array_intersect.rb +42 -30
  271. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  272. data/lib/rubocop/cop/style/block_delimiters.rb +43 -25
  273. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  274. data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
  275. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  276. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  277. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  278. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  279. data/lib/rubocop/cop/style/commented_keyword.rb +20 -3
  280. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  281. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  282. data/lib/rubocop/cop/style/conditional_assignment.rb +39 -27
  283. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  284. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  285. data/lib/rubocop/cop/style/documentation.rb +1 -1
  286. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  287. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  288. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  289. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  290. data/lib/rubocop/cop/style/empty_literal.rb +5 -1
  291. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  292. data/lib/rubocop/cop/style/endless_method.rb +150 -18
  293. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  294. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  295. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  296. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  297. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  298. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  299. data/lib/rubocop/cop/style/file_null.rb +89 -0
  300. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  301. data/lib/rubocop/cop/style/float_division.rb +8 -4
  302. data/lib/rubocop/cop/style/for.rb +1 -1
  303. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  304. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  305. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  306. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  307. data/lib/rubocop/cop/style/guard_clause.rb +17 -3
  308. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  309. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  310. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  311. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  312. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  313. data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
  314. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  315. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  316. data/lib/rubocop/cop/style/identical_conditional_branches.rb +25 -6
  317. data/lib/rubocop/cop/style/if_inside_else.rb +10 -14
  318. data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
  319. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -4
  320. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -9
  321. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  322. data/lib/rubocop/cop/style/inverse_methods.rb +15 -12
  323. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  324. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  325. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  326. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  327. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  328. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  329. data/lib/rubocop/cop/style/lambda.rb +1 -0
  330. data/lib/rubocop/cop/style/lambda_call.rb +10 -4
  331. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  332. data/lib/rubocop/cop/style/map_into_array.rb +11 -3
  333. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  334. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  335. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +27 -17
  336. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  337. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  338. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  339. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  340. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  341. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  342. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  343. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  344. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  345. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  346. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  347. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  348. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  349. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  350. data/lib/rubocop/cop/style/next.rb +44 -0
  351. data/lib/rubocop/cop/style/not.rb +1 -1
  352. data/lib/rubocop/cop/style/object_then.rb +15 -15
  353. data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
  354. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  355. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  356. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  357. data/lib/rubocop/cop/style/parallel_assignment.rb +9 -18
  358. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  359. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  360. data/lib/rubocop/cop/style/proc.rb +2 -2
  361. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  362. data/lib/rubocop/cop/style/raise_args.rb +15 -13
  363. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  364. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  365. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  366. data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
  367. data/lib/rubocop/cop/style/redundant_condition.rb +95 -23
  368. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  369. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  370. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  371. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  372. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  373. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  374. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  375. data/lib/rubocop/cop/style/redundant_line_continuation.rb +54 -18
  376. data/lib/rubocop/cop/style/redundant_parentheses.rb +56 -26
  377. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  378. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  379. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  380. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  381. data/lib/rubocop/cop/style/redundant_self.rb +9 -15
  382. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  383. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  384. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  385. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  386. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  387. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
  388. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  389. data/lib/rubocop/cop/style/safe_navigation.rb +32 -5
  390. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  391. data/lib/rubocop/cop/style/select_by_regexp.rb +5 -2
  392. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  393. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  394. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  395. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  396. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  397. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  398. data/lib/rubocop/cop/style/single_line_do_end_block.rb +15 -4
  399. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  400. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  401. data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -106
  402. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  403. data/lib/rubocop/cop/style/string_concatenation.rb +15 -14
  404. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  405. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  406. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  407. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  408. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  409. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  410. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  411. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +11 -2
  412. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  413. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  414. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  415. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  416. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  417. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  418. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  419. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  420. data/lib/rubocop/cop/util.rb +12 -5
  421. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  422. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  423. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  424. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  425. data/lib/rubocop/cop/variable_force/variable.rb +14 -3
  426. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  427. data/lib/rubocop/cop/variable_force.rb +5 -11
  428. data/lib/rubocop/cops_documentation_generator.rb +50 -25
  429. data/lib/rubocop/directive_comment.rb +45 -11
  430. data/lib/rubocop/ext/regexp_node.rb +0 -1
  431. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -2
  432. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  433. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  434. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  435. data/lib/rubocop/lsp/logger.rb +2 -2
  436. data/lib/rubocop/lsp/routes.rb +7 -23
  437. data/lib/rubocop/lsp/runtime.rb +18 -50
  438. data/lib/rubocop/lsp/server.rb +0 -2
  439. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  440. data/lib/rubocop/magic_comment.rb +11 -3
  441. data/lib/rubocop/options.rb +28 -12
  442. data/lib/rubocop/path_util.rb +15 -8
  443. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  444. data/lib/rubocop/plugin/load_error.rb +26 -0
  445. data/lib/rubocop/plugin/loader.rb +100 -0
  446. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  447. data/lib/rubocop/plugin.rb +46 -0
  448. data/lib/rubocop/rake_task.rb +4 -1
  449. data/lib/rubocop/result_cache.rb +13 -13
  450. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  451. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  452. data/lib/rubocop/rspec/shared_contexts.rb +38 -1
  453. data/lib/rubocop/rspec/support.rb +4 -2
  454. data/lib/rubocop/runner.rb +26 -15
  455. data/lib/rubocop/server/cache.rb +47 -11
  456. data/lib/rubocop/server/cli.rb +2 -2
  457. data/lib/rubocop/target_finder.rb +7 -2
  458. data/lib/rubocop/target_ruby.rb +17 -2
  459. data/lib/rubocop/version.rb +53 -12
  460. data/lib/rubocop.rb +32 -1
  461. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  462. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  463. metadata +78 -16
  464. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  465. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -139,12 +139,16 @@ module RuboCop
139
139
  style == :separated
140
140
  end
141
141
 
142
+ def groupable_sibling_accessor?(node, sibling)
143
+ sibling.attribute_accessor? &&
144
+ sibling.method?(node.method_name) &&
145
+ node_visibility(sibling) == node_visibility(node) &&
146
+ groupable_accessor?(sibling) && !previous_line_comment?(sibling)
147
+ end
148
+
142
149
  def groupable_sibling_accessors(send_node)
143
150
  send_node.parent.each_child_node(:send).select do |sibling|
144
- sibling.attribute_accessor? &&
145
- sibling.method?(send_node.method_name) &&
146
- node_visibility(sibling) == node_visibility(send_node) &&
147
- groupable_accessor?(sibling) && !previous_line_comment?(sibling)
151
+ groupable_sibling_accessor?(send_node, sibling)
148
152
  end
149
153
  end
150
154
 
@@ -155,13 +159,23 @@ module RuboCop
155
159
 
156
160
  def preferred_accessors(node)
157
161
  if grouped_style?
162
+ return if skip_for_grouping?(node)
163
+
158
164
  accessors = groupable_sibling_accessors(node)
159
- group_accessors(node, accessors) if node.loc == accessors.first.loc
165
+ if node.loc == accessors.first.loc || skip_for_grouping?(accessors.first)
166
+ group_accessors(node, accessors)
167
+ end
160
168
  else
161
169
  separate_accessors(node)
162
170
  end
163
171
  end
164
172
 
173
+ # Group after constants
174
+ def skip_for_grouping?(node)
175
+ node.right_siblings.any?(&:casgn_type?) &&
176
+ node.right_siblings.any? { |n| n.send_type? && groupable_sibling_accessor?(node, n) }
177
+ end
178
+
165
179
  def group_accessors(node, accessors)
166
180
  accessor_names = accessors.flat_map { |accessor| accessor.arguments.map(&:source) }.uniq
167
181
 
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Looks for endless methods inside operations of lower precedence (`and`, `or`, and
7
+ # modifier forms of `if`, `unless`, `while`, `until`) that are ambiguous due to
8
+ # lack of parentheses. This may lead to unexpected behavior as the code may appear
9
+ # to use these keywords as part of the method but in fact they modify
10
+ # the method definition itself.
11
+ #
12
+ # In these cases, using a normal method definition is more clear.
13
+ #
14
+ # @example
15
+ #
16
+ # # bad
17
+ # def foo = true if bar
18
+ #
19
+ # # good - using a non-endless method is more explicit
20
+ # def foo
21
+ # true
22
+ # end if bar
23
+ #
24
+ # # ok - method body is explicit
25
+ # def foo = (true if bar)
26
+ #
27
+ # # ok - method definition is explicit
28
+ # (def foo = true) if bar
29
+ class AmbiguousEndlessMethodDefinition < Base
30
+ extend TargetRubyVersion
31
+ extend AutoCorrector
32
+ include EndlessMethodRewriter
33
+ include RangeHelp
34
+
35
+ minimum_target_ruby_version 3.0
36
+
37
+ MSG = 'Avoid using `%<keyword>s` statements with endless methods.'
38
+
39
+ # @!method ambiguous_endless_method_body(node)
40
+ def_node_matcher :ambiguous_endless_method_body, <<~PATTERN
41
+ ^${
42
+ (if _ <def _>)
43
+ ({and or} def _)
44
+ ({while until} _ def)
45
+ }
46
+ PATTERN
47
+
48
+ def on_def(node)
49
+ return unless node.endless?
50
+
51
+ operation = ambiguous_endless_method_body(node)
52
+ return unless operation
53
+
54
+ return unless modifier_form?(operation)
55
+
56
+ add_offense(operation, message: format(MSG, keyword: keyword(operation))) do |corrector|
57
+ correct_to_multiline(corrector, node)
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def modifier_form?(operation)
64
+ return true if operation.operator_keyword?
65
+
66
+ operation.modifier_form?
67
+ end
68
+
69
+ def keyword(operation)
70
+ if operation.respond_to?(:keyword)
71
+ operation.keyword
72
+ else
73
+ operation.operator
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -127,7 +127,7 @@ module RuboCop
127
127
  end
128
128
 
129
129
  def correct_other(node, corrector)
130
- return if node.source_range.begin.is?('(')
130
+ return if node.parenthesized_call?
131
131
 
132
132
  corrector.wrap(node, '(', ')')
133
133
  end
@@ -16,21 +16,35 @@ module RuboCop
16
16
  #
17
17
  # In Ruby 3.2, anonymous args/kwargs forwarding has been added.
18
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`.
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
21
+ # disabled by setting `UseAnonymousForwarding: false`.
22
22
  #
23
23
  # And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
24
24
  # and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
25
25
  # that are sufficient for anonymizing meaningless naming.
26
26
  #
27
27
  # Meaningless names that are commonly used can be anonymized by default:
28
- # e.g., `*args`, `**options`, `&block`, and so on.
28
+ # e.g., `+*args+`, `+**options+`, `&block`, and so on.
29
29
  #
30
30
  # Names not on this list are likely to be meaningful and are allowed by default.
31
31
  #
32
32
  # This cop handles not only method forwarding but also forwarding to `super`.
33
33
  #
34
+ # [NOTE]
35
+ # ====
36
+ # Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
37
+ # no offense will be registered until Ruby 3.4:
38
+ #
39
+ # [source,ruby]
40
+ # ----
41
+ # def foo(&block)
42
+ # # Using an anonymous block would be a syntax error on Ruby 3.3.0
43
+ # block_method { bar(&block) }
44
+ # end
45
+ # ----
46
+ # ====
47
+ #
34
48
  # @example
35
49
  # # bad
36
50
  # def foo(*args, &block)
@@ -132,7 +146,7 @@ module RuboCop
132
146
  minimum_target_ruby_version 2.7
133
147
 
134
148
  FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
135
- ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
149
+ ADDITIONAL_ARG_TYPES = %i[lvar arg optarg].freeze
136
150
 
137
151
  FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
138
152
  ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
@@ -148,7 +162,7 @@ module RuboCop
148
162
 
149
163
  restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
150
164
  forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
151
- send_nodes = node.each_descendant(:send, :csend, :super, :yield).to_a
165
+ send_nodes = node.each_descendant(:call, :super, :yield).to_a
152
166
 
153
167
  send_classifications = classify_send_nodes(
154
168
  node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
@@ -191,9 +205,7 @@ module RuboCop
191
205
 
192
206
  send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
193
207
  if !forward_rest && !forward_kwrest && c != :all_anonymous
194
- # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
195
- # in Ruby 3.3.0.
196
- if outside_block?(forward_block_arg)
208
+ if allow_anonymous_forwarding_in_block?(forward_block_arg)
197
209
  register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
198
210
  register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
199
211
  end
@@ -214,24 +226,22 @@ module RuboCop
214
226
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
215
227
  def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
216
228
  return unless use_anonymous_forwarding?
217
- return if send_inside_block?(send_classifications)
229
+ return unless all_forwarding_offenses_correctable?(send_classifications)
218
230
 
219
231
  rest_arg, kwrest_arg, block_arg = *forwardable_args
220
232
 
221
233
  send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
222
- if outside_block?(forward_rest)
234
+ if allow_anonymous_forwarding_in_block?(forward_rest)
223
235
  register_forward_args_offense(def_node.arguments, rest_arg)
224
236
  register_forward_args_offense(send_node, forward_rest)
225
237
  end
226
238
 
227
- if outside_block?(forward_kwrest)
239
+ if allow_anonymous_forwarding_in_block?(forward_kwrest)
228
240
  register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
229
241
  register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
230
242
  end
231
243
 
232
- # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
233
- # in Ruby 3.3.0.
234
- if outside_block?(forward_block_arg)
244
+ if allow_anonymous_forwarding_in_block?(forward_block_arg)
235
245
  register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
236
246
  register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
237
247
  end
@@ -293,10 +303,25 @@ module RuboCop
293
303
  redundant_arg_names.include?(arg.source) ? arg : nil
294
304
  end
295
305
 
296
- def outside_block?(node)
306
+ # Checks if forwarding is uses both in blocks and outside of blocks.
307
+ # On Ruby 3.3.0, anonymous block forwarding in blocks can be is a syntax
308
+ # error, so we only want to register an offense if we can change all occurrences.
309
+ def all_forwarding_offenses_correctable?(send_classifications)
310
+ return true if target_ruby_version >= 3.4
311
+
312
+ send_classifications.none? do |send_node, *|
313
+ send_node.each_ancestor(:any_block).any?
314
+ end
315
+ end
316
+
317
+ # Ruby 3.3.0 had a bug where accessing an anonymous block argument inside of a block
318
+ # was a syntax error in unambiguous cases: https://bugs.ruby-lang.org/issues/20090
319
+ # We disallow this also for earlier Ruby versions so that code is forwards compatible.
320
+ def allow_anonymous_forwarding_in_block?(node)
297
321
  return false unless node
322
+ return true if target_ruby_version >= 3.4
298
323
 
299
- node.each_ancestor(:block, :numblock).none?
324
+ node.each_ancestor(:any_block).none?
300
325
  end
301
326
 
302
327
  def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
@@ -357,12 +382,6 @@ module RuboCop
357
382
  cop_config.fetch('UseAnonymousForwarding', false)
358
383
  end
359
384
 
360
- def send_inside_block?(send_classifications)
361
- send_classifications.any? do |send_node, *|
362
- send_node.each_ancestor(:block, :numblock).any?
363
- end
364
- end
365
-
366
385
  def add_parens_if_missing(node, corrector)
367
386
  return if parentheses?(node)
368
387
  return if node.send_type? && node.method?(:[])
@@ -460,6 +479,9 @@ module RuboCop
460
479
  end
461
480
 
462
481
  def ruby_32_only_anonymous_forwarding?
482
+ # A block argument and an anonymous block argument are never passed together.
483
+ return false if @send_node.each_ancestor(:any_block).any?
484
+
463
485
  def_all_anonymous_args?(@def_node) && send_all_anonymous_args?(@send_node)
464
486
  end
465
487
 
@@ -511,7 +533,7 @@ module RuboCop
511
533
  end
512
534
 
513
535
  def additional_kwargs?
514
- @def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
536
+ @def_node.arguments.any? { |a| a.type?(:kwarg, :kwoptarg) }
515
537
  end
516
538
 
517
539
  def forward_additional_kwargs?
@@ -540,10 +562,7 @@ module RuboCop
540
562
  end
541
563
 
542
564
  def explicit_block_name?
543
- block_forwarding_config = config.for_cop('Naming/BlockForwarding')
544
- return false unless block_forwarding_config['Enabled']
545
-
546
- block_forwarding_config['EnforcedStyle'] == 'explicit'
565
+ config.for_enabled_cop('Naming/BlockForwarding')['EnforcedStyle'] == 'explicit'
547
566
  end
548
567
  end
549
568
  end
@@ -42,14 +42,30 @@ module RuboCop
42
42
  return if node.parent && brace_method?(node.parent)
43
43
 
44
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}")
45
+ offense_range = find_offense_range(node)
46
+
47
+ add_offense(offense_range, message: format(MSG, preferred: preferred)) do |corrector|
48
+ corrector.replace(offense_range, preferred_value(node, preferred))
47
49
  end
48
50
  end
49
51
  # rubocop:enable Metrics/AbcSize
52
+ alias on_csend on_send
50
53
 
51
54
  private
52
55
 
56
+ def preferred_value(node, value)
57
+ value = ".#{value}" unless node.loc.dot
58
+ value
59
+ end
60
+
61
+ def find_offense_range(node)
62
+ if node.loc.dot
63
+ node.loc.selector.join(node.source_range.end)
64
+ else
65
+ node.loc.selector
66
+ end
67
+ end
68
+
53
69
  def innermost_braces_node(node)
54
70
  node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
55
71
  node
@@ -6,7 +6,8 @@ module RuboCop
6
6
  # In Ruby 3.1, `Array#intersect?` has been added.
7
7
  #
8
8
  # This cop identifies places where `(array1 & array2).any?`
9
- # can be replaced by `array1.intersect?(array2)`.
9
+ # or `(array1.intersection(array2)).any?` can be replaced by
10
+ # `array1.intersect?(array2)`.
10
11
  #
11
12
  # The `array1.intersect?(array2)` method is faster than
12
13
  # `(array1 & array2).any?` and is more readable.
@@ -20,6 +21,10 @@ module RuboCop
20
21
  # [1].intersect?([1,2]) { |x| false } # => true
21
22
  # ----
22
23
  #
24
+ # NOTE: Although `Array#intersection` can take zero or multiple arguments,
25
+ # only cases where exactly one argument is provided can be replaced with
26
+ # `Array#intersect?` and are handled by this cop.
27
+ #
23
28
  # @safety
24
29
  # This cop cannot guarantee that `array1` and `array2` are
25
30
  # actually arrays while method `intersect?` is for arrays only.
@@ -28,6 +33,12 @@ module RuboCop
28
33
  # # bad
29
34
  # (array1 & array2).any?
30
35
  # (array1 & array2).empty?
36
+ # (array1 & array2).none?
37
+ #
38
+ # # bad
39
+ # array1.intersection(array2).any?
40
+ # array1.intersection(array2).empty?
41
+ # array1.intersection(array2).none?
31
42
  #
32
43
  # # good
33
44
  # array1.intersect?(array2)
@@ -52,65 +63,66 @@ module RuboCop
52
63
 
53
64
  minimum_target_ruby_version 3.1
54
65
 
55
- # @!method regular_bad_intersection_check?(node)
56
- def_node_matcher :regular_bad_intersection_check?, <<~PATTERN
57
- (send
58
- (begin
59
- (send $(...) :& $(...))
60
- ) ${:any? :empty?}
61
- )
62
- PATTERN
66
+ PREDICATES = %i[any? empty? none?].to_set.freeze
67
+ ACTIVE_SUPPORT_PREDICATES = (PREDICATES + %i[present? blank?]).freeze
63
68
 
64
- # @!method active_support_bad_intersection_check?(node)
65
- def_node_matcher :active_support_bad_intersection_check?, <<~PATTERN
66
- (send
67
- (begin
68
- (send $(...) :& $(...))
69
- ) ${:present? :any? :blank? :empty?}
69
+ # @!method bad_intersection_check?(node, predicates)
70
+ def_node_matcher :bad_intersection_check?, <<~PATTERN
71
+ (call
72
+ {
73
+ (begin (send $_ :& $_))
74
+ (call $_ :intersection $_)
75
+ }
76
+ $%1
70
77
  )
71
78
  PATTERN
72
79
 
73
- MSG = 'Use `%<negated>s%<receiver>s.intersect?(%<argument>s)` ' \
74
- 'instead of `(%<receiver>s & %<argument>s).%<method_name>s`.'
80
+ MSG = 'Use `%<negated>s%<receiver>s%<dot>sintersect?(%<argument>s)` ' \
81
+ 'instead of `%<existing>s`.'
75
82
  STRAIGHT_METHODS = %i[present? any?].freeze
76
- NEGATED_METHODS = %i[blank? empty?].freeze
83
+ NEGATED_METHODS = %i[blank? empty? none?].freeze
77
84
  RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
78
85
 
79
86
  def on_send(node)
80
- return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
81
- return unless (receiver, argument, method_name = bad_intersection_check?(node))
87
+ return if node.block_literal?
88
+ return unless (receiver, argument, method_name = bad_intersection?(node))
82
89
 
83
- message = message(receiver.source, argument.source, method_name)
90
+ dot = node.loc.dot.source
91
+ message = message(receiver.source, argument.source, method_name, dot, node.source)
84
92
 
85
93
  add_offense(node, message: message) do |corrector|
86
94
  bang = straight?(method_name) ? '' : '!'
87
95
 
88
- corrector.replace(node, "#{bang}#{receiver.source}.intersect?(#{argument.source})")
96
+ corrector.replace(node, "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})")
89
97
  end
90
98
  end
99
+ alias on_csend on_send
91
100
 
92
101
  private
93
102
 
94
- def bad_intersection_check?(node)
95
- if active_support_extensions_enabled?
96
- active_support_bad_intersection_check?(node)
97
- else
98
- regular_bad_intersection_check?(node)
99
- end
103
+ def bad_intersection?(node)
104
+ predicates = if active_support_extensions_enabled?
105
+ ACTIVE_SUPPORT_PREDICATES
106
+ else
107
+ PREDICATES
108
+ end
109
+
110
+ bad_intersection_check?(node, predicates)
100
111
  end
101
112
 
102
113
  def straight?(method_name)
103
114
  STRAIGHT_METHODS.include?(method_name.to_sym)
104
115
  end
105
116
 
106
- def message(receiver, argument, method_name)
117
+ def message(receiver, argument, method_name, dot, existing)
107
118
  negated = straight?(method_name) ? '' : '!'
108
119
  format(
109
120
  MSG,
110
121
  negated: negated,
111
122
  receiver: receiver,
112
123
  argument: argument,
113
- method_name: method_name
124
+ dot: dot,
125
+ existing: existing
114
126
  )
115
127
  end
116
128
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Prefer bitwise predicate methods over direct comparison operations.
7
+ #
8
+ # @safety
9
+ # This cop is unsafe, as it can produce false positives if the receiver
10
+ # is not an `Integer` object.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad - checks any set bits
15
+ # (variable & flags).positive?
16
+ #
17
+ # # good
18
+ # variable.anybits?(flags)
19
+ #
20
+ # # bad - checks all set bits
21
+ # (variable & flags) == flags
22
+ #
23
+ # # good
24
+ # variable.allbits?(flags)
25
+ #
26
+ # # bad - checks no set bits
27
+ # (variable & flags).zero?
28
+ #
29
+ # # good
30
+ # variable.nobits?(flags)
31
+ #
32
+ class BitwisePredicate < Base
33
+ extend AutoCorrector
34
+ extend TargetRubyVersion
35
+
36
+ MSG = 'Replace with `%<preferred>s` for comparison with bit flags.'
37
+ RESTRICT_ON_SEND = %i[!= == > >= positive? zero?].freeze
38
+
39
+ minimum_target_ruby_version 2.5
40
+
41
+ # @!method anybits?(node)
42
+ def_node_matcher :anybits?, <<~PATTERN
43
+ {
44
+ (send #bit_operation? :positive?)
45
+ (send #bit_operation? :> (int 0))
46
+ (send #bit_operation? :>= (int 1))
47
+ (send #bit_operation? :!= (int 0))
48
+ }
49
+ PATTERN
50
+
51
+ # @!method allbits?(node)
52
+ def_node_matcher :allbits?, <<~PATTERN
53
+ {
54
+ (send (begin (send _ :& _flags)) :== _flags)
55
+ (send (begin (send _flags :& _)) :== _flags)
56
+ }
57
+ PATTERN
58
+
59
+ # @!method nobits?(node)
60
+ def_node_matcher :nobits?, <<~PATTERN
61
+ {
62
+ (send #bit_operation? :zero?)
63
+ (send #bit_operation? :== (int 0))
64
+ }
65
+ PATTERN
66
+
67
+ # @!method bit_operation?(node)
68
+ def_node_matcher :bit_operation?, <<~PATTERN
69
+ (begin
70
+ (send _ :& _))
71
+ PATTERN
72
+
73
+ def on_send(node)
74
+ return unless node.receiver&.begin_type?
75
+ return unless (preferred_method = preferred_method(node))
76
+
77
+ bit_operation = node.receiver.children.first
78
+ lhs, _operator, rhs = *bit_operation
79
+ preferred = "#{lhs.source}.#{preferred_method}(#{rhs.source})"
80
+
81
+ add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
82
+ corrector.replace(node, preferred)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def preferred_method(node)
89
+ if anybits?(node)
90
+ 'anybits?'
91
+ elsif allbits?(node)
92
+ 'allbits?'
93
+ elsif nobits?(node)
94
+ 'nobits?'
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end