rubocop 1.71.1 → 1.91.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 (661) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +883 -168
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +47 -4
  7. data/exe/rubocop +2 -9
  8. data/lib/rubocop/cache_config.rb +29 -0
  9. data/lib/rubocop/cached_data.rb +7 -2
  10. data/lib/rubocop/changed_files.rb +112 -0
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
  12. data/lib/rubocop/cli/command/execute_runner.rb +52 -1
  13. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  14. data/lib/rubocop/cli/command/lsp.rb +1 -1
  15. data/lib/rubocop/cli/command/mcp.rb +19 -0
  16. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  17. data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
  18. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
  19. data/lib/rubocop/cli.rb +58 -17
  20. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  21. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  22. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  23. data/lib/rubocop/comment_config.rb +92 -48
  24. data/lib/rubocop/config.rb +137 -19
  25. data/lib/rubocop/config_finder.rb +1 -1
  26. data/lib/rubocop/config_loader.rb +72 -49
  27. data/lib/rubocop/config_loader_resolver.rb +94 -28
  28. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  29. data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
  30. data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
  31. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  32. data/lib/rubocop/config_obsoletion.rb +47 -3
  33. data/lib/rubocop/config_store.rb +7 -2
  34. data/lib/rubocop/config_validator.rb +64 -12
  35. data/lib/rubocop/cop/autocorrect_logic.rb +35 -14
  36. data/lib/rubocop/cop/badge.rb +9 -1
  37. data/lib/rubocop/cop/base.rb +93 -21
  38. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -3
  39. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  40. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
  41. data/lib/rubocop/cop/bundler.rb +19 -0
  42. data/lib/rubocop/cop/commissioner.rb +13 -11
  43. data/lib/rubocop/cop/corrector.rb +4 -4
  44. data/lib/rubocop/cop/correctors/alignment_corrector.rb +79 -10
  45. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  46. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
  47. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  48. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -1
  49. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  50. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  51. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +36 -2
  52. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  53. data/lib/rubocop/cop/correctors.rb +28 -0
  54. data/lib/rubocop/cop/documentation.rb +2 -3
  55. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  56. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  57. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  58. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
  59. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -3
  60. data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
  61. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  62. data/lib/rubocop/cop/gemspec.rb +22 -0
  63. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  64. data/lib/rubocop/cop/generator.rb +5 -1
  65. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  66. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  67. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  68. data/lib/rubocop/cop/internal_affairs/location_exists.rb +142 -0
  69. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  70. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +14 -15
  71. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  72. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  73. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  74. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  75. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +2 -2
  76. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  77. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  78. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  79. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  80. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  81. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  82. data/lib/rubocop/cop/internal_affairs.rb +3 -16
  83. data/lib/rubocop/cop/layout/argument_alignment.rb +4 -2
  84. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  85. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  86. data/lib/rubocop/cop/layout/block_alignment.rb +59 -4
  87. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  88. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  89. data/lib/rubocop/cop/layout/class_structure.rb +163 -35
  90. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  91. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  92. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  93. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  94. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  95. data/lib/rubocop/cop/layout/else_alignment.rb +3 -15
  96. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  97. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +27 -9
  98. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  99. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
  100. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  101. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  102. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  103. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  104. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +13 -2
  105. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
  106. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  107. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  108. data/lib/rubocop/cop/layout/end_alignment.rb +9 -3
  109. data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
  110. data/lib/rubocop/cop/layout/first_argument_indentation.rb +56 -3
  111. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  112. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  113. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +20 -15
  114. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  115. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  116. data/lib/rubocop/cop/layout/hash_alignment.rb +11 -13
  117. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +3 -3
  118. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  119. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  120. data/lib/rubocop/cop/layout/indentation_width.rb +157 -10
  121. data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
  122. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +2 -3
  123. data/lib/rubocop/cop/layout/line_length.rb +160 -23
  124. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  125. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  126. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -0
  127. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  128. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  129. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +245 -40
  130. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  131. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  132. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  133. data/lib/rubocop/cop/layout/redundant_line_break.rb +89 -6
  134. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +14 -7
  135. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  136. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  137. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
  138. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -3
  139. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  140. data/lib/rubocop/cop/layout/space_around_operators.rb +30 -4
  141. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  142. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
  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 +42 -36
  145. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  146. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  147. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  148. data/lib/rubocop/cop/layout.rb +114 -0
  149. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  150. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  151. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  152. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
  153. data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
  154. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  155. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  156. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  157. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  158. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
  159. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  160. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  161. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  162. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +240 -0
  163. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  164. data/lib/rubocop/cop/lint/debugger.rb +13 -4
  165. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  166. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  167. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  168. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  169. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  170. data/lib/rubocop/cop/lint/duplicate_methods.rb +506 -41
  171. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  172. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  173. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  174. data/lib/rubocop/cop/lint/empty_conditional_body.rb +20 -65
  175. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  176. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  177. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  178. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  179. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  180. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -8
  181. data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
  182. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  183. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  184. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  185. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  186. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  187. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  188. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  189. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  190. data/lib/rubocop/cop/lint/literal_as_condition.rb +137 -11
  191. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  192. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +13 -19
  193. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
  194. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +44 -22
  195. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  196. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  197. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  198. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  199. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  200. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  201. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  202. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  203. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +4 -4
  204. data/lib/rubocop/cop/lint/number_conversion.rb +19 -10
  205. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  206. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +11 -0
  207. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  208. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  209. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  210. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  211. data/lib/rubocop/cop/lint/raise_exception.rb +30 -11
  212. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  213. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +149 -39
  214. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  215. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
  216. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  217. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -25
  218. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -12
  219. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  220. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +267 -0
  221. data/lib/rubocop/cop/lint/redundant_with_index.rb +5 -3
  222. data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -0
  223. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  224. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  225. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  226. data/lib/rubocop/cop/lint/require_range_parentheses.rb +3 -2
  227. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  228. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  229. data/lib/rubocop/cop/lint/rescue_type.rb +2 -2
  230. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  231. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +28 -4
  232. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +9 -5
  233. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  234. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  235. data/lib/rubocop/cop/lint/self_assignment.rb +63 -6
  236. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  237. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  238. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  239. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -1
  240. data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
  241. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  242. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  243. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  244. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +122 -0
  245. data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
  246. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  247. data/lib/rubocop/cop/lint/to_enum_arguments.rb +73 -5
  248. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  249. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  250. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  251. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +36 -10
  252. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  253. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
  254. data/lib/rubocop/cop/lint/unreachable_code.rb +16 -9
  255. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  256. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  257. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  258. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  259. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  260. data/lib/rubocop/cop/lint/useless_access_modifier.rb +31 -6
  261. data/lib/rubocop/cop/lint/useless_assignment.rb +56 -27
  262. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +107 -0
  263. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
  264. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  265. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
  266. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  267. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -3
  268. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +13 -7
  269. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
  270. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  271. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +201 -0
  272. data/lib/rubocop/cop/lint/void.rb +60 -21
  273. data/lib/rubocop/cop/lint.rb +179 -0
  274. data/lib/rubocop/cop/message_annotator.rb +7 -3
  275. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  276. data/lib/rubocop/cop/metrics/block_length.rb +2 -1
  277. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  278. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  279. data/lib/rubocop/cop/metrics/method_length.rb +3 -2
  280. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  281. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  282. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  283. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  284. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  285. data/lib/rubocop/cop/metrics.rb +31 -0
  286. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  287. data/lib/rubocop/cop/migration.rb +13 -0
  288. data/lib/rubocop/cop/mixin/alignment.rb +3 -3
  289. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  290. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
  291. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  292. data/lib/rubocop/cop/mixin/check_line_breakable.rb +27 -9
  293. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -7
  294. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  295. data/lib/rubocop/cop/mixin/comments_help.rb +2 -3
  296. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  297. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  298. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  299. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  300. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  301. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  302. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  303. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
  304. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  305. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  306. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +44 -16
  307. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +29 -26
  308. data/lib/rubocop/cop/mixin/hash_subset.rb +28 -6
  309. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  310. data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
  311. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  312. data/lib/rubocop/cop/mixin/line_length_help.rb +52 -11
  313. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  314. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  315. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  316. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  317. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  318. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
  319. data/lib/rubocop/cop/mixin/project_index_help.rb +188 -0
  320. data/lib/rubocop/cop/mixin/range_help.rb +16 -5
  321. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
  322. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  323. data/lib/rubocop/cop/mixin/statement_modifier.rb +47 -11
  324. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  325. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  326. data/lib/rubocop/cop/mixin/trailing_comma.rb +23 -6
  327. data/lib/rubocop/cop/mixin.rb +91 -0
  328. data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -0
  329. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  330. data/lib/rubocop/cop/naming/block_forwarding.rb +7 -4
  331. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  332. data/lib/rubocop/cop/naming/file_name.rb +6 -5
  333. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  334. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +13 -6
  335. data/lib/rubocop/cop/naming/method_name.rb +190 -15
  336. data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
  337. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +80 -8
  338. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -6
  339. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  340. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  341. data/lib/rubocop/cop/naming.rb +31 -0
  342. data/lib/rubocop/cop/offense.rb +52 -9
  343. data/lib/rubocop/cop/registry.rb +233 -64
  344. data/lib/rubocop/cop/security/eval.rb +17 -3
  345. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  346. data/lib/rubocop/cop/security/json_load.rb +33 -11
  347. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  348. data/lib/rubocop/cop/security/open.rb +1 -0
  349. data/lib/rubocop/cop/security.rb +19 -0
  350. data/lib/rubocop/cop/severity.rb +12 -0
  351. data/lib/rubocop/cop/style/access_modifier_declarations.rb +47 -13
  352. data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
  353. data/lib/rubocop/cop/style/alias.rb +15 -3
  354. data/lib/rubocop/cop/style/and_or.rb +2 -1
  355. data/lib/rubocop/cop/style/arguments_forwarding.rb +49 -37
  356. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  357. data/lib/rubocop/cop/style/array_intersect.rb +136 -38
  358. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
  359. data/lib/rubocop/cop/style/array_join.rb +4 -2
  360. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  361. data/lib/rubocop/cop/style/attr.rb +5 -2
  362. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  363. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  364. data/lib/rubocop/cop/style/bitwise_predicate.rb +7 -1
  365. data/lib/rubocop/cop/style/block_delimiters.rb +43 -38
  366. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  367. data/lib/rubocop/cop/style/case_like_if.rb +6 -8
  368. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  369. data/lib/rubocop/cop/style/class_and_module_children.rb +135 -21
  370. data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
  371. data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
  372. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  373. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  374. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  375. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  376. data/lib/rubocop/cop/style/combinable_loops.rb +7 -2
  377. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  378. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  379. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  380. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  381. data/lib/rubocop/cop/style/concat_array_literals.rb +8 -3
  382. data/lib/rubocop/cop/style/conditional_assignment.rb +54 -24
  383. data/lib/rubocop/cop/style/constant_visibility.rb +23 -12
  384. data/lib/rubocop/cop/style/copyright.rb +27 -12
  385. data/lib/rubocop/cop/style/data_inheritance.rb +25 -0
  386. data/lib/rubocop/cop/style/date_time.rb +4 -4
  387. data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
  388. data/lib/rubocop/cop/style/dig_chain.rb +6 -1
  389. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  390. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  391. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +122 -14
  392. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  393. data/lib/rubocop/cop/style/documentation.rb +53 -6
  394. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  395. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  396. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  397. data/lib/rubocop/cop/style/each_with_object.rb +4 -3
  398. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  399. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  400. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  401. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  402. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  403. data/lib/rubocop/cop/style/empty_literal.rb +11 -2
  404. data/lib/rubocop/cop/style/empty_method.rb +12 -8
  405. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -0
  406. data/lib/rubocop/cop/style/encoding.rb +7 -1
  407. data/lib/rubocop/cop/style/end_block.rb +3 -1
  408. data/lib/rubocop/cop/style/endless_method.rb +191 -19
  409. data/lib/rubocop/cop/style/env_home.rb +4 -0
  410. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  411. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  412. data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -1
  413. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  414. data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
  415. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  416. data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
  417. data/lib/rubocop/cop/style/file_null.rb +6 -4
  418. data/lib/rubocop/cop/style/file_open.rb +84 -0
  419. data/lib/rubocop/cop/style/file_write.rb +21 -16
  420. data/lib/rubocop/cop/style/float_division.rb +25 -17
  421. data/lib/rubocop/cop/style/for.rb +9 -0
  422. data/lib/rubocop/cop/style/format_string.rb +17 -4
  423. data/lib/rubocop/cop/style/format_string_token.rb +86 -16
  424. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  425. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  426. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  427. data/lib/rubocop/cop/style/guard_clause.rb +32 -23
  428. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  429. data/lib/rubocop/cop/style/hash_conversion.rb +28 -12
  430. data/lib/rubocop/cop/style/hash_each_methods.rb +4 -4
  431. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  432. data/lib/rubocop/cop/style/hash_lookup_method.rb +105 -0
  433. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  434. data/lib/rubocop/cop/style/hash_syntax.rb +7 -3
  435. data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
  436. data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
  437. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -9
  438. data/lib/rubocop/cop/style/if_inside_else.rb +25 -20
  439. data/lib/rubocop/cop/style/if_unless_modifier.rb +71 -46
  440. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +15 -19
  441. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
  442. data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -6
  443. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  444. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  445. data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
  446. data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
  447. data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
  448. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  449. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  450. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  451. data/lib/rubocop/cop/style/keyword_parameters_order.rb +20 -10
  452. data/lib/rubocop/cop/style/lambda.rb +12 -1
  453. data/lib/rubocop/cop/style/lambda_call.rb +26 -10
  454. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  455. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  456. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  457. data/lib/rubocop/cop/style/map_into_array.rb +5 -2
  458. data/lib/rubocop/cop/style/map_join.rb +123 -0
  459. data/lib/rubocop/cop/style/map_to_hash.rb +13 -5
  460. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  461. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +31 -15
  462. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  463. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +34 -5
  464. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +12 -7
  465. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  466. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -5
  467. data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
  468. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  469. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  470. data/lib/rubocop/cop/style/module_function.rb +4 -2
  471. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  472. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  473. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  474. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  475. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  476. data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -18
  477. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  478. data/lib/rubocop/cop/style/mutable_constant.rb +111 -12
  479. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
  480. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  481. data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
  482. data/lib/rubocop/cop/style/next.rb +44 -0
  483. data/lib/rubocop/cop/style/nil_comparison.rb +41 -13
  484. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  485. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  486. data/lib/rubocop/cop/style/not.rb +5 -1
  487. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  488. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  489. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  490. data/lib/rubocop/cop/style/object_then.rb +1 -0
  491. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  492. data/lib/rubocop/cop/style/one_line_conditional.rb +22 -13
  493. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  494. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  495. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  496. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  497. data/lib/rubocop/cop/style/parallel_assignment.rb +58 -27
  498. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  499. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  500. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +4 -0
  501. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  502. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  503. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  504. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  505. data/lib/rubocop/cop/style/proc.rb +4 -2
  506. data/lib/rubocop/cop/style/raise_args.rb +9 -9
  507. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  508. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  509. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  510. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  511. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  512. data/lib/rubocop/cop/style/redundant_begin.rb +38 -3
  513. data/lib/rubocop/cop/style/redundant_condition.rb +63 -5
  514. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  515. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
  516. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
  517. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  518. data/lib/rubocop/cop/style/redundant_exception.rb +7 -1
  519. data/lib/rubocop/cop/style/redundant_fetch_block.rb +2 -10
  520. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  521. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  522. data/lib/rubocop/cop/style/redundant_format.rb +319 -0
  523. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  524. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  525. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  526. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  527. data/lib/rubocop/cop/style/redundant_line_continuation.rb +83 -119
  528. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  529. data/lib/rubocop/cop/style/redundant_parentheses.rb +164 -82
  530. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  531. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -0
  532. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  533. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +8 -8
  534. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -0
  535. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  536. data/lib/rubocop/cop/style/redundant_self.rb +20 -7
  537. data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -3
  538. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  539. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  540. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  541. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  542. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  543. data/lib/rubocop/cop/style/regexp_literal.rb +32 -3
  544. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
  545. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  546. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  547. data/lib/rubocop/cop/style/safe_navigation.rb +76 -20
  548. data/lib/rubocop/cop/style/sample.rb +11 -6
  549. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  550. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  551. data/lib/rubocop/cop/style/select_by_regexp.rb +54 -22
  552. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  553. data/lib/rubocop/cop/style/semicolon.rb +45 -14
  554. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  555. data/lib/rubocop/cop/style/single_line_do_end_block.rb +22 -8
  556. data/lib/rubocop/cop/style/single_line_methods.rb +13 -8
  557. data/lib/rubocop/cop/style/sole_nested_conditional.rb +96 -104
  558. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  559. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -1
  560. data/lib/rubocop/cop/style/static_class.rb +21 -0
  561. data/lib/rubocop/cop/style/string_concatenation.rb +31 -15
  562. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  563. data/lib/rubocop/cop/style/struct_inheritance.rb +38 -2
  564. data/lib/rubocop/cop/style/super_arguments.rb +4 -6
  565. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  566. data/lib/rubocop/cop/style/symbol_proc.rb +11 -9
  567. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  568. data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
  569. data/lib/rubocop/cop/style/time_now.rb +41 -0
  570. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
  571. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  572. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  573. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
  574. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  575. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  576. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +18 -19
  577. data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
  578. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  579. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  580. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  581. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -1
  582. data/lib/rubocop/cop/style/word_array.rb +1 -0
  583. data/lib/rubocop/cop/style/yoda_condition.rb +2 -3
  584. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  585. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  586. data/lib/rubocop/cop/style.rb +311 -0
  587. data/lib/rubocop/cop/team.rb +163 -45
  588. data/lib/rubocop/cop/util.rb +7 -10
  589. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  590. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  591. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  592. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  593. data/lib/rubocop/cop/variable_force/variable.rb +28 -10
  594. data/lib/rubocop/cop/variable_force.rb +26 -9
  595. data/lib/rubocop/cops_documentation_generator.rb +49 -15
  596. data/lib/rubocop/directive_comment.rb +147 -5
  597. data/lib/rubocop/ext/regexp_node.rb +0 -1
  598. data/lib/rubocop/feature_loader.rb +0 -6
  599. data/lib/rubocop/file_patterns.rb +9 -1
  600. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  601. data/lib/rubocop/formatter/disabled_config_formatter.rb +57 -14
  602. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  603. data/lib/rubocop/formatter/formatter_set.rb +3 -2
  604. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  605. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  606. data/lib/rubocop/formatter/html_formatter.rb +3 -5
  607. data/lib/rubocop/formatter/json_formatter.rb +11 -6
  608. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  609. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  610. data/lib/rubocop/formatter/offense_count_formatter.rb +2 -3
  611. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  612. data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
  613. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  614. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  615. data/lib/rubocop/formatter/worst_offenders_formatter.rb +2 -3
  616. data/lib/rubocop/formatter.rb +23 -21
  617. data/lib/rubocop/lockfile.rb +18 -0
  618. data/lib/rubocop/lsp/diagnostic.rb +22 -41
  619. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  620. data/lib/rubocop/lsp/routes.rb +136 -33
  621. data/lib/rubocop/lsp/runtime.rb +23 -8
  622. data/lib/rubocop/lsp/server.rb +4 -2
  623. data/lib/rubocop/lsp/stdin_runner.rb +31 -18
  624. data/lib/rubocop/magic_comment.rb +55 -0
  625. data/lib/rubocop/mcp/server.rb +199 -0
  626. data/lib/rubocop/options.rb +129 -21
  627. data/lib/rubocop/path_util.rb +20 -5
  628. data/lib/rubocop/pending_cops_reporter.rb +51 -0
  629. data/lib/rubocop/plugin/configuration_integrator.rb +146 -0
  630. data/lib/rubocop/plugin/load_error.rb +26 -0
  631. data/lib/rubocop/plugin/loader.rb +100 -0
  632. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  633. data/lib/rubocop/plugin.rb +46 -0
  634. data/lib/rubocop/project_index_loader.rb +82 -0
  635. data/lib/rubocop/rake_task.rb +6 -4
  636. data/lib/rubocop/remote_config.rb +14 -12
  637. data/lib/rubocop/result_cache.rb +90 -52
  638. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  639. data/lib/rubocop/rspec/expect_offense.rb +11 -7
  640. data/lib/rubocop/rspec/shared_contexts.rb +85 -3
  641. data/lib/rubocop/rspec/support.rb +4 -0
  642. data/lib/rubocop/runner.rb +294 -100
  643. data/lib/rubocop/server/cache.rb +67 -48
  644. data/lib/rubocop/server/cli.rb +2 -4
  645. data/lib/rubocop/server/client_command/base.rb +10 -0
  646. data/lib/rubocop/server/client_command/exec.rb +2 -1
  647. data/lib/rubocop/server/client_command/start.rb +11 -1
  648. data/lib/rubocop/server/core.rb +8 -0
  649. data/lib/rubocop/server.rb +14 -0
  650. data/lib/rubocop/target_finder.rb +25 -11
  651. data/lib/rubocop/target_ruby.rb +31 -14
  652. data/lib/rubocop/todo_audit.rb +111 -0
  653. data/lib/rubocop/unified_diff.rb +257 -0
  654. data/lib/rubocop/version.rb +48 -10
  655. data/lib/rubocop.rb +30 -682
  656. data/lib/ruby_lsp/rubocop/addon.rb +28 -17
  657. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  658. metadata +116 -19
  659. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
  660. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  661. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
