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
@@ -28,6 +28,11 @@ module RuboCop
28
28
  # delegator.upcase # => FOO
29
29
  # ----
30
30
  #
31
+ # When `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is
32
+ # installed, `respond_to_missing?` defined in another definition of the
33
+ # same class or module (e.g. a reopening in another file) also
34
+ # satisfies the check.
35
+ #
31
36
  # @example
32
37
  # # bad
33
38
  # def method_missing(name, *args)
@@ -52,11 +57,14 @@ module RuboCop
52
57
  # end
53
58
  #
54
59
  class MissingRespondToMissing < Base
60
+ include ProjectIndexHelp
61
+
55
62
  MSG = 'When using `method_missing`, define `respond_to_missing?`.'
56
63
 
57
64
  def on_def(node)
58
65
  return unless node.method?(:method_missing)
59
66
  return if implements_respond_to_missing?(node)
67
+ return if respond_to_missing_elsewhere?(node)
60
68
 
61
69
  add_offense(node)
62
70
  end
@@ -64,17 +72,42 @@ module RuboCop
64
72
 
65
73
  private
66
74
 
67
- def implements_respond_to_missing?(node)
68
- return false unless (grand_parent = node.parent.parent)
75
+ # When `AllCops/UseProjectIndex` is enabled, `respond_to_missing?`
76
+ # defined in another definition of the same class or module (e.g. a
77
+ # reopening in another file) also satisfies the check. Ancestors are
78
+ # not consulted: overriding `method_missing` warrants a matching
79
+ # `respond_to_missing?` for the same class.
80
+ def respond_to_missing_elsewhere?(node)
81
+ return false unless project_index
82
+ return false unless (namespace_node = node.each_ancestor(:class, :module).first)
83
+
84
+ declaration = resolve_constant_in_index(namespace_node.identifier)
85
+ return false unless declaration.is_a?(Rubydex::Namespace)
86
+
87
+ scope = singleton_definition?(node) ? indexed_singleton_of(declaration) : declaration
88
+ !scope&.member('respond_to_missing?()').nil?
89
+ rescue StandardError
90
+ false
91
+ end
92
+
93
+ def singleton_definition?(node)
94
+ node.defs_type? || node.each_ancestor(:sclass, :class, :module).first&.sclass_type?
95
+ end
69
96
 
70
- grand_parent.each_descendant(node.type) do |descendant|
71
- return true if descendant.method?(:respond_to_missing?)
97
+ def implements_respond_to_missing?(node)
98
+ scope = enclosing_scope(node)
99
+ search_root = scope || node.parent
100
+ return false unless search_root
72
101
 
73
- child = descendant.children.first
74
- return true if child.respond_to?(:method?) && child.method?(:respond_to_missing?)
102
+ search_root.each_descendant(node.type).any? do |descendant|
103
+ descendant.method?(:respond_to_missing?) && enclosing_scope(descendant).equal?(scope)
75
104
  end
105
+ end
76
106
 
77
- false
107
+ # The class/module/`class << self` body that lexically contains `node`,
108
+ # or `nil` when `node` is defined at the top level.
109
+ def enclosing_scope(node)
110
+ node.each_ancestor(:class, :module, :sclass).first
78
111
  end
79
112
  end
80
113
  end
@@ -117,17 +117,26 @@ module RuboCop
117
117
 
118
118
  def separate_mixins(node)
119
119
  arguments = node.arguments.reverse
120
- mixins = ["#{node.method_name} #{arguments.first.source}"]
120
+ mixins = [mixin_call(node.method_name, arguments.first.source, node.parenthesized?)]
121
121
 
122
122
  arguments[1..].inject(mixins) do |replacement, arg|
123
- replacement << "#{indent(node)}#{node.method_name} #{arg.source}"
123
+ call = mixin_call(node.method_name, arg.source, node.parenthesized?)
124
+ replacement << "#{indent(node)}#{call}"
124
125
  end.join("\n")
125
126
  end
126
127
 
127
128
  def group_mixins(node, mixins)
128
129
  mixin_names = mixins.reverse.flat_map { |mixin| mixin.arguments.map(&:source) }
129
130
 
