rubocop 1.44.1 → 1.78.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 (711) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +95 -88
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +660 -117
  7. data/config/internal_affairs.yml +31 -0
  8. data/config/obsoletion.yml +13 -3
  9. data/exe/rubocop +4 -3
  10. data/lib/rubocop/cached_data.rb +21 -5
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +33 -13
  12. data/lib/rubocop/cli/command/execute_runner.rb +11 -6
  13. data/lib/rubocop/cli/command/lsp.rb +19 -0
  14. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  15. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  16. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  17. data/lib/rubocop/cli/command/version.rb +2 -2
  18. data/lib/rubocop/cli.rb +80 -11
  19. data/lib/rubocop/comment_config.rb +21 -2
  20. data/lib/rubocop/config.rb +99 -25
  21. data/lib/rubocop/config_finder.rb +14 -4
  22. data/lib/rubocop/config_loader.rb +68 -57
  23. data/lib/rubocop/config_loader_resolver.rb +48 -17
  24. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  25. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  26. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  27. data/lib/rubocop/config_obsoletion.rb +58 -11
  28. data/lib/rubocop/config_validator.rb +39 -20
  29. data/lib/rubocop/cop/autocorrect_logic.rb +69 -21
  30. data/lib/rubocop/cop/base.rb +112 -29
  31. data/lib/rubocop/cop/bundler/duplicated_gem.rb +3 -2
  32. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  33. data/lib/rubocop/cop/bundler/gem_comment.rb +4 -4
  34. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  35. data/lib/rubocop/cop/bundler/gem_version.rb +6 -7
  36. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  37. data/lib/rubocop/cop/bundler/ordered_gems.rb +10 -2
  38. data/lib/rubocop/cop/commissioner.rb +8 -2
  39. data/lib/rubocop/cop/cop.rb +55 -9
  40. data/lib/rubocop/cop/corrector.rb +1 -1
  41. data/lib/rubocop/cop/correctors/alignment_corrector.rb +4 -15
  42. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  43. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -15
  44. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  45. data/lib/rubocop/cop/correctors/line_break_corrector.rb +3 -1
  46. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  47. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -1
  48. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +7 -4
  49. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +12 -2
  50. data/lib/rubocop/cop/documentation.rb +32 -5
  51. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  52. data/lib/rubocop/cop/force.rb +12 -0
  53. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  54. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  55. data/lib/rubocop/cop/gemspec/dependency_version.rb +6 -8
  56. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +4 -5
  57. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  58. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +39 -17
  59. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +10 -2
  60. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  61. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -3
  62. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  63. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  64. data/lib/rubocop/cop/generator.rb +6 -0
  65. data/lib/rubocop/cop/internal_affairs/cop_description.rb +37 -17
  66. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  67. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  68. data/lib/rubocop/cop/internal_affairs/example_description.rb +51 -25
  69. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +3 -3
  70. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  71. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  72. data/lib/rubocop/cop/internal_affairs/location_expression.rb +38 -0
  73. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +6 -5
  74. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  75. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  76. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +54 -0
  77. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +129 -35
  78. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  79. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  80. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +231 -0
  81. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  82. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  83. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  84. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  85. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  86. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  87. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  88. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +42 -0
  89. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  90. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  91. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  92. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +7 -22
  93. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  94. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +75 -0
  95. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  96. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  97. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +23 -2
  98. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -5
  99. data/lib/rubocop/cop/internal_affairs.rb +12 -0
  100. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +6 -2
  101. data/lib/rubocop/cop/layout/argument_alignment.rb +3 -10
  102. data/lib/rubocop/cop/layout/array_alignment.rb +2 -2
  103. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  104. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  105. data/lib/rubocop/cop/layout/block_alignment.rb +32 -13
  106. data/lib/rubocop/cop/layout/block_end_newline.rb +8 -21
  107. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  108. data/lib/rubocop/cop/layout/class_structure.rb +59 -28
  109. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +2 -3
  110. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  111. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  112. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  113. data/lib/rubocop/cop/layout/def_end_alignment.rb +2 -2
  114. data/lib/rubocop/cop/layout/dot_position.rb +2 -6
  115. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  116. data/lib/rubocop/cop/layout/empty_comment.rb +6 -4
  117. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +46 -13
  118. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  119. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  120. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +34 -14
  121. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  122. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +39 -7
  123. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  124. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  125. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +14 -8
  126. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  127. data/lib/rubocop/cop/layout/end_alignment.rb +23 -3
  128. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -5
  129. data/lib/rubocop/cop/layout/first_argument_indentation.rb +14 -14
  130. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +19 -10
  131. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  132. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  133. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +8 -20
  134. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +50 -52
  135. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  136. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +3 -3
  137. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -6
  138. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +13 -6
  139. data/lib/rubocop/cop/layout/heredoc_indentation.rb +7 -4
  140. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  141. data/lib/rubocop/cop/layout/indentation_width.rb +16 -16
  142. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  143. data/lib/rubocop/cop/layout/leading_comment_space.rb +85 -3
  144. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -14
  145. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +19 -9
  146. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +4 -2
  147. data/lib/rubocop/cop/layout/line_length.rb +168 -28
  148. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  149. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  150. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +8 -27
  151. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +20 -12
  152. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  153. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +21 -6
  154. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  155. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +7 -30
  156. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -4
  157. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  158. data/lib/rubocop/cop/layout/redundant_line_break.rb +43 -48
  159. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +9 -10
  160. data/lib/rubocop/cop/layout/single_line_block_chain.rb +6 -1
  161. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  162. data/lib/rubocop/cop/layout/space_after_comma.rb +10 -2
  163. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  164. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  165. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  166. data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -2
  167. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +3 -3
  168. data/lib/rubocop/cop/layout/space_around_operators.rb +75 -38
  169. data/lib/rubocop/cop/layout/space_before_block_braces.rb +20 -10
  170. data/lib/rubocop/cop/layout/space_before_brackets.rb +7 -40
  171. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  172. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  173. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  174. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  175. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +28 -13
  176. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +8 -1
  177. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +8 -1
  178. data/lib/rubocop/cop/layout/space_inside_parens.rb +3 -3
  179. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  180. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  181. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
  182. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +6 -7
  183. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  184. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -4
  185. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  186. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +14 -4
  187. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  188. data/lib/rubocop/cop/lint/ambiguous_range.rb +9 -1
  189. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  190. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +118 -0
  191. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -9
  192. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  193. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +11 -13
  194. data/lib/rubocop/cop/lint/boolean_symbol.rb +2 -4
  195. data/lib/rubocop/cop/lint/circular_argument_reference.rb +4 -14
  196. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  197. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  198. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  199. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  200. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  201. data/lib/rubocop/cop/lint/debugger.rb +49 -30
  202. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +6 -6
  203. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -13
  204. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  205. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  206. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -5
  207. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  208. data/lib/rubocop/cop/lint/duplicate_methods.rb +112 -34
  209. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +48 -23
  210. data/lib/rubocop/cop/lint/duplicate_set_element.rb +87 -0
  211. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  212. data/lib/rubocop/cop/lint/else_layout.rb +1 -3
  213. data/lib/rubocop/cop/lint/empty_block.rb +2 -2
  214. data/lib/rubocop/cop/lint/empty_conditional_body.rb +31 -58
  215. data/lib/rubocop/cop/lint/empty_ensure.rb +2 -12
  216. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  217. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  218. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -6
  219. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  220. data/lib/rubocop/cop/lint/ensure_return.rb +2 -10
  221. data/lib/rubocop/cop/lint/erb_new_arguments.rb +27 -27
  222. data/lib/rubocop/cop/lint/float_comparison.rb +58 -15
  223. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -8
  224. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -12
  225. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  226. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  227. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  228. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -16
  229. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +24 -13
  230. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  231. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -8
  232. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  233. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -4
  234. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +50 -0
  235. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  236. data/lib/rubocop/cop/lint/literal_as_condition.rb +114 -11
  237. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  238. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +96 -17
  239. data/lib/rubocop/cop/lint/loop.rb +6 -12
  240. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  241. data/lib/rubocop/cop/lint/missing_super.rb +63 -5
  242. data/lib/rubocop/cop/lint/mixed_case_range.rb +113 -0
  243. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  244. data/lib/rubocop/cop/lint/nested_method_definition.rb +11 -18
  245. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -25
  246. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -7
  247. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +22 -10
  248. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +6 -8
  249. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  250. data/lib/rubocop/cop/lint/number_conversion.rb +13 -4
  251. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +3 -4
  252. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  253. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +3 -2
  254. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  255. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +11 -14
  256. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +6 -11
  257. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -5
  258. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -5
  259. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  260. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  261. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +11 -5
  262. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +9 -7
  263. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  264. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -13
  265. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +79 -10
  266. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +10 -9
  267. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +36 -20
  268. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  269. data/lib/rubocop/cop/lint/redundant_with_index.rb +10 -3
  270. data/lib/rubocop/cop/lint/redundant_with_object.rb +6 -3
  271. data/lib/rubocop/cop/lint/refinement_import_methods.rb +3 -2
  272. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  273. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  274. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -5
  275. data/lib/rubocop/cop/lint/rescue_type.rb +4 -10
  276. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -13
  277. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +31 -13
  278. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +109 -41
  279. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  280. data/lib/rubocop/cop/lint/self_assignment.rb +71 -10
  281. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  282. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  283. data/lib/rubocop/cop/lint/shadowed_exception.rb +7 -13
  284. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +26 -12
  285. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  286. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  287. data/lib/rubocop/cop/lint/suppressed_exception.rb +3 -3
  288. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  289. data/lib/rubocop/cop/lint/symbol_conversion.rb +9 -4
  290. data/lib/rubocop/cop/lint/syntax.rb +14 -4
  291. data/lib/rubocop/cop/lint/to_enum_arguments.rb +17 -7
  292. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  293. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  294. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  295. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  296. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  297. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +4 -3
  298. data/lib/rubocop/cop/lint/unreachable_code.rb +56 -9
  299. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -11
  300. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  301. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  302. data/lib/rubocop/cop/lint/useless_access_modifier.rb +46 -17
  303. data/lib/rubocop/cop/lint/useless_assignment.rb +104 -15
  304. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  305. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  306. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  307. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -4
  308. data/lib/rubocop/cop/lint/useless_method_definition.rb +11 -3
  309. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +78 -0
  310. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  311. data/lib/rubocop/cop/lint/useless_rescue.rb +7 -3
  312. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -5
  313. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -29
  314. data/lib/rubocop/cop/lint/useless_times.rb +3 -3
  315. data/lib/rubocop/cop/lint/void.rb +140 -19
  316. data/lib/rubocop/cop/message_annotator.rb +7 -3
  317. data/lib/rubocop/cop/metrics/abc_size.rb +4 -4
  318. data/lib/rubocop/cop/metrics/block_length.rb +9 -7
  319. data/lib/rubocop/cop/metrics/block_nesting.rb +20 -8
  320. data/lib/rubocop/cop/metrics/class_length.rb +23 -16
  321. data/lib/rubocop/cop/metrics/collection_literal_length.rb +83 -0
  322. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  323. data/lib/rubocop/cop/metrics/method_length.rb +16 -7
  324. data/lib/rubocop/cop/metrics/module_length.rb +7 -6
  325. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  326. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -3
  327. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +40 -13
  328. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  329. data/lib/rubocop/cop/migration/department_name.rb +3 -3
  330. data/lib/rubocop/cop/mixin/alignment.rb +8 -4
  331. data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -2
  332. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  333. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  334. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -3
  335. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  336. data/lib/rubocop/cop/mixin/check_line_breakable.rb +22 -12
  337. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  338. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  339. data/lib/rubocop/cop/mixin/comments_help.rb +26 -11
  340. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  341. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  342. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  343. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  344. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  345. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  346. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  347. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  348. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  349. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  350. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -12
  351. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  352. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +16 -15
  353. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +62 -43
  354. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  355. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  356. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  357. data/lib/rubocop/cop/mixin/line_length_help.rb +34 -12
  358. data/lib/rubocop/cop/mixin/method_complexity.rb +17 -7
  359. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  360. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +0 -3
  361. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +10 -11
  362. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +2 -2
  363. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  364. data/lib/rubocop/cop/mixin/percent_literal.rb +2 -2
  365. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +71 -35
  366. data/lib/rubocop/cop/mixin/range_help.rb +16 -10
  367. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  368. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  369. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  370. data/lib/rubocop/cop/mixin/statement_modifier.rb +13 -7
  371. data/lib/rubocop/cop/mixin/string_help.rb +5 -3
  372. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  373. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
  374. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  375. data/lib/rubocop/cop/mixin/trailing_comma.rb +24 -8
  376. data/lib/rubocop/cop/naming/accessor_method_name.rb +11 -6
  377. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  378. data/lib/rubocop/cop/naming/block_forwarding.rb +40 -9
  379. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  380. data/lib/rubocop/cop/naming/constant_name.rb +8 -10
  381. data/lib/rubocop/cop/naming/file_name.rb +5 -7
  382. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  383. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  384. data/lib/rubocop/cop/naming/inclusive_language.rb +33 -6
  385. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +38 -24
  386. data/lib/rubocop/cop/naming/method_name.rb +146 -15
  387. data/lib/rubocop/cop/naming/predicate_method.rb +303 -0
  388. data/lib/rubocop/cop/naming/predicate_prefix.rb +204 -0
  389. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +26 -17
  390. data/lib/rubocop/cop/naming/variable_name.rb +56 -7
  391. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  392. data/lib/rubocop/cop/offense.rb +4 -5
  393. data/lib/rubocop/cop/registry.rb +12 -7
  394. data/lib/rubocop/cop/security/compound_hash.rb +4 -2
  395. data/lib/rubocop/cop/security/eval.rb +2 -1
  396. data/lib/rubocop/cop/security/open.rb +3 -2
  397. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  398. data/lib/rubocop/cop/style/access_modifier_declarations.rb +177 -30
  399. data/lib/rubocop/cop/style/accessor_grouping.rb +69 -21
  400. data/lib/rubocop/cop/style/alias.rb +11 -9
  401. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  402. data/lib/rubocop/cop/style/and_or.rb +1 -1
  403. data/lib/rubocop/cop/style/arguments_forwarding.rb +478 -62
  404. data/lib/rubocop/cop/style/array_first_last.rb +80 -0
  405. data/lib/rubocop/cop/style/array_intersect.rb +54 -34
  406. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  407. data/lib/rubocop/cop/style/attr.rb +11 -1
  408. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  409. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  410. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +3 -3
  411. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  412. data/lib/rubocop/cop/style/block_comments.rb +2 -2
  413. data/lib/rubocop/cop/style/block_delimiters.rb +60 -19
  414. data/lib/rubocop/cop/style/case_like_if.rb +34 -20
  415. data/lib/rubocop/cop/style/class_and_module_children.rb +55 -14
  416. data/lib/rubocop/cop/style/class_check.rb +1 -0
  417. data/lib/rubocop/cop/style/class_equality_comparison.rb +59 -41
  418. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  419. data/lib/rubocop/cop/style/collection_compact.rb +35 -12
  420. data/lib/rubocop/cop/style/collection_methods.rb +4 -1
  421. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  422. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  423. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  424. data/lib/rubocop/cop/style/combinable_loops.rb +44 -8
  425. data/lib/rubocop/cop/style/command_literal.rb +2 -2
  426. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  427. data/lib/rubocop/cop/style/commented_keyword.rb +32 -6
  428. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  429. data/lib/rubocop/cop/style/concat_array_literals.rb +13 -4
  430. data/lib/rubocop/cop/style/conditional_assignment.rb +57 -42
  431. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  432. data/lib/rubocop/cop/style/copyright.rb +37 -24
  433. data/lib/rubocop/cop/style/data_inheritance.rb +82 -0
  434. data/lib/rubocop/cop/style/date_time.rb +5 -4
  435. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -7
  436. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  437. data/lib/rubocop/cop/style/dir.rb +1 -1
  438. data/lib/rubocop/cop/style/dir_empty.rb +54 -0
  439. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  440. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +3 -3
  441. data/lib/rubocop/cop/style/documentation.rb +36 -30
  442. data/lib/rubocop/cop/style/documentation_method.rb +30 -4
  443. data/lib/rubocop/cop/style/double_negation.rb +6 -6
  444. data/lib/rubocop/cop/style/each_for_simple_loop.rb +11 -15
  445. data/lib/rubocop/cop/style/each_with_object.rb +4 -5
  446. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  447. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  448. data/lib/rubocop/cop/style/empty_else.rb +10 -7
  449. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  450. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  451. data/lib/rubocop/cop/style/empty_literal.rb +36 -23
  452. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  453. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  454. data/lib/rubocop/cop/style/endless_method.rb +150 -18
  455. data/lib/rubocop/cop/style/eval_with_location.rb +27 -35
  456. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  457. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  458. data/lib/rubocop/cop/style/explicit_block_argument.rb +19 -6
  459. data/lib/rubocop/cop/style/exponential_notation.rb +5 -5
  460. data/lib/rubocop/cop/style/fetch_env_var.rb +34 -7
  461. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  462. data/lib/rubocop/cop/style/file_null.rb +89 -0
  463. data/lib/rubocop/cop/style/file_read.rb +5 -8
  464. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  465. data/lib/rubocop/cop/style/file_write.rb +3 -6
  466. data/lib/rubocop/cop/style/float_division.rb +8 -4
  467. data/lib/rubocop/cop/style/for.rb +4 -2
  468. data/lib/rubocop/cop/style/format_string.rb +33 -12
  469. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  470. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -4
  471. data/lib/rubocop/cop/style/global_std_stream.rb +10 -1
  472. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  473. data/lib/rubocop/cop/style/guard_clause.rb +48 -4
  474. data/lib/rubocop/cop/style/hash_conversion.rb +26 -9
  475. data/lib/rubocop/cop/style/hash_each_methods.rb +111 -34
  476. data/lib/rubocop/cop/style/hash_except.rb +38 -135
  477. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  478. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  479. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  480. data/lib/rubocop/cop/style/hash_syntax.rb +38 -7
  481. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  482. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  483. data/lib/rubocop/cop/style/identical_conditional_branches.rb +57 -9
  484. data/lib/rubocop/cop/style/if_inside_else.rb +16 -14
  485. data/lib/rubocop/cop/style/if_unless_modifier.rb +140 -17
  486. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  487. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +10 -8
  488. data/lib/rubocop/cop/style/if_with_semicolon.rb +62 -8
  489. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  490. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  491. data/lib/rubocop/cop/style/inverse_methods.rb +21 -17
  492. data/lib/rubocop/cop/style/invertible_unless_condition.rb +58 -12
  493. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  494. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  495. data/lib/rubocop/cop/style/it_block_parameter.rb +119 -0
  496. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  497. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  498. data/lib/rubocop/cop/style/lambda.rb +5 -4
  499. data/lib/rubocop/cop/style/lambda_call.rb +14 -3
  500. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  501. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  502. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +82 -50
  503. data/lib/rubocop/cop/style/map_into_array.rb +236 -0
  504. data/lib/rubocop/cop/style/map_to_hash.rb +31 -7
  505. data/lib/rubocop/cop/style/map_to_set.rb +6 -2
  506. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +62 -31
  507. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +65 -42
  508. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +30 -13
  509. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  510. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -2
  511. data/lib/rubocop/cop/style/min_max.rb +3 -3
  512. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  513. data/lib/rubocop/cop/style/missing_else.rb +2 -4
  514. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +35 -5
  515. data/lib/rubocop/cop/style/mixin_grouping.rb +5 -5
  516. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  517. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  518. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  519. data/lib/rubocop/cop/style/multiline_method_signature.rb +17 -13
  520. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +21 -4
  521. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  522. data/lib/rubocop/cop/style/multiple_comparison.rb +66 -59
  523. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  524. data/lib/rubocop/cop/style/negated_if_else_condition.rb +18 -11
  525. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  526. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  527. data/lib/rubocop/cop/style/nested_ternary_operator.rb +8 -15
  528. data/lib/rubocop/cop/style/next.rb +45 -1
  529. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  530. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  531. data/lib/rubocop/cop/style/not.rb +1 -1
  532. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
  533. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  534. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  535. data/lib/rubocop/cop/style/numeric_predicate.rb +12 -4
  536. data/lib/rubocop/cop/style/object_then.rb +16 -14
  537. data/lib/rubocop/cop/style/one_line_conditional.rb +31 -6
  538. data/lib/rubocop/cop/style/open_struct_use.rb +6 -6
  539. data/lib/rubocop/cop/style/operator_method_call.rb +33 -9
  540. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  541. data/lib/rubocop/cop/style/parallel_assignment.rb +38 -40
  542. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  543. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -4
  544. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  545. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  546. data/lib/rubocop/cop/style/proc.rb +2 -2
  547. data/lib/rubocop/cop/style/quoted_symbols.rb +2 -4
  548. data/lib/rubocop/cop/style/raise_args.rb +19 -14
  549. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  550. data/lib/rubocop/cop/style/redundant_argument.rb +35 -4
  551. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  552. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  553. data/lib/rubocop/cop/style/redundant_assignment.rb +11 -3
  554. data/lib/rubocop/cop/style/redundant_begin.rb +17 -4
  555. data/lib/rubocop/cop/style/redundant_condition.rb +114 -27
  556. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  557. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +50 -0
  558. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +91 -7
  559. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  560. data/lib/rubocop/cop/style/redundant_exception.rb +33 -13
  561. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -16
  562. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  563. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  564. data/lib/rubocop/cop/style/redundant_format.rb +262 -0
  565. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  566. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
  567. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  568. data/lib/rubocop/cop/style/redundant_interpolation.rb +3 -3
  569. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  570. data/lib/rubocop/cop/style/redundant_line_continuation.rb +236 -0
  571. data/lib/rubocop/cop/style/redundant_parentheses.rb +140 -40
  572. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
  573. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +107 -0
  574. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -9
  575. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  576. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +20 -28
  577. data/lib/rubocop/cop/style/redundant_return.rb +16 -5
  578. data/lib/rubocop/cop/style/redundant_self.rb +32 -20
  579. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  580. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +12 -5
  581. data/lib/rubocop/cop/style/redundant_sort.rb +14 -13
  582. data/lib/rubocop/cop/style/redundant_sort_by.rb +19 -3
  583. data/lib/rubocop/cop/style/redundant_string_escape.rb +8 -7
  584. data/lib/rubocop/cop/style/regexp_literal.rb +12 -3
  585. data/lib/rubocop/cop/style/require_order.rb +13 -9
  586. data/lib/rubocop/cop/style/rescue_modifier.rb +19 -7
  587. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  588. data/lib/rubocop/cop/style/return_nil.rb +8 -4
  589. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +137 -0
  590. data/lib/rubocop/cop/style/safe_navigation.rb +145 -63
  591. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  592. data/lib/rubocop/cop/style/sample.rb +3 -4
  593. data/lib/rubocop/cop/style/select_by_regexp.rb +33 -16
  594. data/lib/rubocop/cop/style/self_assignment.rb +12 -18
  595. data/lib/rubocop/cop/style/semicolon.rb +22 -6
  596. data/lib/rubocop/cop/style/send.rb +4 -4
  597. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +105 -0
  598. data/lib/rubocop/cop/style/signal_exception.rb +3 -4
  599. data/lib/rubocop/cop/style/single_argument_dig.rb +16 -8
  600. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  601. data/lib/rubocop/cop/style/single_line_do_end_block.rb +78 -0
  602. data/lib/rubocop/cop/style/single_line_methods.rb +10 -8
  603. data/lib/rubocop/cop/style/slicing_with_range.rb +106 -11
  604. data/lib/rubocop/cop/style/sole_nested_conditional.rb +50 -90
  605. data/lib/rubocop/cop/style/special_global_vars.rb +5 -7
  606. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  607. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  608. data/lib/rubocop/cop/style/string_concatenation.rb +15 -15
  609. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  610. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  611. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  612. data/lib/rubocop/cop/style/strip.rb +7 -4
  613. data/lib/rubocop/cop/style/struct_inheritance.rb +10 -3
  614. data/lib/rubocop/cop/style/super_arguments.rb +221 -0
  615. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  616. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  617. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  618. data/lib/rubocop/cop/style/symbol_proc.rb +78 -6
  619. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  620. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  621. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  622. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +11 -2
  623. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  624. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  625. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  626. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +5 -5
  627. data/lib/rubocop/cop/style/trivial_accessors.rb +3 -3
  628. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  629. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  630. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  631. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  632. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -2
  633. data/lib/rubocop/cop/style/word_array.rb +18 -6
  634. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  635. data/lib/rubocop/cop/style/yoda_condition.rb +25 -12
  636. data/lib/rubocop/cop/style/yoda_expression.rb +20 -9
  637. data/lib/rubocop/cop/style/zero_length_predicate.rb +41 -29
  638. data/lib/rubocop/cop/team.rb +58 -26
  639. data/lib/rubocop/cop/util.rb +33 -11
  640. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  641. data/lib/rubocop/cop/variable_force/assignment.rb +66 -6
  642. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  643. data/lib/rubocop/cop/variable_force/scope.rb +3 -3
  644. data/lib/rubocop/cop/variable_force/variable.rb +18 -5
  645. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  646. data/lib/rubocop/cop/variable_force.rb +19 -12
  647. data/lib/rubocop/cops_documentation_generator.rb +138 -55
  648. data/lib/rubocop/core_ext/string.rb +2 -6
  649. data/lib/rubocop/directive_comment.rb +57 -21
  650. data/lib/rubocop/ext/comment.rb +18 -0
  651. data/lib/rubocop/ext/regexp_node.rb +17 -35
  652. data/lib/rubocop/ext/regexp_parser.rb +7 -21
  653. data/lib/rubocop/file_finder.rb +11 -9
  654. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  655. data/lib/rubocop/formatter/disabled_config_formatter.rb +26 -10
  656. data/lib/rubocop/formatter/formatter_set.rb +8 -2
  657. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  658. data/lib/rubocop/formatter/html_formatter.rb +38 -15
  659. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  660. data/lib/rubocop/formatter/junit_formatter.rb +74 -24
  661. data/lib/rubocop/formatter/offense_count_formatter.rb +13 -3
  662. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  663. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  664. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  665. data/lib/rubocop/formatter.rb +1 -1
  666. data/lib/rubocop/lockfile.rb +58 -7
  667. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  668. data/lib/rubocop/lsp/logger.rb +22 -0
  669. data/lib/rubocop/lsp/routes.rb +227 -0
  670. data/lib/rubocop/lsp/runtime.rb +69 -0
  671. data/lib/rubocop/lsp/server.rb +70 -0
  672. data/lib/rubocop/lsp/severity.rb +27 -0
  673. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  674. data/lib/rubocop/lsp.rb +36 -0
  675. data/lib/rubocop/magic_comment.rb +24 -14
  676. data/lib/rubocop/options.rb +78 -23
  677. data/lib/rubocop/path_util.rb +21 -10
  678. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  679. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  680. data/lib/rubocop/plugin/load_error.rb +26 -0
  681. data/lib/rubocop/plugin/loader.rb +100 -0
  682. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  683. data/lib/rubocop/plugin.rb +46 -0
  684. data/lib/rubocop/rake_task.rb +5 -2
  685. data/lib/rubocop/remote_config.rb +5 -1
  686. data/lib/rubocop/result_cache.rb +20 -23
  687. data/lib/rubocop/rspec/cop_helper.rb +21 -3
  688. data/lib/rubocop/rspec/expect_offense.rb +31 -12
  689. data/lib/rubocop/rspec/shared_contexts.rb +118 -21
  690. data/lib/rubocop/rspec/support.rb +8 -2
  691. data/lib/rubocop/runner.rb +80 -17
  692. data/lib/rubocop/server/cache.rb +66 -8
  693. data/lib/rubocop/server/cli.rb +39 -20
  694. data/lib/rubocop/server/client_command/base.rb +10 -0
  695. data/lib/rubocop/server/client_command/exec.rb +6 -5
  696. data/lib/rubocop/server/client_command/start.rb +17 -2
  697. data/lib/rubocop/server/core.rb +29 -9
  698. data/lib/rubocop/server/helper.rb +1 -1
  699. data/lib/rubocop/server/server_command/exec.rb +1 -2
  700. data/lib/rubocop/string_interpreter.rb +3 -3
  701. data/lib/rubocop/target_finder.rb +97 -82
  702. data/lib/rubocop/target_ruby.rb +105 -79
  703. data/lib/rubocop/version.rb +74 -12
  704. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  705. data/lib/rubocop.rb +81 -2
  706. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  707. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  708. metadata +152 -63
  709. data/lib/rubocop/cop/naming/predicate_name.rb +0 -134
  710. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
  711. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -26,10 +26,18 @@ module RuboCop
