rubocop 1.66.1 → 1.72.2

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 (434) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +162 -14
  5. data/config/internal_affairs.yml +11 -0
  6. data/lib/rubocop/cached_data.rb +12 -4
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
  8. data/lib/rubocop/cli/command/execute_runner.rb +4 -4
  9. data/lib/rubocop/cli/command/lsp.rb +2 -2
  10. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  11. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  12. data/lib/rubocop/cli/command/version.rb +2 -2
  13. data/lib/rubocop/comment_config.rb +2 -2
  14. data/lib/rubocop/config.rb +17 -4
  15. data/lib/rubocop/config_loader.rb +48 -8
  16. data/lib/rubocop/config_loader_resolver.rb +36 -11
  17. data/lib/rubocop/config_validator.rb +20 -9
  18. data/lib/rubocop/cop/autocorrect_logic.rb +36 -19
  19. data/lib/rubocop/cop/base.rb +13 -3
  20. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  21. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  22. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  23. data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
  24. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  25. data/lib/rubocop/cop/cop.rb +8 -0
  26. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  28. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
  30. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  31. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  32. data/lib/rubocop/cop/generator.rb +6 -0
  33. data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
  34. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  35. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
  36. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  37. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  38. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
  39. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  40. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  41. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  42. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  43. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  44. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  45. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  46. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  47. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  48. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +48 -0
  49. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  50. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  51. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +11 -2
  52. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  53. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  54. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  55. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
  56. data/lib/rubocop/cop/internal_affairs.rb +6 -0
  57. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +6 -2
  58. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -9
  59. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  60. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  61. data/lib/rubocop/cop/layout/block_alignment.rb +3 -2
  62. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  63. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  64. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  65. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  66. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -3
  67. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  68. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +3 -3
  69. data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
  70. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +4 -5
  71. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +23 -1
  72. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  73. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  74. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  75. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  76. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  77. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  78. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  79. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  80. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  81. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  82. data/lib/rubocop/cop/layout/indentation_width.rb +11 -12
  83. data/lib/rubocop/cop/layout/leading_comment_space.rb +71 -1
  84. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
  85. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  86. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  87. data/lib/rubocop/cop/layout/line_length.rb +119 -4
  88. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  89. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  90. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +2 -1
  91. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  92. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  93. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  94. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  95. data/lib/rubocop/cop/layout/redundant_line_break.rb +10 -41
  96. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -3
  97. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  98. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  99. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  100. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  101. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  102. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -1
  103. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  104. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -20
  105. data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
  106. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  107. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  108. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  109. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
  110. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  111. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  112. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  113. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  114. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  115. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  116. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  117. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  118. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
  119. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  120. data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
  121. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  122. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  123. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  124. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  125. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
  126. data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
  127. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  128. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  129. data/lib/rubocop/cop/lint/duplicate_set_element.rb +87 -0
  130. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  131. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  132. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  133. data/lib/rubocop/cop/lint/ensure_return.rb +1 -4
  134. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  135. data/lib/rubocop/cop/lint/float_comparison.rb +20 -9
  136. data/lib/rubocop/cop/lint/float_out_of_range.rb +2 -4
  137. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  138. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  139. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +11 -5
  140. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  141. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +8 -14
  142. data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -0
  143. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  144. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +49 -8
  145. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  146. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -6
  147. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  148. data/lib/rubocop/cop/lint/nested_method_definition.rb +9 -5
  149. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  150. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  151. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +12 -3
  152. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
  153. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  154. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  155. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  156. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +93 -0
  157. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  158. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +3 -2
  159. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +6 -11
  160. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  161. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  162. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +13 -8
  163. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  164. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  165. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +231 -0
  166. data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
  167. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  168. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  169. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  170. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -1
  171. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +109 -41
  172. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  173. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  174. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  175. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  176. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  177. data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -2
  178. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  179. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
  180. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  181. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  182. data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
  183. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  184. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  185. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  186. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  187. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  188. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
  189. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  190. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
  191. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  192. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  193. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  194. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  195. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  196. data/lib/rubocop/cop/lint/void.rb +8 -11
  197. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  198. data/lib/rubocop/cop/metrics/class_length.rb +9 -9
  199. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  200. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +5 -2
  201. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  202. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  203. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  204. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  205. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
  206. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  207. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  208. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  209. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  210. data/lib/rubocop/cop/mixin/check_line_breakable.rb +20 -10
  211. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  212. data/lib/rubocop/cop/mixin/comments_help.rb +8 -3
  213. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  214. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
  215. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -2
  216. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  217. data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
  218. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  219. data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
  220. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  221. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  222. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  223. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  224. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +68 -30
  225. data/lib/rubocop/cop/mixin/range_help.rb +3 -4
  226. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  227. data/lib/rubocop/cop/mixin/statement_modifier.rb +11 -5
  228. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  229. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  230. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  231. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  232. data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
  233. data/lib/rubocop/cop/naming/block_forwarding.rb +20 -16
  234. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  235. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  236. data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
  237. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  238. data/lib/rubocop/cop/naming/predicate_name.rb +45 -1
  239. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +6 -14
  240. data/lib/rubocop/cop/naming/variable_name.rb +3 -4
  241. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  242. data/lib/rubocop/cop/offense.rb +4 -5
  243. data/lib/rubocop/cop/security/compound_hash.rb +2 -0
  244. data/lib/rubocop/cop/security/yaml_load.rb +3 -2
  245. data/lib/rubocop/cop/style/access_modifier_declarations.rb +96 -28
  246. data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
  247. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
  248. data/lib/rubocop/cop/style/and_or.rb +1 -1
  249. data/lib/rubocop/cop/style/arguments_forwarding.rb +78 -22
  250. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  251. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  252. data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
  253. data/lib/rubocop/cop/style/block_delimiters.rb +49 -19
  254. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  255. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  256. data/lib/rubocop/cop/style/collection_compact.rb +10 -10
  257. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  258. data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
  259. data/lib/rubocop/cop/style/combinable_loops.rb +9 -2
  260. data/lib/rubocop/cop/style/commented_keyword.rb +17 -1
  261. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  262. data/lib/rubocop/cop/style/conditional_assignment.rb +26 -26
  263. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  264. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  265. data/lib/rubocop/cop/style/dig_chain.rb +89 -0
  266. data/lib/rubocop/cop/style/documentation.rb +1 -1
  267. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  268. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  269. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  270. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  271. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  272. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  273. data/lib/rubocop/cop/style/endless_method.rb +1 -14
  274. data/lib/rubocop/cop/style/eval_with_location.rb +2 -2
  275. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -3
  276. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  277. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  278. data/lib/rubocop/cop/style/fetch_env_var.rb +2 -1
  279. data/lib/rubocop/cop/style/file_null.rb +89 -0
  280. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  281. data/lib/rubocop/cop/style/float_division.rb +8 -4
  282. data/lib/rubocop/cop/style/for.rb +0 -1
  283. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  284. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  285. data/lib/rubocop/cop/style/guard_clause.rb +16 -3
  286. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  287. data/lib/rubocop/cop/style/hash_each_methods.rb +9 -6
  288. data/lib/rubocop/cop/style/hash_except.rb +35 -147
  289. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  290. data/lib/rubocop/cop/style/hash_syntax.rb +8 -5
  291. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  292. data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
  293. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  294. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -3
  295. data/lib/rubocop/cop/style/if_with_semicolon.rb +26 -11
  296. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  297. data/lib/rubocop/cop/style/inverse_methods.rb +6 -7
  298. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  299. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
  300. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  301. data/lib/rubocop/cop/style/lambda.rb +1 -1
  302. data/lib/rubocop/cop/style/lambda_call.rb +3 -2
  303. data/lib/rubocop/cop/style/map_into_array.rb +60 -9
  304. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  305. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  306. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +32 -20
  307. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  308. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +8 -11
  309. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  310. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  311. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  312. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  313. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  314. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  315. data/lib/rubocop/cop/style/multiple_comparison.rb +52 -51
  316. data/lib/rubocop/cop/style/mutable_constant.rb +7 -8
  317. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -5
  318. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  319. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  320. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  321. data/lib/rubocop/cop/style/not.rb +1 -1
  322. data/lib/rubocop/cop/style/object_then.rb +14 -15
  323. data/lib/rubocop/cop/style/one_line_conditional.rb +29 -4
  324. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  325. data/lib/rubocop/cop/style/operator_method_call.rb +25 -7
  326. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  327. data/lib/rubocop/cop/style/parallel_assignment.rb +9 -18
  328. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  329. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  330. data/lib/rubocop/cop/style/proc.rb +1 -2
  331. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  332. data/lib/rubocop/cop/style/raise_args.rb +7 -5
  333. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  334. data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
  335. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  336. data/lib/rubocop/cop/style/redundant_begin.rb +5 -1
  337. data/lib/rubocop/cop/style/redundant_condition.rb +39 -24
  338. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  339. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  340. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  341. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  342. data/lib/rubocop/cop/style/redundant_format.rb +238 -0
  343. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  344. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  345. data/lib/rubocop/cop/style/redundant_line_continuation.rb +56 -17
  346. data/lib/rubocop/cop/style/redundant_parentheses.rb +37 -25
  347. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  348. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  349. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  350. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  351. data/lib/rubocop/cop/style/redundant_self.rb +8 -15
  352. data/lib/rubocop/cop/style/redundant_self_assignment.rb +20 -32
  353. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  354. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  355. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  356. data/lib/rubocop/cop/style/require_order.rb +1 -1
  357. data/lib/rubocop/cop/style/rescue_modifier.rb +15 -4
  358. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  359. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
  360. data/lib/rubocop/cop/style/safe_navigation.rb +105 -51
  361. data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
  362. data/lib/rubocop/cop/style/select_by_regexp.rb +10 -7
  363. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  364. data/lib/rubocop/cop/style/semicolon.rb +2 -2
  365. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  366. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  367. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  368. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  369. data/lib/rubocop/cop/style/single_line_do_end_block.rb +12 -3
  370. data/lib/rubocop/cop/style/single_line_methods.rb +3 -4
  371. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  372. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -5
  373. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  374. data/lib/rubocop/cop/style/string_concatenation.rb +14 -13
  375. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  376. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  377. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  378. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  379. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  380. data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
  381. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  382. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  383. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  384. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  385. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  386. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  387. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  388. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  389. data/lib/rubocop/cop/team.rb +8 -1
  390. data/lib/rubocop/cop/util.rb +12 -5
  391. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  392. data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
  393. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  394. data/lib/rubocop/cop/variable_force/variable.rb +18 -2
  395. data/lib/rubocop/cop/variable_force/variable_table.rb +5 -5
  396. data/lib/rubocop/cop/variable_force.rb +4 -10
  397. data/lib/rubocop/cops_documentation_generator.rb +100 -51
  398. data/lib/rubocop/directive_comment.rb +44 -10
  399. data/lib/rubocop/file_finder.rb +9 -4
  400. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  401. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  402. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  403. data/lib/rubocop/lsp/logger.rb +2 -2
  404. data/lib/rubocop/lsp/routes.rb +7 -23
  405. data/lib/rubocop/lsp/runtime.rb +18 -48
  406. data/lib/rubocop/lsp/server.rb +0 -3
  407. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  408. data/lib/rubocop/magic_comment.rb +3 -3
  409. data/lib/rubocop/options.rb +28 -12
  410. data/lib/rubocop/path_util.rb +15 -8
  411. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  412. data/lib/rubocop/plugin/load_error.rb +26 -0
  413. data/lib/rubocop/plugin/loader.rb +100 -0
  414. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  415. data/lib/rubocop/plugin.rb +39 -0
  416. data/lib/rubocop/rake_task.rb +4 -1
  417. data/lib/rubocop/result_cache.rb +13 -13
  418. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  419. data/lib/rubocop/rspec/expect_offense.rb +7 -2
  420. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  421. data/lib/rubocop/rspec/support.rb +1 -2
  422. data/lib/rubocop/runner.rb +22 -12
  423. data/lib/rubocop/server/cache.rb +39 -1
  424. data/lib/rubocop/server/cli.rb +2 -2
  425. data/lib/rubocop/server/core.rb +1 -0
  426. data/lib/rubocop/target_finder.rb +1 -0
  427. data/lib/rubocop/target_ruby.rb +28 -13
  428. data/lib/rubocop/version.rb +42 -6
  429. data/lib/rubocop/yaml_duplication_checker.rb +20 -27
  430. data/lib/rubocop.rb +29 -0
  431. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  432. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +47 -0
  433. metadata +75 -19
  434. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for calls to `Kernel#format` or `Kernel#sprintf` that are redundant.