@@ -6,6 +6,36 @@ module RuboCop
6
6
  # Checks for duplicated instance (or singleton) method
7
7
  # definitions.
8
8
  #
9
+ # NOTE: Aliasing a method to itself is allowed, as it indicates that
10
+ # the developer intends to suppress Ruby's method redefinition warnings.
11
+ # See https://bugs.ruby-lang.org/issues/13574.
12
+ #
13
+ # By default the cop can only detect duplicates within a single file.
14
+ # When `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is installed,
15
+ # the cop additionally consults the project-wide index and reports methods
16
+ # whose duplicate definition lives in another file.
17
+ #
18
+ # NOTE: The project index does not record whether a definition in another
19
+ # file is wrapped in a conditional, so a platform-specific redefinition in
20
+ # another file may still be reported. Aliasing the method to itself (see above)
21
+ # before redefining marks the redefinition as intentional and is respected
22
+ # across files. With `AllCops/ActiveSupportExtensionsEnabled: true`, Active
23
+ # Support's redefinition markers (`silence_redefinition_of_method` and
24
+ # `redefine_method`) are honored the same way.
25
+ #
26
+ # NOTE: Methods defined with `define_method` are not recorded in the project
27
+ # index, so a duplicate whose other definition uses `define_method` cannot
28
+ # be detected across files.
29
+ #
30
+ # Cross-file duplicates whose other definition lives in a file matching one
31
+ # of the `AllowedCrossFilePaths` patterns are not reported. This suits files
32
+ # that redefine application methods but are never loaded together with them,
33
+ # such as standalone scripts. Patterns are matched with the same glob (or
34
+ # regexp) semantics as `Exclude`, against the other file's path relative to
35
+ # the directory of the `.rubocop.yml` that configures the cop; absolute
36
+ # patterns are matched against the absolute path. Offenses inside such files
37
+ # themselves are best silenced with an ordinary per-cop `Exclude`.
38
+ #
9
39
  # @example