130
- "#{node.method_name} #{mixin_names.join(', ')}"
131
+ mixin_call(node.method_name, mixin_names.join(', '), mixins.any?(&:parenthesized?))
132
+ end
133
+
134
+ def mixin_call(method_name, arguments_source, parenthesized)
135
+ if parenthesized
136
+ "#{method_name}(#{arguments_source})"
137
+ else
138
+ "#{method_name} #{arguments_source}"
139
+ end
131
140
  end
132
141
  end
133
142
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # @!method include_statement(node)
48
48
  def_node_matcher :include_statement, <<~PATTERN
49
49
  (send nil? ${:include :extend :prepend}
50
- const)
50
+ const+)
51
51
  PATTERN
52
52
 
53
53
  # @!method in_top_level_scope?(node)
@@ -110,9 +110,11 @@ module RuboCop
110
110
  def_node_matcher :private_directive?, '(send nil? :private ...)'
111
111
 
112
112
  def on_module(node)
113
- return unless node.body&.begin_type?
113
+ return unless node.body
114
114
 
115
- each_wrong_style(node.body.children) do |child_node|
115
+ body_nodes = node.body.begin_type? ? node.body.children : [node.body]
116
+
117
+ each_wrong_style(body_nodes) do |child_node|
116
118
  add_offense(child_node) do |corrector|
117
119
  next if style == :forbidden
118
120
 
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for usage of `Module` methods returning arrays that can be replaced
7
+ # with equivalent predicates.
8
+ #
9
+ # Calling a method returning an array then checking if an element is inside
10
+ # it is much slower than using an equivalent predicate method. For example,
11
+ # `instance_methods.include?` will return an array of all public and protected
12
+ # instance methods in the module, then check if a given method is inside that
13
+ # array, while `method_defined?` will do direct method lookup, which is much
14
+ # faster and consumes less memory.
15
+ #
16
+ # NOTE: `constants.include?` is not handled by this cop because
17
+ # `Module#const_defined?` has different lookup behavior than
18
+ # `Module#constants` - `const_defined?` searches up to `Object`
19
+ # (top-level constants like `String`, `Integer`, etc.) while
20
+ # `constants` does not, which can cause behavior changes after autocorrection.
21
+ #
22
+ # @example
23
+ # # bad
24
+ # Array.instance_methods.include?(:size)
25
+ # Array.instance_methods.member?(:size)
26
+ # Array.instance_methods(true).include?(:size)
27
+ #
28
+ # Array.instance_methods(false).include?(:find)
29
+ #
30
+ # # good
31
+ # Array.method_defined?(:size)
32
+ #
33
+ # Array.method_defined?(:find, false)
34
+ #
35
+ # # bad
36
+ # Array.class_variables.include?(:foo)
37
+ # Array.private_instance_methods.include?(:foo)
38
+ # Array.protected_instance_methods.include?(:foo)
39
+ # Array.public_instance_methods.include?(:foo)
40
+ #
41
+ # # good
42
+ # Array.class_variable_defined?(:foo)
43
+ # Array.private_method_defined?(:foo)
44
+ # Array.protected_method_defined?(:foo)
45
+ # Array.public_method_defined?(:foo)
46
+ #
47
+ class ModuleMemberExistenceCheck < Base
48
+ extend AutoCorrector
49
+
50
+ MSG = 'Use `%<replacement>s` instead.'
51
+
52
+ # @!method module_member_inclusion?(node)
53
+ def_node_matcher :module_member_inclusion?, <<~PATTERN
54
+ (call
55
+ {(call _ %METHODS_WITH_INHERIT_PARAM _?) (call _ %METHODS_WITHOUT_INHERIT_PARAM)}
56
+ {:include? :member?}
57
+ _)
58
+ PATTERN
59
+
60
+ METHOD_REPLACEMENTS = {
61
+ class_variables: :class_variable_defined?,
62
+ instance_methods: :method_defined?,
63
+ private_instance_methods: :private_method_defined?,
64
+ protected_instance_methods: :protected_method_defined?,
65
+ public_instance_methods: :public_method_defined?
66
+ }.freeze
67
+
68
+ METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables].freeze
69
+ METHODS_WITH_INHERIT_PARAM =
70
+ (METHOD_REPLACEMENTS.keys.to_set - METHODS_WITHOUT_INHERIT_PARAM).freeze
71
+
72
+ RESTRICT_ON_SEND = METHOD_REPLACEMENTS.keys.freeze
73
+
74
+ def on_send(node)
75
+ return unless (parent = node.parent)
76
+ return unless module_member_inclusion?(parent)
77
+ return unless simple_method_argument?(node) && simple_method_argument?(parent)
78
+
79
+ offense_range = node.location.selector.join(parent.source_range.end)
80
+ replacement = replacement_for(node, parent)
81
+
82
+ add_offense(offense_range, message: format(MSG, replacement: replacement)) do |corrector|
83
+ corrector.replace(offense_range, replacement)
84
+ end
85
+ end
86
+ alias on_csend on_send
87
+
88
+ private
89
+
90
+ def replacement_for(node, parent)
91
+ replacement_method = METHOD_REPLACEMENTS.fetch(node.method_name)
92
+ without_inherit_param = METHODS_WITHOUT_INHERIT_PARAM.include?(node.method_name)
93
+
94
+ if without_inherit_param || node.first_argument.nil? || node.first_argument.true_type?
95
+ "#{replacement_method}(#{parent.first_argument.source})"
96
+ else
97
+ "#{replacement_method}(#{parent.first_argument.source}, #{node.first_argument.source})"
98
+ end
99
+ end
100
+
101
+ def simple_method_argument?(node)
102
+ return false if node.splat_argument? || node.block_argument?
103
+ return false if node.first_argument&.hash_type?
104
+
105
+ true
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -17,6 +17,7 @@ module RuboCop
17
17
  class MultilineIfModifier < Base
