rubocop 1.81.7 → 1.92.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 (621) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +626 -111
  5. data/config/obsoletion.yml +39 -1
  6. data/exe/rubocop +1 -1
  7. data/lib/rubocop/cache_config.rb +29 -0
  8. data/lib/rubocop/cached_data.rb +50 -5
  9. data/lib/rubocop/changed_files.rb +134 -0
  10. data/lib/rubocop/cli/command/auto_generate_config.rb +34 -2
  11. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  12. data/lib/rubocop/cli/command/execute_runner.rb +54 -3
  13. data/lib/rubocop/cli/command/explain.rb +34 -0
  14. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  15. data/lib/rubocop/cli/command/lsp.rb +1 -1
  16. data/lib/rubocop/cli/command/mcp.rb +19 -0
  17. data/lib/rubocop/cli/command/show_cops.rb +8 -2
  18. data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
  19. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  20. data/lib/rubocop/cli.rb +41 -14
  21. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  22. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  23. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  24. data/lib/rubocop/comment_config.rb +97 -44
  25. data/lib/rubocop/config.rb +100 -15
  26. data/lib/rubocop/config_finder.rb +1 -1
  27. data/lib/rubocop/config_loader.rb +49 -27
  28. data/lib/rubocop/config_loader_resolver.rb +95 -20
  29. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  30. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  31. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  32. data/lib/rubocop/config_obsoletion.rb +1 -1
  33. data/lib/rubocop/config_store.rb +2 -2
  34. data/lib/rubocop/config_validator.rb +69 -7
  35. data/lib/rubocop/cop/autocorrect_logic.rb +24 -6
  36. data/lib/rubocop/cop/badge.rb +10 -2
  37. data/lib/rubocop/cop/base.rb +128 -35
  38. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
  39. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  40. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -10
  41. data/lib/rubocop/cop/bundler.rb +19 -0
  42. data/lib/rubocop/cop/commissioner.rb +13 -11
  43. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  44. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  45. data/lib/rubocop/cop/corrector.rb +4 -4
  46. data/lib/rubocop/cop/correctors/alignment_corrector.rb +87 -9
  47. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  48. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
  49. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  50. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +31 -4
  51. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +35 -5
  52. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  53. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +70 -2
  54. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  55. data/lib/rubocop/cop/correctors.rb +28 -0
  56. data/lib/rubocop/cop/documentation.rb +3 -4
  57. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  58. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  59. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  60. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +14 -4
  61. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -8
  62. data/lib/rubocop/cop/gemspec/require_mfa.rb +9 -6
  63. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  64. data/lib/rubocop/cop/gemspec.rb +22 -0
  65. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  66. data/lib/rubocop/cop/generator.rb +5 -1
  67. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  68. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  69. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  70. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  71. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +12 -16
  72. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  73. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  74. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  75. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  76. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  77. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  78. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  79. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  80. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  81. data/lib/rubocop/cop/layout/argument_alignment.rb +9 -3
  82. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  83. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  84. data/lib/rubocop/cop/layout/block_alignment.rb +84 -4
  85. data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
  86. data/lib/rubocop/cop/layout/class_structure.rb +156 -41
  87. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  88. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  89. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  90. data/lib/rubocop/cop/layout/dot_position.rb +26 -16
  91. data/lib/rubocop/cop/layout/else_alignment.rb +2 -14
  92. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  93. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +25 -7
  94. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  95. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
  96. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +15 -2
  97. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  98. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
  99. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
  100. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +21 -5
  101. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  102. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  103. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  104. data/lib/rubocop/cop/layout/end_alignment.rb +23 -15
  105. data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
  106. data/lib/rubocop/cop/layout/first_argument_indentation.rb +81 -2
  107. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  108. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +41 -0
  109. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +36 -23
  110. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  111. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  112. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  113. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  114. data/lib/rubocop/cop/layout/hash_alignment.rb +16 -11
  115. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -4
  116. data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
  117. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  118. data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
  119. data/lib/rubocop/cop/layout/indentation_width.rb +158 -12
  120. data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
  121. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
  122. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  123. data/lib/rubocop/cop/layout/line_length.rb +265 -29
  124. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
  125. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  126. data/lib/rubocop/cop/layout/multiline_block_layout.rb +10 -1
  127. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +65 -56
  128. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
  129. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +268 -38
  130. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  131. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  132. data/lib/rubocop/cop/layout/redundant_line_break.rb +102 -2
  133. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +19 -5
  134. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  135. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  136. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  137. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  138. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  139. data/lib/rubocop/cop/layout/space_around_keyword.rb +14 -2
  140. data/lib/rubocop/cop/layout/space_around_operators.rb +18 -3
  141. data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
  142. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  143. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  144. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +44 -34
  145. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
  146. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  147. data/lib/rubocop/cop/layout.rb +114 -0
  148. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  149. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  150. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  151. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  152. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
  153. data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
  154. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  155. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  156. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  157. data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
  158. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  159. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  160. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  161. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
  162. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  163. data/lib/rubocop/cop/lint/debugger.rb +13 -2
  164. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  165. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  166. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  167. data/lib/rubocop/cop/lint/duplicate_methods.rb +405 -28
  168. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  169. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  170. data/lib/rubocop/cop/lint/empty_conditional_body.rb +9 -2
  171. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  172. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  173. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  174. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -2
  175. data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
  176. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  177. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  178. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  179. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  180. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  181. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  182. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  183. data/lib/rubocop/cop/lint/literal_as_condition.rb +36 -9
  184. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  185. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
  186. data/lib/rubocop/cop/lint/loop.rb +24 -2
  187. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  188. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +46 -18
  189. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  190. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  191. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  192. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  193. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  194. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  195. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  196. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  197. data/lib/rubocop/cop/lint/number_conversion.rb +22 -11
  198. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  199. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +10 -0
  200. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  201. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  202. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  203. data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
  204. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  205. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
  206. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  207. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
  208. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -4
  209. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +37 -14
  210. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  211. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +11 -5
  212. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -3
  213. data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
  214. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  215. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  216. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  217. data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
  218. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  219. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  220. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +24 -0
  221. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +56 -6
  222. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  223. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  224. data/lib/rubocop/cop/lint/self_assignment.rb +33 -2
  225. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  226. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  227. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
  228. data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
  229. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  230. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  231. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +13 -2
  232. data/lib/rubocop/cop/lint/symbol_conversion.rb +22 -4
  233. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  234. data/lib/rubocop/cop/lint/to_enum_arguments.rb +72 -4
  235. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  236. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  237. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  238. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
  239. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  240. data/lib/rubocop/cop/lint/unreachable_code.rb +15 -9
  241. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  242. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  243. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  244. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
  245. data/lib/rubocop/cop/lint/useless_assignment.rb +61 -27
  246. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +40 -4
  247. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  248. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  249. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
  250. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  251. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
  252. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +10 -4
  253. data/lib/rubocop/cop/lint/useless_setter_call.rb +11 -5
  254. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  255. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +94 -14
  256. data/lib/rubocop/cop/lint/void.rb +59 -22
  257. data/lib/rubocop/cop/lint.rb +179 -0
  258. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  259. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  260. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  261. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  262. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  263. data/lib/rubocop/cop/metrics/method_length.rb +2 -2
  264. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  265. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  266. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  267. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  268. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  269. data/lib/rubocop/cop/metrics.rb +31 -0
  270. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  271. data/lib/rubocop/cop/migration.rb +13 -0
  272. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  273. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  274. data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
  275. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  276. data/lib/rubocop/cop/mixin/check_line_breakable.rb +47 -25
  277. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +12 -8
  278. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  279. data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
  280. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  281. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  282. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  283. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
  284. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  285. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  286. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
  287. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +58 -12
  288. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +37 -10
  289. data/lib/rubocop/cop/mixin/hash_subset.rb +9 -2
  290. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  291. data/lib/rubocop/cop/mixin/hash_transform_method.rb +14 -60
  292. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  293. data/lib/rubocop/cop/mixin/line_length_help.rb +28 -3
  294. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  295. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  296. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  297. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  298. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
  299. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  300. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  301. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
  302. data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
  303. data/lib/rubocop/cop/mixin/range_help.rb +1 -2
  304. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
  305. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  306. data/lib/rubocop/cop/mixin/statement_modifier.rb +69 -12
  307. data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -6
  308. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  309. data/lib/rubocop/cop/mixin.rb +93 -0
  310. data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
  311. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  312. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  313. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  314. data/lib/rubocop/cop/naming/file_name.rb +4 -3
  315. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  316. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  317. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  318. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -5
  319. data/lib/rubocop/cop/naming/method_name.rb +6 -3
  320. data/lib/rubocop/cop/naming/predicate_method.rb +13 -2
  321. data/lib/rubocop/cop/naming/predicate_prefix.rb +30 -17
  322. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -7
  323. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  324. data/lib/rubocop/cop/naming.rb +31 -0
  325. data/lib/rubocop/cop/offense.rb +108 -9
  326. data/lib/rubocop/cop/registry.rb +232 -66
  327. data/lib/rubocop/cop/security/eval.rb +15 -2
  328. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  329. data/lib/rubocop/cop/security/json_load.rb +16 -4
  330. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  331. data/lib/rubocop/cop/security.rb +19 -0
  332. data/lib/rubocop/cop/severity.rb +12 -0
  333. data/lib/rubocop/cop/style/access_modifier_declarations.rb +55 -8
  334. data/lib/rubocop/cop/style/accessor_grouping.rb +16 -5
  335. data/lib/rubocop/cop/style/alias.rb +33 -8
  336. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  337. data/lib/rubocop/cop/style/and_or.rb +8 -3
  338. data/lib/rubocop/cop/style/arguments_forwarding.rb +61 -17
  339. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  340. data/lib/rubocop/cop/style/array_intersect.rb +28 -5
  341. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +3 -0
  342. data/lib/rubocop/cop/style/array_join.rb +4 -2
  343. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  344. data/lib/rubocop/cop/style/attr.rb +8 -6
  345. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  346. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  347. data/lib/rubocop/cop/style/bitwise_predicate.rb +7 -6
  348. data/lib/rubocop/cop/style/block_delimiters.rb +74 -38
  349. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  350. data/lib/rubocop/cop/style/case_like_if.rb +11 -10
  351. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  352. data/lib/rubocop/cop/style/class_and_module_children.rb +151 -35
  353. data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
  354. data/lib/rubocop/cop/style/class_methods_definitions.rb +26 -5
  355. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  356. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  357. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  358. data/lib/rubocop/cop/style/combinable_loops.rb +91 -9
  359. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  360. data/lib/rubocop/cop/style/concat_array_literals.rb +65 -9
  361. data/lib/rubocop/cop/style/conditional_assignment.rb +34 -18
  362. data/lib/rubocop/cop/style/constant_visibility.rb +13 -7
  363. data/lib/rubocop/cop/style/copyright.rb +27 -12
  364. data/lib/rubocop/cop/style/data_inheritance.rb +18 -0
  365. data/lib/rubocop/cop/style/date_time.rb +4 -4
  366. data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
  367. data/lib/rubocop/cop/style/dig_chain.rb +5 -0
  368. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  369. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  370. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
  371. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  372. data/lib/rubocop/cop/style/documentation.rb +53 -6
  373. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  374. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  375. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  376. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  377. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  378. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  379. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  380. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  381. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  382. data/lib/rubocop/cop/style/empty_literal.rb +8 -3
  383. data/lib/rubocop/cop/style/empty_method.rb +15 -9
  384. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +74 -22
  385. data/lib/rubocop/cop/style/encoding.rb +7 -1
  386. data/lib/rubocop/cop/style/end_block.rb +3 -1
  387. data/lib/rubocop/cop/style/endless_method.rb +100 -21
  388. data/lib/rubocop/cop/style/env_home.rb +4 -0
  389. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  390. data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
  391. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  392. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  393. data/lib/rubocop/cop/style/file_null.rb +6 -4
  394. data/lib/rubocop/cop/style/file_open.rb +84 -0
  395. data/lib/rubocop/cop/style/file_write.rb +21 -16
  396. data/lib/rubocop/cop/style/float_division.rb +28 -14
  397. data/lib/rubocop/cop/style/for.rb +60 -1
  398. data/lib/rubocop/cop/style/format_string.rb +44 -9
  399. data/lib/rubocop/cop/style/format_string_token.rb +50 -7
  400. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  401. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  402. data/lib/rubocop/cop/style/guard_clause.rb +57 -40
  403. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +31 -9
  404. data/lib/rubocop/cop/style/hash_conversion.rb +39 -11
  405. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
  406. data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
  407. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  408. data/lib/rubocop/cop/style/hash_syntax.rb +19 -5
  409. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  410. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  411. data/lib/rubocop/cop/style/identical_conditional_branches.rb +38 -10
  412. data/lib/rubocop/cop/style/if_inside_else.rb +36 -8
  413. data/lib/rubocop/cop/style/if_unless_modifier.rb +80 -76
  414. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +17 -14
  415. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  416. data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
  417. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  418. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  419. data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
  420. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  421. data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
  422. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  423. data/lib/rubocop/cop/style/keyword_parameters_order.rb +10 -4
  424. data/lib/rubocop/cop/style/lambda.rb +45 -2
  425. data/lib/rubocop/cop/style/lambda_call.rb +24 -8
  426. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  427. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  428. data/lib/rubocop/cop/style/map_into_array.rb +2 -3
  429. data/lib/rubocop/cop/style/map_join.rb +123 -0
  430. data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
  431. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +102 -20
  432. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  433. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +42 -6
  434. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
  435. data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
  436. data/lib/rubocop/cop/style/min_max_comparison.rb +4 -1
  437. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  438. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  439. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  440. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  441. data/lib/rubocop/cop/style/module_function.rb +4 -2
  442. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  443. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  444. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  445. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  446. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  447. data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -13
  448. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  449. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  450. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  451. data/lib/rubocop/cop/style/mutable_constant.rb +158 -14
  452. data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
  453. data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
  454. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  455. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  456. data/lib/rubocop/cop/style/next.rb +24 -10
  457. data/lib/rubocop/cop/style/nil_comparison.rb +50 -12
  458. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  459. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  460. data/lib/rubocop/cop/style/not.rb +12 -3
  461. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  462. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  463. data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
  464. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  465. data/lib/rubocop/cop/style/one_line_conditional.rb +18 -6
  466. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  467. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  468. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  469. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  470. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -7
  471. data/lib/rubocop/cop/style/parentheses_around_condition.rb +7 -2
  472. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  473. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
  474. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  475. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  476. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  477. data/lib/rubocop/cop/style/proc.rb +3 -2
  478. data/lib/rubocop/cop/style/raise_args.rb +20 -10
  479. data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
  480. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  481. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  482. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  483. data/lib/rubocop/cop/style/redundant_begin.rb +25 -7
  484. data/lib/rubocop/cop/style/redundant_condition.rb +41 -23
  485. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  486. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
  487. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
  488. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  489. data/lib/rubocop/cop/style/redundant_exception.rb +21 -3
  490. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
  491. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  492. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  493. data/lib/rubocop/cop/style/redundant_format.rb +43 -7
  494. data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
  495. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  496. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +49 -10
  497. data/lib/rubocop/cop/style/redundant_line_continuation.rb +82 -115
  498. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  499. data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -83
  500. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  501. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +13 -2
  502. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  503. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
  504. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -4
  505. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  506. data/lib/rubocop/cop/style/redundant_self.rb +11 -2
  507. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
  508. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +27 -4
  509. data/lib/rubocop/cop/style/redundant_sort.rb +45 -11
  510. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  511. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  512. data/lib/rubocop/cop/style/regexp_literal.rb +106 -28
  513. data/lib/rubocop/cop/style/require_order.rb +25 -8
  514. data/lib/rubocop/cop/style/rescue_modifier.rb +15 -14
  515. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  516. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  517. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  518. data/lib/rubocop/cop/style/safe_navigation.rb +18 -9
  519. data/lib/rubocop/cop/style/sample.rb +19 -13
  520. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  521. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  522. data/lib/rubocop/cop/style/select_by_regexp.rb +52 -23
  523. data/lib/rubocop/cop/style/self_assignment.rb +13 -16
  524. data/lib/rubocop/cop/style/semicolon.rb +39 -13
  525. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  526. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  527. data/lib/rubocop/cop/style/single_line_do_end_block.rb +19 -7
  528. data/lib/rubocop/cop/style/single_line_methods.rb +24 -5
  529. data/lib/rubocop/cop/style/sole_nested_conditional.rb +25 -7
  530. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  531. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +31 -5
  532. data/lib/rubocop/cop/style/static_class.rb +21 -0
  533. data/lib/rubocop/cop/style/string_concatenation.rb +25 -6
  534. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  535. data/lib/rubocop/cop/style/struct_inheritance.rb +36 -1
  536. data/lib/rubocop/cop/style/super_arguments.rb +6 -4
  537. data/lib/rubocop/cop/style/symbol_proc.rb +32 -14
  538. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  539. data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
  540. data/lib/rubocop/cop/style/time_now.rb +41 -0
  541. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  542. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  543. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  544. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
  545. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  546. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  547. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  548. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  549. data/lib/rubocop/cop/style/word_array.rb +1 -0
  550. data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
  551. data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
  552. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  553. data/lib/rubocop/cop/style.rb +311 -0
  554. data/lib/rubocop/cop/team.rb +171 -48
  555. data/lib/rubocop/cop/util.rb +5 -8
  556. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  557. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  558. data/lib/rubocop/cop/variable_force/variable.rb +33 -9
  559. data/lib/rubocop/cops_documentation_generator.rb +27 -9
  560. data/lib/rubocop/directive_comment.rb +116 -7
  561. data/lib/rubocop/feature_loader.rb +0 -6
  562. data/lib/rubocop/file_patterns.rb +9 -1
  563. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  564. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  565. data/lib/rubocop/formatter/disabled_config_formatter.rb +39 -10
  566. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  567. data/lib/rubocop/formatter/formatter_set.rb +7 -2
  568. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  569. data/lib/rubocop/formatter/html_formatter.rb +2 -4
  570. data/lib/rubocop/formatter/json_formatter.rb +82 -7
  571. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  572. data/lib/rubocop/formatter/offense_count_formatter.rb +4 -3
  573. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  574. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  575. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  576. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  577. data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
  578. data/lib/rubocop/formatter.rb +23 -21
  579. data/lib/rubocop/lockfile.rb +18 -0
  580. data/lib/rubocop/lsp/diagnostic.rb +22 -42
  581. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  582. data/lib/rubocop/lsp/routes.rb +130 -83
  583. data/lib/rubocop/lsp/runtime.rb +64 -15
  584. data/lib/rubocop/lsp/server.rb +6 -2
  585. data/lib/rubocop/lsp/stdin_runner.rb +35 -2
  586. data/lib/rubocop/lsp.rb +5 -2
  587. data/lib/rubocop/magic_comment.rb +47 -0
  588. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  589. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  590. data/lib/rubocop/mcp/scope.rb +65 -0
  591. data/lib/rubocop/mcp/server.rb +307 -0
  592. data/lib/rubocop/mcp/source_files.rb +35 -0
  593. data/lib/rubocop/offense_limit.rb +30 -0
  594. data/lib/rubocop/options.rb +141 -13
  595. data/lib/rubocop/path_util.rb +16 -5
  596. data/lib/rubocop/pending_cops_reporter.rb +1 -6
  597. data/lib/rubocop/plugin/configuration_integrator.rb +13 -3
  598. data/lib/rubocop/plugin/loader.rb +2 -2
  599. data/lib/rubocop/project_index_loader.rb +82 -0
  600. data/lib/rubocop/rake_task.rb +2 -3
  601. data/lib/rubocop/remote_config.rb +18 -13
  602. data/lib/rubocop/result_cache.rb +102 -59
  603. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  604. data/lib/rubocop/rspec/expect_offense.rb +2 -4
  605. data/lib/rubocop/rspec/shared_contexts.rb +53 -5
  606. data/lib/rubocop/rspec/support.rb +2 -1
  607. data/lib/rubocop/runner.rb +362 -106
  608. data/lib/rubocop/server/cache.rb +21 -40
  609. data/lib/rubocop/server/cli.rb +2 -4
  610. data/lib/rubocop/server/core.rb +8 -0
  611. data/lib/rubocop/server.rb +14 -0
  612. data/lib/rubocop/target_finder.rb +18 -8
  613. data/lib/rubocop/target_ruby.rb +42 -22
  614. data/lib/rubocop/todo_audit.rb +111 -0
  615. data/lib/rubocop/unified_diff.rb +257 -0
  616. data/lib/rubocop/util.rb +69 -0
  617. data/lib/rubocop/version.rb +23 -7
  618. data/lib/rubocop.rb +34 -701
  619. data/lib/ruby_lsp/rubocop/addon.rb +1 -2
  620. metadata +80 -14
  621. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -132,10 +132,11 @@ module RuboCop