10
40
  #
11
41
  # # bad
@@ -39,29 +69,151 @@ module RuboCop
39
69
  # end
40
70
  #
41
71
  # alias bar foo
42
- class DuplicateMethods < Base
72
+ #
73
+ # # good
74
+ # alias foo foo
75
+ # def foo
76
+ # 1
77
+ # end
78
+ #
79
+ # # good
80
+ # alias_method :foo, :foo
81
+ # def foo
82
+ # 1
83
+ # end
84
+ #
85
+ # # bad
86
+ # class MyClass
87
+ # extend Forwardable
88
+ #
89
+ # # or with: `def_instance_delegator`, `def_delegators`, `def_instance_delegators`
90
+ # def_delegator :delegation_target, :delegated_method_name
91
+ #
92
+ # def delegated_method_name
93
+ # end
94
+ # end
95
+ #
96
+ # # good
97
+ # class MyClass
98
+ # extend Forwardable
99
+ #
100
+ # def_delegator :delegation_target, :delegated_method_name
101
+ #
102
+ # def non_duplicated_delegated_method_name
103
+ # end
104
+ # end
105
+ #
106
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
107
+ #
108
+ # # good
109
+ # def foo
110
+ # 1
111
+ # end
112
+ #
113
+ # delegate :foo, to: :bar
114
+ #
115
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
116
+ #
117
+ # # bad
118
+ # def foo
119
+ # 1
120
+ # end
121
+ #
122
+ # delegate :foo, to: :bar
123
+ #
124
+ # # good
125
+ # def foo
126
+ # 1
127
+ # end
128
+ #
129
+ # delegate :baz, to: :bar
130
+ #
131
+ # # good - delegate with splat arguments is ignored
132
+ # def foo
133
+ # 1
134
+ # end
135
+ #
136
+ # delegate :foo, **options
137
+ #
138
+ # # good - delegate inside a condition is ignored
139
+ # def foo
140
+ # 1
141
+ # end
142
+ #
143
+ # if cond
144
+ # delegate :foo, to: :bar
145
+ # end
146
+ #
147
+ # # good - Active Support's redefinition markers signal an intentional
148
+ # # redefinition of a method defined in another file
149
+ # silence_redefinition_of_method :foo
150
+ # def foo
151
+ # 1
152
+ # end
153
+ #
154
+ # @example AllowedCrossFilePaths: ['script/**/*'] (default: [])
155
+ # # Cross-file duplicates whose other definition lives in a file
156
+ # # matching one of the patterns are not reported.
157
+ #
158
+ # # good - assuming `AppHelper#format` is also defined in
159
+ # # `script/backfill.rb`, which is never loaded with this file
160
+ # class AppHelper
161
+ # def format
162
+ # end
163
+ # end
164
+ #
165
+ # @example DelegatingMethods: ['delegate', 'expose'] (default: ['delegate'])
166
+ # # A project's own `delegate`-shaped macros can be registered so the
167
+ # # methods they define are recognized (with
168
+ # # `AllCops/ActiveSupportExtensionsEnabled: true`).
169
+ #
170
+ # # bad
171
+ # def foo
172
+ # 1
173
+ # end
174
+ #
175
+ # expose :foo, to: :bar
176
+ #
177
+ class DuplicateMethods < Base # rubocop:disable Metrics/ClassLength
178
+ include ProjectIndexHelp
179
+
43
180
  MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
