rubocop 1.46.0 → 1.52.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (269) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +83 -11
  4. data/lib/rubocop/cli/command/auto_generate_config.rb +7 -0
  5. data/lib/rubocop/cli/command/execute_runner.rb +7 -2
  6. data/lib/rubocop/cli.rb +6 -6
  7. data/lib/rubocop/comment_config.rb +2 -0
  8. data/lib/rubocop/config.rb +7 -3
  9. data/lib/rubocop/config_loader.rb +8 -8
  10. data/lib/rubocop/config_obsoletion.rb +2 -2
  11. data/lib/rubocop/cop/autocorrect_logic.rb +29 -13
  12. data/lib/rubocop/cop/base.rb +6 -2
  13. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  14. data/lib/rubocop/cop/cop.rb +2 -2
  15. data/lib/rubocop/cop/corrector.rb +1 -1
  16. data/lib/rubocop/cop/correctors/alignment_corrector.rb +3 -3
  17. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +3 -3
  18. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +3 -3
  19. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  20. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  21. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -1
  22. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  23. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  24. data/lib/rubocop/cop/gemspec/dependency_version.rb +1 -1
  25. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -1
  26. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/cop_description.rb +37 -13
  28. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +3 -3
  29. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +1 -1
  30. data/lib/rubocop/cop/internal_affairs/location_expression.rb +37 -0
  31. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +3 -3
  32. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +1 -1
  33. data/lib/rubocop/cop/internal_affairs/processed_source_buffer_name.rb +1 -1
  34. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +1 -1
  35. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +66 -0
  37. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  38. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -21
  39. data/lib/rubocop/cop/layout/class_structure.rb +6 -3
  40. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  41. data/lib/rubocop/cop/layout/empty_comment.rb +3 -3
  42. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  43. data/lib/rubocop/cop/layout/empty_lines.rb +1 -1
  44. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -0
  45. data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
  46. data/lib/rubocop/cop/layout/extra_spacing.rb +6 -1
  47. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  48. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  49. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
  50. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
  51. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  52. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  53. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  54. data/lib/rubocop/cop/layout/initial_indentation.rb +1 -1
  55. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  56. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -3
  57. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  58. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
  59. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
  60. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
  61. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -7
  62. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  63. data/lib/rubocop/cop/layout/space_before_first_arg.rb +1 -1
  64. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +2 -2
  65. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +3 -1
  66. data/lib/rubocop/cop/layout/space_inside_parens.rb +2 -2
  67. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +1 -1
  68. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  69. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  70. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  71. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  72. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  73. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +122 -0
  74. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  75. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -3
  76. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  77. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  78. data/lib/rubocop/cop/lint/empty_conditional_body.rb +4 -2
  79. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  80. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
  81. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  82. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  83. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  84. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  85. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  86. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +46 -4
  87. data/lib/rubocop/cop/lint/missing_super.rb +34 -2
  88. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  89. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  90. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +2 -0
  91. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  92. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  93. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  94. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  95. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +4 -4
  96. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -5
  97. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -1
  98. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  99. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +35 -15
  100. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
  101. data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
  102. data/lib/rubocop/cop/lint/rescue_type.rb +3 -3
  103. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +1 -1
  104. data/lib/rubocop/cop/lint/script_permission.rb +1 -1
  105. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  106. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -12
  107. data/lib/rubocop/cop/lint/syntax.rb +4 -0
  108. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -1
  109. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  110. data/lib/rubocop/cop/lint/unreachable_loop.rb +3 -3
  111. data/lib/rubocop/cop/lint/useless_access_modifier.rb +9 -1
  112. data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
  113. data/lib/rubocop/cop/lint/useless_method_definition.rb +10 -2
  114. data/lib/rubocop/cop/lint/useless_rescue.rb +4 -1
  115. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  116. data/lib/rubocop/cop/lint/void.rb +69 -9
  117. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  118. data/lib/rubocop/cop/metrics/class_length.rb +1 -0
  119. data/lib/rubocop/cop/metrics/collection_literal_length.rb +76 -0
  120. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  121. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +3 -3
  122. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  123. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  124. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  125. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  126. data/lib/rubocop/cop/mixin/comments_help.rb +9 -5
  127. data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
  128. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +1 -1
  129. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -2
  130. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  131. data/lib/rubocop/cop/mixin/min_branches_count.rb +40 -0
  132. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  133. data/lib/rubocop/cop/mixin/range_help.rb +1 -6
  134. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  135. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -3
  136. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  137. data/lib/rubocop/cop/naming/ascii_identifiers.rb +1 -1
  138. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  139. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +1 -1
  140. data/lib/rubocop/cop/naming/inclusive_language.rb +23 -4
  141. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
  142. data/lib/rubocop/cop/naming/method_name.rb +3 -3
  143. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  144. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -4
  145. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  146. data/lib/rubocop/cop/registry.rb +3 -1
  147. data/lib/rubocop/cop/style/accessor_grouping.rb +32 -7
  148. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  149. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  150. data/lib/rubocop/cop/style/attr.rb +11 -1
  151. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  152. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +1 -1
  153. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  154. data/lib/rubocop/cop/style/block_delimiters.rb +11 -2
  155. data/lib/rubocop/cop/style/case_like_if.rb +20 -3
  156. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -2
  157. data/lib/rubocop/cop/style/class_equality_comparison.rb +51 -40
  158. data/lib/rubocop/cop/style/collection_compact.rb +20 -7
  159. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  160. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  161. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  162. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  163. data/lib/rubocop/cop/style/concat_array_literals.rb +10 -2
  164. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -8
  165. data/lib/rubocop/cop/style/copyright.rb +6 -3
  166. data/lib/rubocop/cop/style/data_inheritance.rb +75 -0
  167. data/lib/rubocop/cop/style/dir.rb +1 -1
  168. data/lib/rubocop/cop/style/dir_empty.rb +54 -0
  169. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
  170. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +2 -2
  171. data/lib/rubocop/cop/style/documentation.rb +11 -5
  172. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  173. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  174. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  175. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  176. data/lib/rubocop/cop/style/eval_with_location.rb +8 -8
  177. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  178. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  179. data/lib/rubocop/cop/style/file_empty.rb +71 -0
  180. data/lib/rubocop/cop/style/file_read.rb +3 -3
  181. data/lib/rubocop/cop/style/file_write.rb +1 -1
  182. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  183. data/lib/rubocop/cop/style/guard_clause.rb +3 -1
  184. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  185. data/lib/rubocop/cop/style/hash_except.rb +23 -12
  186. data/lib/rubocop/cop/style/hash_like_case.rb +3 -9
  187. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  188. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  189. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  190. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  191. data/lib/rubocop/cop/style/if_unless_modifier.rb +111 -15
  192. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  193. data/lib/rubocop/cop/style/inverse_methods.rb +5 -5
  194. data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
  195. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +2 -2
  196. data/lib/rubocop/cop/style/map_to_hash.rb +4 -1
  197. data/lib/rubocop/cop/style/map_to_set.rb +4 -1
  198. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -9
  199. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +44 -37
  200. data/lib/rubocop/cop/style/min_max.rb +3 -3
  201. data/lib/rubocop/cop/style/mixin_grouping.rb +4 -4
  202. data/lib/rubocop/cop/style/multiline_method_signature.rb +7 -4
  203. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
  204. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  205. data/lib/rubocop/cop/style/negated_if_else_condition.rb +12 -7
  206. data/lib/rubocop/cop/style/nil_lambda.rb +2 -2
  207. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  208. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -18
  209. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -3
  210. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  211. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  212. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  213. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +2 -2
  214. data/lib/rubocop/cop/style/redundant_fetch_block.rb +6 -4
  215. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  216. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  217. data/lib/rubocop/cop/style/redundant_line_continuation.rb +183 -0
  218. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  219. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  220. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -2
  221. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  222. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +11 -4
  223. data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
  224. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -4
  225. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  226. data/lib/rubocop/cop/style/require_order.rb +12 -8
  227. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  228. data/lib/rubocop/cop/style/rescue_standard_error.rb +2 -2
  229. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  230. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  231. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  232. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  233. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -4
  234. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  235. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  236. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  237. data/lib/rubocop/cop/style/trailing_body_on_class.rb +1 -0
  238. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -1
  239. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  240. data/lib/rubocop/cop/style/unless_logical_operators.rb +1 -0
  241. data/lib/rubocop/cop/style/unpack_first.rb +3 -3
  242. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  243. data/lib/rubocop/cop/style/zero_length_predicate.rb +9 -5
  244. data/lib/rubocop/cop/team.rb +2 -2
  245. data/lib/rubocop/cop/util.rb +1 -1
  246. data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
  247. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  248. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  249. data/lib/rubocop/cop/variable_force.rb +1 -0
  250. data/lib/rubocop/cops_documentation_generator.rb +10 -3
  251. data/lib/rubocop/directive_comment.rb +3 -3
  252. data/lib/rubocop/ext/comment.rb +18 -0
  253. data/lib/rubocop/ext/regexp_node.rb +1 -1
  254. data/lib/rubocop/ext/regexp_parser.rb +1 -1
  255. data/lib/rubocop/formatter/junit_formatter.rb +4 -1
  256. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  257. data/lib/rubocop/options.rb +4 -1
  258. data/lib/rubocop/result_cache.rb +2 -2
  259. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  260. data/lib/rubocop/rspec/support.rb +1 -0
  261. data/lib/rubocop/server/cache.rb +1 -1
  262. data/lib/rubocop/server/client_command/exec.rb +2 -1
  263. data/lib/rubocop/server/core.rb +1 -1
  264. data/lib/rubocop/server/helper.rb +1 -1
  265. data/lib/rubocop/server/server_command/exec.rb +1 -1
  266. data/lib/rubocop/target_ruby.rb +3 -2
  267. data/lib/rubocop/version.rb +10 -6
  268. data/lib/rubocop.rb +13 -0
  269. metadata +23 -8