132
132
  # private alias_method :qux, :foo
133
133
  #
134
134
  # end
135
- class AccessModifierDeclarations < Base
135
+ class AccessModifierDeclarations < Base # rubocop:disable Metrics/ClassLength
136
136
  extend AutoCorrector
137
137
 
138
138
  include ConfigurableEnforcedStyle
139
+ include EndlessMethodBodyHelp
139
140
  include RangeHelp
140
141
 
141
142
  GROUP_STYLE_MESSAGE = [
@@ -169,6 +170,10 @@ module RuboCop
169
170
  (send nil? :alias_method _ _))
170
171
  PATTERN
171
172
 
173
+ def self.autocorrect_incompatible_with
174
+ [Style::EndlessMethod, Style::SingleLineMethods]
175
+ end
176
+
172
177
  def on_send(node)
173
178
  return if allowed?(node)
174
179
 
@@ -187,11 +192,18 @@ module RuboCop
187
192
  def allowed?(node)
188
193
  !node.access_modifier? ||
189
194
  node.parent&.type?(:pair, :any_block) ||
195
+ dynamic_method_list?(node) ||
190
196
  allow_modifiers_on_symbols?(node) ||
191
197
  allow_modifiers_on_attrs?(node) ||
192
198
  allow_modifiers_on_alias_method?(node)