44
- RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr].freeze
45
- DEF_TYPES = %i[def defs].freeze
181
+
182
+ # Method names the cop registers that can be looked up in the project index:
183
+ # a fully qualified namespace followed by `#` (instance) or `.` (singleton)
184
+ # and the method name.
185
+ INDEXABLE_METHOD_NAME =
186
+ /\A(?<owner>[A-Z]\w*(?:::[A-Z]\w*)*)(?<separator>[#.])(?<name>[^#.]+)\z/.freeze
187
+ # No `RESTRICT_ON_SEND`: the delegating method names are configurable
188
+ # (`DelegatingMethods`), so `on_send` must see every call. The handler
189
+ # returns quickly for calls that are not method definitions, and
190
+ # benchmarks show no measurable cost over the previous fixed list.
46
191
 
47
192
  def initialize(config = nil, options = nil)
48
193
  super
49
194
  @definitions = {}
50
195
  @scopes = Hash.new { |hash, key| hash[key] = [] }
196
+ @intentionally_redefined = Set.new
197
+ end
198
+
199
+ def on_new_investigation
200
+ # The self-alias trick and Active Support's redefinition markers declare
201
+ # an intentional redefinition only within the file that uses them, so the
202
+ # tracked names do not carry over.
203
+ @intentionally_redefined = Set.new
204
+ super
51
205
  end
52
206
 
53
207
  def on_def(node)
54
208
  # if a method definition is inside an if, it is very likely
55
209
  # that a different definition is used depending on platform, etc.
56
210
  return if node.each_ancestor.any?(&:if_type?)
57
- return if possible_dsl?(node)
58
211
 
59
212
  found_instance_method(node, node.method_name)
60
213
  end
61
214
 
62
215
  def on_defs(node)
63
216
  return if node.each_ancestor.any?(&:if_type?)
64
- return if possible_dsl?(node)
65
217
 
66
218
  if node.receiver.const_type?
67
219
  _, const_name = *node.receiver
@@ -73,32 +225,113 @@ module RuboCop
73
225
 
74
226
  # @!method method_alias?(node)
75
227
  def_node_matcher :method_alias?, <<~PATTERN
76
- (alias (sym $_name) sym)
228
+ (alias (sym $_name) (sym $_original_name))
77
229
  PATTERN
78
230
 
79
231
  def on_alias(node)
80
- return unless (name = method_alias?(node))
232
+ name, original_name = method_alias?(node)
233
+ return unless name && original_name
234
+
235
+ if name == original_name
236
+ track_intentional_redefinition(node, name)
237
+ return
238
+ end
81
239
  return if node.ancestors.any?(&:if_type?)
82
- return if possible_dsl?(node)
83
240
 
84
241
  found_instance_method(node, name)
85
242
  end
86
243
 
87
244
  # @!method alias_method?(node)
88
245
  def_node_matcher :alias_method?, <<~PATTERN
89
- (send nil? :alias_method (sym $_name) _)
246
+ (send nil? :alias_method (sym $_name) (sym $_original_name))
247
+ PATTERN
248
+
249
+ # Matches the argument shape of an Active Support `delegate` call
250
+ # (`delegate :a, :b, to: :target`), regardless of the method name; the
251
+ # name is checked separately against `DelegatingMethods`.
252
+ # @!method delegate_args(node)
253
+ def_node_matcher :delegate_args, <<~PATTERN
254
+ (send nil? _
255
+ ({sym str} $_)+
256
+ (hash <(pair (sym :to) {sym str}) ...>)
257
+ )
258
+ PATTERN
259
+
260
+ # @!method delegator?(node)
261
+ def_node_matcher :delegator?, <<~PATTERN
262
+ (send nil? {:def_delegator :def_instance_delegator}
263
+ {
264
+ {sym str} ({sym str} $_) |
265
+ {sym str} {sym str} ({sym str} $_)
266
+ }
267
+ )
268
+ PATTERN
269
+
270
+ # @!method delegators?(node)
271
+ def_node_matcher :delegators?, <<~PATTERN
272
+ (send nil? {:def_delegators :def_instance_delegators}
273
+ {sym str}
274
+ ({sym str} $_)+
275
+ )
276
+ PATTERN
277
+
278
+ # Matches Active Support's markers of an intentional method redefinition:
279
+ # `silence_redefinition_of_method :name` suppresses Ruby's redefinition
280
+ # warning for a subsequent definition of `name`, and
281
+ # `redefine_method(:name) { ... }` both silences the warning and redefines.
282
+ # @!method active_support_redefinition_marker(node)
283
+ def_node_matcher :active_support_redefinition_marker, <<~PATTERN
284
+ (send nil? {:silence_redefinition_of_method :redefine_method} ({sym str} $_) ...)
90
285
  PATTERN
91
286
 
92
287
  # @!method sym_name(node)
93
288
  def_node_matcher :sym_name, '(sym $_name)'
94
- def on_send(node)
95
- if (name = alias_method?(node))
96
- return if node.ancestors.any?(&:if_type?)
97
- return if possible_dsl?(node)
289
+
290
+ # @!method class_or_module_new_block?(node)
291
+ def_node_matcher :class_or_module_new_block?, <<~PATTERN
292
+ (block
293
+ (send (const _ {:Class :Module}) :new ...)
294
+ ...)
295
+ PATTERN
296
+
297
+ # @!method class_new_block?(node)
298
+ def_node_matcher :class_new_block?, <<~PATTERN
299
+ (block
300
+ (send (const _ :Class) :new ...)
301
+ ...)
302
+ PATTERN
303
+
304
+ def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
305
+ name, original_name = alias_method?(node)
306
+
307
+ if name && original_name
308
+ if name == original_name
309
+ track_intentional_redefinition(node, name)
310
+ return
311
+ end
312
+ return if inside_condition?(node)
98
313
 
99
314
  found_instance_method(node, name)
100
315
  elsif (attr = node.attribute_accessor?)
101
316
  on_attr(node, *attr)
317
+ elsif delegating_method?(node) && (names = delegate_args(node))
318
+ return if inside_condition?(node)
319
+
320
+ on_delegate(node, names)
321
+ elsif (name = delegator?(node))
322
+ return if inside_condition?(node)
323
+
324
+ found_instance_method(node, name)
325
+ elsif (names = delegators?(node))
326
+ return if inside_condition?(node)
327
+
328
+ names.each { |name| found_instance_method(node, name) }
329
+ elsif (name = active_support_redefinition_marker(node))
330
+ # `redefine_method` takes a block; scope resolution must start from the
331
+ # block node, since `parent_module_name` cannot see through a block
332
+ # ancestor that is not a module constructor.
333
+ track_intentional_redefinition(node.block_node || node, name) if
334
+ active_support_extensions_enabled?
102
335
  end
103
336
  end
104
337
 
@@ -113,9 +346,16 @@ module RuboCop
113
346
 
114
347
  def check_self_receiver(node, name)
115
348
  enclosing = node.parent_module_name
116
- return unless enclosing
349
+ if enclosing
350
+ found_method(node, "#{enclosing}.#{name}")
351
+ elsif (anon_block = anonymous_class_block(node))
352
+ scope = qualified_name(anon_block.parent_module_name, nil, 'Object')
353
+ found_method(node, "#{scope}.#{name}", scope_id: anon_block_scope_id(anon_block))
354
+ end
355
+ end
117
356
 
118
- found_method(node, "#{enclosing}.#{name}")
357
+ def inside_condition?(node)
358
+ node.ancestors.any?(&:if_type?)
119
359
  end
120
360
 
121
361
  def message_for_dup(node, method_name, key)
@@ -123,17 +363,104 @@ module RuboCop
123
363
  current: source_location(node))
124
364
  end
125
365
 
366
+ # Recognizing a delegating call as a method definition is Active
367
+ # Support behavior, so it stays gated on `ActiveSupportExtensionsEnabled`
368
+ # as it was when only `delegate` was supported. `DelegatingMethods` lets
369
+ # a project register its own `delegate`-shaped macros.
370
+ def delegating_method?(node)
371
+ active_support_extensions_enabled? &&
372
+ delegating_methods.include?(node.method_name.to_s)
373
+ end
374
+
375
+ def delegating_methods
376
+ cop_config.fetch('DelegatingMethods', ['delegate'])
377
+ end
378
+
379
+ def on_delegate(node, method_names)
380
+ name_prefix = delegate_prefix(node)
381
+
382
+ method_names.each do |name|
383
+ name = "#{name_prefix}_#{name}" if name_prefix
384
+
385
+ found_instance_method(node, name)
386
+ end
387
+ end
388
+
389
+ def delegate_prefix(node)
390
+ kwargs_node = node.last_argument
391
+
392
+ return unless (prefix = hash_value(kwargs_node, :prefix))
393
+
394
+ if prefix.true_type?
395
+ hash_value(kwargs_node, :to).value
396
+ elsif prefix.type?(:sym, :str)
397
+ prefix.value
398
+ end
399
+ end
400
+
401
+ def hash_value(node, key)
402
+ node.pairs.find { |pair| pair.key.value == key }&.value
403
+ end
404
+
126
405
  def found_instance_method(node, name)
127
- return found_sclass_method(node, name) unless (scope = node.parent_module_name)
406
+ if (scope = node.parent_module_name)
407
+ found_method(node, "#{humanize_scope(scope)}#{name}")
408
+ elsif (anon_block = anonymous_class_block(node))
409
+ base = qualified_name(anon_block.parent_module_name, nil, 'Object')
410
+ scope = node.each_ancestor(:sclass).any? ? "#<Class:#{base}>" : base
411
+ found_method(
412
+ node, "#{humanize_scope(scope)}#{name}", scope_id: anon_block_scope_id(anon_block)
413
+ )
414
+ else
415
+ found_sclass_method(node, name)
416
+ end
417
+ end
128
418
 
129
- # Humanize the scope
419
+ def humanize_scope(scope)
130
420
  scope = scope.sub(
131
421
  /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/,
132
422
  '\k<name>.'
133
423
  )
134
- scope << '#' unless scope.end_with?('.')
424
+ scope.end_with?('.') ? scope : "#{scope}#"
425
+ end
426
+
427
+ def anonymous_class_block(node)
428
+ first_block = node.each_ancestor(:block).first
429
+ return unless class_or_module_new_block?(first_block)
430
+ return if first_block.parent&.type?(:lvasgn)
431
+ return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? }
432
+
433
+ first_block
434
+ end
435
+
436
+ def anon_block_scope_id(anon_block)
437
+ parent = anon_block.parent
438
+ return unless parent&.type?(:any_block, :begin, :call, :casgn, :ivasgn, :any_def)
439
+
440
+ if (receiver = scope_receiver(parent, anon_block))
441
+ "#{receiver.source}.#{parent.method_name}"
442
+ elsif !parent.begin_type? || parent.parent&.any_block_type?
443
+ anon_block_identity(anon_block)
444
+ end
445
+ end
135
446
 