26
26
  MSG = 'Precede `%<method>s` with a `@!method` YARD directive.'
27
27
  MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
28
28
  'use `%<expected>s` instead of `%<actual>s`.'
29
+ MSG_MISSING_SCOPE_SELF = 'Follow the `@!method` YARD directive with ' \
30
+ '`@!scope class` if it is a class method.'
31
+ MSG_WRONG_SCOPE_SELF = 'Do not use the `@!scope class` YARD directive if it ' \
32
+ 'is not a class method.'
29
33
  MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
30
34
 
31
35
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].to_set.freeze
32
- REGEXP = /^\s*#\s*@!method\s+(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?/.freeze
36
+ REGEXP_METHOD = /
37
+ ^\s*\#\s*
38
+ @!method\s+(?<receiver>self\.)?(?<method_name>[a-z0-9_]+[?!]?)(?:\((?<args>.*)\))?
39
+ /x.freeze
40
+ REGEXP_SCOPE = /^\s*\#\s*@!scope class/.freeze
33
41
 
34
42
  # @!method pattern_matcher?(node)
35
43
  def_node_matcher :pattern_matcher?, <<~PATTERN
@@ -37,69 +45,138 @@ module RuboCop
37
45
  PATTERN
38
46
 
39
47
  def on_send(node)