193
199
  end
194
200
 
201
+ # `private(*names)` with a list computed at runtime names no definition
202
+ # the modifier could be grouped with.
203
+ def dynamic_method_list?(node)
204
+ node.arguments.any?(&:splat_type?) && !access_modifier_with_symbol?(node)
205
+ end
206
+
195
207
  def autocorrect(corrector, node)
196
208
  case style
197
209
  when :group
@@ -241,10 +253,33 @@ module RuboCop
241
253
 
242
254
  access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node)
243
255
  else
244
- access_modifier_is_not_inlined?(node) && select_grouped_def_nodes(node).any?
256
+ access_modifier_is_not_inlined?(node) && inlinable?(select_grouped_def_nodes(node))
245
257
  end
246
258
  end
247
259
 
260
+ def inlinable?(def_nodes)
261
+ return false if def_nodes.empty?
262
+
263
+ def_nodes.none? { |def_node| def_node.endless? && body_unsafe_to_inline?(def_node.body) }
264
+ end
265
+
266
+ def body_unsafe_to_inline?(body)
267
+ return true if body.each_node(:any_block).any? { |block| do_end_block?(block) }
268
+
269
+ target_ruby_version < 4.0 && command_body?(body)
270
+ end
271
+
272
+ def do_end_block?(block)
273
+ block.keywords? && !block.send_node.lambda_literal?
274
+ end
275
+
276
+ def command_body?(body)
277
+ body = body.body while body.rescue_type?
278
+ return true if body.send_type? && body.prefix_not? && !body.parenthesized?
279
+
280
+ command_call?(body)
281
+ end
282
+
248
283
  def correctable_group_offense?(node)
