rubocop 1.41.1 → 1.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +6 -4
  4. data/config/default.yml +243 -48
  5. data/config/obsoletion.yml +5 -0
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +7 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +7 -2
  8. data/lib/rubocop/cli/command/lsp.rb +19 -0
  9. data/lib/rubocop/cli.rb +59 -10
  10. data/lib/rubocop/comment_config.rb +19 -0
  11. data/lib/rubocop/config.rb +14 -10
  12. data/lib/rubocop/config_finder.rb +2 -2
  13. data/lib/rubocop/config_loader.rb +20 -23
  14. data/lib/rubocop/config_loader_resolver.rb +5 -1
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  16. data/lib/rubocop/config_obsoletion.rb +2 -2
  17. data/lib/rubocop/cop/autocorrect_logic.rb +31 -13
  18. data/lib/rubocop/cop/base.rb +96 -73
  19. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  20. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  21. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  22. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  24. data/lib/rubocop/cop/commissioner.rb +8 -2
  25. data/lib/rubocop/cop/cop.rb +53 -33
  26. data/lib/rubocop/cop/corrector.rb +31 -11
  27. data/lib/rubocop/cop/correctors/alignment_corrector.rb +3 -3
  28. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +3 -3
  29. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +3 -3
  30. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  31. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  32. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  33. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +2 -7
  34. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  35. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  36. data/lib/rubocop/cop/gemspec/dependency_version.rb +19 -21
  37. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -1
  38. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  39. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  40. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  41. data/lib/rubocop/cop/internal_affairs/cop_description.rb +37 -13
  42. data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
  43. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +3 -3
  44. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  45. data/lib/rubocop/cop/internal_affairs/location_expression.rb +37 -0
  46. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  47. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +6 -6
  48. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  49. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +42 -0
  50. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  51. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  52. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  53. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  54. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +66 -0
  55. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  56. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  57. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  58. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -15
  59. data/lib/rubocop/cop/layout/class_structure.rb +44 -26
  60. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +2 -3
  61. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  62. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  63. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  64. data/lib/rubocop/cop/layout/empty_comment.rb +3 -3
  65. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  66. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +28 -5
  67. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  68. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
  69. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  70. data/lib/rubocop/cop/layout/end_alignment.rb +9 -1
  71. data/lib/rubocop/cop/layout/extra_spacing.rb +6 -1
  72. data/lib/rubocop/cop/layout/first_argument_indentation.rb +8 -3
  73. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  74. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
  75. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
  76. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  77. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +10 -4
  78. data/lib/rubocop/cop/layout/heredoc_indentation.rb +11 -11
  79. data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
  80. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  81. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  82. data/lib/rubocop/cop/layout/leading_comment_space.rb +2 -2
  83. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +18 -12
  84. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +17 -13
  85. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  86. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  87. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  88. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
  89. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
  90. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  91. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
  92. data/lib/rubocop/cop/layout/redundant_line_break.rb +20 -11
  93. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  94. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  95. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  96. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  97. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  98. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -2
  99. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  100. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  101. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -13
  102. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +3 -1
  103. data/lib/rubocop/cop/layout/space_inside_parens.rb +3 -3
  104. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  105. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  106. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
  107. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +5 -4
  108. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  109. data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -3
  110. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  111. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  112. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  113. data/lib/rubocop/cop/lint/debugger.rb +22 -25
  114. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  115. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  116. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  117. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  118. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  119. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +47 -22
  120. data/lib/rubocop/cop/lint/else_layout.rb +3 -7
  121. data/lib/rubocop/cop/lint/empty_block.rb +2 -2
  122. data/lib/rubocop/cop/lint/empty_conditional_body.rb +4 -2
  123. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  124. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  125. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -7
  126. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +16 -18
  127. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  128. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  129. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  130. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  131. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  132. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  133. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +47 -5
  134. data/lib/rubocop/cop/lint/missing_super.rb +63 -5
  135. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  136. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  137. data/lib/rubocop/cop/lint/nested_method_definition.rb +4 -9
  138. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  139. data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
  140. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  141. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
  142. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  143. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +16 -1
  144. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  145. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  146. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +11 -5
  147. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -5
  148. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  149. data/lib/rubocop/cop/lint/redundant_require_statement.rb +21 -2
  150. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +20 -4
  151. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  152. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
  153. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  154. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  155. data/lib/rubocop/cop/lint/refinement_import_methods.rb +2 -1
  156. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  157. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  158. data/lib/rubocop/cop/lint/rescue_type.rb +3 -3
  159. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +11 -4
  160. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +1 -1
  161. data/lib/rubocop/cop/lint/script_permission.rb +1 -1
  162. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  163. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -12
  164. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  165. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  166. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  167. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  168. data/lib/rubocop/cop/lint/syntax.rb +4 -0
  169. data/lib/rubocop/cop/lint/to_enum_arguments.rb +18 -6
  170. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  171. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
  172. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  173. data/lib/rubocop/cop/lint/useless_access_modifier.rb +10 -7
  174. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  175. data/lib/rubocop/cop/lint/useless_method_definition.rb +12 -4
  176. data/lib/rubocop/cop/lint/useless_rescue.rb +89 -0
  177. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +14 -4
  178. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  179. data/lib/rubocop/cop/lint/void.rb +79 -16
  180. data/lib/rubocop/cop/metrics/block_length.rb +2 -2
  181. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  182. data/lib/rubocop/cop/metrics/class_length.rb +3 -2
  183. data/lib/rubocop/cop/metrics/collection_literal_length.rb +76 -0
  184. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  185. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  186. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  187. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  188. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -8
  189. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +33 -5
  190. data/lib/rubocop/cop/migration/department_name.rb +3 -3
  191. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  192. data/lib/rubocop/cop/mixin/allowed_methods.rb +3 -1
  193. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  194. data/lib/rubocop/cop/mixin/annotation_comment.rb +2 -2
  195. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  196. data/lib/rubocop/cop/mixin/comments_help.rb +13 -7
  197. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  198. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  199. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  200. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +1 -1
  201. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +62 -23
  202. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  203. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  204. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
  205. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  206. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +0 -3
  207. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
  208. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  209. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  210. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  211. data/lib/rubocop/cop/mixin/range_help.rb +1 -6
  212. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  213. data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -3
  214. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  215. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
  216. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  217. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  218. data/lib/rubocop/cop/naming/block_forwarding.rb +5 -1
  219. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
  220. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  221. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  222. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  223. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  224. data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
  225. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +25 -10
  226. data/lib/rubocop/cop/naming/method_name.rb +3 -3
  227. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  228. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -4
  229. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  230. data/lib/rubocop/cop/registry.rb +37 -30
  231. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  232. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -11
  233. data/lib/rubocop/cop/style/accessor_grouping.rb +43 -17
  234. data/lib/rubocop/cop/style/alias.rb +9 -8
  235. data/lib/rubocop/cop/style/arguments_forwarding.rb +280 -62
  236. data/lib/rubocop/cop/style/array_intersect.rb +14 -6
  237. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  238. data/lib/rubocop/cop/style/attr.rb +11 -1
  239. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  240. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +1 -1
  241. data/lib/rubocop/cop/style/block_comments.rb +3 -3
  242. data/lib/rubocop/cop/style/block_delimiters.rb +22 -6
  243. data/lib/rubocop/cop/style/case_like_if.rb +20 -3
  244. data/lib/rubocop/cop/style/class_and_module_children.rb +5 -12
  245. data/lib/rubocop/cop/style/class_equality_comparison.rb +58 -40
  246. data/lib/rubocop/cop/style/collection_compact.rb +20 -7
  247. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  248. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  249. data/lib/rubocop/cop/style/combinable_loops.rb +30 -8
  250. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  251. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  252. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  253. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  254. data/lib/rubocop/cop/style/concat_array_literals.rb +32 -4
  255. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -15
  256. data/lib/rubocop/cop/style/copyright.rb +6 -3
  257. data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
  258. data/lib/rubocop/cop/style/dir.rb +1 -1
  259. data/lib/rubocop/cop/style/dir_empty.rb +54 -0
  260. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  261. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +3 -3
  262. data/lib/rubocop/cop/style/documentation.rb +12 -6
  263. data/lib/rubocop/cop/style/documentation_method.rb +10 -4
  264. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  265. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  266. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  267. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  268. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  269. data/lib/rubocop/cop/style/eval_with_location.rb +8 -8
  270. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  271. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  272. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  273. data/lib/rubocop/cop/style/file_read.rb +3 -3
  274. data/lib/rubocop/cop/style/file_write.rb +1 -1
  275. data/lib/rubocop/cop/style/for.rb +1 -1
  276. data/lib/rubocop/cop/style/format_string.rb +24 -3
  277. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +4 -2
  278. data/lib/rubocop/cop/style/guard_clause.rb +40 -8
  279. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  280. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -10
  281. data/lib/rubocop/cop/style/hash_except.rb +23 -12
  282. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  283. data/lib/rubocop/cop/style/hash_syntax.rb +16 -9
  284. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  285. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  286. data/lib/rubocop/cop/style/identical_conditional_branches.rb +36 -3
  287. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  288. data/lib/rubocop/cop/style/if_unless_modifier.rb +111 -15
  289. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  290. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  291. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  292. data/lib/rubocop/cop/style/inverse_methods.rb +5 -5
  293. data/lib/rubocop/cop/style/invertible_unless_condition.rb +118 -0
  294. data/lib/rubocop/cop/style/lambda.rb +3 -3
  295. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  296. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +2 -2
  297. data/lib/rubocop/cop/style/map_to_hash.rb +4 -1
  298. data/lib/rubocop/cop/style/map_to_set.rb +64 -0
  299. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +35 -24
  300. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +44 -37
  301. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  302. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  303. data/lib/rubocop/cop/style/min_max.rb +3 -3
  304. data/lib/rubocop/cop/style/min_max_comparison.rb +83 -0
  305. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  306. data/lib/rubocop/cop/style/mixin_grouping.rb +5 -5
  307. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  308. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  309. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  310. data/lib/rubocop/cop/style/multiline_method_signature.rb +7 -4
  311. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +19 -4
  312. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  313. data/lib/rubocop/cop/style/negated_if_else_condition.rb +13 -12
  314. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  315. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  316. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
  317. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  318. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  319. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  320. data/lib/rubocop/cop/style/operator_method_call.rb +22 -2
  321. data/lib/rubocop/cop/style/parallel_assignment.rb +29 -19
  322. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
  323. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  324. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  325. data/lib/rubocop/cop/style/redundant_argument.rb +6 -1
  326. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  327. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  328. data/lib/rubocop/cop/style/redundant_condition.rb +18 -3
  329. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -14
  330. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
  331. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +96 -9
  332. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  333. data/lib/rubocop/cop/style/redundant_fetch_block.rb +6 -4
  334. data/lib/rubocop/cop/style/redundant_filter_chain.rb +117 -0
  335. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
  336. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  337. data/lib/rubocop/cop/style/redundant_line_continuation.rb +183 -0
  338. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -8
  339. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  340. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  341. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -8
  342. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  343. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +13 -4
  344. data/lib/rubocop/cop/style/redundant_return.rb +7 -2
  345. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  346. data/lib/rubocop/cop/style/redundant_sort.rb +4 -4
  347. data/lib/rubocop/cop/style/redundant_string_escape.rb +9 -6
  348. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  349. data/lib/rubocop/cop/style/require_order.rb +16 -17
  350. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  351. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  352. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  353. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  354. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  355. data/lib/rubocop/cop/style/select_by_regexp.rb +20 -6
  356. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  357. data/lib/rubocop/cop/style/semicolon.rb +35 -5
  358. data/lib/rubocop/cop/style/signal_exception.rb +9 -7
  359. data/lib/rubocop/cop/style/single_line_do_end_block.rb +65 -0
  360. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  361. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  362. data/lib/rubocop/cop/style/sole_nested_conditional.rb +9 -5
  363. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  364. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  365. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  366. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  367. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  368. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  369. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  370. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  371. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -1
  372. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  373. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  374. data/lib/rubocop/cop/style/unpack_first.rb +3 -3
  375. data/lib/rubocop/cop/style/word_array.rb +54 -1
  376. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  377. data/lib/rubocop/cop/style/yoda_condition.rb +17 -8
  378. data/lib/rubocop/cop/style/yoda_expression.rb +91 -0
  379. data/lib/rubocop/cop/style/zero_length_predicate.rb +40 -19
  380. data/lib/rubocop/cop/team.rb +60 -52
  381. data/lib/rubocop/cop/util.rb +14 -5
  382. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  383. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  384. data/lib/rubocop/cop/variable_force/scope.rb +3 -3
  385. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  386. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -3
  387. data/lib/rubocop/cop/variable_force.rb +2 -4
  388. data/lib/rubocop/cops_documentation_generator.rb +11 -4
  389. data/lib/rubocop/directive_comment.rb +3 -3
  390. data/lib/rubocop/ext/comment.rb +18 -0
  391. data/lib/rubocop/ext/regexp_node.rb +1 -1
  392. data/lib/rubocop/ext/regexp_parser.rb +5 -2
  393. data/lib/rubocop/file_finder.rb +4 -7
  394. data/lib/rubocop/formatter/junit_formatter.rb +4 -1
  395. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  396. data/lib/rubocop/formatter.rb +0 -1
  397. data/lib/rubocop/lsp/logger.rb +22 -0
  398. data/lib/rubocop/lsp/routes.rb +246 -0
  399. data/lib/rubocop/lsp/runtime.rb +99 -0
  400. data/lib/rubocop/lsp/server.rb +68 -0
  401. data/lib/rubocop/lsp/severity.rb +27 -0
  402. data/lib/rubocop/magic_comment.rb +12 -10
  403. data/lib/rubocop/options.rb +37 -3
  404. data/lib/rubocop/path_util.rb +17 -7
  405. data/lib/rubocop/result_cache.rb +7 -3
  406. data/lib/rubocop/rspec/cop_helper.rb +2 -2
  407. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  408. data/lib/rubocop/rspec/shared_contexts.rb +6 -3
  409. data/lib/rubocop/rspec/support.rb +1 -0
  410. data/lib/rubocop/runner.rb +55 -10
  411. data/lib/rubocop/server/cache.rb +12 -4
  412. data/lib/rubocop/server/cli.rb +37 -18
  413. data/lib/rubocop/server/client_command/exec.rb +4 -3
  414. data/lib/rubocop/server/client_command/start.rb +6 -1
  415. data/lib/rubocop/server/core.rb +24 -9
  416. data/lib/rubocop/server/helper.rb +1 -1
  417. data/lib/rubocop/server/server_command/exec.rb +1 -1
  418. data/lib/rubocop/string_interpreter.rb +3 -3
  419. data/lib/rubocop/target_finder.rb +7 -3
  420. data/lib/rubocop/target_ruby.rb +13 -9
  421. data/lib/rubocop/version.rb +10 -6
  422. data/lib/rubocop.rb +31 -0
  423. metadata +84 -37
