rubocop 1.50.2 → 1.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (494) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +73 -72
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +316 -38
  7. data/config/internal_affairs.yml +11 -0
  8. data/config/obsoletion.yml +5 -0
  9. data/exe/rubocop +4 -3
  10. data/lib/rubocop/cached_data.rb +21 -5
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +28 -15
  12. data/lib/rubocop/cli/command/execute_runner.rb +1 -1
  13. data/lib/rubocop/cli/command/lsp.rb +19 -0
  14. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  15. data/lib/rubocop/cli/command/version.rb +2 -2
  16. data/lib/rubocop/cli.rb +14 -2
  17. data/lib/rubocop/comment_config.rb +1 -1
  18. data/lib/rubocop/config.rb +45 -13
  19. data/lib/rubocop/config_finder.rb +14 -4
  20. data/lib/rubocop/config_loader.rb +15 -10
  21. data/lib/rubocop/config_loader_resolver.rb +17 -11
  22. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  23. data/lib/rubocop/config_obsoletion.rb +13 -10
  24. data/lib/rubocop/config_validator.rb +17 -9
  25. data/lib/rubocop/cop/autocorrect_logic.rb +30 -3
  26. data/lib/rubocop/cop/base.rb +78 -19
  27. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  28. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  29. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  30. data/lib/rubocop/cop/bundler/gem_version.rb +6 -7
  31. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  32. data/lib/rubocop/cop/cop.rb +30 -4
  33. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -13
  34. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  35. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  36. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  37. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  38. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  39. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  40. data/lib/rubocop/cop/documentation.rb +32 -5
  41. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  42. data/lib/rubocop/cop/force.rb +12 -0
  43. data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
  44. data/lib/rubocop/cop/gemspec/dependency_version.rb +5 -7
  45. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  46. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  47. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  48. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  49. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  50. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  51. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  52. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -12
  53. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  54. data/lib/rubocop/cop/internal_affairs/example_description.rb +46 -24
  55. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  56. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  57. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  58. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  59. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +128 -34
  60. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  61. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  62. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  63. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
  64. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
  65. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -5
  66. data/lib/rubocop/cop/internal_affairs.rb +18 -0
  67. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
  68. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  69. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  70. data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
  71. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  72. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  73. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  74. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  75. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  76. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  77. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  78. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  79. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +43 -10
  80. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  81. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
  82. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +29 -5
  83. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +10 -3
  84. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  85. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  86. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  87. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +24 -10
  88. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  89. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  90. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  91. data/lib/rubocop/cop/layout/heredoc_indentation.rb +5 -2
  92. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  93. data/lib/rubocop/cop/layout/indentation_width.rb +8 -9
  94. data/lib/rubocop/cop/layout/leading_comment_space.rb +57 -2
  95. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  96. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  97. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  98. data/lib/rubocop/cop/layout/line_length.rb +20 -20
  99. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  100. data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
  101. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  102. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  103. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  104. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  105. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  106. data/lib/rubocop/cop/layout/space_around_operators.rb +56 -21
  107. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  108. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  109. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +6 -0
  110. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  111. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  112. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  113. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  114. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  115. data/lib/rubocop/cop/legacy/corrector.rb +12 -2
  116. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -3
  117. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  118. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  119. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  120. data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -6
  121. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  122. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  123. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -3
  124. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  125. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  126. data/lib/rubocop/cop/lint/debugger.rb +45 -10
  127. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  128. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  129. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  130. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -5
  131. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -5
  132. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -11
  133. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  134. data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
  135. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  136. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  137. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  138. data/lib/rubocop/cop/lint/empty_conditional_body.rb +29 -8
  139. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  140. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  141. data/lib/rubocop/cop/lint/empty_when.rb +1 -3
  142. data/lib/rubocop/cop/lint/ensure_return.rb +1 -9
  143. data/lib/rubocop/cop/lint/erb_new_arguments.rb +27 -21
  144. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  145. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  146. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  147. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  148. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  149. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  150. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +23 -12
  151. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  152. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  153. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  154. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  155. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +47 -0
  156. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  157. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
  158. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  159. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +26 -7
  160. data/lib/rubocop/cop/lint/loop.rb +6 -12
  161. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  162. data/lib/rubocop/cop/lint/mixed_case_range.rb +116 -0
  163. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -7
  164. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -25
  165. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  166. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +17 -7
  167. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  168. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  169. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  170. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  171. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  172. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
  173. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  174. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  175. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  176. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  177. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  178. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  179. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  180. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  181. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -5
  182. data/lib/rubocop/cop/lint/redundant_with_index.rb +6 -2
  183. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  184. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  185. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  186. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  187. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  188. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +23 -12
  189. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +107 -41
  190. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  191. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  192. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  193. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  194. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  195. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -11
  196. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  197. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  198. data/lib/rubocop/cop/lint/symbol_conversion.rb +9 -4
  199. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  200. data/lib/rubocop/cop/lint/to_enum_arguments.rb +6 -6
  201. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  202. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  203. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  204. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  205. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +3 -2
  206. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -7
  207. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  208. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  209. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  210. data/lib/rubocop/cop/lint/useless_assignment.rb +102 -15
  211. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  212. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
  213. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  214. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  215. data/lib/rubocop/cop/lint/void.rb +128 -15
  216. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  217. data/lib/rubocop/cop/metrics/block_length.rb +7 -6
  218. data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
  219. data/lib/rubocop/cop/metrics/class_length.rb +14 -8
  220. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
  221. data/lib/rubocop/cop/metrics/method_length.rb +7 -6
  222. data/lib/rubocop/cop/metrics/module_length.rb +6 -5
  223. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  224. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +37 -9
  225. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  226. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  227. data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
  228. data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
  229. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  230. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  231. data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -1
  232. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  233. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  234. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  235. data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
  236. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  237. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  238. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  239. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +22 -10
  240. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +23 -13
  241. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  242. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
  243. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  244. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  245. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  246. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  247. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  248. data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
  249. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  250. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  251. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  252. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
  253. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  254. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  255. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  256. data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
  257. data/lib/rubocop/cop/naming/block_forwarding.rb +35 -8
  258. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  259. data/lib/rubocop/cop/naming/file_name.rb +3 -3
  260. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  261. data/lib/rubocop/cop/naming/inclusive_language.rb +13 -5
  262. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  263. data/lib/rubocop/cop/naming/predicate_name.rb +55 -29
  264. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +21 -4
  265. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  266. data/lib/rubocop/cop/offense.rb +4 -5
  267. data/lib/rubocop/cop/registry.rb +1 -1
  268. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  269. data/lib/rubocop/cop/security/open.rb +2 -2
  270. data/lib/rubocop/cop/style/access_modifier_declarations.rb +63 -3
  271. data/lib/rubocop/cop/style/accessor_grouping.rb +14 -2
  272. data/lib/rubocop/cop/style/alias.rb +11 -9
  273. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  274. data/lib/rubocop/cop/style/arguments_forwarding.rb +459 -63
  275. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  276. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  277. data/lib/rubocop/cop/style/attr.rb +11 -1
  278. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  279. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  280. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  281. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  282. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  283. data/lib/rubocop/cop/style/block_delimiters.rb +36 -7
  284. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  285. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  286. data/lib/rubocop/cop/style/class_check.rb +1 -0
  287. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  288. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  289. data/lib/rubocop/cop/style/collection_compact.rb +31 -11
  290. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  291. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  292. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  293. data/lib/rubocop/cop/style/combinable_loops.rb +43 -8
  294. data/lib/rubocop/cop/style/commented_keyword.rb +12 -3
  295. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  296. data/lib/rubocop/cop/style/conditional_assignment.rb +13 -12
  297. data/lib/rubocop/cop/style/copyright.rb +36 -23
  298. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  299. data/lib/rubocop/cop/style/date_time.rb +5 -4
  300. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  301. data/lib/rubocop/cop/style/dir.rb +1 -1
  302. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  303. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  304. data/lib/rubocop/cop/style/documentation.rb +25 -25
  305. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  306. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -8
  307. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  308. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  309. data/lib/rubocop/cop/style/empty_else.rb +6 -5
  310. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  311. data/lib/rubocop/cop/style/empty_literal.rb +32 -23
  312. data/lib/rubocop/cop/style/endless_method.rb +1 -14
  313. data/lib/rubocop/cop/style/eval_with_location.rb +24 -32
  314. data/lib/rubocop/cop/style/exact_regexp_match.rb +70 -0
  315. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  316. data/lib/rubocop/cop/style/file_read.rb +4 -7
  317. data/lib/rubocop/cop/style/file_write.rb +2 -5
  318. data/lib/rubocop/cop/style/for.rb +3 -1
  319. data/lib/rubocop/cop/style/format_string.rb +33 -12
  320. data/lib/rubocop/cop/style/format_string_token.rb +2 -2
  321. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  322. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  323. data/lib/rubocop/cop/style/guard_clause.rb +45 -2
  324. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  325. data/lib/rubocop/cop/style/hash_each_methods.rb +112 -33
  326. data/lib/rubocop/cop/style/hash_except.rb +29 -14
  327. data/lib/rubocop/cop/style/hash_syntax.rb +26 -4
  328. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  329. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  330. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  331. data/lib/rubocop/cop/style/if_inside_else.rb +7 -1
  332. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  333. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -4
  334. data/lib/rubocop/cop/style/if_with_semicolon.rb +51 -8
  335. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  336. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  337. data/lib/rubocop/cop/style/invertible_unless_condition.rb +56 -10
  338. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  339. data/lib/rubocop/cop/style/lambda.rb +4 -4
  340. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  341. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  342. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +82 -50
  343. data/lib/rubocop/cop/style/map_into_array.rb +233 -0
  344. data/lib/rubocop/cop/style/map_to_hash.rb +18 -8
  345. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  346. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +40 -15
  347. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -5
  348. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +22 -2
  349. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  350. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  351. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  352. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  353. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  354. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  355. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  356. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  357. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  358. data/lib/rubocop/cop/style/multiple_comparison.rb +41 -46
  359. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  360. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  361. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  362. data/lib/rubocop/cop/style/next.rb +1 -1
  363. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  364. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  365. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  366. data/lib/rubocop/cop/style/numeric_predicate.rb +12 -4
  367. data/lib/rubocop/cop/style/object_then.rb +5 -3
  368. data/lib/rubocop/cop/style/one_line_conditional.rb +6 -2
  369. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  370. data/lib/rubocop/cop/style/operator_method_call.rb +32 -7
  371. data/lib/rubocop/cop/style/parallel_assignment.rb +8 -9
  372. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  373. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  374. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  375. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -3
  376. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  377. data/lib/rubocop/cop/style/redundant_argument.rb +33 -4
  378. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  379. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  380. data/lib/rubocop/cop/style/redundant_begin.rb +15 -3
  381. data/lib/rubocop/cop/style/redundant_condition.rb +4 -4
  382. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  383. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  384. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  385. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  386. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  387. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  388. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
  389. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  390. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  391. data/lib/rubocop/cop/style/redundant_line_continuation.rb +48 -9
  392. data/lib/rubocop/cop/style/redundant_parentheses.rb +80 -33
  393. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  394. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +103 -0
  395. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  396. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -24
  397. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  398. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  399. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  400. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  401. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  402. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  403. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  404. data/lib/rubocop/cop/style/require_order.rb +13 -7
  405. data/lib/rubocop/cop/style/rescue_modifier.rb +14 -4
  406. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  407. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +137 -0
  408. data/lib/rubocop/cop/style/safe_navigation.rb +106 -52
  409. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  410. data/lib/rubocop/cop/style/sample.rb +3 -4
  411. data/lib/rubocop/cop/style/select_by_regexp.rb +29 -15
  412. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  413. data/lib/rubocop/cop/style/semicolon.rb +21 -5
  414. data/lib/rubocop/cop/style/send.rb +4 -4
  415. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +104 -0
  416. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  417. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  418. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  419. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  420. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  421. data/lib/rubocop/cop/style/sole_nested_conditional.rb +27 -4
  422. data/lib/rubocop/cop/style/special_global_vars.rb +4 -6
  423. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  424. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  425. data/lib/rubocop/cop/style/strip.rb +7 -4
  426. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  427. data/lib/rubocop/cop/style/super_arguments.rb +174 -0
  428. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  429. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  430. data/lib/rubocop/cop/style/symbol_proc.rb +75 -5
  431. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  432. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  433. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  434. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  435. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  436. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  437. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  438. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  439. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  440. data/lib/rubocop/cop/style/zero_length_predicate.rb +32 -24
  441. data/lib/rubocop/cop/team.rb +27 -3
  442. data/lib/rubocop/cop/util.rb +9 -3
  443. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  444. data/lib/rubocop/cop/variable_force/assignment.rb +62 -6
  445. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  446. data/lib/rubocop/cop/variable_force/variable.rb +5 -1
  447. data/lib/rubocop/cop/variable_force/variable_table.rb +4 -4
  448. data/lib/rubocop/cop/variable_force.rb +14 -1
  449. data/lib/rubocop/cops_documentation_generator.rb +97 -44
  450. data/lib/rubocop/core_ext/string.rb +2 -6
  451. data/lib/rubocop/directive_comment.rb +10 -8
  452. data/lib/rubocop/ext/regexp_node.rb +18 -35
  453. data/lib/rubocop/ext/regexp_parser.rb +7 -21
  454. data/lib/rubocop/file_finder.rb +11 -9
  455. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  456. data/lib/rubocop/formatter/disabled_config_formatter.rb +24 -9
  457. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  458. data/lib/rubocop/formatter/html_formatter.rb +37 -14
  459. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  460. data/lib/rubocop/formatter/junit_formatter.rb +71 -24
  461. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  462. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  463. data/lib/rubocop/formatter.rb +1 -1
  464. data/lib/rubocop/lockfile.rb +58 -7
  465. data/lib/rubocop/lsp/logger.rb +22 -0
  466. data/lib/rubocop/lsp/routes.rb +243 -0
  467. data/lib/rubocop/lsp/runtime.rb +101 -0
  468. data/lib/rubocop/lsp/server.rb +72 -0
  469. data/lib/rubocop/lsp/severity.rb +27 -0
  470. data/lib/rubocop/lsp.rb +36 -0
  471. data/lib/rubocop/magic_comment.rb +13 -11
  472. data/lib/rubocop/options.rb +28 -13
  473. data/lib/rubocop/path_util.rb +6 -2
  474. data/lib/rubocop/rake_task.rb +1 -1
  475. data/lib/rubocop/remote_config.rb +5 -1
  476. data/lib/rubocop/result_cache.rb +7 -10
  477. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  478. data/lib/rubocop/rspec/expect_offense.rb +17 -8
  479. data/lib/rubocop/rspec/shared_contexts.rb +77 -21
  480. data/lib/rubocop/rspec/support.rb +3 -0
  481. data/lib/rubocop/runner.rb +36 -12
  482. data/lib/rubocop/server/cache.rb +16 -1
  483. data/lib/rubocop/server/client_command/exec.rb +5 -5
  484. data/lib/rubocop/server/client_command/start.rb +1 -1
  485. data/lib/rubocop/server/core.rb +5 -0
  486. data/lib/rubocop/server/server_command/exec.rb +0 -1
  487. data/lib/rubocop/string_interpreter.rb +3 -3
  488. data/lib/rubocop/target_finder.rb +91 -81
  489. data/lib/rubocop/target_ruby.rb +90 -79
  490. data/lib/rubocop/version.rb +53 -13
  491. data/lib/rubocop/yaml_duplication_checker.rb +20 -26
  492. data/lib/rubocop.rb +40 -1
  493. metadata +73 -36
  494. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # @!method redundant_fetch_block_candidate?(node)