249
284
  return false unless group_style?
250
285
  return false if allowed?(node)
@@ -316,7 +351,7 @@ module RuboCop
316
351
  end
317
352
 
318
353
  def select_grouped_def_nodes(node)
319
- node.right_siblings.take_while do |sibling|
354
+ node.right_siblings.compact.take_while do |sibling|
320
355
  !(sibling.send_type? && sibling.bare_access_modifier_declaration?)
321
356
  end.select(&:def_type?)
322
357
  end
@@ -326,8 +361,7 @@ module RuboCop
326
361
  argument_less_modifier_node = find_argument_less_modifier_node(node)
327
362
  if argument_less_modifier_node
328
363
  corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
329
- elsif (ancestor = node.each_ancestor(:class, :module).first)
330
-
364
+ elsif (ancestor = node.each_ancestor(:class, :module, :sclass).first)
331
365
  corrector.insert_before(ancestor.loc.end, "#{node.method_name}\n\n#{source}\n")
332
366
  else
333
367
  corrector.replace(node, "#{node.method_name}\n\n#{source}")
@@ -348,9 +382,22 @@ module RuboCop
348
382
  end
349
383
 
350
384
  def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
351
- def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
352
- range = modifier_node.source_range.begin.join(def_node.source_range.begin)
353
- corrector.remove(range)
385
+ modifier_index = begin_node.children.find_index { |child| child.equal?(modifier_node) }
386
+ def_node = begin_node.children[modifier_index + 1]
387
+ # Stop the removal range at the first comment that precedes the def, if
388
+ # any exist. Without this, comments between the modifier and the def are
389
+ # dropped because they fall inside the removed range.
390
+ end_pos = first_comment_or_node_start(def_node)
391
+ corrector.remove(modifier_node.source_range.begin.join(end_pos))
392
+ end
393
+
394
+ def first_comment_or_node_start(node)
395
+ preceding = processed_source.ast_with_comments[node].select do |comment|
396
+ comment.loc.line < node.loc.line
397
+ end
398
+ return node.source_range.begin if preceding.empty?
399
+
400
+ preceding.first.source_range.begin
354
401
  end