@@ -5,17 +5,21 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for RuntimeError as the argument of raise/fail.
7
7
  #
8
- # It checks for code like this:
9
- #
10
8
  # @example
11
- # # Bad
9
+ # # bad
12
10
  # raise RuntimeError, 'message'
13
- #
14
- # # Bad
15
11
  # raise RuntimeError.new('message')
16
12
  #
17
- # # Good
13
+ # # good
18
14
  # raise 'message'
15
+ #
16
+ # # bad - message is not a string
17
+ # raise RuntimeError, Object.new
18
+ # raise RuntimeError.new(Object.new)
19
+ #
20
+ # # good
21
+ # raise Object.new.to_s
22
+ #
19
23
  class RedundantException < Base
20
24
  extend AutoCorrector
21
25
 
@@ -30,26 +34,42 @@ module RuboCop
30
34
  fix_exploded(node) || fix_compact(node)
31
35
  end
32
36
 
37
+ private
38
+
33
39
  def fix_exploded(node)
34
40
  exploded?(node) do |command, message|
35
41
  add_offense(node, message: MSG_1) do |corrector|
36
- if node.parenthesized?
37
- corrector.replace(node, "#{command}(#{message.source})")
38
- else
39
- corrector.replace(node, "#{command} #{message.source}")
40
- end
42
+ corrector.replace(node, replaced_exploded(node, command, message))
41
43
  end
