rubocop 1.79.2 → 1.88.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (421) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +259 -90
  5. data/config/obsoletion.yml +30 -1
  6. data/exe/rubocop +1 -8
  7. data/lib/rubocop/cache_config.rb +29 -0
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
  9. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  10. data/lib/rubocop/cli/command/lsp.rb +1 -1
  11. data/lib/rubocop/cli/command/mcp.rb +19 -0
  12. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  13. data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
  14. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  15. data/lib/rubocop/cli.rb +35 -9
  16. data/lib/rubocop/comment_config.rb +59 -17
  17. data/lib/rubocop/config.rb +14 -10
  18. data/lib/rubocop/config_finder.rb +1 -1
  19. data/lib/rubocop/config_loader.rb +37 -23
  20. data/lib/rubocop/config_loader_resolver.rb +20 -10
  21. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  22. data/lib/rubocop/config_store.rb +7 -2
  23. data/lib/rubocop/config_validator.rb +1 -1
  24. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  25. data/lib/rubocop/cop/base.rb +25 -4
  26. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  28. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  29. data/lib/rubocop/cop/correctors/alignment_corrector.rb +26 -7
  30. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  31. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  32. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  33. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
  34. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  35. data/lib/rubocop/cop/correctors.rb +28 -0
  36. data/lib/rubocop/cop/documentation.rb +2 -3
  37. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  38. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  39. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  40. data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
  41. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  42. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  43. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  44. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  45. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  46. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
  47. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  48. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  49. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  50. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  51. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  52. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  53. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  54. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  55. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  56. data/lib/rubocop/cop/layout/block_alignment.rb +41 -4
  57. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  58. data/lib/rubocop/cop/layout/class_structure.rb +14 -7
  59. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  60. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +26 -7
  61. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
  62. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
  63. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  64. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  65. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  66. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  67. data/lib/rubocop/cop/layout/end_alignment.rb +10 -3
  68. data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
  69. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  70. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  71. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  72. data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
  73. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  74. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  75. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  76. data/lib/rubocop/cop/layout/indentation_width.rb +123 -7
  77. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  78. data/lib/rubocop/cop/layout/line_length.rb +26 -9
  79. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  80. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  81. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  82. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  83. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  84. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +229 -39
  85. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  86. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  87. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
  88. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  89. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  90. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  91. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  92. data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
  93. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  94. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  95. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  96. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +1 -11
  97. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  98. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
  99. data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
  100. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  101. data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
  102. data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
  103. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  104. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  105. data/lib/rubocop/cop/lint/debugger.rb +0 -3
  106. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  107. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  108. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  109. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
  110. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  111. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  112. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  113. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  114. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  115. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  116. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  117. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  118. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -2
  119. data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
  120. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  121. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -5
  122. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  123. data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
  124. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  125. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +9 -12
  126. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -10
  127. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  128. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  129. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  130. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  131. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  132. data/lib/rubocop/cop/lint/number_conversion.rb +19 -10
  133. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  134. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +3 -0
  135. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  136. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  137. data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
  138. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  139. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -10
  140. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +6 -12
  141. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
  142. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  143. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +36 -12
  144. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +12 -2
  145. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +10 -3
  146. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  147. data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
  148. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  149. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  150. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  151. data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
  152. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  153. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  154. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  155. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +18 -0
  156. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  157. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  158. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  159. data/lib/rubocop/cop/lint/self_assignment.rb +39 -7
  160. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  161. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  162. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  163. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
  164. data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
  165. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  166. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +12 -0
  167. data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
  168. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  169. data/lib/rubocop/cop/lint/to_enum_arguments.rb +28 -1
  170. data/lib/rubocop/cop/lint/to_json.rb +12 -16
  171. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  172. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  173. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +4 -2
  174. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  175. data/lib/rubocop/cop/lint/unreachable_code.rb +7 -5
  176. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  177. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  178. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  179. data/lib/rubocop/cop/lint/useless_assignment.rb +53 -25
  180. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  181. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  182. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  183. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +8 -4
  184. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
  185. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  186. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +37 -11
  187. data/lib/rubocop/cop/lint/void.rb +39 -12
  188. data/lib/rubocop/cop/message_annotator.rb +1 -1
  189. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  190. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  191. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  192. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  193. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  194. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  195. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  196. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  197. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
  198. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  199. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  200. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  201. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
  202. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  203. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  204. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  205. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  206. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  207. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  208. data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
  209. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  210. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  211. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  212. data/lib/rubocop/cop/mixin.rb +86 -0
  213. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  214. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  215. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  216. data/lib/rubocop/cop/naming/method_name.rb +5 -3
  217. data/lib/rubocop/cop/naming/predicate_method.rb +32 -8
  218. data/lib/rubocop/cop/naming/predicate_prefix.rb +12 -12
  219. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  220. data/lib/rubocop/cop/offense.rb +17 -1
  221. data/lib/rubocop/cop/registry.rb +62 -38
  222. data/lib/rubocop/cop/security/eval.rb +15 -2
  223. data/lib/rubocop/cop/security/io_methods.rb +1 -1
  224. data/lib/rubocop/cop/security/json_load.rb +33 -11
  225. data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
  226. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  227. data/lib/rubocop/cop/style/alias.rb +15 -3
  228. data/lib/rubocop/cop/style/and_or.rb +2 -1
  229. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  230. data/lib/rubocop/cop/style/array_first_last.rb +12 -1
  231. data/lib/rubocop/cop/style/array_intersect.rb +50 -12
  232. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
  233. data/lib/rubocop/cop/style/array_join.rb +4 -2
  234. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  235. data/lib/rubocop/cop/style/attr.rb +5 -2
  236. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  237. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  238. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  239. data/lib/rubocop/cop/style/block_delimiters.rb +39 -32
  240. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  241. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  242. data/lib/rubocop/cop/style/class_and_module_children.rb +19 -2
  243. data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
  244. data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
  245. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  246. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  247. data/lib/rubocop/cop/style/combinable_loops.rb +5 -0
  248. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  249. data/lib/rubocop/cop/style/concat_array_literals.rb +7 -1
  250. data/lib/rubocop/cop/style/conditional_assignment.rb +14 -19
  251. data/lib/rubocop/cop/style/constant_visibility.rb +20 -12
  252. data/lib/rubocop/cop/style/copyright.rb +22 -11
  253. data/lib/rubocop/cop/style/date_time.rb +4 -4
  254. data/lib/rubocop/cop/style/dig_chain.rb +5 -0
  255. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  256. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  257. data/lib/rubocop/cop/style/documentation.rb +6 -6
  258. data/lib/rubocop/cop/style/documentation_method.rb +8 -8
  259. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  260. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  261. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  262. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  263. data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
  264. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  265. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  266. data/lib/rubocop/cop/style/encoding.rb +7 -1
  267. data/lib/rubocop/cop/style/end_block.rb +3 -1
  268. data/lib/rubocop/cop/style/endless_method.rb +23 -5
  269. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  270. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  271. data/lib/rubocop/cop/style/file_open.rb +84 -0
  272. data/lib/rubocop/cop/style/file_write.rb +21 -16
  273. data/lib/rubocop/cop/style/float_division.rb +15 -1
  274. data/lib/rubocop/cop/style/for.rb +3 -0
  275. data/lib/rubocop/cop/style/format_string.rb +4 -3
  276. data/lib/rubocop/cop/style/format_string_token.rb +49 -5
  277. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  278. data/lib/rubocop/cop/style/guard_clause.rb +27 -22
  279. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  280. data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
  281. data/lib/rubocop/cop/style/hash_lookup_method.rb +106 -0
  282. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  283. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  284. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  285. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  286. data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
  287. data/lib/rubocop/cop/style/if_unless_modifier.rb +58 -18
  288. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
  289. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  290. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  291. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  292. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  293. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  294. data/lib/rubocop/cop/style/lambda_call.rb +8 -8
  295. data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
  296. data/lib/rubocop/cop/style/map_join.rb +123 -0
  297. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  298. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  299. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
  300. data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
  301. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  302. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
  303. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  304. data/lib/rubocop/cop/style/mutable_constant.rb +106 -12
  305. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  306. data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
  307. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  308. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  309. data/lib/rubocop/cop/style/not.rb +2 -0
  310. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  311. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  312. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
  313. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  314. data/lib/rubocop/cop/style/parallel_assignment.rb +14 -3
  315. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  316. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  317. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  318. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  319. data/lib/rubocop/cop/style/proc.rb +3 -2
  320. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  321. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  322. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  323. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  324. data/lib/rubocop/cop/style/redundant_begin.rb +37 -3
  325. data/lib/rubocop/cop/style/redundant_condition.rb +6 -3
  326. data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
  327. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  328. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  329. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  330. data/lib/rubocop/cop/style/redundant_format.rb +27 -5
  331. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  332. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  333. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  334. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  335. data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -30
  336. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  337. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  338. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
  339. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  340. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  341. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  342. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  343. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  344. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  345. data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
  346. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
  347. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  348. data/lib/rubocop/cop/style/safe_navigation.rb +25 -8
  349. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  350. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  351. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  352. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  353. data/lib/rubocop/cop/style/semicolon.rb +41 -8
  354. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  355. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  356. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  357. data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -3
  358. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  359. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  360. data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
  361. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  362. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  363. data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
  364. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  365. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  366. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  367. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  368. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  369. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  370. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  371. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  372. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  373. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  374. data/lib/rubocop/cop/style/word_array.rb +1 -0
  375. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  376. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  377. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  378. data/lib/rubocop/cop/team.rb +87 -36
  379. data/lib/rubocop/cop/util.rb +2 -3
  380. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  381. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  382. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  383. data/lib/rubocop/cop/variable_force.rb +9 -7
  384. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  385. data/lib/rubocop/directive_comment.rb +48 -4
  386. data/lib/rubocop/file_patterns.rb +9 -1
  387. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  388. data/lib/rubocop/formatter/disabled_config_formatter.rb +38 -14
  389. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  390. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  391. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  392. data/lib/rubocop/formatter/tap_formatter.rb +5 -2
  393. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  394. data/lib/rubocop/formatter.rb +22 -21
  395. data/lib/rubocop/lsp/diagnostic.rb +18 -33
  396. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  397. data/lib/rubocop/lsp/routes.rb +43 -7
  398. data/lib/rubocop/lsp/runtime.rb +13 -4
  399. data/lib/rubocop/lsp/stdin_runner.rb +8 -17
  400. data/lib/rubocop/magic_comment.rb +20 -0
  401. data/lib/rubocop/mcp/server.rb +200 -0
  402. data/lib/rubocop/options.rb +35 -4
  403. data/lib/rubocop/path_util.rb +14 -2
  404. data/lib/rubocop/plugin/loader.rb +1 -1
  405. data/lib/rubocop/project_index_loader.rb +66 -0
  406. data/lib/rubocop/rake_task.rb +1 -1
  407. data/lib/rubocop/remote_config.rb +10 -8
  408. data/lib/rubocop/result_cache.rb +61 -38
  409. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  410. data/lib/rubocop/rspec/shared_contexts.rb +39 -5
  411. data/lib/rubocop/rspec/support.rb +2 -1
  412. data/lib/rubocop/runner.rb +134 -57
  413. data/lib/rubocop/server/cache.rb +6 -29
  414. data/lib/rubocop/server/core.rb +8 -0
  415. data/lib/rubocop/target_finder.rb +17 -10
  416. data/lib/rubocop/target_ruby.rb +31 -14
  417. data/lib/rubocop/version.rb +21 -3
  418. data/lib/rubocop.rb +28 -96
  419. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  420. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  421. metadata +38 -9