355
402
 
356
403
  def def_source(node, def_nodes)
@@ -4,8 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for grouping of accessors in `class` and `module` bodies.
7
- # By default it enforces accessors to be placed in grouped declarations,
8
- # but it can be configured to enforce separating them in multiple declarations.
7
+ # By default it enforces accessors to be placed in grouped
8
+ # declarations, reducing boilerplate. It can also be configured
9
+ # to enforce separating them into individual declarations for
10
+ # easier diffing and per-attribute documentation.
9
11
  #
10
12
  # NOTE: If there is a method call before the accessor method it is always allowed
11
13
  # as it might be intended like Sorbet.
@@ -98,7 +100,7 @@ module RuboCop
98
100
  comment_line?(processed_source[node.first_line - 2])
99
101
  end
100
102
 
101
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
103
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
102
104
  def groupable_accessor?(node)
103
105
  return true unless (previous_expression = node.left_siblings.last)
104
106
 
@@ -120,7 +122,6 @@ module RuboCop
120
122
  previous_expression.access_modifier? ||
121
123
  node.first_line - previous_expression.last_line > 1 # there is a space between nodes
122
124
  end
123
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
124
125
 
125
126
  def class_send_elements(class_node)
126
127
  class_def = class_node.body
@@ -201,13 +202,23 @@ module RuboCop
201
202
  end
202
203
 
203
204
  def range_with_trailing_argument_comment(node)
204
- comment = processed_source.ast_with_comments[node.last_argument].last
205
+ comment = trailing_argument_comment(node)
205
206
  if comment
206
207
  add_range(node.source_range, comment.source_range)
207
208
  else
208
209
  node
209
210
  end
210
211
  end
212
+
213
+ # For a single-line declaration the parser associates the trailing
214
+ # comment with the first argument, not `last_argument`, so look through
215
+ # all arguments for a comment that trails the whole node.
216
+ def trailing_argument_comment(node)
217
+ comments = node.arguments.filter_map do |argument|
218
+ processed_source.ast_with_comments[argument].last
219
+ end
220
+ comments.find { |comment| comment.source_range.begin_pos >= node.source_range.end_pos }
221
+ end
211
222
  end
212
223
  end
213
224
  end
@@ -4,10 +4,13 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Enforces the use of either `#alias` or `#alias_method`
7
- # depending on configuration.
7
+ # depending on configuration. Consistent use of one or the
8
+ # other prevents confusion about their different semantics
9
+ # (e.g., `alias` is resolved at parse time, while `alias_method`
10
+ # is resolved at runtime).
8
11
  # It also flags uses of `alias :symbol` rather than `alias bareword`.
9
12
  #
10
- # However, it will always enforce `method_alias` when used `alias`
13
+ # However, it will always enforce `alias_method` when `alias` is used
11
14
  # in an instance method definition and in a singleton method definition.
12
15
  # If used in a block, always enforce `alias_method`
13
16
  # unless it is an `instance_eval` block.
@@ -42,6 +45,7 @@ module RuboCop
42
45
  return unless node.command?(:alias_method)
43
46
  return unless style == :prefer_alias && alias_keyword_possible?(node)
44
47
  return unless node.arguments.count == 2
48
+ return if alias_method_value_used?(node)
45
49
 
46
50
  msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
47
51
  add_offense(node.loc.selector, message: msg) do |corrector|
@@ -56,7 +60,7 @@ module RuboCop
56
60
  add_offense(node.loc.keyword, message: MSG_ALIAS) do |corrector|
57
61
  autocorrect(corrector, node)
58
62
  end
59
- elsif node.children.none? { |arg| bareword?(arg) }
63
+ elsif node.children.all? { |arg| !bareword?(arg) && bareword_symbol?(arg) }
60
64
  add_offense_for_args(node) { |corrector| autocorrect(corrector, node) }
61
65
  end
62
66
  end
@@ -77,6 +81,14 @@ module RuboCop
77
81
  scope_type(node) != :dynamic && node.arguments.all?(&:sym_type?)
78
82
  end
79
83
 
84
+ # `alias_method` is a method call whose return value can be used
85
+ # (e.g., as an argument to `public`/`module_function`, or as an assignment),
86
+ # but `alias` is a keyword statement that cannot appear in such positions.
87
+ # Detect these positions so the conversion does not produce a syntax error.
88
+ def alias_method_value_used?(node)
89
+ node.argument? || node.parent&.assignment?
90
+ end
91
+
80
92
  def alias_method_possible?(node)
81
93
  scope_type(node) != :instance_eval &&
82
94
  node.children.none?(&:gvar_type?) &&
@@ -85,7 +97,7 @@ module RuboCop
85
97
 
86
98
  def add_offense_for_args(node, &block)
87
99
  existing_args = node.children.map(&:source).join(' ')
