rubocop 1.67.0 → 1.81.6

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 (526) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +384 -72
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +8 -3
  7. data/exe/rubocop +1 -8
  8. data/lib/rubocop/cached_data.rb +12 -4
  9. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  10. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  11. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  12. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  13. data/lib/rubocop/cli/command/version.rb +2 -2
  14. data/lib/rubocop/cli.rb +19 -4
  15. data/lib/rubocop/comment_config.rb +2 -2
  16. data/lib/rubocop/config.rb +52 -10
  17. data/lib/rubocop/config_loader.rb +56 -48
  18. data/lib/rubocop/config_loader_resolver.rb +36 -10
  19. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  20. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  21. data/lib/rubocop/config_obsoletion.rb +46 -2
  22. data/lib/rubocop/config_store.rb +5 -0
  23. data/lib/rubocop/config_validator.rb +25 -14
  24. data/lib/rubocop/cop/autocorrect_logic.rb +53 -28
  25. data/lib/rubocop/cop/base.rb +7 -1
  26. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  28. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  29. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  30. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -16
  32. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +8 -3
  33. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  34. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  35. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  36. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  37. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
  38. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  39. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  40. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  41. data/lib/rubocop/cop/generator.rb +6 -0
  42. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  43. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  44. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  45. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  46. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  47. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  48. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +5 -5
  49. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  50. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  51. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +233 -0
  52. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
  53. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  54. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  55. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  56. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  57. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  58. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  59. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  60. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  61. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  62. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  63. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  64. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  65. data/lib/rubocop/cop/internal_affairs.rb +7 -16
  66. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  67. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  68. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  69. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  70. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  71. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  72. data/lib/rubocop/cop/layout/class_structure.rb +45 -10
  73. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  74. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  75. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  76. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  77. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -3
  78. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +34 -20
  79. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  80. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +37 -7
  81. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  82. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  83. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  84. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  85. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  86. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  87. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  88. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  89. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -9
  90. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  91. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  92. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  93. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  94. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -11
  95. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  96. data/lib/rubocop/cop/layout/indentation_width.rb +8 -7
  97. data/lib/rubocop/cop/layout/leading_comment_space.rb +57 -2
  98. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  99. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  100. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  101. data/lib/rubocop/cop/layout/line_length.rb +158 -10
  102. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  103. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  104. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  105. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  106. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  107. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  108. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  109. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +11 -8
  110. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  111. data/lib/rubocop/cop/layout/redundant_line_break.rb +19 -46
  112. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +14 -7
  113. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  114. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  115. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  116. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  117. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  118. data/lib/rubocop/cop/layout/space_around_keyword.rb +8 -2
  119. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  120. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -21
  121. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  122. data/lib/rubocop/cop/layout/space_before_brackets.rb +7 -40
  123. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  124. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  125. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +18 -3
  126. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +5 -0
  127. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +7 -0
  128. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  129. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -4
  130. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  131. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  132. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +118 -0
  133. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  134. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  135. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  136. data/lib/rubocop/cop/lint/circular_argument_reference.rb +4 -1
  137. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  138. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  139. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  140. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +90 -0
  141. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  142. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  143. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +7 -3
  144. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  145. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  146. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -23
  147. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +6 -43
  148. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  149. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  150. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  151. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  152. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  153. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  154. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  155. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  156. data/lib/rubocop/cop/lint/float_comparison.rb +51 -18
  157. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  158. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  159. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  160. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  161. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  162. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  163. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  164. data/lib/rubocop/cop/lint/literal_as_condition.rb +125 -10
  165. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  166. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  167. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
  168. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  169. data/lib/rubocop/cop/lint/mixed_case_range.rb +5 -8
  170. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  171. data/lib/rubocop/cop/lint/nested_method_definition.rb +10 -6
  172. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  173. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  174. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  175. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  176. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  177. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  178. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  179. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +94 -0
  180. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -3
  181. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  182. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  183. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  184. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  185. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +2 -2
  186. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  187. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +113 -9
  188. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  189. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  190. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  191. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  192. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  193. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  194. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  195. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  196. data/lib/rubocop/cop/lint/rescue_exception.rb +2 -5
  197. data/lib/rubocop/cop/lint/rescue_type.rb +4 -8
  198. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  199. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  200. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
  201. data/lib/rubocop/cop/lint/self_assignment.rb +39 -15
  202. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  203. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  204. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -1
  205. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  206. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  207. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  208. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  209. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  210. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  211. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  212. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  213. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  214. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  215. data/lib/rubocop/cop/lint/unreachable_code.rb +52 -2
  216. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  217. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  218. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  219. data/lib/rubocop/cop/lint/useless_access_modifier.rb +34 -8
  220. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -1
  221. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  222. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  223. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  224. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  225. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  226. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +3 -1
  227. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  228. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -2
  229. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -5
  230. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  231. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  232. data/lib/rubocop/cop/lint/void.rb +23 -12
  233. data/lib/rubocop/cop/message_annotator.rb +7 -3
  234. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  235. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  236. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  237. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  238. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  239. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  240. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  241. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  242. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  243. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  244. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -4
  245. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  246. data/lib/rubocop/cop/mixin/alignment.rb +3 -3
  247. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  248. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  249. data/lib/rubocop/cop/mixin/check_line_breakable.rb +22 -12
  250. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  251. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  252. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  253. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  254. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  255. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  256. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  257. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  258. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  259. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -3
  260. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  261. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
  262. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  263. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  264. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  265. data/lib/rubocop/cop/mixin/line_length_help.rb +27 -10
  266. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  267. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -9
  268. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  269. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  270. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  271. data/lib/rubocop/cop/mixin/range_help.rb +15 -4
  272. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  273. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  274. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  275. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  276. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  277. data/lib/rubocop/cop/mixin/trailing_comma.rb +21 -5
  278. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  279. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  280. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  281. data/lib/rubocop/cop/naming/file_name.rb +2 -4
  282. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -13
  283. data/lib/rubocop/cop/naming/method_name.rb +185 -15
  284. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  285. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +48 -4
  286. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  287. data/lib/rubocop/cop/naming/variable_name.rb +50 -6
  288. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  289. data/lib/rubocop/cop/offense.rb +2 -3
  290. data/lib/rubocop/cop/registry.rb +9 -6
  291. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  292. data/lib/rubocop/cop/security/eval.rb +2 -1
  293. data/lib/rubocop/cop/security/json_load.rb +33 -11
  294. data/lib/rubocop/cop/security/open.rb +1 -0
  295. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  296. data/lib/rubocop/cop/style/access_modifier_declarations.rb +114 -34
  297. data/lib/rubocop/cop/style/accessor_grouping.rb +32 -6
  298. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  299. data/lib/rubocop/cop/style/and_or.rb +1 -1
  300. data/lib/rubocop/cop/style/arguments_forwarding.rb +57 -44
  301. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  302. data/lib/rubocop/cop/style/array_intersect.rb +115 -39
  303. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  304. data/lib/rubocop/cop/style/bitwise_predicate.rb +107 -0
  305. data/lib/rubocop/cop/style/block_delimiters.rb +44 -26
  306. data/lib/rubocop/cop/style/case_like_if.rb +9 -12
  307. data/lib/rubocop/cop/style/class_and_module_children.rb +52 -11
  308. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  309. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  310. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  311. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  312. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  313. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  314. data/lib/rubocop/cop/style/commented_keyword.rb +20 -3
  315. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  316. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  317. data/lib/rubocop/cop/style/conditional_assignment.rb +49 -31
  318. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  319. data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
  320. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  321. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  322. data/lib/rubocop/cop/style/documentation.rb +1 -1
  323. data/lib/rubocop/cop/style/double_negation.rb +5 -5
  324. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  325. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  326. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  327. data/lib/rubocop/cop/style/empty_literal.rb +5 -1
  328. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  329. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  330. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  331. data/lib/rubocop/cop/style/eval_with_location.rb +4 -4
  332. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  333. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  334. data/lib/rubocop/cop/style/explicit_block_argument.rb +17 -4
  335. data/lib/rubocop/cop/style/exponential_notation.rb +6 -5
  336. data/lib/rubocop/cop/style/fetch_env_var.rb +34 -7
  337. data/lib/rubocop/cop/style/file_null.rb +89 -0
  338. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  339. data/lib/rubocop/cop/style/float_division.rb +8 -4
  340. data/lib/rubocop/cop/style/for.rb +1 -1
  341. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  342. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  343. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  344. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  345. data/lib/rubocop/cop/style/guard_clause.rb +17 -3
  346. data/lib/rubocop/cop/style/hash_conversion.rb +16 -9
  347. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  348. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  349. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  350. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  351. data/lib/rubocop/cop/style/hash_syntax.rb +9 -3
  352. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  353. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  354. data/lib/rubocop/cop/style/identical_conditional_branches.rb +25 -6
  355. data/lib/rubocop/cop/style/if_inside_else.rb +10 -14
  356. data/lib/rubocop/cop/style/if_unless_modifier.rb +36 -9
  357. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  358. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -4
  359. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -9
  360. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  361. data/lib/rubocop/cop/style/inverse_methods.rb +16 -13
  362. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  363. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  364. data/lib/rubocop/cop/style/it_assignment.rb +93 -0
  365. data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
  366. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  367. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  368. data/lib/rubocop/cop/style/lambda.rb +1 -0
  369. data/lib/rubocop/cop/style/lambda_call.rb +10 -4
  370. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  371. data/lib/rubocop/cop/style/map_into_array.rb +11 -3
  372. data/lib/rubocop/cop/style/map_to_hash.rb +13 -4
  373. data/lib/rubocop/cop/style/map_to_set.rb +4 -5
  374. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +28 -20
  375. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +18 -0
  376. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  377. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  378. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  379. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  380. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  381. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  382. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  383. data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
  384. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  385. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  386. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  387. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  388. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  389. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  390. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  391. data/lib/rubocop/cop/style/next.rb +44 -0
  392. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  393. data/lib/rubocop/cop/style/not.rb +1 -1
  394. data/lib/rubocop/cop/style/object_then.rb +15 -15
  395. data/lib/rubocop/cop/style/one_line_conditional.rb +42 -13
  396. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  397. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  398. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  399. data/lib/rubocop/cop/style/parallel_assignment.rb +41 -38
  400. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  401. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  402. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  403. data/lib/rubocop/cop/style/proc.rb +2 -2
  404. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  405. data/lib/rubocop/cop/style/raise_args.rb +15 -13
  406. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  407. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  408. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  409. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  410. data/lib/rubocop/cop/style/redundant_begin.rb +36 -1
  411. data/lib/rubocop/cop/style/redundant_condition.rb +95 -23
  412. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  413. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  414. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  415. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  416. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  417. data/lib/rubocop/cop/style/redundant_format.rb +283 -0
  418. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  419. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  420. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  421. data/lib/rubocop/cop/style/redundant_line_continuation.rb +55 -19
  422. data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -36
  423. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -0
  424. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  425. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -1
  426. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  427. data/lib/rubocop/cop/style/redundant_self.rb +15 -18
  428. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  429. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  430. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  431. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  432. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  433. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  434. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
  435. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  436. data/lib/rubocop/cop/style/safe_navigation.rb +75 -16
  437. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  438. data/lib/rubocop/cop/style/select_by_regexp.rb +5 -2
  439. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  440. data/lib/rubocop/cop/style/semicolon.rb +21 -6
  441. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  442. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  443. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  444. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  445. data/lib/rubocop/cop/style/single_line_do_end_block.rb +15 -4
  446. data/lib/rubocop/cop/style/single_line_methods.rb +13 -11
  447. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  448. data/lib/rubocop/cop/style/sole_nested_conditional.rb +68 -102
  449. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  450. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  451. data/lib/rubocop/cop/style/string_concatenation.rb +21 -17
  452. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  453. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  454. data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
  455. data/lib/rubocop/cop/style/super_arguments.rb +66 -19
  456. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  457. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  458. data/lib/rubocop/cop/style/symbol_proc.rb +3 -1
  459. data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
  460. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  461. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +56 -2
  462. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  463. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  464. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  465. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  466. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  467. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  468. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  469. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  470. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  471. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  472. data/lib/rubocop/cop/team.rb +1 -1
  473. data/lib/rubocop/cop/util.rb +12 -5
  474. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  475. data/lib/rubocop/cop/variable_force/assignment.rb +24 -5
  476. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  477. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  478. data/lib/rubocop/cop/variable_force/variable.rb +14 -3
  479. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  480. data/lib/rubocop/cop/variable_force.rb +30 -19
  481. data/lib/rubocop/cops_documentation_generator.rb +54 -28
  482. data/lib/rubocop/directive_comment.rb +45 -11
  483. data/lib/rubocop/ext/regexp_node.rb +0 -1
  484. data/lib/rubocop/formatter/disabled_config_formatter.rb +20 -6
  485. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  486. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  487. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  488. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  489. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  490. data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
  491. data/lib/rubocop/lsp/diagnostic.rb +190 -0
  492. data/lib/rubocop/lsp/logger.rb +2 -2
  493. data/lib/rubocop/lsp/routes.rb +66 -26
  494. data/lib/rubocop/lsp/runtime.rb +18 -50
  495. data/lib/rubocop/lsp/server.rb +2 -4
  496. data/lib/rubocop/lsp/stdin_runner.rb +69 -0
  497. data/lib/rubocop/magic_comment.rb +11 -3
  498. data/lib/rubocop/options.rb +28 -12
  499. data/lib/rubocop/path_util.rb +15 -8
  500. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  501. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  502. data/lib/rubocop/plugin/load_error.rb +26 -0
  503. data/lib/rubocop/plugin/loader.rb +100 -0
  504. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  505. data/lib/rubocop/plugin.rb +46 -0
  506. data/lib/rubocop/rake_task.rb +4 -1
  507. data/lib/rubocop/result_cache.rb +27 -25
  508. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  509. data/lib/rubocop/rspec/expect_offense.rb +15 -5
  510. data/lib/rubocop/rspec/shared_contexts.rb +38 -1
  511. data/lib/rubocop/rspec/support.rb +4 -2
  512. data/lib/rubocop/runner.rb +31 -18
  513. data/lib/rubocop/server/cache.rb +51 -13
  514. data/lib/rubocop/server/cli.rb +2 -2
  515. data/lib/rubocop/server/client_command/base.rb +10 -0
  516. data/lib/rubocop/server/client_command/exec.rb +2 -1
  517. data/lib/rubocop/server/client_command/start.rb +11 -1
  518. data/lib/rubocop/target_finder.rb +14 -9
  519. data/lib/rubocop/target_ruby.rb +27 -3
  520. data/lib/rubocop/version.rb +53 -12
  521. data/lib/rubocop.rb +44 -2
  522. data/lib/ruby_lsp/rubocop/addon.rb +90 -0
  523. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  524. metadata +91 -21
  525. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  526. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -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,233 @@
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
+ any_str: %i[str dstr xstr],
34
+ any_sym: %i[sym dsym],
35
+ argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
36
+ boolean: %i[true false],
37
+ call: %i[send csend],
38
+ numeric: %i[int float rational complex],
39
+ range: %i[irange erange]
40
+ }.freeze
41
+
42
+ def on_new_investigation
43
+ @walker = ASTWalker.new
44
+ end
45
+
46
+ # When a Node Pattern matcher is defined, investigate the pattern string to search
47
+ # for node types that can be replaced with a node group (ie. `{send csend}` can be
48
+ # replaced with `call`).
49
+ #
50
+ # In order to deal with node patterns in an efficient and non-brittle way, we will
51
+ # parse the Node Pattern string given to this `send` node using
52
+ # `RuboCop::AST::NodePattern::Parser::WithMeta`. `WithMeta` is important! We need
53
+ # location information so that we can calculate the exact locations within the
54
+ # pattern to report and correct.
55
+ #
56
+ # The resulting AST is processed by `NodePatternGroups::ASTProccessor` which rewrites
57
+ # the AST slightly to handle node sequences (ie. `(send _ :foo ...)`). See the
58
+ # documentation of that class for more details.
59
+ #
60
+ # Then the processed AST is walked, and metadata is collected for node types that
61
+ # can be replaced with a node group.
62
+ #
63
+ # Finally, the metadata is used to register offenses and make corrections, using
64
+ # the location data captured earlier. The ranges captured while parsing the Node
65
+ # Pattern are offset using the string argument to this `send` node to ensure
66
+ # that offenses are registered at the correct location.
67
+ #
68
+ def on_send(node)
69
+ pattern_node = node.arguments[1]
70
+ return unless acceptable_heredoc?(pattern_node) || pattern_node.str_type?
71
+
72
+ process_pattern(pattern_node)
73
+ return if node_groups.nil?
74
+
75
+ apply_range_offsets(pattern_node)
76
+
77
+ node_groups.each_with_index do |group, index|
78
+ register_offense(group, index)
79
+ end
80
+ end
81
+
82
+ def after_send(_)
83
+ @walker.reset!
84
+ end
85
+
86
+ private
87
+
88
+ def node_groups
89
+ @walker.node_groups
90
+ end
91
+
92
+ # rubocop:disable InternalAffairs/RedundantSourceRange -- `node` here is a NodePatternNode
93
+ def register_offense(group, index)
94
+ replacement = replacement(group)
95
+ message = format(
96
+ MSG,
97
+ names: group.node_types.map { |node| node.source_range.source }.join('`, `'),
98
+ replacement: replacement
99
+ )
100
+
101
+ add_offense(group.offense_range, message: message) do |corrector|
102
+ # Only correct one group at a time to avoid clobbering.
103
+ # Other offenses will be corrected in the subsequent iterations of the
104
+ # correction loop.
105
+ next if index.positive?
106
+
107
+ if group.other_elements?
108
+ replace_types_with_node_group(corrector, group, replacement)
109
+ else
110
+ replace_union(corrector, group, replacement)
111
+ end
112
+ end
113
+ end
114
+
115
+ def replacement(group)
116
+ if group.sequence?
117
+ # If the original nodes were in a sequence (ie. wrapped in parentheses),
118
+ # use it to generate the resulting NodePattern syntax.
119
+ first_node_type = group.node_types.first
120
+ template = first_node_type.source_range.source
121
+ template.sub(first_node_type.child.to_s, group.name.to_s)
122
+ else
123
+ group.name
124
+ end
125
+ end
126
+ # rubocop:enable InternalAffairs/RedundantSourceRange
127
+
128
+ # When there are other elements in the union, remove the node types that can be replaced.
129
+ def replace_types_with_node_group(corrector, group, replacement)
130
+ ranges = group.ranges.map.with_index do |range, index|
131
+ # Collect whitespace and pipes preceding each element
132
+ range_for_full_union_element(range, index, group.pipe)
133
+ end
134
+
135
+ ranges.each { |range| corrector.remove(range) }
136
+
137
+ corrector.insert_before(ranges.first, replacement)
138
+ end
139
+
140
+ # If the union contains pipes, remove the pipe character as well.
141
+ # Unfortunately we don't get the location of the pipe in `loc` object, so we have
142
+ # to find it.
143
+ def range_for_full_union_element(range, index, pipe)
144
+ if index.positive?
145
+ range = if pipe
146
+ range_with_preceding_pipe(range)
147
+ else
148
+ range_with_surrounding_space(range: range, side: :left, newlines: true)
149
+ end
150
+ end
151
+
152
+ range
153
+ end
154
+
155
+ # Collect a preceding pipe and any whitespace left of the pipe
156
+ def range_with_preceding_pipe(range)
157
+ pos = range.begin_pos - 1
158
+
159
+ while pos
160
+ unless processed_source.buffer.source[pos].match?(/[\s|]/)
161
+ return range.with(begin_pos: pos + 1)
162
+ end
163
+
164
+ pos -= 1
165
+ end
166
+
167
+ range
168
+ end
169
+
170
+ # When there are no other elements, the entire union can be replaced
171
+ def replace_union(corrector, group, replacement)
172
+ corrector.replace(group.ranges.first, replacement)
173
+ end
174
+
175
+ # rubocop:disable Metrics/AbcSize
176
+ # Calculate the ranges for each node within the pattern string that will
177
+ # be replaced or removed. Takes the offset of the string node into account.
178
+ def apply_range_offsets(pattern_node)
179
+ range, offset = range_with_offset(pattern_node)
180
+
181
+ node_groups.each do |node_group|
182
+ node_group.ranges ||= []
183
+ node_group.offense_range = pattern_range(range, node_group.union, offset)
184
+
185
+ if node_group.other_elements?
186
+ node_group.node_types.each do |node_type|
187
+ node_group.ranges << pattern_range(range, node_type, offset)
188
+ end
189
+ else
190
+ node_group.ranges << node_group.offense_range
191
+ end
192
+ end
193
+ end
194
+ # rubocop:enable Metrics/AbcSize
195
+
196
+ def pattern_range(range, node, offset)
197
+ begin_pos = node.source_range.begin_pos
198
+ end_pos = node.source_range.end_pos
199
+ size = end_pos - begin_pos
200
+
201
+ range.adjust(begin_pos: begin_pos + offset).resize(size)
202
+ end
203
+
204
+ def range_with_offset(pattern_node)
205
+ if pattern_node.heredoc?
206
+ [pattern_node.loc.heredoc_body, 0]
207
+ else
208
+ [pattern_node.source_range, pattern_node.loc.begin.size]
209
+ end
210
+ end
211
+
212
+ # A heredoc can be a `dstr` without interpolation, but if there is interpolation
213
+ # there'll be a `begin` node, in which case, we cannot evaluate the pattern.
214
+ def acceptable_heredoc?(node)
215
+ node.any_str_type? && node.heredoc? && node.each_child_node(:begin).none?
216
+ end
217
+
218
+ def process_pattern(pattern_node)
219
+ parser = RuboCop::AST::NodePattern::Parser::WithMeta.new
220
+ ast = parser.parse(pattern_value(pattern_node))
221
+ ast = ASTProcessor.new.process(ast)
222
+ @walker.walk(ast)
223
+ rescue RuboCop::AST::NodePattern::Invalid
224
+ # if the pattern is invalid, no offenses will be registered
225
+ end
226
+
227
+ def pattern_value(pattern_node)
228
+ pattern_node.heredoc? ? pattern_node.loc.heredoc_body.source : pattern_node.value
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks that node types are checked against their group when all types of a
7
+ # group are checked.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.type?(:irange, :erange)
12
+ #
13
+ # # good
14
+ # node.range_type?
15
+ #
16
+ # # bad
17
+ # node.type?(:irange, :erange, :send, :csend)
18
+ #
19
+ # # good
20
+ # node.type?(:range, :call)
21
+ #
22
+ class NodeTypeGroup < Base
23
+ extend AutoCorrector
24
+ include RangeHelp
25
+
26
+ MSG = 'Use `:%<group>s` instead of individually listing group types.'
27
+
28
+ RESTRICT_ON_SEND = %i[type? each_ancestor each_child_node each_descendant each_node].freeze
29
+
30
+ def on_send(node)
31
+ return unless node.receiver
32
+
33
+ symbol_args = node.arguments.select(&:sym_type?)
34
+ return if symbol_args.none?
35
+
36
+ NodePatternGroups::NODE_GROUPS.each do |group_name, group_types|
37
+ next unless group_satisfied?(group_types, symbol_args)
38
+
39
+ offense_range = arguments_range(node)
40
+ add_offense(offense_range, message: format(MSG, group: group_name)) do |corrector|
41
+ autocorrect(corrector, node, symbol_args, group_name, group_types)
42
+ end
43
+ end
44
+ end
45
+ alias on_csend on_send
46
+
47
+ private
48
+
49
+ def arguments_range(node)
50
+ range_between(
51
+ node.first_argument.source_range.begin_pos,
52
+ node.last_argument.source_range.end_pos
53
+ )
54
+ end
55
+
56
+ def group_satisfied?(group_types, symbol_args)
57
+ group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
58
+ end
59
+
60
+ def autocorrect(corrector, node, symbol_args, group_name, group_types)
61
+ if node.method?(:type?) && node.arguments.count == group_types.count
62
+ autocorrect_to_explicit_predicate(corrector, node, group_name)
63
+ else
64
+ autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
65
+ end
66
+ end
67
+
68
+ def autocorrect_to_explicit_predicate(corrector, node, group_name)
69
+ range = node.loc.selector.begin.join(node.source_range.end)
70
+
71
+ corrector.replace(range, "#{group_name}_type?")
72
+ end
73
+
74
+ def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
75
+ first_replaced = false
76
+ symbol_args.each do |arg|
77
+ next unless group_types.include?(arg.value)
78
+
79
+ if first_replaced
80
+ range = range_with_surrounding_space(arg.source_range)
81
+ range = range_with_surrounding_comma(range, :left)
82
+ corrector.remove(range)
83
+ else
84
+ first_replaced = true
85
+ corrector.replace(arg, ":#{group_name}")
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Use `node.type?(:foo, :bar)` instead of `node.foo_type? || node.bar_type?`,
7
+ # and `!node.type?(:foo, :bar)` instead of `!node.foo_type? && !node.bar_type?`.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # node.str_type? || node.sym_type?
13
+ #
14
+ # # good
15
+ # node.type?(:str, :sym)
16
+ #
17
+ # # bad
18
+ # node.type?(:str, :sym) || node.boolean_type?
19
+ #
20
+ # # good
21
+ # node.type?(:str, :sym, :boolean)
22
+ #
23
+ # # bad
24
+ # !node.str_type? && !node.sym_type?
25
+ #
26
+ # # good
27
+ # !node.type?(:str, :sym)
28
+ #
29
+ # # bad
30
+ # !node.type?(:str, :sym) && !node.boolean_type?
31
+ #
32
+ # # good
33
+ # !node.type?(:str, :sym, :boolean)
34
+ #
35
+ class NodeTypeMultiplePredicates < Base
36
+ extend AutoCorrector
37
+
38
+ MSG_OR = 'Use `%<replacement>s` instead of checking for multiple node types.'
39
+ MSG_AND = 'Use `%<replacement>s` instead of checking against multiple node types.'
40
+
41
+ # @!method one_of_node_types?(node)
42
+ def_node_matcher :one_of_node_types?, <<~PATTERN
43
+ (or $(call _receiver #type_predicate?) (call _receiver #type_predicate?))
44
+ PATTERN
45
+
46
+ # @!method or_another_type?(node)
47
+ def_node_matcher :or_another_type?, <<~PATTERN
48
+ (or {
49
+ $(call _receiver :type? sym+) (call _receiver #type_predicate?) |
50
+ (call _receiver #type_predicate?) $(call _receiver :type? sym+)
51
+ })
52
+ PATTERN
53
+
54
+ # @!method none_of_node_types?(node)
55
+ def_node_matcher :none_of_node_types?, <<~PATTERN
56
+ (and
57
+ (send $(call _receiver #type_predicate?) :!)
58
+ (send (call _receiver #type_predicate?) :!)
59
+ )
60
+ PATTERN
61
+
62
+ # @!method and_not_another_type?(node)
63
+ def_node_matcher :and_not_another_type?, <<~PATTERN
64
+ (and {
65
+ (send $(call _receiver :type? sym+) :!) (send (call _receiver #type_predicate?) :!) |
66
+ (send (call _receiver #type_predicate?) :!) (send $(call _receiver :type? sym+) :!)
67
+ })
68
+ PATTERN
69
+
70
+ def on_or(node)
71
+ return unless (send_node = one_of_node_types?(node) || or_another_type?(node))
72
+ return unless send_node.receiver
73
+
74
+ replacement = replacement(node, send_node)
75
+ add_offense(node, message: format(MSG_OR, replacement: replacement)) do |corrector|
76
+ corrector.replace(node, replacement)
77
+ end
78
+ end
79
+
80
+ def on_and(node)
81
+ return unless (send_node = none_of_node_types?(node) || and_not_another_type?(node))
82
+ return unless send_node.receiver
83
+
84
+ replacement = "!#{replacement(node, send_node)}"
85
+
86
+ add_offense(node, message: format(MSG_AND, replacement: replacement)) do |corrector|
87
+ corrector.replace(node, replacement)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def type_predicate?(method_name)
94
+ method_name.end_with?('_type?')
95
+ end
96
+
97
+ def replacement(node, send_node)
98
+ send_node = send_node.children.first if send_node.method?(:!)
99
+
100
+ types = types(node)
101
+ receiver = send_node.receiver.source
102
+ dot = send_node.loc.dot.source
103
+
104
+ "#{receiver}#{dot}type?(:#{types.join(', :')})"
105
+ end
106
+
107
+ def types(node)
108
+ [types_in_branch(node.lhs), types_in_branch(node.rhs)]
109
+ end
110
+
111
+ def types_in_branch(branch)
112
+ branch = branch.children.first if branch.method?(:!)
113
+
114
+ if branch.method?(:type?)
115
+ branch.arguments.map(&:value)
116
+ elsif branch.method?(:defined_type?)
117
+ # `node.defined_type?` relates to `node.type == :defined?`
118
+ 'defined?'
119
+ else
120
+ branch.method_name.to_s.delete_suffix('_type?')
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -21,16 +21,17 @@ module RuboCop
21
21
 
22
22
  # @!method node_type_check(node)
23
23
  def_node_matcher :node_type_check, <<~PATTERN
24
- (send (send $_ :type) :== (sym $_))
24
+ (send (call _ :type) :== (sym $_))
25
25
  PATTERN
26
26
 
27
27
  def on_send(node)
28
- node_type_check(node) do |receiver, node_type|
28
+ node_type_check(node) do |node_type|
29
29
  return unless Parser::Meta::NODE_TYPES.include?(node_type)
30
30
 
31
31
  message = format(MSG, type: node_type)
32
32
  add_offense(node, message: message) do |corrector|
33
- range = node.source_range.with(begin_pos: receiver.source_range.end_pos + 1)
33
+ range = node.receiver.loc.selector.join(node.source_range.end)
34
+
34
35
  corrector.replace(range, "#{node_type}_type?")
35
36
  end
36
37
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module InternalAffairs
6
- # Checks for missing `numblock handlers. The blocks with numbered
6
+ # Checks for missing `numblock` handlers. The blocks with numbered
7
7
  # arguments introduced in Ruby 2.7 are parsed with a node type of
8
8
  # `numblock` instead of block. Cops that define `block` handlers
9
9
  # need to define `numblock` handlers or disable this cope for them.