7
+ #
8
+ # Calling `format` with only a single string argument is redundant, as it can be
9
+ # replaced by the string itself.
10
+ #
11
+ # Also looks for `format` calls where the arguments are literals that can be
12
+ # inlined into a string easily. This applies to the `%s`, `%d`, `%i`, `%u`, and
13
+ # `%f` format specifiers.
14
+ #
15
+ # @safety
16
+ # This cop's autocorrection is unsafe because string object returned by
17
+ # `format` and `sprintf` are never frozen. If `format('string')` is autocorrected to
18
+ # `'string'`, `FrozenError` may occur when calling a destructive method like `String#<<`.
19
+ # Consider using `'string'.dup` instead of `format('string')`.
20
+ # Additionally, since the necessity of `dup` cannot be determined automatically,
21
+ # this autocorrection is inherently unsafe.
22
+ #
23
+ # [source,ruby]
24
+ # ----
25
+ # # frozen_string_literal: true
26
+ #
27
+ # format('template').frozen? # => false
28
+ # 'template'.frozen? # => true
29
+ # ----
30
+ #
31
+ # @example
32
+ #
33
+ # # bad
34
+ # format('the quick brown fox jumps over the lazy dog.')
35
+ # sprintf('the quick brown fox jumps over the lazy dog.')
36
+ #
37
+ # # good
38
+ # 'the quick brown fox jumps over the lazy dog.'
39
+ #
40
+ # # bad
41
+ # format('%s %s', 'foo', 'bar')
42
+ # sprintf('%s %s', 'foo', 'bar')
43
+ #
44
+ # # good
45
+ # 'foo bar'
46
+ #
47
+ class RedundantFormat < Base
48
+ extend AutoCorrector
49
+
50
+ MSG = 'Redundant `%<method_name>s` can be removed.'
51
+
52
+ RESTRICT_ON_SEND = %i[format sprintf].to_set.freeze
53
+ ACCEPTABLE_LITERAL_TYPES = %i[str dstr sym dsym numeric boolean nil].freeze
54
+
55
+ # @!method format_without_additional_args?(node)
56
+ def_node_matcher :format_without_additional_args?, <<~PATTERN
57
+ (send {(const {nil? cbase} :Kernel) nil?} %RESTRICT_ON_SEND ${str dstr})
58
+ PATTERN
59
+
60
+ # @!method rational_number?(node)
61
+ def_node_matcher :rational_number?, <<~PATTERN
62
+ {rational (send int :/ rational) (begin rational) (begin (send int :/ rational))}
63
+ PATTERN
64
+
65
+ # @!method complex_number?(node)
66
+ def_node_matcher :complex_number?, <<~PATTERN
67
+ {complex (send int :+ complex) (begin complex) (begin (send int :+ complex))}
68
+ PATTERN
69
+
70
+ # @!method find_hash_value_node(node, name)
71
+ def_node_search :find_hash_value_node, <<~PATTERN
72
+ (pair (sym %1) $_)
73
+ PATTERN
74
+
75
+ def on_send(node)
76
+ format_without_additional_args?(node) do |value|
77
+ add_offense(node, message: message(node)) do |corrector|
78
+ corrector.replace(node, value.source)
79
+ end
80
+ return
81
+ end
82
+
83
+ detect_unnecessary_fields(node)
84
+ end
85
+
86
+ private
87
+
88
+ def message(node)
89
+ format(MSG, method_name: node.method_name)
90
+ end
91
+
92
+ def detect_unnecessary_fields(node)
93
+ return unless node.first_argument&.str_type?
94
+
95
+ string = node.first_argument.value
96
+ arguments = node.arguments[1..]
97
+
98
+ return unless string && arguments.any?
99
+ return if arguments.any?(&:splat_type?)
100
+
101
+ register_all_fields_literal(node, string, arguments)
102
+ end
103
+
104
+ def register_all_fields_literal(node, string, arguments)
105
+ return unless all_fields_literal?(string, arguments.dup)
106
+
107
+ add_offense(node, message: message(node)) do |corrector|
108
+ replacement = format(string, *argument_values(arguments))
109
+ corrector.replace(node, quote(replacement, node))
110
+ end
111
+ end
112
+
113
+ def all_fields_literal?(string, arguments)
114
+ count = 0
115
+ sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
116
+ return false unless sequences.any?
117
+
118
+ sequences.each do |sequence|
119
+ next if sequence.percent?
120
+
121
+ hash = arguments.detect(&:hash_type?)
122
+ argument = find_argument(sequence, arguments, hash)
123
+ next unless matching_argument?(sequence, argument)
124
+
125
+ count += 1
126
+ end
127
+
128
+ sequences.size == count
129
+ end
130
+
131
+ def find_argument(sequence, arguments, hash)
132
+ if hash && (sequence.annotated? || sequence.template?)
133
+ find_hash_value_node(hash, sequence.name.to_sym).first
134
+ elsif sequence.arg_number
135
+ arguments[sequence.arg_number.to_i - 1]
136
+ else
137
+ # If the specifier contains `*`, the following arguments will be used
138
+ # to specify the width and can be ignored.
139
+ (sequence.arity - 1).times { arguments.shift }
140
+ arguments.shift
141
+ end
142
+ end
143
+
144
+ def matching_argument?(sequence, argument)
145
+ # Template specifiers don't give a type, any acceptable literal type is ok.
146
+ return argument.type?(*ACCEPTABLE_LITERAL_TYPES) if sequence.template?
147
+
148
+ # An argument matches a specifier if it can be easily converted
149
+ # to that type.
150
+ case sequence.type
151
+ when 's'
152
+ argument.type?(*ACCEPTABLE_LITERAL_TYPES)
153
+ when 'd', 'i', 'u'
154
+ integer?(argument)
155
+ when 'f'
156
+ float?(argument)
157
+ else
158
+ false
159
+ end
160
+ end
161
+
162
+ def numeric?(argument)
163
+ argument&.type?(:numeric, :str) ||
164
+ rational_number?(argument) ||
165
+ complex_number?(argument)
166
+ end
167
+
168
+ def integer?(argument)
169
+ numeric?(argument) && Integer(argument_value(argument), exception: false)
170
+ end
171
+
172
+ def float?(argument)
173
+ numeric?(argument) && Float(argument_value(argument), exception: false)
174
+ end
175
+
176
+ # Add correct quotes to the formatted string, preferring retaining the existing
177
+ # quotes if possible.
178
+ def quote(string, node)
179
+ str_node = node.first_argument
180
+ start_delimiter = str_node.loc.begin.source
181
+ end_delimiter = str_node.loc.end.source
182
+
183
+ # If there is any interpolation, the delimiters need to be changed potentially
184
+ if node.each_descendant(:dstr, :dsym).any?
185
+ case start_delimiter
186
+ when "'"
187
+ start_delimiter = end_delimiter = '"'
188
+ when /\A%q(.)/
189
+ start_delimiter = "%Q#{Regexp.last_match[1]}"
190
+ end
191
+ end
192
+
193
+ "#{start_delimiter}#{string}#{end_delimiter}"
194
+ end
195
+
196
+ def argument_values(arguments)
197
+ arguments.map { |argument| argument_value(argument) }
198
+ end
199
+
200
+ def argument_value(argument)
201
+ argument = argument.children.first if argument.begin_type?
202
+
203
+ if argument.dsym_type?
204
+ dsym_value(argument)
205
+ elsif argument.hash_type?
206
+ hash_value(argument)
207
+ elsif rational_number?(argument)
208
+ rational_value(argument)
209
+ elsif complex_number?(argument)
210
+ complex_value(argument)
211
+ elsif argument.respond_to?(:value)
212
+ argument.value
213
+ else
214
+ argument.source
215
+ end
216
+ end
217
+
218
+ def dsym_value(dsym_node)
219
+ dsym_node.children.first.source
220
+ end
221
+
222
+ def hash_value(hash_node)
223
+ hash_node.each_pair.with_object({}) do |pair, hash|
224
+ hash[pair.key.value] = argument_value(pair.value)
225
+ end
226
+ end
227
+
228
+ def rational_value(rational_node)
229
+ rational_node.source.to_r
230
+ end
231
+
232
+ def complex_value(complex_node)
233
+ Complex(complex_node.source)
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Style
6
6
  # Check for uses of `Object#freeze` on immutable objects.