@@ -198,12 +198,13 @@ module RuboCop
198
198
  alias on_csend on_send
199
199
 
200
200
  def on_block(node)
201
- return if ignored_node?(node)
201
+ return if part_of_ignored_node?(node)
202
202
  return if proper_block_style?(node)
203
203
 
204
204
  message = message(node)
205
205
  add_offense(node.loc.begin, message: message) do |corrector|
206
206
  autocorrect(corrector, node)
207
+ ignore_node(node)
207
208
  end
208
209
  end
209
210
 
@@ -231,9 +232,7 @@ module RuboCop
231
232
  end
232
233
 
233
234
  def semantic_message(node)
234
- block_begin = node.loc.begin.source
235
-
236
- if block_begin == '{'
235
+ if node.braces?
237
236
  'Prefer `do...end` over `{...}` for procedural blocks.'
238
237
  else
239
238
  'Prefer `{...}` over `do...end` for functional blocks.'
@@ -371,36 +370,42 @@ module RuboCop
371
370
  end
372
371
  # rubocop:enable Metrics/CyclomaticComplexity
373
372
 
373
+ # rubocop:disable Metrics/CyclomaticComplexity -- inlined special_method checks to avoid double evaluation
374
374
  def proper_block_style?(node)
375
375
  return true if require_do_end?(node)