@@ -31,22 +31,26 @@ module RuboCop
31
31
  def on_masgn(node)
32
32
  lhs, rhs = *node
33
33
  lhs_elements = *lhs
34
+ rhs = rhs.body if rhs.rescue_type?
34
35
  rhs_elements = Array(rhs).compact # edge case for one constant
35
36
 
36
37
  return if allowed_lhs?(lhs) || allowed_rhs?(rhs) ||
37
38
  allowed_masign?(lhs_elements, rhs_elements)
38
39
 
39
- add_offense(node) { |corrector| autocorrect(corrector, node) }
40
+ range = node.source_range.begin.join(rhs.source_range.end)
41
+
42
+ add_offense(range) do |corrector|
43
+ autocorrect(corrector, node, lhs, rhs)
44
+ end
40
45
  end
41
46
 
42
47
  private
43
48
 
44
- def autocorrect(corrector, node)
45
- left, right = *node
46
- left_elements = *left
47
- right_elements = Array(right).compact
49
+ def autocorrect(corrector, node, lhs, rhs)
50
+ left_elements = *lhs
51
+ right_elements = Array(rhs).compact
48
52
  order = find_valid_order(left_elements, right_elements)
49
- correction = assignment_corrector(node, order)
53
+ correction = assignment_corrector(node, rhs, order)
50
54
 