42
44
  end
43
45
  end
44
46
 
47
+ def replaced_exploded(node, command, message)
48
+ arg = string_message?(message) ? message.source : "#{message.source}.to_s"
49
+ arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
50
+ "#{command}#{arg}"
51
+ end
52
+
53
+ def string_message?(message)
54
+ message.str_type? || message.dstr_type? || message.xstr_type?
55
+ end
56
+
45
57
  def fix_compact(node)
46
58
  compact?(node) do |new_call, message|
47
59
  add_offense(node, message: MSG_2) do |corrector|
48
- corrector.replace(new_call, message.source)
60
+ corrector.replace(new_call, replaced_compact(message))
49
61
  end
50
62
  end
51
63
  end
52
64
 
65
+ def replaced_compact(message)
66
+ if string_message?(message)
67
+ message.source
68
+ else
69
+ "#{message.source}.to_s"
70
+ end
71
+ end
72
+
53
73
  # @!method exploded?(node)
54
74
  def_node_matcher :exploded?, <<~PATTERN
55
75
  (send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)
@@ -3,11 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Identifies places where `fetch(key) { value }`
7
- # can be replaced by `fetch(key, value)`.
6
+ # Identifies places where `fetch(key) { value }` can be replaced by `fetch(key, value)`.
8
7
  #