376
- return special_method_proper_block_style?(node) if special_method?(node.method_name)
376
+
377
+ method_name = node.method_name
378
+ return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name)
379
+ return node.braces? if braces_required_method?(method_name)
377
380
 
378
381
  case style
379
382
  when :line_count_based then line_count_based_block_style?(node)
380
383
  when :semantic then semantic_block_style?(node)
381
384
  when :braces_for_chaining then braces_for_chaining_style?(node)
382
- when :always_braces then braces_style?(node)
385
+ when :always_braces then node.braces?
383
386
  end
384
387
  end
388
+ # rubocop:enable Metrics/CyclomaticComplexity
385
389
 
386
390
  def require_do_end?(node)
387
391
  return false if node.braces? || node.multiline?
388
- return false unless (resbody = node.each_descendant(:resbody).first)
389
392
 
390
- resbody.children.first&.array_type?
391
- end
393
+ body = node.body
394
+ return false unless body
395
+ # `ensure` and a block-level `rescue` are illegal inside `{ }`; only a
396
+ # bare modifier rescue (`expr rescue expr`) can be written with braces.
397
+ return true if body.ensure_type?
398
+ return false unless body.rescue_type?
392
399
 
393
- def special_method?(method_name)
394
- allowed_method?(method_name) ||
395
- matches_allowed_pattern?(method_name) ||
396
- braces_required_method?(method_name)
400
+ !modifier_rescue?(body)
397
401
  end