48
48
  def_node_matcher :redundant_fetch_block_candidate?, <<~PATTERN
49
49
  (block
50
- $(send _ :fetch _)
50
+ $(call _ :fetch _)
51
51
  (args)
52
52
  ${nil? #basic_literal? #const_type?})
53
53
  PATTERN
@@ -61,10 +61,10 @@ module RuboCop
61
61
  bad = build_bad_method(send, body)
62
62
 
63
63
  add_offense(range, message: format(MSG, good: good, bad: bad)) do |corrector|
64
- receiver, _, key = send.children
64
+ _, _, key = send.children
65
65
  default_value = body ? body.source : 'nil'
66
66
 
67
- corrector.replace(node, "#{receiver.source}.fetch(#{key.source}, #{default_value})")
67
+ corrector.replace(range, "fetch(#{key.source}, #{default_value})")
68
68
  end
69
69
  end
70
70
  end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for the presence of superfluous `.rb` extension in
7
7
  # the filename provided to `require` and `require_relative`.
8
8
  #
9
- # Note: If the extension is omitted, Ruby tries adding '.rb', '.so',
9
+ # NOTE: If the extension is omitted, Ruby tries adding '.rb', '.so',
10
10
  # and so on to the name until found. If the file named cannot be found,
11
11
  # a `LoadError` will be raised.
12
12
  # There is an edge case where `foo.so` file is loaded instead of a `LoadError`
@@ -0,0 +1,118 @@
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
+ (call
64
+ {
65
+ (block $(call _ {:select :filter :find_all}) ...)
66
+ $(call _ {: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_literal?
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
+ alias on_csend on_send
91
+
92
+ private
93
+
94
+ def register_offense(select_node, predicate_node)
95
+ replacement = REPLACEMENT_METHODS[predicate_node.method_name]
96
+ message = format(MSG, prefer: replacement,
97
+ first_method: select_node.method_name,
98
+ second_method: predicate_node.method_name)
99
+
100
+ offense_range = offense_range(select_node, predicate_node)
101
+
102
+ add_offense(offense_range, message: message) do |corrector|
103
+ corrector.remove(predicate_range(predicate_node))
104
+ corrector.replace(select_node.loc.selector, replacement)
105
+ end
106
+ end
107
+
108
+ def offense_range(select_node, predicate_node)
109
+ select_node.loc.selector.join(predicate_node.loc.selector)
110
+ end
111
+
112
+ def predicate_range(predicate_node)
113
+ predicate_node.receiver.source_range.end.join(predicate_node.loc.selector)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Before Ruby 3.0, interpolated strings followed the frozen string literal
7
+ # magic comment which sometimes made it necessary to explicitly unfreeze them.
8
+ # Ruby 3.0 changed interpolated strings to always be unfrozen which makes
9
+ # unfreezing them redundant.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # +"#{foo} bar"
14
+ #
15
+ # # bad
16
+ # "#{foo} bar".dup
17
+ #
18
+ # # good
19
+ # "#{foo} bar"
20
+ #
21
+ class RedundantInterpolationUnfreeze < Base
22
+ include FrozenStringLiteral
23
+ extend AutoCorrector
24
+ extend TargetRubyVersion
25
+
26
+ MSG = "Don't unfreeze interpolated strings as they are already unfrozen."
27
+
28
+ RESTRICT_ON_SEND = %i[+@ dup].freeze
29
+
30
+ minimum_target_ruby_version 3.0
31
+
32
+ def on_send(node)
33
+ return if node.arguments?
34
+ return unless (receiver = node.receiver)
35
+ return unless receiver.dstr_type?
36
+ return if uninterpolated_string?(receiver) || uninterpolated_heredoc?(receiver)
37
+
38
+ add_offense(node.loc.selector) do |corrector|
39
+ corrector.remove(node.loc.selector)
40
+ corrector.remove(node.loc.dot) unless node.unary_operation?
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -69,12 +69,19 @@ module RuboCop
69
69
  extend AutoCorrector
70
70
 
71
71
  MSG = 'Redundant line continuation.'
72
+ LINE_CONTINUATION = "\\\n"
73
+ LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
72
74
  ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
75
+ ARGUMENT_TYPES = %i[
76
+ kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
77
+ tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
78
+ ].freeze
79
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
73
80
 
74
81
  def on_new_investigation
75
82
  return unless processed_source.ast
76
83
 
77
- each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
84
+ each_match_range(processed_source.ast.source_range, LINE_CONTINUATION_PATTERN) do |range|
78
85
  next if require_line_continuation?(range)
79
86
  next unless redundant_line_continuation?(range)
80
87
 
@@ -82,6 +89,8 @@ module RuboCop
82
89
  corrector.remove_leading(range, 1)
83
90
  end
84
91
  end
92
+
93
+ inspect_eof_line_continuation
85
94
  end
86
95
 
87
96
  private
@@ -90,7 +99,8 @@ module RuboCop
90
99
  !ends_with_backslash_without_comment?(range.source_line) ||
91
100
  string_concatenation?(range.source_line) ||
92
101
  start_with_arithmetic_operator?(processed_source[range.line]) ||
93
- inside_string_literal_or_method_with_argument?(range)
102
+ inside_string_literal_or_method_with_argument?(range) ||
103
+ leading_dot_method_chain_with_blank_line?(range)
94
104
  end
95
105
 
96
106
  def ends_with_backslash_without_comment?(source_line)
@@ -103,16 +113,38 @@ module RuboCop
103
113
 
104
114
  def inside_string_literal_or_method_with_argument?(range)
105
115
  processed_source.tokens.each_cons(2).any? do |token, next_token|
116
+ next if token.line == next_token.line
117
+
106
118
  inside_string_literal?(range, token) || method_with_argument?(token, next_token)
107
119
  end
108
120
  end
109
121
 
122
+ def leading_dot_method_chain_with_blank_line?(range)
123
+ return false unless range.source_line.strip.start_with?('.', '&.')
124
+
125
+ processed_source[range.line].strip.empty?
126
+ end
127
+
110
128
  def redundant_line_continuation?(range)
111
- return true unless (node = find_node_for_line(range.line))
129
+ return true unless (node = find_node_for_line(range.last_line))
112
130
  return false if argument_newline?(node)
113
131
 
114
- source = node.parent ? node.parent.source : node.source
115
- parse(source.gsub(/\\\n/, "\n")).valid_syntax?
132
+ source = node.source
133
+ while (node = node.parent)
134
+ source = node.source
135
+ end
136
+ parse(source.gsub("\\\n", "\n")).valid_syntax?
137
+ end
138
+
139
+ def inspect_eof_line_continuation
140
+ return unless processed_source.raw_source.end_with?(LINE_CONTINUATION)
141
+
142
+ rindex = processed_source.raw_source.rindex(LINE_CONTINUATION)
143
+ line_continuation_range = range_between(rindex, rindex + 1)
144
+
145
+ add_offense(line_continuation_range) do |corrector|
146
+ corrector.remove_trailing(line_continuation_range, 1)
147
+ end
116
148
  end
117
149
 
118
150
  def inside_string_literal?(range, token)
@@ -124,10 +156,16 @@ module RuboCop
124
156
  # do_something \
125
157
  # argument
126
158
  def method_with_argument?(current_token, next_token)
127
- current_token.type == :tIDENTIFIER && next_token.type == :tIDENTIFIER
159
+ return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
160
+
161
+ ARGUMENT_TYPES.include?(next_token.type)
128
162
  end
129
163
 
164
+ # rubocop:disable Metrics/AbcSize
130
165
  def argument_newline?(node)
166
+ node = node.to_a.last if node.assignment?
167
+ return false if node.parenthesized_call?
168
+
131
169
  node = node.children.first if node.root? && node.begin_type?
132
170
 
133
171
  if argument_is_method?(node)
@@ -138,15 +176,16 @@ module RuboCop
138
176
  node.loc.selector.line != node.first_argument.loc.line
139
177
  end
140
178
  end
179
+ # rubocop:enable Metrics/AbcSize
141
180
 
142
- def find_node_for_line(line)
181
+ def find_node_for_line(last_line)
143
182
  processed_source.ast.each_node do |node|
144
- return node if same_line?(node, line)
183
+ return node if node.respond_to?(:expression) && node.expression&.last_line == last_line
145
184
  end
146
185
  end
147
186
 
148
187
  def same_line?(node, line)
149
- return unless (source_range = node.source_range)
188
+ return false unless (source_range = node.source_range)
150
189
 
151
190
  if node.is_a?(AST::StrNode)
152
191
  if node.heredoc?
@@ -17,12 +17,11 @@ module RuboCop
17
17
  include Parentheses
18
18
  extend AutoCorrector
19
19
 
20
+ ALLOWED_NODE_TYPES = %i[and or send splat kwsplat].freeze
21
+
20
22
  # @!method square_brackets?(node)
21
23
  def_node_matcher :square_brackets?, '(send {(send _recv _msg) str array hash} :[] ...)'
22
24
 
23
- # @!method range_end?(node)
24
- def_node_matcher :range_end?, '^^{irange erange}'
25
-
26
25
  # @!method method_node_and_args(node)
27
26
  def_node_matcher :method_node_and_args, '$(call _recv _msg $...)'
28
27
 
@@ -32,9 +31,6 @@ module RuboCop
32
31
  # @!method allowed_pin_operator?(node)
33
32
  def_node_matcher :allowed_pin_operator?, '^(pin (begin !{lvar ivar cvar gvar}))'
34
33
 
35
- # @!method arg_in_call_with_block?(node)
36
- def_node_matcher :arg_in_call_with_block?, '^^(block (send _ _ equal?(%0) ...) ...)'
37
-
38
34
  def on_begin(node)
39
35
  return if !parentheses?(node) || parens_allowed?(node) || ignore_syntax?(node)
40
36
 
@@ -54,15 +50,15 @@ module RuboCop
54
50
  def ignore_syntax?(node)
55
51
  return false unless (parent = node.parent)
56
52
 
57
- parent.while_post_type? || parent.until_post_type? ||
58
- like_method_argument_parentheses?(parent)
53
+ parent.while_post_type? || parent.until_post_type? || parent.match_with_lvasgn_type? ||
54
+ like_method_argument_parentheses?(parent) || multiline_control_flow_statements?(node)
59
55
  end
60
56
 
61
57
  def allowed_expression?(node)
62
58
  allowed_ancestor?(node) ||
63
- allowed_method_call?(node) ||
64
59
  allowed_multiple_expression?(node) ||
65
- allowed_ternary?(node)
60
+ allowed_ternary?(node) ||
61
+ node.parent&.range_type?
66
62
  end
67
63
 
68
64
  def allowed_ancestor?(node)
@@ -70,11 +66,6 @@ module RuboCop
70
66
  keyword_ancestor?(node) && parens_required?(node)
71
67
  end
72
68
 
73
- def allowed_method_call?(node)
74
- # Don't flag `method (arg) { }`
75
- arg_in_call_with_block?(node) && !parentheses?(node.parent)
76
- end
77
-
78
69
  def allowed_multiple_expression?(node)
79
70
  return false if node.children.one?
80
71
 
@@ -85,7 +76,7 @@ module RuboCop
85
76
  end
86
77
 
87
78
  def allowed_ternary?(node)
88
- return unless node&.parent&.if_type?
79
+ return false unless node&.parent&.if_type?
89
80
 
90
81
  node.parent.ternary? && ternary_parentheses_required?
91
82
  end
@@ -98,10 +89,19 @@ module RuboCop
98
89
  end
99
90
 
100
91
  def like_method_argument_parentheses?(node)
101
- node.send_type? && node.arguments.one? && !node.parenthesized? &&
92
+ return false if !node.send_type? && !node.super_type? && !node.yield_type?
93
+
94
+ node.arguments.one? && !node.parenthesized? &&
102
95
  !node.arithmetic_operation? && node.first_argument.begin_type?
103
96
  end
104
97
 
98
+ def multiline_control_flow_statements?(node)
99
+ return false unless (parent = node.parent)
100
+ return false if parent.single_line?
101
+
102
+ parent.return_type? || parent.next_type? || parent.break_type?
103
+ end
104
+
105
105
  def empty_parentheses?(node)
106
106
  # Don't flag `()`
107
107
  node.children.empty?
@@ -109,39 +109,75 @@ module RuboCop
109
109
 
110
110
  def first_arg_begins_with_hash_literal?(node)
111
111
  # Don't flag `method ({key: value})` or `method ({key: value}.method)`
112
- method_chain_begins_with_hash_literal?(node.children.first) &&
113
- first_argument?(node) &&
114
- !parentheses?(node.parent)
112
+ hash_literal = method_chain_begins_with_hash_literal(node.children.first)
113
+ if (root_method = node.each_ancestor(:send).to_a.last)
114
+ parenthesized = root_method.parenthesized_call?
115
+ end
116
+ hash_literal && first_argument?(node) && !parentheses?(hash_literal) && !parenthesized
115
117
  end
116
118
 
117
- def method_chain_begins_with_hash_literal?(node)
118
- return false if node.nil?
119
- return true if node.hash_type?
120
- return false unless node.send_type?
119
+ def method_chain_begins_with_hash_literal(node)
120
+ return if node.nil?
121
+ return node if node.hash_type?
122
+ return unless node.send_type?
121
123
 
122
- method_chain_begins_with_hash_literal?(node.children.first)
124
+ method_chain_begins_with_hash_literal(node.children.first)
123
125
  end
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/MethodLength, 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
+ if node.lambda_or_proc? && (node.braces? || node.send_node.lambda_literal?)
144
+ return 'an expression'
145
+ end
146
+ return 'an interpolated expression' if interpolation?(begin_node)
147
+
148
+ return if begin_node.chained?
149
+
150
+ if node.and_type? || node.or_type?
151
+ return if node.semantic_operator? && begin_node.parent
152
+ return if node.multiline? && allow_in_multiline_conditions?
153
+ return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
154
+ return if begin_node.parent&.if_type? && begin_node.parent.ternary?
155
+
156
+ 'a logical expression'
157
+ elsif node.respond_to?(:comparison_method?) && node.comparison_method?
158
+ return unless begin_node.parent.nil?
159
+
160
+ 'a comparison expression'
161
+ end
162
+ end
163
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
164
+
137
165
  # @!method interpolation?(node)
138
166
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
139
167
 
168
+ def allow_in_multiline_conditions?
169
+ parentheses_around_condition_config = config.for_cop('Style/ParenthesesAroundCondition')
170
+ return false unless parentheses_around_condition_config['Enabled']
171
+
172
+ !!parentheses_around_condition_config['AllowInMultilineConditions']
173
+ end
174
+
140
175
  def check_send(begin_node, node)
141
176
  return check_unary(begin_node, node) if node.unary_operation?
142
177
 
143
178
  return unless method_call_with_redundant_parentheses?(node)
144
- return if call_chain_starts_with_int?(begin_node, node)
179
+ return if call_chain_starts_with_int?(begin_node, node) ||
180
+ do_end_block_in_method_chain?(begin_node, node)
145
181
 
146
182
  offense(begin_node, 'a method call')
147
183
  end
@@ -201,7 +237,6 @@ module RuboCop
201
237
  def method_call_with_redundant_parentheses?(node)
202
238
  return false unless node.call_type?
203
239
  return false if node.prefix_not?
204
- return false if range_end?(node)
205
240
 
206
241
  send_node, args = method_node_and_args(node)
207
242
 
@@ -213,7 +248,13 @@ module RuboCop
213
248
  end
214
249
 
215
250
  def first_argument?(node)
216
- first_send_argument?(node) || first_super_argument?(node) || first_yield_argument?(node)
251
+ if first_send_argument?(node) ||
252
+ first_super_argument?(node) ||
253
+ first_yield_argument?(node)
254
+ return true
255
+ end
256
+
257
+ node.each_ancestor.any? { |ancestor| first_argument?(ancestor) }
217
258
  end
218
259
 
219
260
  # @!method first_send_argument?(node)
@@ -236,6 +277,12 @@ module RuboCop
236
277
  recv&.int_type? && (parent = begin_node.parent) &&
237
278
  parent.send_type? && (parent.method?(:-@) || parent.method?(:+@))
238
279
  end
280
+
281
+ def do_end_block_in_method_chain?(begin_node, node)
282
+ return false unless (block = node.each_descendant(:block, :numblock).first)
283
+
284
+ block.keywords? && begin_node.each_ancestor(:send, :csend).any?
285
+ end
239
286
  end
240
287
  end
241
288
  end
@@ -53,7 +53,7 @@ module RuboCop
53
53
  return if interpolated_quotes?(node) || allowed_percent_q?(node)
54
54
 
55
55
  add_offense(node) do |corrector|
56
- delimiter = /^%Q[^"]+$|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
56
+ delimiter = /\A%Q[^"]+\z|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
57
57
 
58
58
  corrector.replace(node.loc.begin, delimiter)
59
59
  corrector.replace(node.loc.end, delimiter)
@@ -0,0 +1,103 @@
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
+ include StringLiteralsHelp
37
+ extend AutoCorrector
38
+
39
+ MSG = 'Use string `%<prefer>s` as argument instead of regexp `%<current>s`.'
40
+ RESTRICT_ON_SEND = %i[
41
+ byteindex byterindex gsub gsub! partition rpartition scan split start_with? sub sub!
42
+ ].freeze
43
+ DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze
44
+ STR_SPECIAL_CHARS = %w[
45
+ \a \c \C \e \f \M \n \" \' \\\\ \t \b \f \r \u \v \x \0 \1 \2 \3 \4 \5 \6 \7
46
+ ].freeze
47
+
48
+ def on_send(node)
49
+ return unless (regexp_node = node.first_argument)
50
+ return unless regexp_node.regexp_type?
51
+ return if !regexp_node.regopt.children.empty? || regexp_node.content == ' '
52
+ return unless determinist_regexp?(regexp_node)
53
+
54
+ prefer = preferred_argument(regexp_node)
55
+ message = format(MSG, prefer: prefer, current: regexp_node.source)
56
+
57
+ add_offense(regexp_node, message: message) do |corrector|
58
+ corrector.replace(regexp_node, prefer)
59
+ end
60
+ end
61
+ alias on_csend on_send
62
+
63
+ private
64
+
65
+ def determinist_regexp?(regexp_node)
66
+ DETERMINISTIC_REGEX.match?(regexp_node.source)
67
+ end
68
+
69
+ def preferred_argument(regexp_node)
70
+ new_argument = replacement(regexp_node)
71
+
72
+ if new_argument.include?('"')
73
+ new_argument.gsub!("'", "\\\\'")
74
+ quote = "'"
75
+ elsif new_argument.include?('\\')
76
+ quote = '"'
77
+ else
78
+ quote = enforce_double_quotes? ? '"' : "'"
79
+ end
80
+
81
+ "#{quote}#{new_argument}#{quote}"
82
+ end
83
+
84
+ def replacement(regexp_node)
85
+ regexp_content = regexp_node.content
86
+ stack = []
87
+ chars = regexp_content.chars.each_with_object([]) do |char, strings|
88
+ if stack.empty? && char == '\\'
89
+ stack.push(char)
90
+ else
91
+ strings << "#{stack.pop}#{char}"
92
+ end
93
+ end
94
+ chars.map do |char|
95
+ char = char.dup
96
+ char.delete!('\\') unless STR_SPECIAL_CHARS.include?(char)
97
+ char
98
+ end.join
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.
7
+ # Autocorrect replaces to regexp literal which is the simplest and fastest.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Regexp.new(/regexp/)
13
+ # Regexp.compile(/regexp/)
14
+ #
15
+ # # good
16
+ # /regexp/
17
+ # Regexp.new('regexp')
18
+ # Regexp.compile('regexp')
19
+ #
20
+ class RedundantRegexpConstructor < Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Remove the redundant `Regexp.%<method>s`.'
24
+ RESTRICT_ON_SEND = %i[new compile].freeze
25
+
26
+ # @!method redundant_regexp_constructor(node)
27
+ def_node_matcher :redundant_regexp_constructor, <<~PATTERN
28
+ (send
29
+ (const {nil? cbase} :Regexp) {:new :compile}
30
+ (regexp $... (regopt $...)))
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ return unless (regexp, regopt = redundant_regexp_constructor(node))
35
+
36
+ add_offense(node, message: format(MSG, method: node.method_name)) do |corrector|
37
+ pattern = regexp.map(&:source).join
38
+ regopt = regopt.join
39
+
40
+ corrector.replace(node, "/#{pattern}/#{regopt}")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end