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
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for missing `itblock` handlers. The blocks with the `it`
7
+ # parameter introduced in Ruby 3.4 are parsed with a node type of
8
+ # `itblock` instead of block. Cops that define `block` handlers
9
+ # need to define `itblock` handlers or disable this cop for them.
10
+ #
11
+ # @example
12
+ #
13
+ # # bad
14
+ # class BlockRelatedCop < Base
15
+ # def on_block(node)
16
+ # end
17
+ # end
18
+ #
19
+ # # good
20
+ # class BlockRelatedCop < Base
21
+ # def on_block(node)
22
+ # end
23
+ #
24
+ # alias on_itblock on_block
25
+ # end
26
+ #
27
+ # class BlockRelatedCop < Base
28
+ # def on_block(node)
29
+ # end
30
+ #
31
+ # alias_method :on_itblock, :on_block
32
+ # end
33
+ #
34
+ # class BlockRelatedCop < Base
35
+ # def on_block(node)
36
+ # end
37
+ #
38
+ # def on_itblock(node)
39
+ # end
40
+ # end
41
+ class ItblockHandler < Base
42
+ MSG = 'Define on_itblock to handle blocks with the `it` parameter.'
43
+
44
+ def on_def(node)
45
+ return unless block_handler?(node)
46
+ return unless node.parent
47
+
48
+ add_offense(node) unless itblock_handler?(node.parent)
49
+ end
50
+
51
+ private
52
+
53
+ # @!method block_handler?(node)
54
+ def_node_matcher :block_handler?, <<~PATTERN
55
+ (def :on_block (args (arg :node)) ...)
56
+ PATTERN
57
+
58
+ # @!method itblock_handler?(node)
59
+ def_node_matcher :itblock_handler?, <<~PATTERN
60
+ {
61
+ `(def :on_itblock (args (arg :node)) ...)
62
+ `(alias (sym :on_itblock) (sym :on_block))
63
+ `(send nil? :alias_method (sym :on_itblock) (sym :on_block))
64
+ }
65
+ PATTERN
66
+ end
67
+ end
68
+ end
69
+ end
@@ -9,6 +9,12 @@ module RuboCop
9
9
  #
10
10
  # @example
11
11
  # # bad
12
+ # node.loc.respond_to?(:begin)
13
+ #
14
+ # # good
15
+ # node.loc?(:begin)
16
+ #
17
+ # # bad
12
18
  # node.loc.respond_to?(:begin) && node.loc.begin
13
19
  #
14
20
  # # good
@@ -29,7 +35,16 @@ module RuboCop
29
35
  class LocationExists < Base
30
36
  extend AutoCorrector
31
37
 
32
- MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
38
+ MSG = 'Use `node.loc?` instead of `loc.respond_to?`.'
39
+ MSG_CORRECTABLE = 'Use `%<replacement>s` instead of `%<source>s`.'
40
+ RESTRICT_ON_SEND = %i[respond_to?].freeze
41
+
42
+ # @!method loc_respond_to?(node)
43
+ def_node_matcher :loc_respond_to?, <<~PATTERN
44
+ (call
45
+ (call $_receiver :loc) :respond_to?
46
+ $(sym _location))
47
+ PATTERN
33
48
 
34
49
  # @!method replaceable_with_loc_is(node)
35
50
  def_node_matcher :replaceable_with_loc_is, <<~PATTERN
@@ -64,6 +79,15 @@ module RuboCop
64
79
  replace_with_loc(node) || replace_with_loc_is(node)
65
80
  end
66
81
 
82
+ def on_send(node)
83
+ return if ignored_node?(node.parent)
84
+
85
+ loc_respond_to?(node) do |receiver, location|
86
+ register_offense(node, replacement(receiver, "loc?(#{location.source})"))
87
+ end
88
+ end
89
+ alias on_csend on_send
90
+
67
91
  private
68
92
 
69
93
  def replace_with_loc(node)
@@ -84,11 +108,13 @@ module RuboCop
84
108
  end
85
109
 
86
110
  def register_offense(node, replacement)
87
- message = format(MSG, replacement: replacement, source: node.source)
111
+ message = format(MSG_CORRECTABLE, replacement: replacement, source: node.source)
88
112
 
89
113
  add_offense(node, message: message) do |corrector|
90
114
  corrector.replace(node, replacement)
91
115
  end
116
+
117
+ ignore_node(node)
92
118
  end
93
119
 
94
120
  def replacement(receiver, rest)
@@ -25,6 +25,7 @@ module RuboCop
25
25
  def_node_matcher :line_send, <<~PATTERN
26
26
  {
27
27
  (send (send _ {:loc :source_range}) {:line :first_line})
28
+ (send (send (send _ :loc) {:begin :end}) :line)
28
29
  (send _ :first_line)
29
30
  }
30
31
  PATTERN
@@ -8,16 +8,16 @@ module RuboCop
8
8
  # method.
9
9
  #
10
10
  # @example
11
- # # bad
12
- # def_node_matcher :foo?, <<~PATTERN
13
- # ...
14
- # PATTERN
11
+ # # bad
12
+ # def_node_matcher :foo?, <<~PATTERN
13
+ # ...
14
+ # PATTERN
15
15
  #
16
- # # good
17
- # # @!method foo?(node)
18
- # def_node_matcher :foo?, <<~PATTERN
19
- # ...
20
- # PATTERN
16
+ # # good
17
+ # # @!method foo?(node)
18
+ # def_node_matcher :foo?, <<~PATTERN
19
+ # ...
20
+ # PATTERN
21
21
  #
22
22
  class NodeMatcherDirective < Base
23
23
  extend AutoCorrector
@@ -146,7 +146,7 @@ module RuboCop
146
146
  end
147
147
  end
148
148
 
149
- # rubocop:disable Metrics/MethodLength
149
+ # rubocop:disable-next Metrics/MethodLength
150
150
  def formatted_message(offense_type, directive, actual_name, method_name)
151
151
  case offense_type
152
152
  when :wrong_name
@@ -166,7 +166,6 @@ module RuboCop
166
166
  format(MSG, method: method_name)
167
167
  end
168
168
  end
169
- # rubocop:enable Metrics/MethodLength
170
169
 
171
170
  def remove_receiver(current)
172
171
  current.delete_prefix('self.')
@@ -202,11 +201,8 @@ module RuboCop
202
201
  def add_newline?(node)
203
202
  # Determine if a blank line should be inserted before the new directive
204
203
  # in order to spread out pattern matchers
205
- return false if node.sibling_index&.zero?
206
- return false unless node.parent
207
-
208
- prev_sibling = node.parent.child_nodes[node.sibling_index - 1]
209
- return false unless prev_sibling && pattern_matcher?(prev_sibling)
204
+ prev_sibling = node.left_sibling
205
+ return false unless prev_sibling.is_a?(AST::Node) && pattern_matcher?(prev_sibling)
210
206
 
211
207
  node.loc.line == last_line(prev_sibling) + 1
212
208
  end
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # AST Processor for NodePattern ASTs, for use with `InternalAffairs/NodePatternGroups`.
8
8
  #
9
9
  # Looks for sequences and subsequences where the first item is a `node_type` node,
10
- # and converts them to `node_sequence` nodes (not a true `Rubocop::AST::NodePattern`
10
+ # and converts them to `node_sequence` nodes (not a true `RuboCop::AST::NodePattern`
11
11
  # node type).
12
12
  #
13
13
  # The resulting AST will be walked by `InternalAffairs::NodePatternGroups::ASTWalker`
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module InternalAffairs
6
- # rubocop:disable InternalAffairs/RedundantSourceRange -- node here is a `NodePattern::Node`
6
+ # rubocop:disable-next InternalAffairs/RedundantSourceRange -- node here is a `NodePattern::Node`
7
7
  class NodePatternGroups
8
8
  # Walks an AST that has been processed by `InternalAffairs::NodePatternGroups::Processor`
9
9
  # in order to find `node_type` and `node_sequence` nodes that can be replaced with a node
@@ -125,7 +125,6 @@ module RuboCop
125
125
  end
126
126
  end
127
127
  end
128
- # rubocop:enable InternalAffairs/RedundantSourceRange
129
128
  end
130
129
  end
131
130
  end
@@ -46,13 +46,6 @@ module RuboCop
46
46
 
47
47
  private
48
48
 
49
- def arguments_range(node)
50
- range_between(
51
- node.first_argument.source_range.begin_pos,
52
- node.last_argument.source_range.end_pos
53
- )
54
- end
55
-
56
49
  def group_satisfied?(group_types, symbol_args)
57
50
  group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
58
51
  end
@@ -75,7 +75,7 @@ module RuboCop
75
75
  @on_csend_definition = node if node.new_identifier.value == :on_csend
76
76
  end
77
77
 
78
- def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
78
+ def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend -- this cop is what enforces the rule, and does not apply to itself
79
79
  return unless (new_identifier = node.first_argument)
80
80
  return unless new_identifier.basic_literal?
81
81
 
@@ -31,15 +31,9 @@ module RuboCop
31
31
  dup_arguments = arguments.dup
32
32
  dup_arguments.delete(config_node)
33
33
 
34
- corrector.replace(offense_range(arguments), dup_arguments.map(&:source).join(', '))
34
+ corrector.replace(arguments_range(node), dup_arguments.map(&:source).join(', '))
35
35
  end
36
36
  end
37
-
38
- private
39
-
40
- def offense_range(arguments)
41
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
42
- end
43
37
  end
44
38
  end
45
39
  end
@@ -46,8 +46,7 @@ module RuboCop
46
46
 
47
47
  def on_block(node)
48
48
  return unless let_rubocop_config_new?(node)
49
-
50
- describe = find_describe_method_node(node)
49
+ return unless (describe = find_describe_method_node(node))
51
50
 
52
51
  unless (exist_config = describe.last_argument.source == ':config')
53
52
  additional_message = ' and specify `:config` in `describe`'
@@ -65,7 +64,10 @@ module RuboCop
65
64
  private
66
65
 
67
66
  def find_describe_method_node(block_node)
68
- block_node.ancestors.find { |node| node.block_type? && node.method?(:describe) }.send_node
67
+ describe = block_node.ancestors.find do |ancestor|
68
+ ancestor.block_type? && ancestor.method?(:describe)
69
+ end
70
+ describe&.send_node
69
71
  end
70
72
  end
71
73
  end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def on_if(node)
112
- traverse_condition(node.condition) do |cond|
112
+ node.condition.each_node(:send) do |cond|
113
113
  add_offense(cond, message: MSG_FOR_CONDITIONAL_USE) if style_detected_api_used?(cond)
114
114
  end
115
115
  end
@@ -134,12 +134,6 @@ module RuboCop
134
134
  no_acceptable_style_check(node) ||
135
135
  style_detected_check(node)
136
136
  end
137
-
138
- def traverse_condition(condition, &block)
139
- yield condition if condition.send_type?
140
-
141
- condition.each_child_node { |child| traverse_condition(child, &block) }
142
- end
143
137
  end
144
138
  end
145
139
  end
@@ -7,11 +7,11 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  #
10
- # # bad
11
- # expect(cop.messages).to eq([described_class::MSG])
10
+ # # bad
11
+ # expect(cop.messages).to eq([described_class::MSG])
12
12
  #
13
- # # good
14
- # expect(cop.messages).to eq(['Do not write bad code like that.'])
13
+ # # good
14
+ # expect(cop.messages).to eq(['Do not write bad code like that.'])
15
15
  #
16
16
  class UselessMessageAssertion < Base
17
17
  MSG = 'Do not specify cop behavior using `described_class::MSG`.'
@@ -7,6 +7,7 @@ require_relative 'internal_affairs/empty_line_between_expect_offense_and_correct
7
7
  require_relative 'internal_affairs/example_description'
8
8
  require_relative 'internal_affairs/example_heredoc_delimiter'
9
9
  require_relative 'internal_affairs/inherit_deprecated_cop_class'
10
+ require_relative 'internal_affairs/itblock_handler'
10
11
  require_relative 'internal_affairs/lambda_or_proc'
11
12
  require_relative 'internal_affairs/location_exists'
12
13
  require_relative 'internal_affairs/location_expression'
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Check that the arguments on a multi-line method call are aligned.
6
+ # Checks that the arguments on a multi-line method call are aligned.
7
7
  #
8
8
  # @example EnforcedStyle: with_first_argument (default)
9
9
  # # good
@@ -52,8 +52,8 @@ module RuboCop
52
52
  'following the first line of a multi-line method call.'
53
53
 
54
54
  def on_send(node)
55
- return if !multiple_arguments?(node) || (node.send_type? && node.method?(:[]=)) ||
56
- autocorrect_incompatible_with_other_cops?
55
+ return if !multiple_arguments?(node) || (node.call_type? && node.method?(:[]=)) ||
56
+ binary_operator_call?(node) || autocorrect_incompatible_with_other_cops?
57
57
 
58
58
  items = flattened_arguments(node)
59
59
 
@@ -64,6 +64,10 @@ module RuboCop
64
64
 
65
65
  private
66
66
 
67
+ def binary_operator_call?(node)
68
+ node.binary_operation? && !node.method?(:[]) && !node.loc.dot
69
+ end
70
+
67
71
  def autocorrect_incompatible_with_other_cops?
68
72
  with_first_argument_style? && enforce_hash_argument_with_separator?
69
73
  end
@@ -81,6 +85,8 @@ module RuboCop
81
85
  last_arg = node.last_argument
82
86
 
83
87
  if last_arg.hash_type? && !last_arg.braces?
88
+ return items if enforce_hash_argument_with_separator?
89
+
84
90
  items += last_arg.pairs
85
91
  else
86
92
  items << last_arg
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Check that the elements of a multi-line array literal are
6
+ # Checks that the elements of a multi-line array literal are
7
7
  # aligned.
8
8
  #
9
9
  # @example EnforcedStyle: with_first_element (default)
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
15
15
  # by default. On the other hand, `||= begin` that this cop targets tends to
16
16
  # align with the start of the line, it defaults to `EnforcedStyleAlignWith: start_of_line`.
17
- # These style can be configured by each cop.
17
+ # These styles can be configured by each cop.
18
18
  #
19
19
  # @example EnforcedStyleAlignWith: start_of_line (default)
20
20
  # # bad
@@ -18,6 +18,10 @@ module RuboCop
18
18
  # `either` (which is the default) : the `end` is allowed to be in either
19
19
  # location. The autocorrect will default to `start_of_line`.
20
20
  #
21
+ # When the `do` or `{` appears on a continuation line of multiline
22
+ # method arguments, the start of the line where the method is called
23
+ # is used as the alignment target instead of that continuation line.
24
+ #
21
25
  # @example EnforcedStyleAlignWith: either (default)
22
26
  # # bad
23
27
  #
@@ -64,6 +68,7 @@ module RuboCop
64
68
  # end
65
69
  #
66
70
  class BlockAlignment < Base
71
+ include Alignment
67
72
  include ConfigurableEnforcedStyle
68
73
  include RangeHelp
69
74
  extend AutoCorrector
@@ -116,6 +121,7 @@ module RuboCop
116
121
  end_loc = block_node.loc.end
117
122
  return unless begins_its_line?(end_loc)
118
123
 
124
+ start_node = start_for_line_node(block_node) if style == :start_of_line
119
125
  start_loc = start_node.source_range
120
126
  return unless start_loc.column != end_loc.column || style == :start_of_block
121
127
 
@@ -149,6 +155,32 @@ module RuboCop
149
155
  else
150
156
  start_for_line_node(node)
151
157
  end
158
+
159
+ if using_tabs? && (indentation = anchor_indentation(ancestor_node, node))
160
+ replace_end_indentation(corrector, node, indentation)
161
+ else
162
+ shift_end_to_start_col(corrector, ancestor_node, node)
163
+ end
164
+ end
165
+
166
+ def anchor_indentation(ancestor_node, node)
167
+ if style == :start_of_block
168
+ do_line_anchor_loc(node, node.loc.begin).source_line[/\A\s*/]
169
+ else
170
+ anchor_loc = (ancestor_node || node).source_range
171
+ anchor_loc.source_line[/\A\s*/] if begins_its_line?(anchor_loc)
172
+ end
173
+ end
174
+
175
+ def replace_end_indentation(corrector, node, indentation)
176
+ loc_end = node.loc.end
177
+ whitespace = range_between(loc_end.begin_pos - loc_end.column, loc_end.begin_pos)
178
+ return if whitespace.source == indentation
179
+
180
+ corrector.replace(whitespace, indentation)
181
+ end
182
+
183
+ def shift_end_to_start_col(corrector, ancestor_node, node)
152
184
  start_col = compute_start_col(ancestor_node, node)
153
185
  loc_end = node.loc.end
154
186
  delta = start_col - loc_end.column
@@ -196,23 +228,34 @@ module RuboCop
196
228
 
197
229
  def compute_do_source_line_column(node, end_loc)
198
230
  do_loc = node.loc.begin # Actually it's either do or {.
231
+ anchor_loc = do_line_anchor_loc(node, do_loc)
199
232
 
200
233
  # We've found that "end" is not aligned with the start node (which
201
234
  # can be a block, a variable assignment, etc). But we also allow
202
235
  # the "end" to be aligned with the start of the line where the "do"
203
236
  # is, which is a style some people use in multi-line chains of
204
237
  # blocks.
205
- match = /\S.*/.match(do_loc.source_line)
238
+ match = /\S.*/.match(anchor_loc.source_line)
206
239
  indentation_of_do_line = match.begin(0)
207
- return unless end_loc.column != indentation_of_do_line || style == :start_of_line
240
+ permitted_columns = permitted_do_line_columns(do_loc, indentation_of_do_line)
241
+ return if permitted_columns.include?(end_loc.column) && style != :start_of_line
208
242
 
209
243
  {
210
244
  source: match[0],
211
- line: do_loc.line,
245
+ line: anchor_loc.line,
212
246
  column: indentation_of_do_line
213
247
  }
214
248
  end
215
249
 
250
+ # `end` aligned with an argument continuation line that holds the `do`
251
+ # was accepted before the anchor moved to the method dispatch line;
252
+ # keep accepting it so that such code does not become an offense.
253
+ def permitted_do_line_columns(do_loc, indentation_of_do_line)
254
+ columns = [indentation_of_do_line]
255
+ columns << (do_loc.source_line =~ /\S/) if style == :either
256
+ columns
257
+ end
258
+
216
259
  def loc_to_source_line_column(loc)
217
260
  {
218
261
  source: loc.source.lines.to_a.first.chomp,
@@ -239,7 +282,7 @@ module RuboCop
239
282
  def compute_start_col(ancestor_node, node)
240
283
  if style == :start_of_block
241
284
  do_loc = node.loc.begin
242
- return do_loc.source_line =~ /\S/
285
+ return do_line_anchor_loc(node, do_loc).source_line =~ /\S/
243
286
  end
244
287
  (ancestor_node || node).source_range.column
245
288
  end
@@ -253,6 +296,43 @@ module RuboCop
253
296
 
254
297
  corrector.remove(range)
255
298
  end
299
+
300
+ # When the `do` or `{` is on a continuation line of multiline method
301
+ # arguments, the indentation of that line is not a meaningful
302
+ # alignment target; anchor on the method dispatch position instead.
303
+ def do_line_anchor_loc(node, do_loc)
304
+ if do_line_begins_inside_argument?(node, do_loc)
305
+ node.send_node.selector || node.send_node.source_range
306
+ else
307
+ do_loc
308
+ end
309
+ end
310
+
311
+ # rubocop:disable-next Metrics/AbcSize
312
+ def do_line_begins_inside_argument?(node, do_loc)
313
+ line_begin_pos = do_loc.begin_pos - do_loc.column
314
+ first_char_pos = line_begin_pos + (do_loc.source_line =~ /\S/)
315
+ return false unless inside_parentheses?(node, first_char_pos)
316
+
317
+ (node.send_node.arguments + node.arguments).any? do |argument|
318
+ argument.source_range.begin_pos <= first_char_pos &&
319
+ first_char_pos < argument.source_range.end_pos
320
+ end
321
+ end
322
+
323
+ # The continuation line indentation is only an unmeaningful alignment target when
324
+ # it is dictated by an opening delimiter, i.e. the line begins inside `(` or `[`.
325
+ # For a bare argument list without parentheses the indentation is the author's
326
+ # deliberate alignment, so the anchor must not move to the method dispatch line.
327
+ def inside_parentheses?(node, pos)
328
+ preceding_tokens = processed_source.tokens.select do |token|
329
+ token.begin_pos >= node.source_range.begin_pos && token.begin_pos < pos
330
+ end
331
+ opens = preceding_tokens.count { |token| token.left_parens? || token.left_bracket? }
332
+ closes = preceding_tokens.count { |token| token.right_parens? || token.right_bracket? }
333
+
334
+ opens > closes
335
+ end
256
336
  end
257
337
  end
258
338
  end
@@ -128,7 +128,9 @@ module RuboCop
128
128
  return if case_match_node.single_line?
129
129
  return if enforced_style_end? && end_and_last_conditional_same_line?(case_match_node)
130
130
 
131
- case_match_node.each_in_pattern { |in_pattern_node| check_when(in_pattern_node, 'in') }
131
+ case_match_node.in_pattern_branches.each do |in_pattern_node|
132
+ check_when(in_pattern_node, 'in')
133
+ end
132
134
  end
133
135
 
134
136
  private
@@ -162,8 +164,12 @@ module RuboCop
162
164
  cop_config['IndentOneStep']
163
165
  end
164
166
 
167
+ # Under tabs one step is a single tab character, which counts as one column
168
+ # regardless of the configured indentation width.
165
169
  def indentation_width
166
- indent_one_step? ? configured_indentation_width : 0
170
+ return 0 unless indent_one_step?
171
+
172
+ using_tabs? ? 1 : configured_indentation_width
167
173
  end
168
174
 
169
175
  def incorrect_style(when_node, branch_type)
@@ -174,8 +180,10 @@ module RuboCop
174
180
  detect_incorrect_style(when_node)
175
181
 
176
182
  whitespace = whitespace_range(when_node)
183
+ next unless whitespace.source.strip.empty?
177
184
 
178
- corrector.replace(whitespace, replacement(when_node)) if whitespace.source.strip.empty?
185
+ indentation = replacement(when_node)
186
+ corrector.replace(whitespace, indentation) if indentation
179
187
  end
180
188
  end
181
189
 
@@ -191,10 +199,7 @@ module RuboCop
191
199
  end
192
200
 
193
201
  def base_column(case_node, base)
194
- case base
195
- when :case then case_node.location.keyword.column
196
- when :end then case_node.location.end.column
197
- end
202
+ base_location(case_node, base)&.column
198
203
  end
199
204
 
200
205
  def whitespace_range(node)
@@ -205,13 +210,26 @@ module RuboCop
205
210
  end
206
211
 
207
212
  def replacement(node)
213
+ base_loc = configured_base_location(node)
214
+
215
+ return ' ' * (base_loc.column + indentation_width) unless using_tabs?
216
+ return unless begins_its_line?(base_loc)
217
+
218
+ base_loc.source_line[/\A\s*/] + ("\t" * indentation_width)
219
+ end
220
+
221
+ def configured_base_location(node)
208
222
  case_node = node.each_ancestor(:case, :case_match).first
209
223
  base_type = cop_config[style_parameter_name] == 'end' ? :end : :case
210
224
 
211
- column = base_column(case_node, base_type)
212
- column += indentation_width
225
+ base_location(case_node, base_type)
226
+ end
213
227
 
214
- ' ' * column
228
+ def base_location(case_node, base)
229
+ case base
230
+ when :case then case_node.location.keyword
231
+ when :end then case_node.location.end
232
+ end
215
233
  end
216
234
  end
217
235
  end