51
55
  corrector.replace(correction.correction_range, correction.correction)
52
56
  end
@@ -77,14 +81,19 @@ module RuboCop
77
81
  node.block_type? || node.send_type?
78
82
  end
79
83
 
80
- def assignment_corrector(node, order)
81
- _assignment, modifier = *node.parent
84
+ def assignment_corrector(node, rhs, order)
85
+ if node.parent&.rescue_type?
86
+ _assignment, modifier = *node.parent
87
+ else
88
+ _assignment, modifier = *rhs.parent
89
+ end
90
+
82
91
  if modifier_statement?(node.parent)
83
- ModifierCorrector.new(node, config, order)
92
+ ModifierCorrector.new(node, rhs, modifier, config, order)
84
93
  elsif rescue_modifier?(modifier)
85
- RescueCorrector.new(node, config, order)
94
+ RescueCorrector.new(node, rhs, modifier, config, order)
86
95
  else
87
- GenericCorrector.new(node, config, order)
96
+ GenericCorrector.new(node, rhs, modifier, config, order)
88
97
  end
89
98
  end
90
99
 
@@ -181,10 +190,12 @@ module RuboCop
181
190
  class GenericCorrector
182
191
  include Alignment
183
192
 
184
- attr_reader :config, :node
193
+ attr_reader :node, :rhs, :rescue_result, :config
185
194
 