88
- preferred_args = node.children.map { |a| a.source[1..] }.join(' ')
100
+ preferred_args = node.children.map { |node| bareword_for(node) }.join(' ')
89
101
  arg_ranges = node.children.map(&:source_range)
90
102
  msg = format(MSG_SYMBOL_ARGS, prefer: preferred_args, current: existing_args)
91
103
  add_offense(arg_ranges.reduce(&:join), message: msg, &block)
@@ -101,7 +113,7 @@ module RuboCop
101
113
  return :lexical
102
114
  when :def, :defs
103
115
  return :dynamic
104
- when :block
116
+ when :block, :numblock, :itblock
105
117
  return :instance_eval if parent.method?(:instance_eval)
106
118
 
107
119
  return :dynamic
@@ -126,6 +138,15 @@ module RuboCop
126
138
  !sym_node.source.start_with?(':') || sym_node.dsym_type?
127
139
  end
128
140
 
141
+ def bareword_symbol?(sym_node)
142
+ return false unless sym_node.sym_type?
143
+
144
+ value = sym_node.value.to_s
145
+ return true if value.match?(/\A[A-Za-z_]\w*[?!=]?\z/)
146
+
147
+ !sym_node.source.start_with?(':"', ":'") && !value.start_with?('@', '$')
148
+ end
149
+
129
150
  def correct_alias_method_to_alias(corrector, send_node)
130
151
  new, old = *send_node.arguments
131
152
  replacement = "alias #{identifier(new)} #{identifier(old)}"
@@ -141,17 +162,21 @@ module RuboCop
141
162
  end
142
163
 
143
164
  def correct_alias_with_symbol_args(corrector, node)
144
- corrector.replace(node.new_identifier, node.new_identifier.source[1..])
145
- corrector.replace(node.old_identifier, node.old_identifier.source[1..])
165
+ corrector.replace(node.new_identifier, bareword_for(node.new_identifier))
166
+ corrector.replace(node.old_identifier, bareword_for(node.old_identifier))
146
167
  end
147
168
 
148
169
  def identifier(node)
149
- if node.sym_type?
170
+ if bareword_symbol?(node)
150
171
  ":#{node.children.first}"
151
172
  else
152
173
  node.source
153
174
  end
154
175
  end
176
+
177
+ def bareword_for(sym_node)
178
+ sym_node.value.to_s
179
+ end
155
180
  end
156
181
  end
157
182
  end
@@ -39,9 +39,9 @@ module RuboCop
39
39
  # @!method ambiguous_endless_method_body(node)
40
40
  def_node_matcher :ambiguous_endless_method_body, <<~PATTERN
41
41
  ^${
42
- (if _ <def _>)
43
- ({and or} def _)
44
- ({while until} _ def)
42
+ (if _ <any_def _>)
43
+ ({and or} any_def _)
44
+ ({while until} _ any_def)
45
45
  }
46
46
  PATTERN
47
47
 
@@ -57,6 +57,7 @@ module RuboCop
57
57
  correct_to_multiline(corrector, node)
58
58
  end
59
59
  end
60
+ alias on_defs on_def
60
61
 
61
62
  private
62
63
 
@@ -48,6 +48,10 @@ module RuboCop
48
48
 
49
49
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
50
50
 
51
+ def self.autocorrect_incompatible_with
52
+ [Style::MethodCallWithArgsParentheses, Style::ReturnNil, Style::ReturnNilInPredicateMethodDefinition]
53
+ end
54
+
51
55
  def on_and(node)
52
56
  process_logical_operator(node) if style == :always
53
57
  end
@@ -69,9 +73,9 @@ module RuboCop
69
73
  message = message(node)
70
74
  add_offense(node.loc.operator, message: message) do |corrector|
71
75
  node.each_child_node do |expr|
72
- if expr.send_type?
76
+ if expr.call_type?
73
77
  correct_send(expr, corrector)
74
- elsif expr.return_type? || expr.assignment?
78
+ elsif expr.type?(:return, :next, :break, :yield) || expr.assignment?
75
79
  correct_other(expr, corrector)
76
80
  end
77
81
  end
@@ -116,7 +120,7 @@ module RuboCop
116
120
  # however, 'not x' also parses as (send x :!)
117
121
  def correct_not(node, receiver, corrector)
118
122
  if node.prefix_bang?
119
- return unless receiver.send_type?
123
+ return unless receiver.call_type?
120
124
 
121
125
  correct_send(receiver, corrector)
122
126
  elsif node.prefix_not?
@@ -128,6 +132,7 @@ module RuboCop
128
132
 
129
133
  def correct_other(node, corrector)
130
134
  return if node.parenthesized_call?
135
+ return if node.children.empty? && node.equal?(node.parent.children.last)
131
136
 
132
137
  corrector.wrap(node, '(', ')')
133
138
  end
@@ -153,7 +153,7 @@ module RuboCop
153
153
  BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
154
154
 
155
155
  def self.autocorrect_incompatible_with
156
- [Naming::BlockForwarding]
156
+ [Naming::BlockForwarding, Style::EndlessMethod, Style::MethodDefParentheses]
157
157
  end
158
158
 
159
159
  def on_def(node)
@@ -169,7 +169,7 @@ module RuboCop
169
169
 
170
170
  return if send_classifications.empty?
171
171
 
172
- if only_forwards_all?(send_classifications)
172
+ if forward_all?(send_nodes, send_classifications)
173
173
  add_forward_all_offenses(node, send_classifications, forwardable_args)
174
174
  elsif target_ruby_version >= 3.2
175
175
  add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
@@ -192,17 +192,39 @@ module RuboCop
192
192
  [restarg_node, kwrestarg_node, blockarg_node]
193
193
  end
194
194
 
195
+ def forward_all?(send_nodes, send_classifications)
196
+ only_forwards_all?(send_classifications) &&
197
+ !anonymous_forwarding_elsewhere?(send_nodes, send_classifications)
198
+ end
199
+
195
200
  def only_forwards_all?(send_classifications)
196
201
  all_classifications = %i[all all_anonymous].freeze
197
202
  send_classifications.all? { |_, c, _, _| all_classifications.include?(c) }
198
203
  end
199
204
 