7
7
  #
8
- # NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
8
+ # NOTE: `Regexp` and `Range` literals are frozen objects since Ruby 3.0.
9
9
  #
10
10
  # NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
11
11
  # string literals when `# frozen-string-literal: true` is used.
@@ -42,7 +42,7 @@ module RuboCop
42
42
  return true if node.immutable_literal?
43
43
  return true if frozen_string_literal?(node)
44
44
 
45
- target_ruby_version >= 3.0 && (node.regexp_type? || node.range_type?)
45
+ target_ruby_version >= 3.0 && node.type?(:regexp, :range)
46
46
  end
47
47
 
48
48
  def strip_parenthesis(node)
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # will not register an offense, because it allows the initializer to take a different
12
12
  # number of arguments as its superclass potentially does.
13
13
  #
14
+ # NOTE: If an initializer takes any arguments and has an empty body, RuboCop
15
+ # assumes it to *not* be redundant. This is to prevent potential `ArgumentError`.
16
+ #
14
17
  # NOTE: If an initializer argument has a default value, RuboCop assumes it
15
18
  # to *not* be redundant.
16
19
  #
@@ -19,8 +22,10 @@ module RuboCop
19
22
  # initializer.
20
23
  #
21
24
  # @safety
22
- # This cop is unsafe because if subclass overrides `initialize` method with
23
- # a different arity than superclass.
25
+ # This cop is unsafe because removing an empty initializer may alter
26
+ # the behavior of the code, particularly if the superclass initializer
27
+ # raises an exception. In such cases, the empty initializer may act as
28
+ # a safeguard to prevent unintended errors from propagating.
24
29
  #