186
- def initialize(node, config, new_elements)
195
+ def initialize(node, rhs, modifier, config, new_elements)
187
196
  @node = node
197
+ @rhs = rhs
198
+ _, _, @rescue_result = *modifier
188
199
  @config = config
189
200
  @new_elements = new_elements
190
201
  end
@@ -228,13 +239,10 @@ module RuboCop
228
239
  # protected by rescue
229
240
  class RescueCorrector < GenericCorrector
230
241
  def correction
231
- _node, rescue_clause = *node.parent
232
- _, _, rescue_result = *rescue_clause
233
-
234
242
  # If the parallel assignment uses a rescue modifier and it is the
235
243
  # only contents of a method, then we want to make use of the
236
244
  # implicit begin
237
- if node.parent.parent&.def_type?
245
+ if rhs.parent.parent.parent&.def_type?
238
246
  super + def_correction(rescue_result)
239
247
  else
240
248
  begin_correction(rescue_result)
@@ -242,7 +250,7 @@ module RuboCop
242
250
  end
243
251
 
244
252
  def correction_range
245
- node.parent.source_range
253
+ rhs.parent.parent.source_range
246
254
  end
247
255
 
248
256
  private
@@ -92,9 +92,8 @@ module RuboCop
92
92
 
93
93
  def contains_delimiter?(node, delimiters)
94
94
  delimiters_regexp = Regexp.union(delimiters)
95
- node
96
- .children.map { |n| string_source(n) }.compact
97
- .any? { |s| delimiters_regexp.match?(s) }
95
+
96
+ node.children.filter_map { |n| string_source(n) }.any?(delimiters_regexp)
98
97
  end
99
98
 
100
99
  def string_source(node)
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  # Report offense only if changing case doesn't change semantics,
46
46
  # i.e., if the string would become dynamic or has special characters.
47
- ast = ProcessedSource.new(corrected(node.source), target_ruby_version).ast
47
+ ast = parse(corrected(node.source)).ast
48
48
  return if node.children != ast.children
49
49
 