398
402
 
399
- def special_method_proper_block_style?(node)
400
- method_name = node.method_name
401
- return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name)
403
+ def modifier_rescue?(rescue_node)
404
+ return false if rescue_node.body.nil? || rescue_node.else_branch
405
+ return false unless rescue_node.resbody_branches.one?
402
406
 
403
- node.braces? if braces_required_method?(method_name)
407
+ resbody = rescue_node.resbody_branches.first
408
+ resbody.exceptions.empty? && resbody.exception_variable.nil?
404
409
  end
405
410
 
406
411
  def braces_required_method?(method_name)
@@ -420,24 +425,18 @@ module RuboCop
420
425
 
421
426
  if node.braces?
422
427
  functional_method?(method_name) || functional_block?(node) ||
423
- (procedural_oneliners_may_have_braces? && !node.multiline?)
428
+ (procedural_oneliners_may_have_braces? && node.single_line?)
424
429
  else
425
430
  procedural_method?(method_name) || !return_value_used?(node)
426
431
  end
427
432
  end
428
433
 
429
434
  def braces_for_chaining_style?(node)
430
- block_begin = node.loc.begin.source
431
-
432
- block_begin == if node.multiline?
433
- (node.chained? ? '{' : 'do')
434
- else
435
- '{'
436
- end
437
- end
438
-
439
- def braces_style?(node)
440
- node.loc.begin.source == '{'
435
+ if node.multiline?
436
+ node.chained? ? node.braces? : !node.braces?
437
+ else
438
+ node.braces?
439
+ end
441
440
  end
442
441
 
443
442
  def correction_would_break_code?(node)
@@ -447,7 +446,11 @@ module RuboCop
447
446
  end
448
447
 
449
448
  def functional_method?(method_name)
450
- cop_config['FunctionalMethods'].map(&:to_sym).include?(method_name)
449
+ functional_methods.include?(method_name)
450
+ end
451
+
452
+ def functional_methods
453
+ @functional_methods ||= cop_config['FunctionalMethods'].to_set(&:to_sym).freeze
451
454
  end
452
455
 
453
456
  def functional_block?(node)
@@ -459,7 +462,11 @@ module RuboCop
459
462
  end
460
463
 
461
464
  def procedural_method?(method_name)
462
- cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name)
465
+ procedural_methods.include?(method_name)
466
+ end
467
+
468
+ def procedural_methods
469
+ @procedural_methods ||= cop_config['ProceduralMethods'].to_set(&:to_sym).freeze
463
470
  end
464
471
 
465
472
  def return_value_used?(node)
@@ -488,7 +495,7 @@ module RuboCop
488
495
  def begin_required?(block_node)
489
496
  # If the block contains `rescue` or `ensure`, it needs to be wrapped in
490
497
  # `begin`...`end` when changing `do-end` to `{}`.
491
- block_node.each_child_node(:rescue, :ensure).any? && !block_node.single_line?
498
+ block_node.each_child_node(:rescue, :ensure).any? && block_node.multiline?
492
499
  end
493
500
 
494
501
  def single_argument_operator_method?(node)
@@ -3,31 +3,40 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of the case equality operator(===).
6
+ # Checks for uses of the case equality operator (`===`).
7
+ # The `===` operator has different behavior depending on the
8
+ # receiver and its use outside of `case`/`when` is confusing.
9
+ # Prefer more explicit alternatives like `is_a?`, `include?`,
10
+ # or `match?`.
7
11
  #
8
12
  # If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
9
13
  # the case equality operator is a constant.
10
-
14
+ #
11
15
  # If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
12
16
  # the case equality operator is `self.class`. Note intermediate variables are not accepted.
13
17
  #
18
+ # NOTE: Regexp case equality (`/regexp/ === var`) is allowed because changing it to
19
+ # `/regexp/.match?(var)` needs to take into account `Regexp.last_match?`, `$~`, `$1`, etc.
20
+ # This potentially incompatible transformation is handled by `Performance/RegexpMatch` cop.
21
+ #
14
22
  # @example
15
23
  # # bad
16
24
  # (1..100) === 7
17
- # /something/ === some_string
18
25
  #
19
26
  # # good
20
- # something.is_a?(Array)
21
27
  # (1..100).include?(7)
22
- # /something/.match?(some_string)
23
28
  #
24
29
  # @example AllowOnConstant: false (default)
25
30
  # # bad
26
31
  # Array === something
27
32
  #
33
+ # # good
34
+ # something.is_a?(Array)
35
+ #
28
36
  # @example AllowOnConstant: true
29
37
  # # good
30
38
  # Array === something
39
+ # something.is_a?(Array)
31
40
  #
32
41
  # @example AllowOnSelfClass: false (default)
33
42
  # # bad