40
- return if node.arguments.none?
48
+ return unless node.arguments.count == 2
41
49
  return unless valid_method_name?(node)
42
50
 
43
- actual_name = node.arguments.first.value
51
+ actual_name = node.first_argument.value.to_s
52
+
53
+ # Ignore cases where the method has a receiver that isn't self
54
+ return if actual_name.include?('.') && !actual_name.start_with?('self.')
55
+
44
56
  directives = method_directives(node)
45
57
  return too_many_directives(node) if directives.size > 1
46
58
 
47
- directive = directives.first
48
- return if directive_correct?(directive, actual_name)
49
-
50
- register_offense(node, directive, actual_name)
59
+ process_directive(node, actual_name, directives.first)
51
60
  end
52
61
 
53
62
  private
54
63
 
55
64
  def valid_method_name?(node)
56
- node.arguments.first.str_type? || node.arguments.first.sym_type?
65
+ node.first_argument.type?(:str, :sym)
57
66
  end
58
67
 
59
68
  def method_directives(node)
60
69
  comments = processed_source.ast_with_comments[node]
61
-
62
- comments.map do |comment|
63
- match = comment.text.match(REGEXP)
70
+ group_comments(comments).filter_map do |comment_method, comment_scope|
71
+ match = comment_method.text.match(REGEXP_METHOD)
64
72
  next unless match