25
30
  # @example
26
31
  # # bad
@@ -69,6 +74,10 @@ module RuboCop
69
74
  # end
70
75
  #
71
76
  # # good (changes the parameter requirements)
77
+ # def initialize(_)
78
+ # end
79
+ #
80
+ # # good (changes the parameter requirements)
72
81
  # def initialize(*)
73
82
  # end
74
83
  #
@@ -111,7 +120,7 @@ module RuboCop
111
120
  return if acceptable?(node)
112
121
 
113
122
  if node.body.nil?
114
- register_offense(node, MSG_EMPTY)
123
+ register_offense(node, MSG_EMPTY) if node.arguments.empty?
115
124
  else
116
125
  return if node.body.begin_type?
117
126
 
@@ -69,17 +69,24 @@ module RuboCop
69
69
  extend AutoCorrector
70
70
 
71
71
  MSG = 'Redundant line continuation.'
72
+ LINE_CONTINUATION = '\\'
73
+ LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
72
74
  ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
73
75
  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
+ kDEF kDEFINED kFALSE kNIL kSELF kTRUE tAMPER tBANG tCARET tCHARACTER tCOLON3 tCONSTANT
77
+ tCVAR tDOT2 tDOT3 tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR tLAMBDA tLBRACK tLCURLY
78
+ tLPAREN_ARG tPIPE tQSYMBOLS_BEG tQWORDS_BEG tREGEXP_BEG tSTAR tSTRING tSTRING_BEG tSYMBEG
79
+ tSYMBOL tSYMBOLS_BEG tTILDE tUMINUS tUNARY_NUM tUPLUS tWORDS_BEG tXSTRING_BEG
76
80
  ].freeze