200
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
205
+ def anonymous_forwarding_elsewhere?(send_nodes, send_classifications)
206
+ classified = send_classifications.map(&:first)
207
+
208
+ send_nodes.any? do |send_node|
209
+ classified.none? { |node| node.equal?(send_node) } &&
210
+ forwards_anonymous_args?(send_node)
211
+ end
212
+ end
213
+
214
+ def forwards_anonymous_args?(send_node)
215
+ send_node.arguments.any? do |arg|
216
+ next arg.children.any?(&:forwarded_kwrestarg_type?) if arg.hash_type?
217
+
218
+ arg.forwarded_restarg_type?
219
+ end
220
+ end
221
+
222
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
201
223
  def add_forward_all_offenses(node, send_classifications, forwardable_args)
202
224
  rest_arg, kwrest_arg, block_arg = *forwardable_args
203
225
  registered_block_arg_offense = false
204
226
 
205
- send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
227
+ send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength -- the block parameter list does not wrap
206
228
  if !forward_rest && !forward_kwrest && c != :all_anonymous
207
229
  if allow_anonymous_forwarding_in_block?(forward_block_arg)
208
230
  register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
@@ -220,20 +242,19 @@ module RuboCop
220
242
 
221
243
  register_forward_all_offense(node, node.arguments, rest_arg || kwrest_arg)
222
244
  end
223
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
224
245
 
225
246
  def forward_all_first_argument(node)
226
247
  node.arguments.reverse_each.find(&:forwarded_restarg_type?)
227
248
  end
228
249
 
229
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
250
+ # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
230
251
  def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
231
252
  return unless use_anonymous_forwarding?
232
253
  return unless all_forwarding_offenses_correctable?(send_classifications)
233
254
 
234
255
  rest_arg, kwrest_arg, block_arg = *forwardable_args
235
256
 
236
- send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
257
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength -- the block parameter list does not wrap
237
258
  if allow_anonymous_forwarding_in_block?(forward_rest)
238
259
  register_forward_args_offense(def_node.arguments, rest_arg)
239
260
  register_forward_args_offense(send_node, forward_rest)
@@ -250,7 +271,6 @@ module RuboCop
250
271
  end
251
272
  end
252
273
  end
253
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
254
274
 
255
275
  def non_splat_or_block_pass_lvar_references(body)
256
276
  body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
@@ -378,11 +398,16 @@ module RuboCop
378
398
 
379
399
  def add_parens_if_missing(node, corrector)
380
400
  return if parentheses?(node)
381
- return if node.send_type? && node.method?(:[])
401
+ return if node.call_type? && operator_or_setter_call?(node)
402
+ return unless (@parenthesized_nodes ||= Set.new.compare_by_identity).add?(node)
382
403
 
383
404
  add_parentheses(node, corrector)
384
405
  end
385
406
 
407
+ def operator_or_setter_call?(node)
408
+ node.setter_method? || (node.operator_method? && !node.loc.dot)
409
+ end
410
+
386
411
  # Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
387
412
  class SendNodeClassifier
388
413
  extend NodePattern::Macros
@@ -424,21 +449,39 @@ module RuboCop
424
449
  end
425
450
 
426
451
  def forwarded_rest_arg
427
- return nil if referenced_rest_arg?
452
+ return @forwarded_rest_arg if defined?(@forwarded_rest_arg)
428
453
 
429
- arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
454
+ @forwarded_rest_arg = if referenced_rest_arg?
455
+ nil
456
+ else
457
+ arguments.find do |arg|
458
+ forwarded_rest_arg?(arg, @rest_arg_name)
459
+ end
460
+ end
430
461
  end
431
462
 
432
463
  def forwarded_kwrest_arg
433
- return nil if referenced_kwrest_arg?
464
+ return @forwarded_kwrest_arg if defined?(@forwarded_kwrest_arg)
434
465
 
435
- arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
466
+ @forwarded_kwrest_arg = if referenced_kwrest_arg?
467
+ nil
468
+ else
469
+ arguments.filter_map do |arg|
470
+ extract_forwarded_kwrest_arg(arg, @kwrest_arg_name)
471
+ end.first
472
+ end
436
473
  end
437
474
 
438
475
  def forwarded_block_arg
439
- return nil if referenced_block_arg?
476
+ return @forwarded_block_arg if defined?(@forwarded_block_arg)
440
477
 
441
- arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
478
+ @forwarded_block_arg = if referenced_block_arg?
479
+ nil
480
+ else
481
+ arguments.find do |arg|
482
+ forwarded_block_arg?(arg, @block_arg_name)
483
+ end
484
+ end
442
485
  end
443
486
 
444
487
  def classification
@@ -455,7 +498,7 @@ module RuboCop
455
498
 
456
499
  private
457
500
 
458
- # rubocop:disable Metrics/CyclomaticComplexity
501
+ # rubocop:disable-next Metrics/CyclomaticComplexity
459
502
  def can_forward_all?
460
503
  return false if any_arg_referenced?
461
504
  return false if ruby_30_or_lower_optarg?
@@ -465,7 +508,6 @@ module RuboCop
465
508
 
466
509
  no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
467
510
  end
468
- # rubocop:enable Metrics/CyclomaticComplexity
469
511
 
470
512
  # def foo(a = 41, ...) is a syntax error in 3.0.
471
513
  def ruby_30_or_lower_optarg?
@@ -484,6 +526,8 @@ module RuboCop
484
526
  end
485
527
 
486
528
  def offensive_block_forwarding?
529
+ return false if @send_node.block_literal?
530
+
487
531
  @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
488
532
  end
489
533
 
@@ -31,7 +31,7 @@ module RuboCop
31
31
  MSG = 'Use `%<preferred>s`.'
32
32
  RESTRICT_ON_SEND = %i[[]].freeze
33
33
 
34
- # rubocop:disable Metrics/AbcSize
34
+ # rubocop:disable-next Metrics/AbcSize
35
35
  def on_send(node)
36
36
  return unless node.arguments.size == 1 && node.first_argument.int_type?
37
37
 
@@ -40,19 +40,23 @@ module RuboCop
40
40
 
41
41
  node = innermost_braces_node(node)
42
42
  return if node.parent && brace_method?(node.parent)
43
+ return if compound_assignment_target?(node)
43
44
 