65
73
 
66
- { node: comment, method_name: match[:method_name], args: match[:args] }
67
- end.compact
74
+ {
75
+ node_method: comment_method,
76
+ node_scope: comment_scope,
77
+ method_name: match[:method_name],
78
+ args: match[:args],
79
+ receiver: match[:receiver],
80
+ has_scope_directive: comment_scope&.text&.match?(REGEXP_SCOPE)
81
+ }
82
+ end
83
+ end
84
+
85
+ def group_comments(comments)
86
+ result = []
87
+ comments.each.with_index do |comment, index|
88
+ # Grab the scope directive if it is preceded by a method directive
89
+ if comment.text.include?('@!method')
90
+ result << if (next_comment = comments[index + 1])&.text&.include?('@!scope')
91
+ [comment, next_comment]
92
+ else
93
+ [comment, nil]
94
+ end
95
+ end
96
+ end
97
+ result
68
98
  end
69
99
 
70
100
  def too_many_directives(node)
71
101
  add_offense(node, message: MSG_TOO_MANY)
72
102
  end
73
103
 
74
- def directive_correct?(directive, actual_name)
75
- directive && directive[:method_name] == actual_name.to_s
104
+ def process_directive(node, actual_name, directive)
105
+ return unless (offense_type = directive_offense_type(directive, actual_name))
106
+
107
+ register_offense(offense_type, node, directive, actual_name)
108
+ end
109
+
110
+ def directive_offense_type(directive, actual_name)
111
+ return :missing_directive unless directive
112
+
113
+ return :wrong_scope if wrong_scope?(directive, actual_name)
114
+ return :no_scope if no_scope?(directive, actual_name)
115
+
116
+ # The method directive being prefixed by 'self.' is always an offense.
117
+ # The matched method_name does not contain the receiver but the
118
+ # def_node_match method name may so it must be removed.
119
+ if directive[:method_name] != remove_receiver(actual_name) || directive[:receiver]
120
+ :wrong_name
121
+ end
122
+ end
123
+
124
+ def wrong_scope?(directive, actual_name)
125
+ !actual_name.start_with?('self.') && directive[:has_scope_directive]
76
126
  end