77
- ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
81
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[
82
+ tIDENTIFIER kBREAK kNEXT kRETURN kSUPER kYIELD
83
+ ].freeze
84
+ ARITHMETIC_OPERATOR_TOKENS = %i[tDIVIDE tDSTAR tMINUS tPERCENT tPLUS tSTAR2].freeze
78
85
 
79
86
  def on_new_investigation
80
87
  return unless processed_source.ast
81
88
 
82
- each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
89
+ each_match_range(processed_source.ast.source_range, LINE_CONTINUATION_PATTERN) do |range|
83
90
  next if require_line_continuation?(range)
84
91
  next unless redundant_line_continuation?(range)
85
92
 
@@ -87,20 +94,27 @@ module RuboCop
87
94
  corrector.remove_leading(range, 1)
88
95
  end
89
96
  end
97
+
98
+ inspect_end_of_ruby_code_line_continuation
90
99
  end
91
100
 
92
101
  private
93
102
 
94
103
  def require_line_continuation?(range)
95
- !ends_with_backslash_without_comment?(range.source_line) ||
104
+ !ends_with_uncommented_backslash?(range) ||
96
105
  string_concatenation?(range.source_line) ||
97
- start_with_arithmetic_operator?(processed_source[range.line]) ||
106
+ start_with_arithmetic_operator?(range) ||
98
107
  inside_string_literal_or_method_with_argument?(range) ||