44
- preferred = (value.zero? ? 'first' : 'last')
45
+ preferred = preferred_name(value)
45
46
  offense_range = find_offense_range(node)
46
47
 
47
48
  add_offense(offense_range, message: format(MSG, preferred: preferred)) do |corrector|
48
49
  corrector.replace(offense_range, preferred_value(node, preferred))
49
50
  end
50
51
  end
51
- # rubocop:enable Metrics/AbcSize
52
52
  alias on_csend on_send
53
53
 
54
54
  private
55
55
 
56
+ def preferred_name(value)
57
+ value.zero? ? 'first' : 'last'
58
+ end
59
+
56
60
  def preferred_value(node, value)
57
61
  value = ".#{value}" unless node.loc.dot
58
62
  value
@@ -74,6 +78,12 @@ module RuboCop
74
78
  def brace_method?(node)
75
79
  node.send_type? && (node.method?(:[]) || node.method?(:[]=))
76
80
  end
81
+
82
+ # `arr[0] += 1` etc. would autocorrect to `arr.first += 1`, which calls the
83
+ # nonexistent `first=`/`last=` setter and raises `NoMethodError`.
84
+ def compound_assignment_target?(node)
85
+ node.parent&.type?(:op_asgn, :or_asgn, :and_asgn) && node.parent.children.first == node
86
+ end
77
87
  end
78
88
  end
79
89
  end
@@ -30,6 +30,11 @@ module RuboCop
30
30
  # only cases where exactly one argument is provided can be replaced with
31
31
  # `Array#intersect?` and are handled by this cop.
32
32
  #
33
+ # NOTE: In the block form, `include?` is only detected when its receiver is
34
+ # an array literal, because `include?` is defined with different semantics
35
+ # on many non-array classes (e.g. `String#include?` checks for substrings).
36
+ # `member?` does not have this restriction.
37
+ #
33
38
  # @safety
34
39
  # This cop cannot guarantee that `array1` and `array2` are
35
40
  # actually arrays while method `intersect?` is for arrays only.
@@ -47,7 +52,7 @@ module RuboCop
47
52
  #
48
53
  # # bad
49
54
  # array1.any? { |elem| array2.member?(elem) }
50
- # array1.none? { |elem| array2.member?(elem) }
55
+ # array1.none? { |elem| [1, 2].include?(elem) }
51
56
  #
52
57
  # # good
53
58
  # array1.intersect?(array2)
@@ -121,15 +126,15 @@ module RuboCop
121
126
  (block
122
127
  (call $_receiver ${:any? :none?})
123
128
  (args (arg _key))
124
- (send $_argument :member? (lvar _key))
129
+ (send $!nil? ${:member? :include?} (lvar _key))
125
130
  )
126
131
  (numblock
127
132
  (call $_receiver ${:any? :none?}) 1
128
- (send $_argument :member? (lvar :_1))
133
+ (send $!nil? ${:member? :include?} (lvar :_1))
129
134
  )
130
135
  (itblock
131
136
  (call $_receiver ${:any? :none?}) :it
132
- (send $_argument :member? (lvar :it))
137
+ (send $!nil? ${:member? :include?} (lvar :it))
133
138
  )
134
139
  }
135
140
  PATTERN
@@ -145,6 +150,10 @@ module RuboCop
145
150
 
146
151
  dot = dot_node.loc.dot.source
147
152
  bang = straight?(method_name) ? '' : '!'
153
+ # `a&.intersection(b)&.none?` returns `nil` when `a` is `nil`, but the negated
154
+ # rewrite `!a&.intersect?(b)` returns `true` there, flipping the result.
155
+ return if bang == '!' && dot == '&.'
156
+
148
157
  replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
149
158
 
150
159
  register_offense(node, replacement)
@@ -152,7 +161,10 @@ module RuboCop
152
161
  alias on_csend on_send
153
162
 
154
163
  def on_block(node)
155
- return unless (receiver, method_name, argument = any_none_block_intersection(node))
164
+ return unless (captures = any_none_block_intersection(node))
165
+
166
+ receiver, method_name, argument, block_method = captures
167
+ return if uncorrectable_block_intersection?(node, method_name, argument, block_method)
156
168
 
157
169
  dot = node.send_node.loc.dot.source
158
170
  bang = method_name == :any? ? '' : '!'
@@ -182,6 +194,17 @@ module RuboCop
182
194
  STRAIGHT_METHODS.include?(method_name.to_sym)
183
195
  end
184
196
 
197
+ def uncorrectable_block_intersection?(node, method_name, argument, block_method)
198
+ # `a&.none? { |elem| b.include?(elem) }` returns `nil` when `a` is `nil`,
199
+ # but the negated rewrite `!a&.intersect?(b)` returns `true` there, flipping the result.
200
+ return true if method_name == :none? && node.send_node.safe_navigation?
201
+
202
+ # `include?` is defined with different semantics on many non-array classes
203
+ # (e.g. `String#include?` checks for substrings), so it is only a reliable
204
+ # signal of an intersection check when the receiver is an array literal.
205
+ block_method == :include? && !argument.array_type?
206
+ end
207
+
185
208
  def register_offense(node, replacement)
186
209
  message = format(MSG, replacement: replacement, existing: node.source)
187
210
 
@@ -29,6 +29,9 @@ module RuboCop
29
29
  def on_send(node)
30
30
  array, element = single_element(node)
31
31
  return unless array
32
+ # `[*foo]` is not a single element: the splat can expand to any number of
33
+ # elements, so `intersect?([*foo])` is not equivalent to `include?(*foo)`.
34
+ return if element.splat_type?
32
35
 
33
36
  add_offense(
34
37
  node.source_range.with(begin_pos: node.loc.selector.begin_pos)
@@ -3,9 +3,11 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of "*" as a substitute for _join_.
6
+ # Checks for uses of `*` as a substitute for `Array#join`.
7
+ # Using `join` is clearer about intent and more readable than
8
+ # overloading the `*` operator for string conversion.
7
9
  #
8
- # Not all cases can reliably checked, due to Ruby's dynamic
10
+ # Not all cases can be reliably checked, due to Ruby's dynamic
9
11
  # types, so we consider only cases when the first argument is an
10
12
  # array literal or the second is a string literal.
11
13
  #