77
127
 
78
- def register_offense(node, directive, actual_name)
79
- message = formatted_message(directive, actual_name, node.method_name)
128
+ def no_scope?(directive, actual_name)
129
+ actual_name.start_with?('self.') && !directive[:has_scope_directive]
130
+ end
131
+
132
+ def register_offense(offense_type, node, directive, actual_name)
133
+ message = formatted_message(offense_type, directive, actual_name, node.method_name)
80
134
 
81
135
  add_offense(node, message: message) do |corrector|
82
- if directive
83
- correct_directive(corrector, directive, actual_name)
84
- else
85
- insert_directive(corrector, node, actual_name)
136
+ case offense_type
137
+ when :wrong_name
138
+ correct_method_directive(corrector, directive, actual_name)
139
+ when :wrong_scope
140
+ remove_scope_directive(corrector, directive)
141
+ when :no_scope
142
+ insert_scope_directive(corrector, directive[:node_method])
143
+ when :missing_directive
144
+ insert_method_directive(corrector, node, actual_name)
86
145
  end
87
146
  end
88
147
  end
89
148
 
90
- def formatted_message(directive, actual_name, method_name)
91
- if directive
92
- format(MSG_WRONG_NAME, expected: actual_name, actual: directive[:method_name])
93
- else
149
+ # rubocop:disable Metrics/MethodLength
150
+ def formatted_message(offense_type, directive, actual_name, method_name)
151
+ case offense_type
152
+ when :wrong_name
153
+ # Add the receiver to the name when showing an offense
154
+ current_name = if directive[:receiver]
155
+ directive[:receiver] + directive[:method_name]
156
+ else
157
+ directive[:method_name]
158
+ end
159
+ # The correct name will never include a receiver, remove it
160
+ format(MSG_WRONG_NAME, expected: remove_receiver(actual_name), actual: current_name)
161
+ when :wrong_scope
162
+ MSG_WRONG_SCOPE_SELF
163
+ when :no_scope
164
+ MSG_MISSING_SCOPE_SELF
165
+ when :missing_directive
94
166
  format(MSG, method: method_name)