50
50
  add_offense(node.loc.begin) do |corrector|
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the instantiation of array using redundant `Array` constructor.
7
+ # Autocorrect replaces to array literal which is the simplest and fastest.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Array.new([])
13
+ # Array[]
14
+ # Array([])
15
+ # Array.new(['foo', 'foo', 'foo'])
16
+ # Array['foo', 'foo', 'foo']
17
+ # Array(['foo', 'foo', 'foo'])
18
+ #
19
+ # # good
20
+ # []
21
+ # ['foo', 'foo', 'foo']
22
+ # Array.new(3, 'foo')
23
+ # Array.new(3) { 'foo' }
24
+ #
25
+ class RedundantArrayConstructor < Base
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Remove the redundant `Array` constructor.'
29
+
30
+ RESTRICT_ON_SEND = %i[new [] Array].freeze
31
+
32
+ # @!method redundant_array_constructor(node)
33
+ def_node_matcher :redundant_array_constructor, <<~PATTERN
34
+ {
35
+ (send
36
+ (const {nil? cbase} :Array) :new
37
+ $(array ...))
38
+ (send
39
+ (const {nil? cbase} :Array) :[]
40
+ $...)
41
+ (send
42
+ nil? :Array
43
+ $(array ...))
44
+ }
45
+ PATTERN
46
+
47
+ def on_send(node)
48
+ return unless (array_literal = redundant_array_constructor(node))
49
+
50
+ receiver = node.receiver
51
+ selector = node.loc.selector
52
+
53
+ if node.method?(:new)
54
+ range = receiver.source_range.join(selector)
55
+ replacement = array_literal
56
+ elsif node.method?(:Array)
57
+ range = selector
58
+ replacement = array_literal
59
+ else
60
+ range = receiver
61
+ replacement = selector.begin.join(node.source_range.end)
62
+ end
63
+
64
+ register_offense(range, node, replacement)
65
+ end
66
+
67
+ private
68
+
69
+ def register_offense(range, node, replacement)
70
+ add_offense(range) do |corrector|
71
+ corrector.replace(node, replacement.source)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -70,8 +70,8 @@ module RuboCop
70
70
  end
71
71
 
72
72
  def range_of_offense(node)
73
- return node.loc.expression unless node.ternary?
74
- return node.loc.expression if node.ternary? && branches_have_method?(node)
73
+ return node.source_range unless node.ternary?
74
+ return node.source_range if node.ternary? && branches_have_method?(node)
75
75
 
76
76
  range_between(node.loc.question.begin_pos, node.loc.colon.end_pos)
77
77
  end
@@ -33,11 +33,11 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def opening_brace(node)
36
- node.loc.begin.join(node.children.first.loc.expression.begin)
36
+ node.loc.begin.join(node.children.first.source_range.begin)
37
37
  end
38
38
 
39
39
  def closing_brace(node)
40
- node.children.last.loc.expression.end.join(node.loc.end)
40
+ node.children.last.source_range.end.join(node.loc.end)
41
41
  end
42
42
  end
43
43
  end
@@ -3,11 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Identifies places where `fetch(key) { value }`
7
- # can be replaced by `fetch(key, value)`.
6
+ # Identifies places where `fetch(key) { value }` can be replaced by `fetch(key, value)`.
8
7
  #
9
- # In such cases `fetch(key, value)` method is faster
10
- # than `fetch(key) { value }`.
8
+ # In such cases `fetch(key, value)` method is faster than `fetch(key) { value }`.
9
+ #
10
+ # NOTE: The block string `'value'` in `hash.fetch(:key) { 'value' }` is detected
11
+ # when frozen string literal magic comment is enabled (i.e. `# frozen_string_literal: true`),
12
+ # but not when disabled.
11
13
  #
12
14
  # @safety
13
15
  # This cop is unsafe because it cannot be guaranteed that the receiver