18
18
  include StatementModifier
19
19
  include Alignment
20
+ include RangeHelp
20
21
  extend AutoCorrector
21
22
 
22
23
  MSG = 'Favor a normal %<keyword>s-statement over a modifier ' \
@@ -27,31 +28,70 @@ module RuboCop
27
28
  return unless node.modifier_form? && node.body.multiline?
28
29
 
29
30
  add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
30
- corrector.replace(node, to_normal_if(node))
31
+ autocorrect(corrector, node)
31
32
  end
32
33
  ignore_node(node)
33
34
  end
34
35
 
35
36
  private
36
37
 
37
- def to_normal_if(node)
38
+ def autocorrect(corrector, node)
39
+ condition_heredoc, body_heredoc = [node.condition, node.body].map do |part|
40
+ next unless (range = heredoc_after(part, node))
41
+
42
+ corrector.remove(range)
43
+ range.source.chomp
44
+ end
45
+ corrector.replace(node, to_normal_if(node, condition_heredoc, body_heredoc))
46
+ end
47
+
48
+ # Heredocs opened on the modifier line have their bodies after it, so
49
+ # they are moved along with the part of the `if` they belong to.
50
+ def heredoc_after(part, node)
51
+ ranges = part.each_node(:any_str).select(&:heredoc?).map do |heredoc|
52
+ heredoc.loc.heredoc_body.join(heredoc.loc.heredoc_end)
53
+ end
54
+ ranges.select! { |range| range.line > node.last_line }
55
+ return if ranges.empty?
56
+
57
+ range_by_whole_lines(ranges.reduce(:join), include_final_newline: true)
58
+ end
59
+
60
+ def to_normal_if(node, condition_heredoc, body_heredoc)
38
61
  indented_body = indented_body(node.body, node)
39
62
  condition = "#{node.keyword} #{node.condition.source}"
40
63
  indented_end = "#{offset(node)}end"
41
64
 
42
- [condition, indented_body, indented_end].join("\n")
65
+ lines = [condition, condition_heredoc, indented_body, body_heredoc, indented_end]
66
+ lines.compact.join("\n")
43
67
  end
44
68
 
45
69
  def indented_body(body, node)
46
70
  body_source = "#{offset(node)}#{body.source}"
47
- body_source.each_line.map do |line|
48
- if line == "\n"
71
+ verbatim_lines = verbatim_lines_in(body)
72
+ body_source.each_line.with_index(body.first_line).map do |line, line_number|
73
+ if line == "\n" || verbatim_lines.include?(line_number)
49
74
  line