@@ -51,7 +60,7 @@ module RuboCop
51
60
 
52
61
  def on_send(node)
53
62
  case_equality?(node) do |lhs, rhs|
54
- return if lhs.const_type? && !lhs.module_name?
63
+ return if lhs.regexp_type? || (lhs.const_type? && !lhs.module_name?)
55
64
 
56
65
  add_offense(node.loc.selector) do |corrector|
57
66
  replacement = replacement(lhs, rhs)
@@ -71,13 +80,6 @@ module RuboCop
71
80
 
72
81
  def replacement(lhs, rhs)
73
82
  case lhs.type
74
- when :regexp
75
- # The automatic correction from `a === b` to `a.match?(b)` needs to
76
- # consider `Regexp.last_match?`, `$~`, `$1`, and etc.
77
- # This correction is expected to be supported by `Performance/Regexp` cop.
78
- # See: https://github.com/rubocop/rubocop-performance/issues/152
79
- #
80
- # So here is noop.
81
83
  when :begin
82
84
  begin_replacement(lhs, rhs)
83
85
  when :const
@@ -94,13 +96,25 @@ module RuboCop
94
96
  end
95
97
 
96
98
  def const_replacement(lhs, rhs)
97
- "#{rhs.source}.is_a?(#{lhs.source})"
99
+ "#{parenthesize_if_needed(rhs)}.is_a?(#{lhs.source})"
98
100
  end
99
101
 
100
102
  def send_replacement(lhs, rhs)
101
103
  return unless self_class?(lhs)
102
104
 
103
- "#{rhs.source}.is_a?(#{lhs.source})"
105
+ "#{parenthesize_if_needed(rhs)}.is_a?(#{lhs.source})"
106
+ end
107
+
108
+ # `Array === a + b` must become `(a + b).is_a?(Array)`, not
109
+ # `a + b.is_a?(Array)` (which parses as `a + (b.is_a?(Array))`).
110
+ def parenthesize_if_needed(node)
111
+ requires_parentheses?(node) ? "(#{node.source})" : node.source
112
+ end
113
+
114
+ def requires_parentheses?(node)
115
+ return true if node.type?(:and, :or, :if, :range) || node.assignment?
116
+
117
+ node.send_type? && (node.operator_method? || node.unary_operation?)
104
118
  end
105
119
  end
106
120
  end
@@ -8,8 +8,8 @@ module RuboCop
8
8
  # essentially one-character strings, so this syntax
9
9
  # is mostly redundant at this point.
10
10
  #
11
- # ? character literal can be used to express meta and control character.
12
- # That's a good use case of ? literal so it doesn't count it as an offense.
11
+ # A `?` character literal can be used to express meta and control characters.
12
+ # That's a good use case of a `?` literal so it doesn't count as an offense.
13
13
  #
14
14
  # @example
15
15
  # # bad
@@ -28,16 +28,24 @@ module RuboCop
28
28
  # manual oversight.
29
29
  #
30
30
  # @example EnforcedStyle: nested (default)
31
+ # # bad
32
+ # class Foo::Bar
33
+ # end
34
+ #
31
35
  # # good
32
- # # have each child on its own line
33
36
  # class Foo
34
37
  # class Bar
35
38
  # end
36
39
  # end
37
40
  #
38
41
  # @example EnforcedStyle: compact
42
+ # # bad
43
+ # class Foo
44
+ # class Bar
45
+ # end
46
+ # end
47
+ #
39
48
  # # good
40
- # # combine definitions as much as possible
41
49
  # class Foo::Bar
42
50
  # end
43
51
  #
@@ -173,6 +181,7 @@ module RuboCop
173
181
 
174
182
  def check_style(node, body, style)
175
183
  return if node.identifier.namespace&.cbase_type?
184
+ return unless const_namespace?(node.identifier.namespace)
176
185
 
177
186
  if style == :nested
178
187
  check_nested_style(node)
@@ -181,8 +190,16 @@ module RuboCop
181
190
  end
182
191
  end
183
192
 
193
+ def const_namespace?(node)
194
+ return true if node.nil? || node.cbase_type?
195
+ return false unless node.const_type?
196
+
197
+ const_namespace?(node.namespace)
198
+ end
199
+
184
200
  def check_nested_style(node)
185
201
  return unless compact_node_name?(node)
202
+ return if node.parent&.type?(:class, :module)
186
203
 
187
204
  add_offense(node.loc.name, message: NESTED_MSG) do |corrector|
188
205
  autocorrect(corrector, node)
@@ -90,25 +90,33 @@ module RuboCop
90
90
  private
91
91
 
92
92
  def class_name(class_node, node)