136
- found_method(node, "#{scope}#{name}")
447
+ # When a Class.new block is passed as an argument to a named-receiver
448
+ # method call (e.g. T.cast(Class.new(Base) do ... end, ...)), the
449
+ # receiver-based scope id (e.g. "T.cast") is the same for every call,
450
+ # causing false positives for methods defined in distinct anonymous
451
+ # classes. Return nil so the block falls through to the unique
452
+ # source-location-based scope id.
453
+ # Module.new blocks are excluded because they may be intentionally
454
+ # mixed into the same target via prepend/include/extend.
455
+ def scope_receiver(parent, anon_block)
456
+ return if class_new_block?(anon_block) && parent.call_type?
457
+
458
+ named_receiver(parent)
459
+ end
460
+
461
+ def named_receiver(node)
462
+ receiver = node.receiver
463
+ receiver unless class_or_module_new_block?(receiver)
137
464
  end
138
465
 
139
466
  def found_sclass_method(node, name)
@@ -146,27 +473,60 @@ module RuboCop
146
473
  found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
147
474
  end
148
475
 
149
- def found_method(node, method_name)
476
+ def found_method(node, method_name, scope_id: nil)
150
477
  key = method_key(node, method_name)
478
+ key = "#{key}@#{scope_id}" if scope_id
151
479
  scope = node.each_ancestor(:rescue, :ensure).first&.type