50
75
  else
51
76
  line.sub(/^\s{#{offset(node).length}}/, indentation(node))
52
77
  end
53
78
  end.join
54
79
  end
80
+
81
+ def verbatim_lines_in(body)
82
+ body.each_node(:any_str).filter_map { |str| verbatim_line_range(str) }.flat_map(&:to_a)
83
+ end
84
+
85
+ # The indentation of a line that starts inside a string is part of the
86
+ # string. Only squiggly heredocs strip it from their bodies, and a `<<`
87
+ # terminator has to stay at the start of its line.
88
+ def verbatim_line_range(str)
89
+ if str.heredoc?
90
+ str.loc.heredoc_body.line..str.loc.heredoc_end.line unless str.source.start_with?('<<~')
91
+ elsif str.loc?(:begin) && str.loc?(:end)
92
+ (str.first_line + 1)..str.last_line
93
+ end
94
+ end
55
95
  end
56
96
  end
57
97
  end
@@ -3,7 +3,9 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of the `then` keyword in multi-line if statements.
6
+ # Checks for uses of the `then` keyword in multi-line `if` statements.
7
+ # In multi-line `if` statements, `then` is redundant because the newline
8
+ # already separates the condition from the body.
7
9
  #
8
10
  # @example
9
11
  # # bad
@@ -21,8 +23,6 @@ module RuboCop
21
23
  include RangeHelp
22
24
  extend AutoCorrector
23
25
 
24
- NON_MODIFIER_THEN = /then\s*(#.*)?$/.freeze
25
-
26
26
  MSG = 'Do not use `then` for multi-line `%<keyword>s`.'
27
27
 
28
28
  def on_normal_if_unless(node)
@@ -36,7 +36,13 @@ module RuboCop
36
36
  private
37
37
 
38
38
  def non_modifier_then?(node)
39
- NON_MODIFIER_THEN.match?(node.loc.begin&.source_line)
39
+ node.multiline? && own_then?(node) && node.loc.begin.line != node.if_branch&.loc&.line
40
+ end
41
+
42
+ # Prism gives an `elsif` with no `then` of its own the previous branch's `then` location,
43
+ # which lies outside the node.
44
+ def own_then?(node)
45
+ node.then? && node.source_range.contains?(node.loc.begin)
40
46
  end
41
47
  end
42
48
  end
@@ -50,10 +50,17 @@ module RuboCop
50
50
  # Requires `then` for write `in` and its body on the same line.
51
51
  def require_then?(in_pattern_node)
52
52
  return true unless in_pattern_node.pattern.single_line?
53
+ return true if ends_with_endless_range?(in_pattern_node.pattern)
53
54
  return false unless in_pattern_node.body
54
55
 
55
56
  same_line?(in_pattern_node, in_pattern_node.body)
56
57
  end
58
+
59
+ def ends_with_endless_range?(node)
60
+ node.each_node(:range).any? do |range|
61
+ range.end.nil? && range.source_range.end_pos == node.source_range.end_pos
62
+ end
63
+ end
57
64
  end
58
65
  end
59
66
  end
@@ -65,10 +65,16 @@ module RuboCop
65
65
  if style == :keyword
66
66
  rhs.begin_type?
67
67
  else
68
- rhs.kwbegin_type?
68
+ # A `begin` block with `rescue`/`ensure` cannot be expressed with
69
+ # parentheses, so wrapping it in `(` and `)` is not possible.
70
+ rhs.kwbegin_type? && !contains_rescue_or_ensure?(rhs)
69
71
  end
70
72
  end
71
73
 
74
+ def contains_rescue_or_ensure?(node)
75
+ node.each_child_node(:rescue, :ensure).any?
76
+ end
77
+
72
78
  def keyword_autocorrect(node, corrector)
73
79
  node_buf = node.source_range.source_buffer
74
80
  corrector.replace(node.loc.begin, keyword_begin_str(node, node_buf))
@@ -27,6 +27,7 @@ module RuboCop
27
27
  def on_def(node)
28
28
  return unless node.arguments?
29
29
  return if opening_line(node) == closing_line(node)
30
+ return if node.arguments.any?(&:multiline?)
30
31
  return if correction_exceeds_max_line_length?(node)
31
32
  return unless (begin_of_arguments = node.arguments.loc.begin)
32
33
 
@@ -38,7 +39,7 @@ module RuboCop
38
39
 
39
40
  private
40
41
 
41
- # rubocop:disable Metrics/AbcSize
42
+ # rubocop:disable-next Metrics/AbcSize
42
43
  def autocorrect(corrector, node, begin_of_arguments)
43
44
  arguments = node.arguments
44
45
  joined_arguments = arguments.map(&:source).join(', ')
@@ -51,16 +52,17 @@ module RuboCop
51
52
  end
52
53
 
53
54
  arguments_range = range_with_surrounding_space(arguments_range(node), side: :left)
54
- # If the method name isn't on the same line as def, move it directly after def
55
+ # If the method name isn't on the same line as `def`, pull the name and
56
+ # the opening parenthesis up next to `def` so the collapsed signature
57
+ # stays on a single line and remains valid Ruby.
55
58
  if arguments_range.first_line != opening_line(node)
56
- corrector.remove(node.loc.name)
57
- corrector.insert_after(node.loc.keyword, " #{node.loc.name.source}")
59
+ prefix_range = range_between(node.loc.keyword.end_pos, begin_of_arguments.begin_pos)
60
+ corrector.replace(prefix_range, " #{prefix_range.source.strip}")
58
61
  end
59
62
 
60
63
  corrector.remove(arguments_range)
61
64
  corrector.insert_after(begin_of_arguments, joined_arguments)
62
65
  end
63
- # rubocop:enable Metrics/AbcSize
64
66
 
65
67
  def last_line_source_of_arguments(arguments)
66
68
  processed_source[arguments.last_line - 1].strip
@@ -75,19 +77,18 @@ module RuboCop
75
77
  end
76
78
 
77
79
  def correction_exceeds_max_line_length?(node)
78
- indentation_width(node) + definition_width(node) > max_line_length
79
- end
80
+ return false unless max_line_length
80
81
 
81
- def indentation_width(node)
82
- processed_source.line_indentation(node.source_range.line)
82
+ node.source_range.column + definition_width(node) > max_line_length
83
83
  end
84
84
 
85
85
  def definition_width(node)
86
- node.source_range.begin.join(node.arguments.source_range.end).length
87
- end
86
+ # Measure the collapsed single-line width the autocorrect would
87
+ # produce, not the multi-line source length, so a signature that
88
+ # would fit on one line is not skipped.
89
+ signature = node.source_range.begin.join(node.arguments.source_range.end).source
88
90
 
89
- def max_line_length
90
- config.for_cop('Layout/LineLength')['Max'] || 120
91
+ signature.gsub(/\s+/, ' ').length
91
92
  end
92
93
  end
93
94
  end
@@ -7,7 +7,8 @@ module RuboCop
7
7
  #
8
8
  # NOTE: `return if ... else ... end` is syntax error. If `return` is used before
9
9
  # multiline ternary operator expression, it will be autocorrected to single-line
10
- # ternary operator. The same is true for `break`, `next`, and method call.
10
+ # ternary operator. The same is true for `break`, `next`, `yield`, `super`,
11
+ # `defined?` without parentheses, and method call.
11
12
  #
12
13
  # @example
13
14
  # # bad
@@ -39,7 +40,7 @@ module RuboCop
39
40
 
40
41
  MSG_IF = 'Avoid multi-line ternary operators, use `if` or `unless` instead.'
41
42
  MSG_SINGLE_LINE = 'Avoid multi-line ternary operators, use single-line instead.'
42
- SINGLE_LINE_TYPES = %i[return break next send csend].freeze
43
+ SINGLE_LINE_TYPES = %i[return break next send csend super yield].freeze
43
44
 
44
45
  def on_if(node)
45
46
  return unless offense?(node)
@@ -90,7 +91,10 @@ module RuboCop
90
91
  end
91
92
 
92
93
  def enforce_single_line_ternary_operator?(node)
93
- SINGLE_LINE_TYPES.include?(node.parent&.type) && !use_assignment_method?(node.parent)
94
+ return false unless (parent = node.parent)
95
+ return !parent.parenthesized? if parent.defined_type?
96
+
97
+ SINGLE_LINE_TYPES.include?(parent.type) && !use_assignment_method?(parent)
94
98
  end
95
99
 
96
100
  def use_assignment_method?(node)
@@ -50,10 +50,17 @@ module RuboCop
50
50
  unless when_node.conditions.first.first_line == when_node.conditions.last.last_line
51
51
  return true
52
52
  end
53
+ return true if ends_with_endless_range?(when_node.conditions.last)
53
54
  return false unless when_node.body
54
55
 
55
56
  same_line?(when_node, when_node.body)
56
57
  end
58
+
59
+ def ends_with_endless_range?(node)
60
+ node.each_node(:range).any? do |range|
61
+ range.end.nil? && range.source_range.end_pos == node.source_range.end_pos
62
+ end
63
+ end
57
64
  end
58
65
  end
59
66
  end
@@ -70,48 +70,59 @@ module RuboCop
70
70
  (send $_ :== ${lvar call})
71
71
  PATTERN
72
72
 
73
- # rubocop:disable Metrics/AbcSize
74
73
  def on_or(node)
75
- root_of_or_node = root_of_or_node(node)
76
- return unless node == root_of_or_node
74
+ return unless node == root_of_or_node(node)
77
75
  return unless nested_comparison?(node)
78
-
79
- return unless (variable, values = find_offending_var(node))
76
+ return unless (variable, values, skipped = find_offending_var(node))
80
77
  return if values.size < comparisons_threshold
81
78
 
82
79
  range = offense_range(values)
80
+ # Bail when an allowed method comparison sits between the collected
81
+ # values: collapsing them into a single `include?` would drop it.
82
+ return if skipped_within_range?(skipped, range)
83
83
 
84
84
  add_offense(range) do |corrector|
85
- elements = values.map(&:source).join(', ')
86
- argument = variable.lvar_type? ? variable_name(variable) : variable.source
87
- prefer_method = "[#{elements}].include?(#{argument})"
88
-
89
- corrector.replace(range, prefer_method)
85
+ corrector.replace(range, preferred_method(variable, values))
90
86
  end
91
87
  end
92
- # rubocop:enable Metrics/AbcSize
93
88
 
94
89
  private
95
90
 
96
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
97
- def find_offending_var(node, variables = Set.new, values = [])
91
+ def skipped_within_range?(skipped, range)
92
+ skipped.any? { |node_part| range.contains?(node_part.source_range) }
93
+ end
94
+
95
+ def preferred_method(variable, values)
96
+ elements = values.map(&:source).join(', ')
97
+ argument = variable.lvar_type? ? variable_name(variable) : variable.source
98
+ "[#{elements}].include?(#{argument})"
99
+ end
100
+
101
+ def find_offending_var(node, variables = Set.new, values = [], skipped = [])
98
102
  if node.or_type?
99
- find_offending_var(node.lhs, variables, values)
100
- find_offending_var(node.rhs, variables, values)
103
+ find_offending_var(node.lhs, variables, values, skipped)
104
+ find_offending_var(node.rhs, variables, values, skipped)
101
105
  elsif simple_double_comparison?(node)
102
106
  return
103
- elsif (var, obj = simple_comparison(node))
104
- return if allow_method_comparison? && obj.call_type?
107
+ elsif (comparison = simple_comparison(node))
108
+ collect_comparison(node, comparison, variables, values, skipped)
109
+ end
105
110
 
106
- variables << var
107
- return if variables.size > 1
111
+ [variables.first, values, skipped] if variables.any?
112
+ end
108
113
 
109
- values << obj
114
+ def collect_comparison(node, comparison, variables, values, skipped)
115
+ var, obj = comparison
116
+ if allow_method_comparison? && obj.call_type?
117
+ skipped << node
118
+ return
110
119
  end
111
120
 
112
- [variables.first, values] if variables.any?
121
+ variables << var
122
+ return if variables.size > 1
123
+
124
+ values << obj
113
125
  end
114
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
115
126
 
116
127
  def offense_range(values)
117
128
  values.first.parent.source_range.begin.join(values.last.parent.source_range.end)