93
- if class_name_method?(node.children.first.method_name)
94
- if (receiver = class_node.receiver) && class_name_method?(class_node.method_name)
95
- return receiver.source
96
- end
93
+ unless class_name_method?(node.children.first.method_name)
94
+ # `var.class == 'Foo'` compares a `Class` to a `String` (always false) and
95
+ # has no valid `instance_of?` rewrite, so don't suggest one.
96
+ return if class_node.str_type?
97
97
 
98
- if class_node.str_type?
99
- value = trim_string_quotes(class_node)
100
- value.prepend('::') if require_cbase?(class_node)
101
- return value
102
- elsif unable_to_determine_type?(class_node)
103
- # When a variable or return value of a method is used, it returns nil
104
- # because the type is not known and cannot be suggested.
105
- return
106
- end
98
+ return class_node.source
99
+ end
100
+
101
+ if (receiver = class_node.receiver) && class_name_method?(class_node.method_name)
102
+ return receiver.source
107
103
  end
108
104
 
105
+ return string_class_name(class_node) if class_node.str_type?
106
+ # When a variable or return value of a method is used, the type is not known
107
+ # and cannot be suggested.
108
+ return if unable_to_determine_type?(class_node)
109
+
109
110
  class_node.source
110
111
  end
111
112
 
113
+ def string_class_name(class_node)
114
+ value = trim_string_quotes(class_node)
115
+ # Avoid `::::Foo` when the name is already fully qualified.
116
+ value.prepend('::') if require_cbase?(class_node) && !value.start_with?('::')
117
+ value
118
+ end
119
+
112
120
  def class_name_method?(method_name)
113
121
  CLASS_NAME_METHODS.include?(method_name)
114
122
  end
@@ -140,15 +140,21 @@ module RuboCop
140
140
 
141
141
  def extract_def_from_sclass(def_node, sclass_node)
142
142
  range = source_range_with_comment(def_node)
143
- source = range.source.sub!(
144
- "def #{def_node.method_name}",
145
- "def self.#{def_node.method_name}"
146
- )
147
-
143
+ source = prefix_def_with_self(range, def_node)
148
144
  source = source.gsub(/^ {#{indentation_diff(def_node, sclass_node)}}/, '')
149
145
  [range, source.chomp]
150
146
  end
151
147
 
148
+ # Splice in `self.` at the actual `def` keyword rather than substituting the
149
+ # first textual `def <name>`, which may appear inside a preceding comment.
150
+ def prefix_def_with_self(range, def_node)
151
+ keyword_offset = def_node.loc.keyword.begin_pos - range.begin_pos
152
+ name_end_offset = def_node.loc.name.end_pos - range.begin_pos
153
+ source = range.source.dup
154
+ source[keyword_offset...name_end_offset] = "def self.#{def_node.method_name}"
155
+ source
156
+ end
157
+
152
158
  def indentation_diff(node1, node2)
153
159
  node1.loc.column - node2.loc.column
154
160
  end
@@ -64,22 +64,34 @@ module RuboCop
64
64
  # @!method reject_method?(node)
65
65
  def_node_matcher :reject_method?, <<~PATTERN
66
66
  (block
67
- (call
68
- !nil? {:reject :reject!})
67
+ (call !nil? {:reject :reject!})
69
68
  $(args ...)
70
- (call
71
- $(lvar _) :nil?))
69
+ (call $(lvar _) :nil?))
70
+ PATTERN
71
+
72
+ # @!method reject_method_for_numblock_or_itblock?(node)
73
+ def_node_matcher :reject_method_for_numblock_or_itblock?, <<~PATTERN
74
+ {
75
+ (numblock (call !nil? {:reject :reject!}) _ (call (lvar :_1) :nil?))
76
+ (itblock (call !nil? {:reject :reject!}) _ (call (lvar :it) :nil?))
77
+ }
72
78
  PATTERN
73
79
 
74
80
  # @!method select_method?(node)
75
81
  def_node_matcher :select_method?, <<~PATTERN
76
82
  (block
77
- (call
78
- !nil? {:select :select! :filter :filter!})
83
+ (call !nil? {:select :select! :filter :filter!})
79
84
  $(args ...)
80
85
  (call
81
- (call
82
- $(lvar _) :nil?) :!))
86
+ (call $(lvar _) :nil?) :!))
87
+ PATTERN
88
+
89
+ # @!method select_method_for_numblock_or_itblock?(node)
90
+ def_node_matcher :select_method_for_numblock_or_itblock?, <<~PATTERN
91
+ {
92
+ (numblock (call !nil? {:select :select! :filter :filter!}) _ (call (call (lvar :_1) :nil?) :!))
93
+ (itblock (call !nil? {:select :select! :filter :filter!}) _ (call (call (lvar :it) :nil?) :!))
94
+ }
83
95
  PATTERN
84
96
 
85
97
  # @!method grep_v_with_nil?(node)
@@ -102,26 +114,34 @@ module RuboCop
102
114
 
103
115
  private
104
116
 