95
167
  end
96
168
  end
169
+ # rubocop:enable Metrics/MethodLength
170
+
171
+ def remove_receiver(current)
172
+ current.delete_prefix('self.')
173
+ end
97
174
 
98
- def insert_directive(corrector, node, actual_name)
175
+ def insert_method_directive(corrector, node, actual_name)
99
176
  # If the pattern matcher uses arguments (`%1`, `%2`, etc.), include them in the directive
100
177
  arguments = pattern_arguments(node.arguments[1].source)
101
178
 
102
- range = range_with_surrounding_space(node.loc.expression, side: :left, newlines: false)
179
+ range = range_with_surrounding_space(node.source_range, side: :left, newlines: false)
103
180
  indentation = range.source.match(/^\s*/)[0]
104
181
  directive = "#{indentation}# @!method #{actual_name}(#{arguments.join(', ')})\n"
105
182
  directive = "\n#{directive}" if add_newline?(node)
@@ -107,6 +184,14 @@ module RuboCop
107
184
  corrector.insert_before(range, directive)
108
185
  end
109
186
 
187
+ def insert_scope_directive(corrector, node)
188
+ range = range_with_surrounding_space(node.source_range, side: :left, newlines: false)
189
+ indentation = range.source.match(/^\s*/)[0]
190
+ directive = "\n#{indentation}# @!scope class"
191
+
192
+ corrector.insert_after(node, directive)
193
+ end
194
+
110
195
  def pattern_arguments(pattern)
111
196
  arguments = %w[node]
112
197
  max_pattern_var = pattern.scan(/(?<=%)\d+/).map(&:to_i).max
@@ -117,11 +202,11 @@ module RuboCop
117
202
  def add_newline?(node)
118
203
  # Determine if a blank line should be inserted before the new directive
119
204
  # in order to spread out pattern matchers
120
- return if node.sibling_index&.zero?
121
- return unless node.parent
205
+ return false if node.sibling_index&.zero?
206
+ return false unless node.parent
122
207
 
123
208
  prev_sibling = node.parent.child_nodes[node.sibling_index - 1]
124
- return unless prev_sibling && pattern_matcher?(prev_sibling)
209
+ return false unless prev_sibling && pattern_matcher?(prev_sibling)
125
210
 
126
211
  node.loc.line == last_line(prev_sibling) + 1
127
212
  end
@@ -134,12 +219,21 @@ module RuboCop
134
219
  end
135
220
  end
136
221
 
137
- def correct_directive(corrector, directive, actual_name)
138
- correct = "@!method #{actual_name}"
139
- regexp = /@!method\s+#{Regexp.escape(directive[:method_name])}/
222
+ def correct_method_directive(corrector, directive, actual_name)
223
+ correct = "@!method #{remove_receiver(actual_name)}"
224
+ current_name = (directive[:receiver] || '') + directive[:method_name]
225
+ regexp = /@!method\s+#{Regexp.escape(current_name)}/
226
+
227
+ replacement = directive[:node_method].text.gsub(regexp, correct)
228
+ corrector.replace(directive[:node_method], replacement)
229
+ end
140
230
 
141
- replacement = directive[:node].text.gsub(regexp, correct)
142
- corrector.replace(directive[:node], replacement)
231
+ def remove_scope_directive(corrector, directive)
232
+ range = range_by_whole_lines(
233
+ directive[:node_scope].source_range,
234
+ include_final_newline: true
235
+ )
236
+ corrector.remove(range)
143
237
  end
144
238
  end