99
108
  leading_dot_method_chain_with_blank_line?(range)
100
109
  end
101
110
 
102
- def ends_with_backslash_without_comment?(source_line)
103
- source_line.gsub(/#.+/, '').end_with?('\\')
111
+ def ends_with_uncommented_backslash?(range)
112
+ # A line continuation always needs to be the last character on the line, which
113
+ # means that it is impossible to have a comment following a continuation.
114
+ # Therefore, if the line contains a comment, it cannot end with a continuation.
115
+ return false if processed_source.line_with_comment?(range.line)
116
+
117
+ range.source_line.end_with?(LINE_CONTINUATION)
104
118
  end
105
119
 
106
120
  def string_concatenation?(source_line)
@@ -108,10 +122,13 @@ module RuboCop
108
122
  end
109
123
 
110
124
  def inside_string_literal_or_method_with_argument?(range)
125
+ line_range = range_by_whole_lines(range)
126
+
111
127
  processed_source.tokens.each_cons(2).any? do |token, next_token|
112
128
  next if token.line == next_token.line
113
129
 
114
- inside_string_literal?(range, token) || method_with_argument?(token, next_token)
130
+ inside_string_literal?(range, token) ||
131
+ method_with_argument?(line_range, token, next_token)
115
132
  end
116
133
  end
117
134
 
@@ -122,11 +139,31 @@ module RuboCop
122
139
  end
123
140
 
124
141
  def redundant_line_continuation?(range)
125
- return true unless (node = find_node_for_line(range.line))
142
+ return true unless (node = find_node_for_line(range.last_line))
126
143
  return false if argument_newline?(node)
127
144
 
128
- source = node.parent ? node.parent.source : node.source
129
- parse(source.gsub("\\\n", "\n")).valid_syntax?
145
+ # Check if source is still valid without the continuation
146
+ source = processed_source.raw_source.dup
147
+ source[range.begin_pos, range.length] = "\n"
148
+ parse(source).valid_syntax?
149
+ end
150
+
151
+ def inspect_end_of_ruby_code_line_continuation
152
+ last_line = processed_source.lines[processed_source.ast.last_line - 1]
153
+ return unless code_ends_with_continuation?(last_line)
154
+
155
+ last_column = last_line.length
156
+ line_continuation_range = range_between(last_column - 1, last_column)
157
+
158
+ add_offense(line_continuation_range) do |corrector|
159
+ corrector.remove_trailing(line_continuation_range, 1)
160
+ end
161
+ end
162
+
163
+ def code_ends_with_continuation?(last_line)
164
+ return false if processed_source.line_with_comment?(processed_source.ast.last_line)
165
+
166
+ last_line.end_with?(LINE_CONTINUATION)
130
167
  end
131
168
 
132
169
  def inside_string_literal?(range, token)
@@ -137,8 +174,9 @@ module RuboCop
137
174
  #
138
175
  # do_something \
139
176
  # argument
140
- def method_with_argument?(current_token, next_token)
177
+ def method_with_argument?(line_range, current_token, next_token)
141
178
  return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
179
+ return false unless current_token.pos.overlaps?(line_range)
142
180
 
143
181
  ARGUMENT_TYPES.include?(next_token.type)
144
182
  end
@@ -160,9 +198,9 @@ module RuboCop
160
198
  end
161
199
  # rubocop:enable Metrics/AbcSize
162
200
 
163
- def find_node_for_line(line)
201
+ def find_node_for_line(last_line)
164
202
  processed_source.ast.each_node do |node|
165
- return node if same_line?(node, line)
203
+ return node if same_line?(node, last_line)
166
204
  end
167
205
  end
168
206
 
@@ -191,8 +229,9 @@ module RuboCop
191
229
  node.call_type? && !node.arguments.empty?
192
230
  end
193
231
 
194
- def start_with_arithmetic_operator?(source_line)
195
- %r{\A\s*[+\-*/%]}.match?(source_line)
232
+ def start_with_arithmetic_operator?(range)
233
+ line_range = processed_source.buffer.line_range(range.line + 1)
234
+ ARITHMETIC_OPERATOR_TOKENS.include?(processed_source.first_token_of(line_range).type)
196
235
  end
197
236
  end
198
237
  end
@@ -13,14 +13,16 @@ module RuboCop
13
13
  # # good
14
14
  # x if y.z.nil?
15
15
  #
16
- class RedundantParentheses < Base
16
+ class RedundantParentheses < Base # rubocop:disable Metrics/ClassLength
17
17
  include Parentheses
18
18
  extend AutoCorrector
19
19
 
20
20
  ALLOWED_NODE_TYPES = %i[and or send splat kwsplat].freeze
21
21
 
22
22
  # @!method square_brackets?(node)
23
- def_node_matcher :square_brackets?, '(send {(send _recv _msg) str array hash} :[] ...)'
23
+ def_node_matcher :square_brackets?, <<~PATTERN
24
+ (send `{(send _recv _msg) str array hash const #variable?} :[] ...)
25
+ PATTERN
24
26
 
25
27
  # @!method method_node_and_args(node)
26
28
  def_node_matcher :method_node_and_args, '$(call _recv _msg $...)'
@@ -31,9 +33,6 @@ module RuboCop
31
33
  # @!method allowed_pin_operator?(node)
32
34
  def_node_matcher :allowed_pin_operator?, '^(pin (begin !{lvar ivar cvar gvar}))'
33
35
 
34
- # @!method arg_in_call_with_block?(node)
35
- def_node_matcher :arg_in_call_with_block?, '^^(block (send _ _ equal?(%0) ...) ...)'
36
-
37
36
  def on_begin(node)
38
37
  return if !parentheses?(node) || parens_allowed?(node) || ignore_syntax?(node)
39
38
 
@@ -42,6 +41,10 @@ module RuboCop
42
41
 
43
42
  private
44
43
 
44
+ def variable?(node)
45
+ node.respond_to?(:variable?) && node.variable?
46
+ end
47
+
45
48
  def parens_allowed?(node)
46
49
  empty_parentheses?(node) ||
47
50
  first_arg_begins_with_hash_literal?(node) ||
@@ -53,13 +56,12 @@ module RuboCop
53
56
  def ignore_syntax?(node)
54
57
  return false unless (parent = node.parent)
55
58
 
56
- parent.while_post_type? || parent.until_post_type? || parent.match_with_lvasgn_type? ||
59
+ parent.type?(:while_post, :until_post, :match_with_lvasgn) ||
57
60
  like_method_argument_parentheses?(parent) || multiline_control_flow_statements?(node)
58
61
  end
59
62
 
60
63
  def allowed_expression?(node)
61
64
  allowed_ancestor?(node) ||
62
- allowed_method_call?(node) ||
63
65
  allowed_multiple_expression?(node) ||
64
66
  allowed_ternary?(node) ||
65
67
  node.parent&.range_type?
@@ -70,18 +72,13 @@ module RuboCop
70
72
  keyword_ancestor?(node) && parens_required?(node)
71
73
  end
72
74
 
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
75
  def allowed_multiple_expression?(node)
79
76
  return false if node.children.one?
80
77
 
81
78
  ancestor = node.ancestors.first
82
79
  return false unless ancestor
83
80
 
84
- !ancestor.begin_type? && !ancestor.def_type? && !ancestor.block_type?
81
+ !ancestor.type?(:begin, :def, :any_block)
85
82
  end
86
83
 
87
84
  def allowed_ternary?(node)
@@ -98,7 +95,7 @@ module RuboCop
98
95
  end
99
96
 
100
97
  def like_method_argument_parentheses?(node)
101
- return false if !node.send_type? && !node.super_type? && !node.yield_type?
98
+ return false unless node.type?(:send, :super, :yield)
102
99
 
103
100
  node.arguments.one? && !node.parenthesized? &&
104
101
  !node.arithmetic_operation? && node.first_argument.begin_type?
@@ -108,7 +105,7 @@ module RuboCop
108
105
  return false unless (parent = node.parent)
109
106
  return false if parent.single_line?
110
107
 
111
- parent.return_type? || parent.next_type? || parent.break_type?
108
+ parent.type?(:return, :next, :break)
112
109
  end
113
110
 
114
111
  def empty_parentheses?(node)
@@ -137,6 +134,8 @@ module RuboCop
137
134
  node = begin_node.children.first
138
135
 
139
136
  if (message = find_offense_message(begin_node, node))
137
+ begin_node = begin_node.parent if node.range_type?
138
+
140
139
  return offense(begin_node, message)
141
140
  end
142
141
 
@@ -146,9 +145,12 @@ module RuboCop
146
145
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
147
146
  def find_offense_message(begin_node, node)
148
147
  return 'a keyword' if keyword_with_redundant_parentheses?(node)
149
- return 'a literal' if disallowed_literal?(begin_node, node)
148
+ return 'a literal' if node.literal? && disallowed_literal?(begin_node, node)
150
149
  return 'a variable' if node.variable?
151
150
  return 'a constant' if node.const_type?
151
+ if node.assignment? && (begin_node.parent.nil? || begin_node.parent.begin_type?)
152
+ return 'an assignment'
153
+ end
152
154
  if node.lambda_or_proc? && (node.braces? || node.send_node.lambda_literal?)
153
155
  return 'an expression'
154
156
  end
@@ -156,11 +158,11 @@ module RuboCop
156
158
 
157
159
  return if begin_node.chained?
158
160
 
159
- if node.and_type? || node.or_type?
161
+ if node.operator_keyword?
160
162
  return if node.semantic_operator? && begin_node.parent
161
163
  return if node.multiline? && allow_in_multiline_conditions?
162
164
  return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
163
- return if begin_node.parent&.if_type? && begin_node.parent&.ternary?
165
+ return if begin_node.parent&.if_type? && begin_node.parent.ternary?
164
166
 
165
167
  'a logical expression'
166
168
  elsif node.respond_to?(:comparison_method?) && node.comparison_method?
@@ -175,17 +177,15 @@ module RuboCop
175
177
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
176
178
 
177
179
  def allow_in_multiline_conditions?
178
- parentheses_around_condition_config = config.for_cop('Style/ParenthesesAroundCondition')
179
- return false unless parentheses_around_condition_config['Enabled']
180
-
181
- !!parentheses_around_condition_config['AllowInMultilineConditions']
180
+ !!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
182
181
  end
183
182
 
184
183
  def check_send(begin_node, node)
185
184
  return check_unary(begin_node, node) if node.unary_operation?
186
185
 
187
186
  return unless method_call_with_redundant_parentheses?(node)
188
- return if call_chain_starts_with_int?(begin_node, node)
187
+ return if call_chain_starts_with_int?(begin_node, node) ||
188
+ do_end_block_in_method_chain?(begin_node, node)
189
189
 
190
190
  offense(begin_node, 'a method call')
191
191
  end
@@ -215,7 +215,13 @@ module RuboCop
215
215
  end
216
216
 
217
217
  def disallowed_literal?(begin_node, node)
218
- node.literal? && !node.range_type? && !raised_to_power_negative_numeric?(begin_node, node)
218
+ if node.range_type?
219
+ return false unless (parent = begin_node.parent)
220
+
221
+ parent.begin_type? && parent.children.one?
222
+ else
223
+ !raised_to_power_negative_numeric?(begin_node, node)
224
+ end
219
225
  end
220
226
 
221
227
  def raised_to_power_negative_numeric?(begin_node, node)
@@ -252,7 +258,7 @@ module RuboCop
252
258
  end
253
259
 
254
260
  def only_begin_arg?(args)
255
- args.one? && args.first.begin_type?
261
+ args.one? && args.first&.begin_type?
256
262
  end
257
263
 
258
264
  def first_argument?(node)
@@ -285,6 +291,12 @@ module RuboCop
285
291
  recv&.int_type? && (parent = begin_node.parent) &&
286
292
  parent.send_type? && (parent.method?(:-@) || parent.method?(:+@))
287
293
  end
294
+
295
+ def do_end_block_in_method_chain?(begin_node, node)
296
+ return false unless (block = node.each_descendant(:any_block).first)
297
+
298
+ block.keywords? && begin_node.each_ancestor(:call).any?
299
+ end
288
300
  end
289
301
  end
290
302
  end
@@ -70,6 +70,10 @@ module RuboCop
70
70
  new_argument = replacement(regexp_node)
71
71
 
72
72
  if new_argument.include?('"')
73
+ new_argument.gsub!("'", "\\\\'")
74
+ new_argument.gsub!('\"', '"')
75
+ quote = "'"
76
+ elsif new_argument.include?('\'')
73
77
  new_argument.gsub!("'", "\\\\'")
74
78
  quote = "'"
75
79
  elsif new_argument.include?('\\')
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for unnecessary single-element Regexp character classes.
6
+ # Checks for unnecessary single-element `Regexp` character classes.
7
7
  #
8
8
  # @example
9
9
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for redundant escapes inside Regexp literals.
6
+ # Checks for redundant escapes inside `Regexp` literals.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -61,9 +61,9 @@ module RuboCop
61
61
  RESTRICT_ON_SEND = %i[define_method define_singleton_method lambda].freeze
62
62
 
63
63
  def on_send(node)
64
- return unless (parent = node.parent) && parent.block_type?
64
+ return unless node.block_literal?
65
65
 
66
- check_branch(parent.body)
66
+ check_branch(node.parent.body)
67
67
  end
68
68
 
69
69
  def on_def(node)