9
- # In such cases `fetch(key, value)` method is faster
10
- # than `fetch(key) { value }`.
8
+ # In such cases `fetch(key, value)` method is faster than `fetch(key) { value }`.
9
+ #
10
+ # NOTE: The block string `'value'` in `hash.fetch(:key) { 'value' }` is detected
11
+ # when frozen string literal magic comment is enabled (i.e. `# frozen_string_literal: true`),
12
+ # but not when disabled.
11
13
  #
12
14
  # @safety
13
15
  # This cop is unsafe because it cannot be guaranteed that the receiver
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies usages of `any?`, `empty?` or `none?` predicate methods
7
+ # chained to `select`/`filter`/`find_all` and change them to use predicate method instead.
8
+ #
9
+ # @safety
10
+ # This cop's autocorrection is unsafe because `array.select.any?` evaluates all elements
11
+ # through the `select` method, while `array.any?` uses short-circuit evaluation.
12
+ # In other words, `array.select.any?` guarantees the evaluation of every element,
13
+ # but `array.any?` does not necessarily evaluate all of them.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # arr.select { |x| x > 1 }.any?
18
+ #
19
+ # # good
20
+ # arr.any? { |x| x > 1 }
21
+ #
22
+ # # bad
23
+ # arr.select { |x| x > 1 }.empty?
24
+ # arr.select { |x| x > 1 }.none?
25
+ #
26
+ # # good
27
+ # arr.none? { |x| x > 1 }
28
+ #
29
+ # # good
30
+ # relation.select(:name).any?
31
+ # arr.select { |x| x > 1 }.any?(&:odd?)
32
+ #
33
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
34
+ # # good
35
+ # arr.select { |x| x > 1 }.many?
36
+ #
37
+ # # good
38
+ # arr.select { |x| x > 1 }.present?
39
+ #
40
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
41
+ # # bad
42
+ # arr.select { |x| x > 1 }.many?
43
+ #
44
+ # # good
45
+ # arr.many? { |x| x > 1 }
46
+ #
47
+ # # bad
48
+ # arr.select { |x| x > 1 }.present?
49
+ #
50
+ # # good
51
+ # arr.any? { |x| x > 1 }
52
+ #
53
+ class RedundantFilterChain < Base
54
+ extend AutoCorrector
55
+
56
+ MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
57
+
58
+ RAILS_METHODS = %i[many? present?].freeze
59
+ RESTRICT_ON_SEND = (%i[any? empty? none? one?] + RAILS_METHODS).freeze
60
+
61
+ # @!method select_predicate?(node)
62
+ def_node_matcher :select_predicate?, <<~PATTERN
63
+ (send
64
+ {
65
+ (block $(send _ {:select :filter :find_all}) ...)
66
+ $(send _ {:select :filter :find_all} block_pass_type?)
67
+ }
68
+ ${:#{RESTRICT_ON_SEND.join(' :')}})
69
+ PATTERN
70
+
71
+ REPLACEMENT_METHODS = {
72
+ any?: :any?,
73
+ empty?: :none?,
74
+ none?: :none?,
75
+ one?: :one?,
76
+ many?: :many?,
77
+ present?: :any?
78
+ }.freeze
79
+ private_constant :REPLACEMENT_METHODS
80
+
81
+ def on_send(node)
82
+ return if node.arguments? || node.block_node
83
+
84
+ select_predicate?(node) do |select_node, filter_method|
85
+ return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
86
+
87
+ register_offense(select_node, node)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def register_offense(select_node, predicate_node)
94
+ replacement = REPLACEMENT_METHODS[predicate_node.method_name]
95
+ message = format(MSG, prefer: replacement,
96
+ first_method: select_node.method_name,
97
+ second_method: predicate_node.method_name)
98
+
99
+ offense_range = offense_range(select_node, predicate_node)
100
+
101
+ add_offense(offense_range, message: message) do |corrector|
102
+ corrector.remove(predicate_range(predicate_node))
103
+ corrector.replace(select_node.loc.selector, replacement)
104
+ end
105
+ end
106
+
107
+ def offense_range(select_node, predicate_node)
108
+ select_node.loc.selector.join(predicate_node.loc.selector)
109
+ end
110
+
111
+ def predicate_range(predicate_node)
112
+ predicate_node.receiver.source_range.end.join(predicate_node.loc.selector)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for redundant heredoc delimiter quotes.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # do_something(<<~'EOS')
12
+ # no string interpolation style text
13
+ # EOS
14
+ #
15
+ # # good
16
+ # do_something(<<~EOS)
17
+ # no string interpolation style text
18
+ # EOS
19
+ #
20
+ # do_something(<<~'EOS')
21
+ # #{string_interpolation_style_text_not_evaluated}
22
+ # EOS
23
+ #
24
+ # do_something(<<~'EOS')
25
+ # Preserve \
26
+ # newlines
27
+ # EOS
28
+ #
29
+ class RedundantHeredocDelimiterQuotes < Base
30
+ include Heredoc
31
+ extend AutoCorrector
32
+
33
+ MSG = 'Remove the redundant heredoc delimiter quotes, use `%<replacement>s` instead.'
34
+ STRING_INTERPOLATION_OR_ESCAPED_CHARACTER_PATTERN = /#(\{|@|\$)|\\/.freeze
35
+
36
+ def on_heredoc(node)
37
+ return if need_heredoc_delimiter_quotes?(node)
38
+
39
+ replacement = "#{heredoc_type(node)}#{delimiter_string(node)}"
40
+
41
+ add_offense(node, message: format(MSG, replacement: replacement)) do |corrector|
42
+ corrector.replace(node, replacement)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def need_heredoc_delimiter_quotes?(node)
49
+ heredoc_delimiter = node.source.delete(heredoc_type(node))
50
+ return true unless heredoc_delimiter.start_with?("'", '"')
51
+
52
+ node.loc.heredoc_end.source.strip.match?(/\W/) ||
53
+ node.loc.heredoc_body.source.match?(STRING_INTERPOLATION_OR_ESCAPED_CHARACTER_PATTERN)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def autocorrect_variable_interpolation(corrector, embedded_node, node)
100
- replacement = "#{embedded_node.loc.expression.source}.to_s"
100
+ replacement = "#{embedded_node.source}.to_s"
101
101
 
102
102
  corrector.replace(node, replacement)
103
103
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
 
108
108
  source = if require_parentheses?(embedded_var)
109
109
  receiver = range_between(
110
- embedded_var.loc.expression.begin_pos, embedded_var.loc.selector.end_pos
110
+ embedded_var.source_range.begin_pos, embedded_var.loc.selector.end_pos
111
111
  )
112
112
  arguments = embedded_var.arguments.map(&:source).join(', ')
113
113
 
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Check for redundant line continuation.
7
+ #
8
+ # This cop marks a line continuation as redundant if removing the backslash
9
+ # does not result in a syntax error.
10
+ # However, a backslash at the end of a comment or
11
+ # for string concatenation is not redundant and is not considered an offense.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # foo. \
16
+ # bar
17
+ # foo \
18
+ # &.bar \
19
+ # .baz
20
+ #
21
+ # # good
22
+ # foo.
23
+ # bar
24
+ # foo
25
+ # &.bar
26
+ # .baz
27
+ #
28
+ # # bad
29
+ # [foo, \
30
+ # bar]
31
+ # {foo: \
32
+ # bar}
33
+ #
34
+ # # good
35
+ # [foo,
36
+ # bar]
37
+ # {foo:
38
+ # bar}
39
+ #
40
+ # # bad
41
+ # foo(bar, \
42
+ # baz)
43
+ #
44
+ # # good
45
+ # foo(bar,
46
+ # baz)
47
+ #
48
+ # # also good - backslash in string concatenation is not redundant
49
+ # foo('bar' \
50
+ # 'baz')
51
+ #
52
+ # # also good - backslash at the end of a comment is not redundant
53
+ # foo(bar, # \
54
+ # baz)
55
+ #
56
+ # # also good - backslash at the line following the newline begins with a + or -,
57
+ # # it is not redundant
58
+ # 1 \
59
+ # + 2 \
60
+ # - 3
61
+ #
62
+ # # also good - backslash with newline between the method name and its arguments,
63
+ # # it is not redundant.
64
+ # some_method \
65
+ # (argument)
66
+ #
67
+ class RedundantLineContinuation < Base
68
+ include MatchRange
69
+ extend AutoCorrector
70
+
71
+ MSG = 'Redundant line continuation.'
72
+ ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
73
+ ARGUMENT_TYPES = %i[
74
+ kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
+ tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
+ ].freeze
77
+
78
+ def on_new_investigation
79
+ return unless processed_source.ast
80
+
81
+ each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
82
+ next if require_line_continuation?(range)
83
+ next unless redundant_line_continuation?(range)
84
+
85
+ add_offense(range) do |corrector|
86
+ corrector.remove_leading(range, 1)
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def require_line_continuation?(range)
94
+ !ends_with_backslash_without_comment?(range.source_line) ||
95
+ string_concatenation?(range.source_line) ||
96
+ start_with_arithmetic_operator?(processed_source[range.line]) ||
97
+ inside_string_literal_or_method_with_argument?(range)
98
+ end
99
+
100
+ def ends_with_backslash_without_comment?(source_line)
101
+ source_line.gsub(/#.+/, '').end_with?('\\')
102
+ end
103
+
104
+ def string_concatenation?(source_line)
105
+ /["']\s*\\\z/.match?(source_line)
106
+ end
107
+
108
+ def inside_string_literal_or_method_with_argument?(range)
109
+ processed_source.tokens.each_cons(2).any? do |token, next_token|
110
+ inside_string_literal?(range, token) || method_with_argument?(token, next_token)
111
+ end
112
+ end
113
+
114
+ def redundant_line_continuation?(range)
115
+ return true unless (node = find_node_for_line(range.line))
116
+ return false if argument_newline?(node)
117
+
118
+ source = node.parent ? node.parent.source : node.source
119
+ parse(source.gsub("\\\n", "\n")).valid_syntax?
120
+ end
121
+
122
+ def inside_string_literal?(range, token)
123
+ ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
124
+ end
125
+
126
+ # A method call without parentheses such as the following cannot remove `\`:
127
+ #
128
+ # do_something \
129
+ # argument
130
+ def method_with_argument?(current_token, next_token)
131
+ current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
132
+ end
133
+
134
+ def argument_newline?(node)
135
+ node = node.children.first if node.root? && node.begin_type?
136
+
137
+ if argument_is_method?(node)
138
+ argument_newline?(node.first_argument)
139
+ else
140
+ return false unless method_call_with_arguments?(node)
141
+
142
+ node.loc.selector.line != node.first_argument.loc.line
143
+ end
144
+ end
145
+
146
+ def find_node_for_line(line)
147
+ processed_source.ast.each_node do |node|
148
+ return node if same_line?(node, line)
149
+ end
150
+ end
151
+
152
+ def same_line?(node, line)
153
+ return false unless (source_range = node.source_range)
154
+
155
+ if node.is_a?(AST::StrNode)
156
+ if node.heredoc?
157
+ (node.loc.heredoc_body.line..node.loc.heredoc_body.last_line).cover?(line)
158
+ else
159
+ (source_range.line..source_range.last_line).cover?(line)
160
+ end
161
+ else
162
+ source_range.line == line
163
+ end
164
+ end
165
+
166
+ def argument_is_method?(node)
167
+ return false unless node.send_type?
168
+ return false unless (first_argument = node.first_argument)
169
+
170
+ method_call_with_arguments?(first_argument)
171
+ end
172
+
173
+ def method_call_with_arguments?(node)
174
+ node.call_type? && !node.arguments.empty?
175
+ end
176
+
177
+ def start_with_arithmetic_operator?(source_line)
178
+ %r{\A\s*[+\-*/%]}.match?(source_line)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -85,7 +85,7 @@ module RuboCop
85
85
  end
86
86
 
87
87
  def allowed_ternary?(node)
88
- return unless node&.parent&.if_type?
88
+ return false unless node&.parent&.if_type?
89
89
 
90
90
  node.parent.ternary? && ternary_parentheses_required?
91
91
  end
@@ -98,7 +98,9 @@ module RuboCop
98
98
  end
99
99
 
100
100
  def like_method_argument_parentheses?(node)
101
- node.send_type? && node.arguments.one? &&
101
+ return false if !node.send_type? && !node.super_type? && !node.yield_type?
102
+
103
+ node.arguments.one? && !node.parenthesized? &&
102
104
  !node.arithmetic_operation? && node.first_argument.begin_type?
103
105
  end
104
106
 
@@ -124,16 +126,32 @@ module RuboCop
124
126
 
125
127
  def check(begin_node)
126
128
  node = begin_node.children.first
127
- return offense(begin_node, 'a keyword') if keyword_with_redundant_parentheses?(node)
128
- return offense(begin_node, 'a literal') if disallowed_literal?(begin_node, node)
129
- return offense(begin_node, 'a variable') if node.variable?
130
- return offense(begin_node, 'a constant') if node.const_type?
131
129
 
132
- return offense(begin_node, 'an interpolated expression') if interpolation?(begin_node)
130
+ if (message = find_offense_message(begin_node, node))
131
+ return offense(begin_node, message)
132
+ end
133
133
 
134
134
  check_send(begin_node, node) if node.call_type?
135
135
  end
136
136
 
137
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
138
+ def find_offense_message(begin_node, node)
139
+ return 'a keyword' if keyword_with_redundant_parentheses?(node)
140
+ return 'a literal' if disallowed_literal?(begin_node, node)
141
+ return 'a variable' if node.variable?
142
+ return 'a constant' if node.const_type?
143
+ return 'an interpolated expression' if interpolation?(begin_node)
144
+
145
+ return if begin_node.chained? || !begin_node.parent.nil?
146
+
147
+ if node.and_type? || node.or_type?
148
+ 'a logical expression'
149
+ elsif node.respond_to?(:comparison_method?) && node.comparison_method?
150
+ 'a comparison expression'
151
+ end
152
+ end
153
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
154
+
137
155
  # @!method interpolation?(node)
138
156
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
139
157
 
@@ -153,7 +171,7 @@ module RuboCop
153
171
 
154
172
  return if node.send_type? && !method_call_with_redundant_parentheses?(node)
155
173
 
156
- offense(begin_node, 'an unary operation')
174
+ offense(begin_node, 'a unary operation')
157
175
  end
158
176
 
159
177
  def offense(node, msg)
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  return true if STRING_INTERPOLATION_REGEXP.match?(src)
95
95
 
96
- src.scan(/\\./).any? { |s| ESCAPED_NON_BACKSLASH.match?(s) }
96
+ src.scan(/\\./).any?(ESCAPED_NON_BACKSLASH)
97
97
  end
98
98
 
99
99
  def acceptable_capital_q?(node)
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies places where argument can be replaced from
7
+ # a deterministic regexp to a string.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # 'foo'.byteindex(/f/)
12
+ # 'foo'.byterindex(/f/)
13
+ # 'foo'.gsub(/f/, 'x')
14
+ # 'foo'.gsub!(/f/, 'x')
15
+ # 'foo'.partition(/f/)
16
+ # 'foo'.rpartition(/f/)
17
+ # 'foo'.scan(/f/)
18
+ # 'foo'.split(/f/)
19
+ # 'foo'.start_with?(/f/)
20
+ # 'foo'.sub(/f/, 'x')
21
+ # 'foo'.sub!(/f/, 'x')
22
+ #
23
+ # # good
24
+ # 'foo'.byteindex('f')
25
+ # 'foo'.byterindex('f')
26
+ # 'foo'.gsub('f', 'x')
27
+ # 'foo'.gsub!('f', 'x')
28
+ # 'foo'.partition('f')
29
+ # 'foo'.rpartition('f')
30
+ # 'foo'.scan('f')
31
+ # 'foo'.split('f')
32
+ # 'foo'.start_with?('f')
33
+ # 'foo'.sub('f', 'x')
34
+ # 'foo'.sub!('f', 'x')
35
+ class RedundantRegexpArgument < Base
36
+ extend AutoCorrector
37
+
38
+ MSG = 'Use string `%<prefer>s` as argument instead of regexp `%<current>s`.'
39
+ RESTRICT_ON_SEND = %i[
40
+ byteindex byterindex gsub gsub! partition rpartition scan split start_with? sub sub!
41
+ ].freeze
42
+ DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze
43
+ STR_SPECIAL_CHARS = %w[
44
+ \a \c \C \e \f \M \n \" \' \\\\ \t \b \f \r \u \v \x \0 \1 \2 \3 \4 \5 \6 \7
45
+ ].freeze
46
+
47
+ def on_send(node)
48
+ return unless (regexp_node = node.first_argument)
49
+ return unless regexp_node.regexp_type?
50
+ return if !regexp_node.regopt.children.empty? || regexp_node.content == ' '
51
+ return unless determinist_regexp?(regexp_node)
52
+
53
+ prefer = preferred_argument(regexp_node)
54
+ message = format(MSG, prefer: prefer, current: regexp_node.source)
55
+
56
+ add_offense(regexp_node, message: message) do |corrector|
57
+ corrector.replace(regexp_node, prefer)
58
+ end
59
+ end
60
+ alias on_csend on_send
61
+
62
+ private
63
+
64
+ def determinist_regexp?(regexp_node)
65
+ DETERMINISTIC_REGEX.match?(regexp_node.source)
66
+ end
67
+
68
+ def preferred_argument(regexp_node)
69
+ new_argument = replacement(regexp_node)
70
+
71
+ if new_argument.include?('"')
72
+ new_argument.gsub!("'", "\\\\'")
73
+ quote = "'"
74
+ else
75
+ quote = '"'
76
+ end
77
+
78
+ "#{quote}#{new_argument}#{quote}"
79
+ end
80
+
81
+ def replacement(regexp_node)
82
+ regexp_content = regexp_node.content
83
+ stack = []
84
+ chars = regexp_content.chars.each_with_object([]) do |char, strings|
85
+ if stack.empty? && char == '\\'
86
+ stack.push(char)
87
+ else
88
+ strings << "#{stack.pop}#{char}"
89
+ end
90
+ end
91
+ chars.map do |char|
92
+ char = char.dup
93
+ char.delete!('\\') unless STR_SPECIAL_CHARS.include?(char)
94
+ char
95
+ end.join
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -63,7 +63,7 @@ module RuboCop
63
63
  next if expr.type != :set || expr.expressions.size != 1
64
64
  next if expr.negative?
65
65
  next if %i[set posixclass nonposixclass].include?(expr.expressions.first.type)
66
- next if multiple_codepoins?(expr.expressions.first)
66
+ next if multiple_codepoints?(expr.expressions.first)
67
67
 
68
68
  yield expr
69
69
  end
@@ -74,13 +74,13 @@ module RuboCop
74
74
 
75
75
  non_redundant =
76
76
  whitespace_in_free_space_mode?(node, class_elem) ||
77
- backslash_b?(class_elem) || backslash_zero?(class_elem) ||
77
+ backslash_b?(class_elem) || octal_requiring_char_class?(class_elem) ||
78
78
  requires_escape_outside_char_class?(class_elem)
79
79
 
80
80
  !non_redundant
81
81
  end
82
82
 
83
- def multiple_codepoins?(expression)
83
+ def multiple_codepoints?(expression)
84
84
  expression.respond_to?(:codepoints) && expression.codepoints.count >= 2
85
85
  end
86
86
 
@@ -104,11 +104,10 @@ module RuboCop
104
104
  elem == '\b'
105
105
  end
106
106
 
107
- def backslash_zero?(elem)
108
- # See https://github.com/rubocop/rubocop/issues/11067 for details - in short "\0" != "0" -
109
- # the former means an Unicode code point `"\u0000"`, the latter a number character `"0"`.
110
- # Similarly "\032" means "\u001A". Other numbers starting with "\0" can also be mentioned.
111
- elem == '\0'
107
+ def octal_requiring_char_class?(elem)
108
+ # The octal escapes \1 to \7 only work inside a character class
109
+ # because they would be a backreference outside it.
110
+ elem.match?(/\A\\[1-7]\z/)
112
111
  end
113
112
 
114
113
  def requires_escape_outside_char_class?(elem)