105
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
106
117
  def offense_range(node)
107
118
  if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
108
119
  range(node, node)
109
120
  else
110
121
  block_node = node.parent
111
122
 
112
- return unless block_node&.block_type?
113
- unless (args, receiver = reject_method?(block_node) || select_method?(block_node))
114
- return
115
- end
116
- return unless args.last.source == receiver.source
123
+ return unless block_node&.any_block_type?
124
+ return unless match_block_method?(block_node)
117
125
 
118
126
  range(node, block_node)
119
127
  end
120
128
  end
121
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
129
+
130
+ def match_block_method?(block_node)
131
+ if block_node.block_type?
132
+ result = reject_method?(block_node) || select_method?(block_node)
133
+ return false unless result
134
+
135
+ args, receiver = result
136
+ args.last.source == receiver.source
137
+ else
138
+ reject_method_for_numblock_or_itblock?(block_node) ||
139
+ select_method_for_numblock_or_itblock?(block_node)
140
+ end
141
+ end
122
142
 
123
143
  def to_enum_method?(node)
124
- return false unless node.receiver.send_type?
144
+ return false unless node.receiver.call_type?
125
145
 
126
146
  TO_ENUM_METHODS.include?(node.receiver.method_name)
127
147
  end
@@ -4,7 +4,9 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for methods invoked via the `::` operator instead
7
- # of the `.` operator (like `FileUtils::rmdir` instead of `FileUtils.rmdir`).
7
+ # of the `.` operator (like `FileUtils::rmdir` instead of
8
+ # `FileUtils.rmdir`). The `::` operator is conventionally used to
9
+ # reference constants, so using it for method calls can be misleading.
8
10
  #
9
11
  # @example
10
12
  # # bad
@@ -22,10 +24,9 @@ module RuboCop
22
24
 
23
25
  MSG = 'Do not use `::` for method calls.'
24
26
 
25
- # @!method java_type_node?(node)
26
- def_node_matcher :java_type_node?, <<~PATTERN
27
- (send
28
- (const nil? :Java) _)
27
+ # @!method java_root?(node)
28
+ def_node_matcher :java_root?, <<~PATTERN
29
+ (const nil? :Java)
29
30
  PATTERN
30
31
 
31
32
  def self.autocorrect_incompatible_with
@@ -35,11 +36,19 @@ module RuboCop
35
36
  def on_send(node)
36
37
  return unless node.receiver && node.double_colon?
37
38
  return if node.camel_case_method?
38
- # ignore Java interop code like Java::int
39
- return if java_type_node?(node)
39
+ # ignore Java interop code like `Java::int` or `Java::com::method`
40
+ return if java_interop?(node)
40
41
 
41
42
  add_offense(node.loc.dot) { |corrector| corrector.replace(node.loc.dot, '.') }
42
43
  end
44
+
45
+ private
46
+
47
+ def java_interop?(node)
48
+ receiver = node.receiver
49
+ receiver = receiver.receiver while receiver.respond_to?(:receiver) && receiver.receiver
50
+ java_root?(receiver)
51
+ end
43
52
  end
44
53
  end
45
54
  end
@@ -85,8 +85,13 @@ module RuboCop
85
85
  def on_for(node)
86
86
  return unless node.parent&.begin_type?
87
87
  return unless same_collection_looping_for?(node, node.left_sibling)
88
+ return unless node.body && node.left_sibling.body
88
89
 
89
90
  add_offense(node) do |corrector|
91
+ # Combining loops with different iteration variables would leave the second
92
+ # body referencing an undefined variable, so only autocorrect when they match.
93
+ next unless node.variable == node.left_sibling.variable
94
+
90
95
  combine_with_left_sibling(corrector, node)
91
96
  end
92
97
  end
@@ -90,7 +90,7 @@ module RuboCop
90
90
  max = if_body.source
91
91
  end
92
92
 
93
- prefer = "#{else_body_source}.clamp(#{min}, #{max})"
93
+ prefer = "#{parenthesize_if_needed(else_body)}.clamp(#{min}, #{max})"
94
94
 
95
95
  add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
96
96
  autocorrect(corrector, node, prefer)
@@ -119,6 +119,17 @@ module RuboCop
119
119
 
120
120
  (lhs.source == else_body && op == :<) || (rhs.source == else_body && op == :>)
121
121
  end
122
+
123
+ # `a + b` must become `(a + b).clamp(low, high)`, not `a + b.clamp(low, high)`
124
+ # (which parses as `a + (b.clamp(low, high))`).
125
+ def parenthesize_if_needed(node)
126
+ if node.type?(:and, :or, :if, :range) || node.assignment? ||
127
+ (node.send_type? && (node.operator_method? || node.unary_operation?))
128
+ "(#{node.source})"
129
+ else
130
+ node.source
131
+ end
132
+ end
122
133
  end
123
134
  end