152
480
 
153
481
  if @definitions.key?(key)
154
- if scope && !@scopes[scope].include?(key)
155
- @definitions[key] = node
156
- @scopes[scope] << key
157
- return
158
- end
159
-
160
- message = message_for_dup(node, method_name, key)
161
-
162
- add_offense(location(node), message: message)
482
+ found_redefinition(node, method_name, key, scope)
163
483
  else
164
484
  @definitions[key] = node
485
+ check_cross_file_duplicate(node, method_name) if scope_id.nil? && scope.nil?
486
+ end
487
+ end
488
+
489
+ def found_redefinition(node, method_name, key, scope)
490
+ if scope && !@scopes[scope].include?(key)
491
+ @definitions[key] = node
492
+ @scopes[scope] << key
493
+ elsif intentional_cross_file_redefinition?(node, method_name, key) ||
494
+ allowed_cross_file_redefinition?(node, key)
495
+ @definitions[key] = node
496
+ else
497
+ add_offense(location(node), message: message_for_dup(node, method_name, key))
165
498
  end
166
499
  end
167
500
 
501
+ # `AllowedCrossFilePaths` also covers duplicates detected without the index,
502
+ # when the cop instance carries definitions over from an earlier file of the
503
+ # same run.
504
+ def allowed_cross_file_redefinition?(node, key)
505
+ other_path = @definitions[key].source_range.source_buffer.name
506
+ return false if other_path == node.source_range.source_buffer.name
507
+
508
+ allowed_cross_file_path?(other_path)
509
+ end
510
+
511
+ # The self-alias trick (`alias foo foo` or `alias_method :foo, :foo` right before
512
+ # a `def`) suppresses Ruby's method redefinition warning, signaling an intentional
513
+ # redefinition of a method defined in another file. Active Support's redefinition
514
+ # markers (tracked when `ActiveSupportExtensionsEnabled` is on) signal the same.
515
+ def intentional_cross_file_redefinition?(node, method_name, key)
516
+ @intentionally_redefined.include?(method_name) &&
517
+ @definitions[key].source_range.source_buffer.name !=
518
+ node.source_range.source_buffer.name
519
+ end
520
+
521
+ def track_intentional_redefinition(node, name)
522
+ scope = node.parent_module_name
523
+ return unless scope
524
+
525
+ @intentionally_redefined << "#{humanize_scope(scope)}#{name}"
526
+ end
527
+
168
528
  def method_key(node, method_name)