@@ -0,0 +1,101 @@
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
+ # @example
10
+ # # bad
11
+ # arr.select { |x| x > 1 }.any?
12
+ #
13
+ # # good
14
+ # arr.any? { |x| x > 1 }
15
+ #
16
+ # # bad
17
+ # arr.select { |x| x > 1 }.empty?
18
+ # arr.select { |x| x > 1 }.none?
19
+ #
20
+ # # good
21
+ # arr.none? { |x| x > 1 }
22
+ #
23
+ # # good
24
+ # relation.select(:name).any?
25
+ # arr.select { |x| x > 1 }.any?(&:odd?)
26
+ #
27
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
28
+ # # good
29
+ # arr.select { |x| x > 1 }.many?
30
+ #
31
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
32
+ # # bad
33
+ # arr.select { |x| x > 1 }.many?
34
+ #
35
+ # # good
36
+ # arr.many? { |x| x > 1 }
37
+ #
38
+ class RedundantFilterChain < Base
39
+ extend AutoCorrector
40
+
41
+ MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
42
+
43
+ RAILS_METHODS = %i[many?].freeze
44
+ RESTRICT_ON_SEND = (%i[any? empty? none? one?] + RAILS_METHODS).freeze
45
+
46
+ # @!method select_predicate?(node)
47
+ def_node_matcher :select_predicate?, <<~PATTERN
48
+ (send
49
+ {
50
+ (block $(send _ {:select :filter :find_all}) ...)
51
+ $(send _ {:select :filter :find_all} block_pass_type?)
52
+ }
53
+ ${:#{RESTRICT_ON_SEND.join(' :')}})
54
+ PATTERN
55
+
56
+ REPLACEMENT_METHODS = {
57
+ any?: :any?,
58
+ empty?: :none?,
59
+ none?: :none?,
60
+ one?: :one?,
61
+ many?: :many?
62
+ }.freeze
63
+ private_constant :REPLACEMENT_METHODS
64
+
65
+ def on_send(node)
66
+ return if node.arguments? || node.block_node
67
+
68
+ select_predicate?(node) do |select_node, filter_method|
69
+ return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
70
+
71
+ register_offense(select_node, node)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def register_offense(select_node, predicate_node)
78
+ replacement = REPLACEMENT_METHODS[predicate_node.method_name]
79
+ message = format(MSG, prefer: replacement,
80
+ first_method: select_node.method_name,
81
+ second_method: predicate_node.method_name)
82
+
83
+ offense_range = offense_range(select_node, predicate_node)
84
+
85
+ add_offense(offense_range, message: message) do |corrector|
86
+ corrector.remove(predicate_range(predicate_node))
87
+ corrector.replace(select_node.loc.selector, replacement)
88
+ end
89
+ end
90
+
91
+ def offense_range(select_node, predicate_node)
92
+ select_node.loc.selector.join(predicate_node.loc.selector)
93
+ end
94
+
95
+ def predicate_range(predicate_node)
96
+ predicate_node.receiver.source_range.end.join(predicate_node.loc.selector)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def autocorrect_variable_interpolation(corrector, embedded_node, node)
100
- replacement = "#{embedded_node.loc.expression.source}.to_s"
100
+ replacement = "#{embedded_node.source}.to_s"
101
101
 
102
102
  corrector.replace(node, replacement)
103
103
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
 
108
108
  source = if require_parentheses?(embedded_var)
109
109
  receiver = range_between(
110
- embedded_var.loc.expression.begin_pos, embedded_var.loc.selector.end_pos
110
+ embedded_var.source_range.begin_pos, embedded_var.loc.selector.end_pos
111
111
  )
112
112
  arguments = embedded_var.arguments.map(&:source).join(', ')
113
113
 
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Check for redundant line continuation.
7
+ #
8
+ # This cop marks a line continuation as redundant if removing the backslash
9
+ # does not result in a syntax error.
10
+ # However, a backslash at the end of a comment or
11
+ # for string concatenation is not redundant and is not considered an offense.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # foo. \
16
+ # bar
17
+ # foo \
18
+ # &.bar \
19
+ # .baz
20
+ #
21
+ # # good
22
+ # foo.
23
+ # bar
24
+ # foo
25
+ # &.bar
26
+ # .baz
27
+ #
28
+ # # bad
29
+ # [foo, \
30
+ # bar]
31
+ # {foo: \
32
+ # bar}
33
+ #
34
+ # # good
35
+ # [foo,
36
+ # bar]
37
+ # {foo:
38
+ # bar}
39
+ #
40
+ # # bad
41
+ # foo(bar, \
42
+ # baz)
43
+ #
44
+ # # good
45
+ # foo(bar,
46
+ # baz)
47
+ #
48
+ # # also good - backslash in string concatenation is not redundant
49
+ # foo('bar' \
50
+ # 'baz')
51
+ #
52
+ # # also good - backslash at the end of a comment is not redundant
53
+ # foo(bar, # \
54
+ # baz)
55
+ #
56
+ # # also good - backslash at the line following the newline begins with a + or -,
57
+ # # it is not redundant
58
+ # 1 \
59
+ # + 2 \
60
+ # - 3
61
+ #
62
+ # # also good - backslash with newline between the method name and its arguments,
63
+ # # it is not redundant.
64
+ # some_method \
65
+ # (argument)
66
+ #
67
+ class RedundantLineContinuation < Base
68
+ include MatchRange
69
+ extend AutoCorrector
70
+
71
+ MSG = 'Redundant line continuation.'
72
+ ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
73
+ ARGUMENT_TYPES = %i[
74
+ kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
+ tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
+ ].freeze
77
+
78
+ def on_new_investigation
79
+ return unless processed_source.ast
80
+
81
+ each_match_range(processed_source.ast.source_range, /(\\\n)/) do |range|
82
+ next if require_line_continuation?(range)
83
+ next unless redundant_line_continuation?(range)
84
+
85
+ add_offense(range) do |corrector|
86
+ corrector.remove_leading(range, 1)
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def require_line_continuation?(range)
94
+ !ends_with_backslash_without_comment?(range.source_line) ||
95
+ string_concatenation?(range.source_line) ||
96
+ start_with_arithmetic_operator?(processed_source[range.line]) ||
97
+ inside_string_literal_or_method_with_argument?(range)
98
+ end
99
+
100
+ def ends_with_backslash_without_comment?(source_line)
101
+ source_line.gsub(/#.+/, '').end_with?('\\')
102
+ end
103
+
104
+ def string_concatenation?(source_line)
105
+ /["']\s*\\\z/.match?(source_line)
106
+ end
107
+
108
+ def inside_string_literal_or_method_with_argument?(range)
109
+ processed_source.tokens.each_cons(2).any? do |token, next_token|
110
+ inside_string_literal?(range, token) || method_with_argument?(token, next_token)
111
+ end
112
+ end
113
+
114
+ def redundant_line_continuation?(range)
115
+ return true unless (node = find_node_for_line(range.line))
116
+ return false if argument_newline?(node)
117
+
118
+ source = node.parent ? node.parent.source : node.source
119
+ parse(source.gsub(/\\\n/, "\n")).valid_syntax?
120
+ end
121
+
122
+ def inside_string_literal?(range, token)
123
+ ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
124
+ end
125
+
126
+ # A method call without parentheses such as the following cannot remove `\`:
127
+ #
128
+ # do_something \
129
+ # argument
130
+ def method_with_argument?(current_token, next_token)
131
+ current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
132
+ end
133
+
134
+ def argument_newline?(node)
135
+ node = node.children.first if node.root? && node.begin_type?
136
+
137
+ if argument_is_method?(node)
138
+ argument_newline?(node.first_argument)
139
+ else
140
+ return false unless method_call_with_arguments?(node)
141
+
142
+ node.loc.selector.line != node.first_argument.loc.line
143
+ end
144
+ end
145
+
146
+ def find_node_for_line(line)
147
+ processed_source.ast.each_node do |node|
148
+ return node if same_line?(node, line)
149
+ end
150
+ end
151
+
152
+ def same_line?(node, line)
153
+ return unless (source_range = node.source_range)
154
+
155
+ if node.is_a?(AST::StrNode)
156
+ if node.heredoc?
157
+ (node.loc.heredoc_body.line..node.loc.heredoc_body.last_line).cover?(line)
158
+ else
159
+ (source_range.line..source_range.last_line).cover?(line)
160
+ end
161
+ else
162
+ source_range.line == line
163
+ end
164
+ end
165
+
166
+ def argument_is_method?(node)
167
+ return false unless node.send_type?
168
+ return false unless (first_argument = node.first_argument)
169
+
170
+ method_call_with_arguments?(first_argument)
171
+ end
172
+
173
+ def method_call_with_arguments?(node)
174
+ node.call_type? && !node.arguments.empty?
175
+ end
176
+
177
+ def start_with_arithmetic_operator?(source_line)
178
+ %r{\A\s*[+\-*/%]}.match?(source_line)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -98,7 +98,7 @@ module RuboCop
98
98
  end
99
99
 
100
100
  def like_method_argument_parentheses?(node)
101
- node.send_type? && node.arguments.one? &&
101
+ node.send_type? && node.arguments.one? && !node.parenthesized? &&
102
102
  !node.arithmetic_operation? && node.first_argument.begin_type?
103
103
  end
104
104
 
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  return true if STRING_INTERPOLATION_REGEXP.match?(src)
95
95
 
96
- src.scan(/\\./).any? { |s| ESCAPED_NON_BACKSLASH.match?(s) }
96
+ src.scan(/\\./).any?(ESCAPED_NON_BACKSLASH)
97
97
  end
98
98
 
99
99
  def acceptable_capital_q?(node)
@@ -63,7 +63,7 @@ module RuboCop
63
63
  next if expr.type != :set || expr.expressions.size != 1
64
64
  next if expr.negative?
65
65
  next if %i[set posixclass nonposixclass].include?(expr.expressions.first.type)
66
- next if multiple_codepoins?(expr.expressions.first)
66
+ next if multiple_codepoints?(expr.expressions.first)
67
67
 
68
68
  yield expr
69
69
  end
@@ -80,7 +80,7 @@ module RuboCop
80
80
  !non_redundant
81
81
  end
82
82
 
83
- def multiple_codepoins?(expression)
83
+ def multiple_codepoints?(expression)
84
84
  expression.respond_to?(:codepoints) && expression.codepoints.count >= 2
85
85
  end
86
86
 
@@ -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
@@ -74,11 +74,18 @@ module RuboCop
74
74
 
75
75
  def char_class_begins_or_ends_with_escaped_hyphen?(node, index)
76
76
  # The hyphen character is allowed to be escaped within a character class
77
- # but it's not necessry to escape hyphen if it's the first or last character
77
+ # but it's not necessary to escape hyphen if it's the first or last character
78
78
  # within the character class. This method checks if that's the case.
79
79
  # e.g. "[0-9\\-]" or "[\\-0-9]" would return true
80
- contents_range(node).source[index - 1] == '[' ||
81
- contents_range(node).source[index + 2] == ']'
80
+ content = contents_range(node).source
81
+
82
+ if content[index + 2] == ']'
83
+ true
84
+ elsif content[index - 1] == '['
85
+ index < 2 || content[index - 2] != '\\'
86
+ else
87
+ false
88
+ end
82
89
  end
83
90
 
84
91
  def delimiter?(node, char)
@@ -100,7 +107,7 @@ module RuboCop
100
107
  end
101
108
  end
102
109
  # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
103
- # It's for compatibility with regexp_arser 1.8 and will never be maintained.
110
+ # It's for compatibility with regexp_parser 1.8 and will never be maintained.
104
111
  else
105
112
  def each_escape(node)
106
113
  node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
@@ -129,13 +129,13 @@ module RuboCop
129
129
  end
130
130
 
131
131
  def offense_range(sort_node, node)
132
- range_between(sort_node.loc.selector.begin_pos, node.loc.expression.end_pos)
132
+ range_between(sort_node.loc.selector.begin_pos, node.source_range.end_pos)
133
133
  end
134
134
 
135
135
  def message(node, sorter, accessor)
136
136
  accessor_source = range_between(
137
137
  node.loc.selector.begin_pos,
138
- node.loc.expression.end_pos
138
+ node.source_range.end_pos
139
139
  ).source
140
140
 
141
141
  format(MSG,
@@ -146,7 +146,7 @@ module RuboCop
146
146
 
147
147
  def autocorrect(corrector, node, sort_node, sorter, accessor)
148
148
  # Remove accessor, e.g. `first` or `[-1]`.
149
- corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
149
+ corrector.remove(range_between(accessor_start(node), node.source_range.end_pos))
150
150
  # Replace "sort" or "sort_by" with the appropriate min/max method.
151
151
  corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
152
152
  # Replace to avoid syntax errors when followed by a logical operator.