124
135
  end
@@ -52,7 +52,13 @@ module RuboCop
52
52
 
53
53
  add_offense(offense, message: message) do |corrector|
54
54
  if use_percent_literal
55
+ next unless prefer
56
+
55
57
  corrector.replace(offense, prefer)
58
+ elsif node.arguments.any? { |argument| argument.children.empty? }
59
+ # In-place bracket removal would leave dangling commas (e.g.
60
+ # `concat([], [b])` -> `push(, b)`), so rebuild the call instead.
61
+ corrector.replace(offense, preferred_method(node))
56
62
  else
57
63
  corrector.replace(node.loc.selector, 'push')
58
64
  node.arguments.each do |argument|
@@ -73,7 +79,7 @@ module RuboCop
73
79
 
74
80
  def preferred_method(node)
75
81
  new_arguments =
76
- node.arguments.map do |arg|
82
+ node.arguments.flat_map do |arg|
77
83
  if arg.percent_literal?
78
84
  arg.children.map { |child| child.value.inspect }
79
85
  else
@@ -99,10 +99,6 @@ module RuboCop
99
99
  end
100
100
  end
101
101
 
102
- def setter_method?(method_name)
103
- method_name.to_s.end_with?(EQUAL) && !%i[!= == === >= <=].include?(method_name)
104
- end
105
-
106
102
  def assignment_rhs_exist?(node)
107
103
  parent = node.parent
108
104
  return true unless parent
@@ -213,9 +209,7 @@ module RuboCop
213
209
  ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
214
210
  VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
215
211
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
216
- LINE_LENGTH = 'Layout/LineLength'
217
212
  ENABLED = 'Enabled'
218
- MAX = 'Max'
219
213
  SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
220
214
 
221
215
  # The shovel operator `<<` does not have its own type. It is a `send`
@@ -289,7 +283,10 @@ module RuboCop
289
283
 
290
284
  _condition, *branches, else_branch = *assignment
291
285
 
292
- return unless else_branch
286
+ # Use the node accessor rather than the raw destructured branch: for
287
+ # `x = unless cond; body; end` (no `else`) the parser puts `body` in the
288
+ # else slot, but `else_branch` correctly reports there is no `else` clause.
289
+ return unless assignment.else_branch
293
290
  return if allowed_single_line?([*branches, else_branch])
294
291
 
295
292
  add_offense(node, message: ASSIGN_TO_CONDITION_MSG) do |corrector|
@@ -399,7 +396,7 @@ module RuboCop
399
396
  # of the longest line + the length of the corrected assignment is
400
397
  # greater than the max configured line length
401
398
  def correction_exceeds_line_limit?(node, branches)
402
- return false unless line_length_cop_enabled?
399
+ return false unless config.cop_enabled?('Layout/LineLength')
403
400
 
404
401
  assignment = lhs(tail(branches[0]))
405
402
 
@@ -417,14 +414,6 @@ module RuboCop
417
414
  assignment + longest_line
418
415
  end
419
416
 
420
- def line_length_cop_enabled?
421
- config.for_cop(LINE_LENGTH)[ENABLED]
422
- end
423
-
424
- def max_line_length
425
- config.for_cop(LINE_LENGTH)[MAX]
426
- end
427
-
428
417
  def single_line_conditions_only?
429
418
  cop_config[SINGLE_LINE_CONDITIONS_ONLY]
430
419
  end
@@ -444,7 +433,7 @@ module RuboCop
444
433
  next if child.parent.dstr_type?
445
434
 
446
435
  white_space = white_space_range(child, column)
447
- corrector.remove(white_space) if white_space.source.strip.empty?
436
+ corrector.remove(white_space) if white_space
448
437
  end
449
438
 
450
439
  if condition.loc.else && !same_line?(condition.else_branch, condition)
@@ -465,9 +454,13 @@ module RuboCop
465
454
 
466
455
  def white_space_range(node, column)
467
456
  expression = node.source_range
468
- begin_pos = expression.begin_pos - (expression.column - column - 2)
457
+ end_pos = expression.begin_pos
458
+ begin_pos = end_pos - (expression.column - column - 2)
469
459
 
470
- Parser::Source::Range.new(expression.source_buffer, begin_pos, expression.begin_pos)
460
+ return nil if begin_pos > end_pos
461
+
462
+ white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
463
+ white_space if white_space.source.strip.empty?
471
464
  end
472
465
 
473
466
  def assignment(node)
@@ -667,6 +660,8 @@ module RuboCop
667
660
  remove_whitespace_in_branches(corrector, branch, condition, column)
668
661
 
669
662
  parent_keyword = branch.parent.loc.keyword
663
+ return if same_line?(parent_keyword, condition)
664
+
670
665
  corrector.remove_preceding(parent_keyword, parent_keyword.column - column)
671
666
  end
672
667
  end