169
- if (ancestor_def = node.each_ancestor(*DEF_TYPES).first)
529
+ if (ancestor_def = node.each_ancestor(:any_def).first)
170
530
  "#{ancestor_def.method_name}.#{method_name}"
171
531
  else
172
532
  method_name
@@ -174,7 +534,7 @@ module RuboCop
174
534
  end
175
535
 
176
536
  def location(node)
177
- if DEF_TYPES.include?(node.type)
537
+ if node.any_def_type?
178
538
  node.loc.keyword.join(node.loc.name)
179
539
  else
180
540
  node.source_range
@@ -237,21 +597,126 @@ module RuboCop
237
597
  end
238
598
  end
239
599
 
240
- def possible_dsl?(node)
241
- # DSL methods may evaluate a block in the context of a newly created
242
- # class or module
243
- # Assume that if a method definition is inside any block call which
244
- # we can't identify, it could be a DSL
245
- node.each_ancestor(:block).any? do |ancestor|
246
- !ancestor.method?(:class_eval) && !ancestor.class_constructor?
247
- end
248
- end
249
-
250
600
  def source_location(node)
251
601
  range = node.source_range
252
602
  path = smart_path(range.source_buffer.name)
253
603
  "#{path}:#{range.line}"
254
604
  end
605
+
606
+ def check_cross_file_duplicate(node, method_name)
607
+ return unless project_index
608
+ return if @intentionally_redefined.include?(method_name)
609
+ return if node.each_ancestor(:any_def).any?
610
+ return unless (prior = cross_file_prior_definition(method_name))
611
+
612
+ message = format(MSG, method: method_name,
613
+ defined: index_source_location(prior),
614
+ current: source_location(node))
615
+ add_offense(location(node), message: message)
616
+ end
617
+
618
+ def cross_file_prior_definition(method_name)
619
+ return unless (match = INDEXABLE_METHOD_NAME.match(method_name))
620
+
621
+ definitions = definitions_in_other_files(
622
+ indexed_definitions(match[:owner], match[:separator], match[:name])
623
+ ).reject { |definition| allowed_cross_file_path?(definition.location.to_file_path) }
624
+ return if definitions.empty? || cross_file_self_alias_trick?(definitions)
625
+ return if cross_file_redefinition_marker?(definitions, match[:name])
626
+
627
+ first_indexed_definition(definitions)
628
+ end
629
+
630
+ # Cross-file duplicates whose other definition site matches one of the
631
+ # `AllowedCrossFilePaths` patterns are skipped (e.g. standalone scripts that
632
+ # are never loaded together with the code they redefine). Patterns are
633
+ # matched like `Exclude` patterns, against the path relative to the
634
+ # directory of the config file that configures the cop; absolute patterns
635
+ # are matched against the absolute path.
636
+ def allowed_cross_file_path?(path)
637
+ patterns = cop_config.fetch('AllowedCrossFilePaths', [])
638
+ return false if patterns.empty?
639
+
640
+ relative = config.path_relative_to_config(path)
641
+ patterns.any? { |pattern| match_path?(pattern, relative) || match_path?(pattern, path) }
642
+ end
643
+
644
+ def indexed_definitions(owner, separator, name)
645
+ namespace = separator == '.' ? "#{owner}::<#{owner.split('::').last}>" : owner
646
+
647
+ if name.match?(/\A\w+=\z/)
648
+ # Rubydex indexes `attr_writer :foo` under `foo` rather than `foo=`, so
649
+ # writer definitions come from both the `foo=` and the `foo` declarations.
650
+ indexed_declaration_definitions(namespace, name) +
651
+ indexed_declaration_definitions(namespace, name.delete_suffix('='))
652
+ .select { |definition| writer_attr_definition?(definition) }
653
+ else
654
+ indexed_declaration_definitions(namespace, name).grep_v(Rubydex::AttrWriterDefinition)
655
+ end
656
+ end
657
+
658
+ def indexed_declaration_definitions(namespace, name)
659
+ project_index["#{namespace}##{name}()"]&.definitions.to_a
660
+ end
661
+
662
+ def writer_attr_definition?(definition)
663
+ definition.is_a?(Rubydex::AttrWriterDefinition) ||
664
+ definition.is_a?(Rubydex::AttrAccessorDefinition)
665
+ end
666
+
667
+ # An alias of the method alongside one of its definitions in another file may be
668
+ # the self-alias trick marking an intentional redefinition there, so no offense
669
+ # is registered. A genuine `alias` duplicate is still reported when the alias
670
+ # itself is inspected.
671
+ def cross_file_self_alias_trick?(definitions)
672
+ aliases, others = definitions.partition do |definition|
673
+ definition.is_a?(Rubydex::MethodAliasDefinition)
674
+ end
675
+ alias_paths = aliases.map { |definition| definition.location.to_file_path }
676
+
677
+ others.any? { |definition| alias_paths.include?(definition.location.to_file_path) }
678
+ end
679
+
680
+ # An Active Support redefinition marker alongside one of the definitions in
681
+ # another file marks the redefinition there as intentional, like the
682
+ # self-alias trick. The index does not record the marker's method-name
683
+ # argument, so the other file's source is searched for a marker naming
684
+ # the method.
685
+ def cross_file_redefinition_marker?(definitions, name)
686
+ return false unless active_support_extensions_enabled?
687
+
688
+ definitions.map { |definition| definition.location.to_file_path }.uniq.any? do |path|
689
+ redefinition_marker_in_file?(path, name)
690
+ end
691
+ end
692
+
693
+ def redefinition_marker_in_file?(path, name)
694
+ return false unless File.readable?(path)
695
+
696
+ escaped = Regexp.escape(name)
697
+ marker = /\b(?:silence_redefinition_of_method|redefine_method)\s*\(?\s*
698
+ (?::#{escaped}|(["'])#{escaped}\1)(?![\w=!?])/x
699
+ File.read(path).scrub.match?(marker)
700
+ end
701
+
702
+ def first_indexed_definition(definitions)
703
+ definitions.find { |definition| !definition.is_a?(Rubydex::MethodAliasDefinition) }
704
+ end
705
+
706
+ def index_source_location(definition)
707
+ location = definition.location
708
+ "#{smart_path(location.to_file_path)}:#{location.to_display.start_line}"
709
+ end
710
+
711
+ # Internal identity for an anonymous block, used as a scope key.
712
+ # Includes the source range's begin position to distinguish blocks
713
+ # that share the same line (e.g. two Class.new calls separated by `;`).
714
+ # The user-facing offense message still uses `source_location`, which
715
+ # shows only `path:line`.
716
+ def anon_block_identity(anon_block)
717
+ range = anon_block.source_range
718
+ "#{smart_path(range.source_buffer.name)}:#{range.line}:#{range.begin_pos}"
719
+ end
255
720
  end
256
721
  end
257
722
  end