145
239
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ class NodePatternGroups
7
+ # AST Processor for NodePattern ASTs, for use with `InternalAffairs/NodePatternGroups`.
8
+ #
9
+ # Looks for sequences and subsequences where the first item is a `node_type` node,
10
+ # and converts them to `node_sequence` nodes (not a true `Rubocop::AST::NodePattern`
11
+ # node type).
12
+ #
13
+ # The resulting AST will be walked by `InternalAffairs::NodePatternGroups::ASTWalker`
14
+ # in order to find node types in a `union` node that can be rewritten as a node group.
15
+ #
16
+ # NOTE: The `on_*` methods in this class relate not to the normal node types but
17
+ # rather to the Node Pattern node types. Not every node type is handled.
18
+ #
19
+ class ASTProcessor
20
+ include ::AST::Processor::Mixin
21
+
22
+ def handler_missing(node)
23
+ node.updated(nil, process_children(node))
24
+ end
25
+
26
+ # Look for `sequence` and `subsequence` nodes that contain a `node_type` node as
27
+ # their first child. These are rewritten as `node_sequence` nodes so that it is
28
+ # possible to compare nodes while looking for replacement candidates for node groups.
29
+ # This is necessary so that extended patterns can be matched and replaced.
30
+ # ie. `{(send _ :foo ...) (csend _ :foo ...)}` can become `(call _ :foo ...)`
31
+ def on_sequence(node)
32
+ first_child = node.child
33
+
34
+ if first_child.type == :node_type
35
+ children = [first_child.child, *process_children(node, 1..)]
36
+
37
+ # The `node_sequence` node contains the `node_type` symbol as its first child,
38
+ # followed by all the other nodes contained in the `sequence` node.
39
+ # The location is copied from the sequence, so that the entire sequence can
40
+ # eventually be corrected in the cop.
41
+ n(:node_sequence, children, location: node.location)
42
+ else
43
+ node.updated(nil, process_children(node))
44
+ end
45
+ end
46
+ alias on_subsequence on_sequence
47
+
48
+ private
49
+
50
+ def n(type, children = [], properties = {})
51
+ NodePattern::Node.new(type, children, properties)
52
+ end
53
+
54
+ def process_children(node, range = 0..-1)
55
+ node.children[range].map do |child|
56
+ child.is_a?(::AST::Node) ? process(child) : child
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # rubocop:disable InternalAffairs/RedundantSourceRange -- node here is a `NodePattern::Node`
7
+ class NodePatternGroups
8
+ # Walks an AST that has been processed by `InternalAffairs::NodePatternGroups::Processor`
9
+ # in order to find `node_type` and `node_sequence` nodes that can be replaced with a node
10
+ # group in `InternalAffairs/NodePatternGroups`.
11
+ #
12
+ # Calling `ASTWalker#walk` sets `node_groups` with an array of `NodeGroup` structs
13
+ # that contain metadata about nodes that can be replaced, including location data. That
14
+ # metadata is used by the cop to register offenses and perform corrections.
15
+ class ASTWalker
16
+ # Struct to contain data about parts of a node pattern that can be replaced
17
+ NodeGroup = Struct.new(
18
+ :name, # The name of the node group that will be inserted
19
+ :union, # The entire `union` node
20
+ :node_types, # An array of `node_type` nodes that will be removed
21
+ :sequence?, # The pattern matches a node type with given attributes
22
+ :start_index, # The index in the union of the first node type to remove
23
+ :offense_range, # The range to mark an offense on
24
+ :ranges, # Range of each element to remove, since they may not be adjacent
25
+ :pipe, # Is the union delimited by pipes?
26
+ :other_elements?, # Does the union have other elements other than those to remove?
27
+ keyword_init: true
28
+ )
29
+
30
+ def initialize
31
+ reset!
32
+ end
33
+
34
+ def reset!
35
+ @node_groups = []
36
+ end
37
+
38
+ attr_reader :node_groups
39
+
40
+ # Recursively walk the AST in a depth-first manner.
41
+ # Only `union` nodes are handled further.
42
+ def walk(node)
43
+ return if node.nil?
44
+
45
+ on_union(node) if node.type == :union
46
+
47
+ node.child_nodes.each do |child|
48
+ walk(child)
49
+ end
50
+ end
51
+
52
+ # Search `union` nodes for `node_type` and `node_sequence` nodes that can be
53
+ # collapsed into a node group.
54
+ # * `node_type` nodes are nodes with no further configuration (ie. `send`)
55
+ # * `node_sequence` nodes are nodes with further configuration (ie. `(send ...)`)
56
+ #
57
+ # Each group of types that can be collapsed will have a `NodeGroup` record added
58
+ # to `node_groups`, which is then used by the cop.
59
+ def on_union(node)
60
+ all_node_types = each_child_node(node, :node_type, :node_sequence).to_a
61
+
62
+ each_node_group(all_node_types) do |group_name, node_types|
63
+ next unless sequences_match?(node_types)
64
+
65
+ node_groups << node_group_data(
66
+ group_name, node, node_types,
67
+ all_node_types.index(node_types.first),
68
+ (node.children - node_types).any?
69
+ )
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def each_child_node(node, *types)
76
+ return to_enum(__method__, node, *types) unless block_given?
77
+
78
+ node.children.each do |child|
79
+ yield child if types.empty? || types.include?(child.type)
80
+ end
81
+
82
+ self
83
+ end
84
+
85
+ def each_node_group(types_to_check)
86
+ # Find all node groups where all of the members are present in the union
87
+ type_names = types_to_check.map(&:child)
88
+
89
+ NODE_GROUPS.select { |_, group| group & type_names == group }.each_key do |name|
90
+ nodes = get_relevant_nodes(types_to_check, name)
91
+
92
+ yield name, nodes
93
+ end
94
+ end
95
+
96
+ def get_relevant_nodes(node_types, group_name)
97
+ node_types.each_with_object([]) do |node_type, arr|
98
+ next unless NODE_GROUPS[group_name].include?(node_type.child)
99
+
100
+ arr << node_type
101
+ end
102
+ end
103
+
104
+ def node_group_data(name, union, node_types, start_index, other)
105
+ NodeGroup.new(
106
+ name: name,
107
+ union: union,
108
+ node_types: node_types,
109
+ sequence?: node_types.first.type == :node_sequence,
110
+ start_index: start_index,
111
+ pipe: union.source_range.source['|'],
112
+ other_elements?: other
113
+ )
114
+ end
115
+
116
+ def sequences_match?(types)
117
+ # Ensure all given types have the same type and the same sequence
118
+ # ie. `(send ...)` and `(csend ...) is a match
119
+ # `(send)` and `(csend ...)` is not a match
120
+ # `send` and `(csend ...)` is not a match
121
+
122
+ types.each_cons(2).all? do |left, right|
123
+ left.type == right.type && left.children[1..] == right.children[1..]
124
+ end
125
+ end
126
+ end
127
+ end
128
+ # rubocop:enable InternalAffairs/RedundantSourceRange
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Use node groups (`any_block`, `argument`, `boolean`, `call`, `numeric`, `range`)
7
+ # in node patterns instead of a union (`{ ... }`) of the member types of the group.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # def_node_matcher :my_matcher, <<~PATTERN
12
+ # {send csend}
13
+ # PATTERN
14
+ #
15
+ # # good
16
+ # def_node_matcher :my_matcher, <<~PATTERN
17
+ # call
18
+ # PATTERN
19
+ #
20
+ class NodePatternGroups < Base
21
+ require_relative 'node_pattern_groups/ast_processor'
22
+ require_relative 'node_pattern_groups/ast_walker'
23
+
24
+ include RangeHelp
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Replace `%<names>s` in node pattern union with `%<replacement>s`.'
28
+ RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].freeze
29
+ NODE_GROUPS = {
30
+ any_block: %i[block numblock itblock],
31
+ any_def: %i[def defs],
32
+ any_match_pattern: %i[match_pattern match_pattern_p],
33
+ argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
34
+ boolean: %i[true false],
35
+ call: %i[send csend],
36
+ numeric: %i[int float rational complex],
37
+ range: %i[irange erange]
38
+ }.freeze
39
+
40
+ def on_new_investigation
41
+ @walker = ASTWalker.new
42
+ end
43
+
44
+ # When a Node Pattern matcher is defined, investigate the pattern string to search
45
+ # for node types that can be replaced with a node group (ie. `{send csend}` can be
46
+ # replaced with `call`).
47
+ #
48
+ # In order to deal with node patterns in an efficient and non-brittle way, we will
49
+ # parse the Node Pattern string given to this `send` node using
50
+ # `RuboCop::AST::NodePattern::Parser::WithMeta`. `WithMeta` is important! We need
51
+ # location information so that we can calculate the exact locations within the
52
+ # pattern to report and correct.
53
+ #
54
+ # The resulting AST is processed by `NodePatternGroups::ASTProccessor` which rewrites
55
+ # the AST slightly to handle node sequences (ie. `(send _ :foo ...)`). See the
56
+ # documentation of that class for more details.
57
+ #
58
+ # Then the processed AST is walked, and metadata is collected for node types that
59
+ # can be replaced with a node group.
60
+ #
61
+ # Finally, the metadata is used to register offenses and make corrections, using
62
+ # the location data captured earlier. The ranges captured while parsing the Node
63
+ # Pattern are offset using the string argument to this `send` node to ensure
64
+ # that offenses are registered at the correct location.
65
+ #
66
+ def on_send(node)
67
+ pattern_node = node.arguments[1]
68
+ return unless acceptable_heredoc?(pattern_node) || pattern_node.str_type?
69
+
70
+ process_pattern(pattern_node)
71
+ return if node_groups.nil?
72
+
73
+ apply_range_offsets(pattern_node)
74
+
75
+ node_groups.each_with_index do |group, index|
76
+ register_offense(group, index)
77
+ end
78
+ end
79
+
80
+ def after_send(_)
81
+ @walker.reset!
82
+ end
83
+
84
+ private
85
+
86
+ def node_groups
87
+ @walker.node_groups
88
+ end
89
+
90
+ # rubocop:disable InternalAffairs/RedundantSourceRange -- `node` here is a NodePatternNode
91
+ def register_offense(group, index)
92
+ replacement = replacement(group)
93
+ message = format(
94
+ MSG,
95
+ names: group.node_types.map { |node| node.source_range.source }.join('`, `'),
96
+ replacement: replacement
97
+ )
98
+
99
+ add_offense(group.offense_range, message: message) do |corrector|
100
+ # Only correct one group at a time to avoid clobbering.
101
+ # Other offenses will be corrected in the subsequent iterations of the
102
+ # correction loop.
103
+ next if index.positive?
104
+
105
+ if group.other_elements?
106
+ replace_types_with_node_group(corrector, group, replacement)
107
+ else
108
+ replace_union(corrector, group, replacement)
109
+ end
110
+ end
111
+ end
112
+
113
+ def replacement(group)
114
+ if group.sequence?
115
+ # If the original nodes were in a sequence (ie. wrapped in parentheses),
116
+ # use it to generate the resulting NodePattern syntax.
117
+ first_node_type = group.node_types.first
118
+ template = first_node_type.source_range.source
119
+ template.sub(first_node_type.child.to_s, group.name.to_s)
120
+ else
121
+ group.name
122
+ end
123
+ end
124
+ # rubocop:enable InternalAffairs/RedundantSourceRange
125
+
126
+ # When there are other elements in the union, remove the node types that can be replaced.
127
+ def replace_types_with_node_group(corrector, group, replacement)
128
+ ranges = group.ranges.map.with_index do |range, index|
129
+ # Collect whitespace and pipes preceding each element
130
+ range_for_full_union_element(range, index, group.pipe)
131
+ end
132
+
133
+ ranges.each { |range| corrector.remove(range) }
134
+
135
+ corrector.insert_before(ranges.first, replacement)
136
+ end
137
+
138
+ # If the union contains pipes, remove the pipe character as well.
139
+ # Unfortunately we don't get the location of the pipe in `loc` object, so we have
140
+ # to find it.
141
+ def range_for_full_union_element(range, index, pipe)
142
+ if index.positive?
143
+ range = if pipe
144
+ range_with_preceding_pipe(range)
145
+ else
146
+ range_with_surrounding_space(range: range, side: :left, newlines: true)
147
+ end
148
+ end
149
+
150
+ range
151
+ end
152
+
153
+ # Collect a preceding pipe and any whitespace left of the pipe
154
+ def range_with_preceding_pipe(range)
155
+ pos = range.begin_pos - 1
156
+
157
+ while pos
158
+ unless processed_source.buffer.source[pos].match?(/[\s|]/)
159
+ return range.with(begin_pos: pos + 1)
160
+ end
161
+
162
+ pos -= 1
163
+ end
164
+
165
+ range
166
+ end
167
+
168
+ # When there are no other elements, the entire union can be replaced
169
+ def replace_union(corrector, group, replacement)
170
+ corrector.replace(group.ranges.first, replacement)
171
+ end
172
+
173
+ # rubocop:disable Metrics/AbcSize
174
+ # Calculate the ranges for each node within the pattern string that will
175
+ # be replaced or removed. Takes the offset of the string node into account.
176
+ def apply_range_offsets(pattern_node)
177
+ range, offset = range_with_offset(pattern_node)
178
+
179
+ node_groups.each do |node_group|
180
+ node_group.ranges ||= []
181
+ node_group.offense_range = pattern_range(range, node_group.union, offset)
182
+
183
+ if node_group.other_elements?
184
+ node_group.node_types.each do |node_type|
185
+ node_group.ranges << pattern_range(range, node_type, offset)
186
+ end
187
+ else
188
+ node_group.ranges << node_group.offense_range
189
+ end
190
+ end
191
+ end
192
+ # rubocop:enable Metrics/AbcSize
193
+
194
+ def pattern_range(range, node, offset)
195
+ begin_pos = node.source_range.begin_pos
196
+ end_pos = node.source_range.end_pos
197
+ size = end_pos - begin_pos
198
+
199
+ range.adjust(begin_pos: begin_pos + offset).resize(size)
200
+ end
201
+
202
+ def range_with_offset(pattern_node)
203
+ if pattern_node.heredoc?
204
+ [pattern_node.loc.heredoc_body, 0]
205
+ else
206
+ [pattern_node.source_range, pattern_node.loc.begin.size]
207
+ end
208
+ end
209
+
210
+ # A heredoc can be a `dstr` without interpolation, but if there is interpolation
211
+ # there'll be a `begin` node, in which case, we cannot evaluate the pattern.
212
+ def acceptable_heredoc?(node)
213
+ node.type?(:str, :dstr) && node.heredoc? && node.each_child_node(:begin).none?
214
+ end
215
+
216
+ def process_pattern(pattern_node)
217
+ parser = RuboCop::AST::NodePattern::Parser::WithMeta.new
218
+ ast = parser.parse(pattern_value(pattern_node))
219
+ ast = ASTProcessor.new.process(ast)
220
+ @walker.walk(ast)
221
+ rescue RuboCop::AST::NodePattern::Invalid
222
+ # if the pattern is invalid, no offenses will be registered
223
+ end
224
+
225
+ def pattern_value(pattern_node)
226
+ pattern_node.heredoc? ? pattern_node.loc.heredoc_body.source : pattern_node.value
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end