rubocop 1.75.8 → 1.81.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -16
  3. data/config/default.yml +117 -26
  4. data/config/obsoletion.yml +6 -3
  5. data/exe/rubocop +1 -8
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  7. data/lib/rubocop/cli.rb +18 -3
  8. data/lib/rubocop/config_loader.rb +4 -39
  9. data/lib/rubocop/config_store.rb +5 -0
  10. data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
  11. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
  13. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  14. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  15. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  16. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
  17. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  18. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  19. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  21. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
  22. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  23. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  24. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  25. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  26. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  27. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  28. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  29. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  30. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  32. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  33. data/lib/rubocop/cop/layout/line_length.rb +35 -6
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  35. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
  36. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  37. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  38. data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
  39. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
  40. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  41. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  42. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  43. data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
  44. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  45. data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
  46. data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
  47. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  48. data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
  49. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
  50. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  51. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  52. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  53. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
  54. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  55. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  56. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  57. data/lib/rubocop/cop/lint/self_assignment.rb +30 -4
  58. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  59. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  60. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  61. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  62. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  63. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  64. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  65. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  66. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  67. data/lib/rubocop/cop/lint/void.rb +7 -0
  68. data/lib/rubocop/cop/message_annotator.rb +1 -1
  69. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  70. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  71. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  72. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  73. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  74. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  75. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  76. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  77. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  78. data/lib/rubocop/cop/naming/method_name.rb +127 -13
  79. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  80. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  81. data/lib/rubocop/cop/security/eval.rb +2 -1
  82. data/lib/rubocop/cop/security/open.rb +1 -0
  83. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  84. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  85. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  86. data/lib/rubocop/cop/style/array_intersect.rb +98 -34
  87. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  88. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  89. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  90. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  91. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  92. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
  93. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  94. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  95. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  96. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  97. data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
  98. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  99. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  100. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  101. data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
  102. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  103. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  104. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  105. data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
  106. data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
  107. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  108. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
  109. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
  110. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  111. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  112. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  113. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  114. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  115. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  116. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  117. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  118. data/lib/rubocop/cop/style/redundant_format.rb +18 -3
  119. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  120. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  121. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  122. data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
  123. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  124. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  125. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  126. data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
  127. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  128. data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
  129. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  130. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  131. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  132. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  133. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  134. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  135. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  136. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  137. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  138. data/lib/rubocop/cop/variable_force.rb +25 -8
  139. data/lib/rubocop/cops_documentation_generator.rb +1 -0
  140. data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
  141. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  142. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  143. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  144. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  145. data/lib/rubocop/lsp/diagnostic.rb +25 -24
  146. data/lib/rubocop/lsp/routes.rb +65 -9
  147. data/lib/rubocop/lsp/runtime.rb +2 -2
  148. data/lib/rubocop/lsp/server.rb +2 -2
  149. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  150. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  151. data/lib/rubocop/result_cache.rb +14 -12
  152. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  153. data/lib/rubocop/runner.rb +6 -4
  154. data/lib/rubocop/server/cache.rb +4 -2
  155. data/lib/rubocop/server/client_command/base.rb +10 -0
  156. data/lib/rubocop/server/client_command/exec.rb +2 -1
  157. data/lib/rubocop/server/client_command/start.rb +11 -1
  158. data/lib/rubocop/target_finder.rb +9 -9
  159. data/lib/rubocop/target_ruby.rb +10 -1
  160. data/lib/rubocop/version.rb +1 -1
  161. data/lib/rubocop.rb +12 -1
  162. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  163. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  164. metadata +22 -8
@@ -138,7 +138,7 @@ module RuboCop
138
138
  end
139
139
 
140
140
  def previous_line_ignoring_comments(processed_source, send_line)
141
- processed_source[0..send_line - 2].reverse.find { |line| !comment_line?(line) }
141
+ processed_source[0..(send_line - 2)].reverse.find { |line| !comment_line?(line) }
142
142
  end
143
143
 
144
144
  def previous_line_empty?(send_line)
@@ -62,40 +62,19 @@ module RuboCop
62
62
  node.receiver && node.receiver.loc.last_line != node.loc.selector&.line
63
63
  end
64
64
 
65
- def empty_lines(node)
66
- lines = processed_lines(node)
67
- lines.select! { |code, _| code.empty? }
68
- lines.map { |_, line| line }
69
- end
70
-
71
- def extra_lines(node)
72
- empty_lines(node).each do |line|
73
- range = source_range(processed_source.buffer, line, 0)
74
- yield(range)
75
- end
76
- end
77
-
78
- def processed_lines(node)
79
- line_numbers(node).each_with_object([]) do |num, array|
80
- array << [processed_source.lines[num - 1], num]
65
+ def extra_lines(node, &block)
66
+ node.arguments.each do |arg|
67
+ empty_range_for_starting_point(arg.source_range.begin, &block)
81
68
  end
82
- end
83
69
 
84
- def line_numbers(node)
85
- inner_lines = []
86
- line_nums = node.arguments.each_with_object([]) do |arg_node, lines|
87
- lines << outer_lines(arg_node)
88
- inner_lines << inner_lines(arg_node) if arg_node.multiline?
89
- end
90
- line_nums.flatten.uniq - inner_lines.flatten - outer_lines(node)
70
+ empty_range_for_starting_point(node.loc.end.begin, &block) if node.loc.end
91
71
  end
92
72
 
93
- def inner_lines(node)
94
- [node.first_line + 1, node.last_line - 1]
95
- end
73
+ def empty_range_for_starting_point(start)
74
+ range = range_with_surrounding_space(start, whitespace: true, side: :left)
75
+ return unless range.last_line - range.first_line > 1
96
76
 
97
- def outer_lines(node)
98
- [node.first_line - 1, node.last_line + 1]
77
+ yield range.source_buffer.line_range(range.last_line - 1).adjust(end_pos: 1)
99
78
  end
100
79
  end
101
80
  end
@@ -71,7 +71,7 @@ module RuboCop
71
71
  KIND = 'class'
72
72
 
73
73
  def on_class(node)
74
- first_line = node.parent_class.first_line if node.parent_class
74
+ first_line = node.parent_class.last_line if node.parent_class
75
75
 
76
76
  check(node, node.body, adjusted_first_line: first_line)
77
77
  end
@@ -134,6 +134,7 @@ module RuboCop
134
134
 
135
135
  def check_for_breakable_block(block_node)
136
136
  return unless block_node.single_line?
137
+ return if receiver_contains_heredoc?(block_node)
137
138
 
138
139
  line_index = block_node.loc.line - 1
139
140
  range = breakable_block_range(block_node)
@@ -258,7 +259,7 @@ module RuboCop
258
259
  if ignore_cop_directives? && directive_on_source_line?(line_index)
259
260
  return check_directive_line(line, line_index)
260
261
  end
261
- return check_uri_line(line, line_index) if allow_uri?
262
+ return check_line_for_exemptions(line, line_index) if allow_uri? || allow_qualified_name?
262
263
 
263
264
  register_offense(excess_range(nil, line, line_index), line, line_index)
264
265
  end
@@ -321,7 +322,7 @@ module RuboCop
321
322
  def extract_heredocs(ast)
322
323
  return [] unless ast
323
324
 
324
- ast.each_node(:str, :dstr, :xstr).select(&:heredoc?).map do |node|
325
+ ast.each_node(:any_str).select(&:heredoc?).map do |node|
325
326
  body = node.location.heredoc_body
326
327
  delimiter = node.location.heredoc_end.source.strip
327
328
  [body.first_line...body.last_line, delimiter]
@@ -341,6 +342,13 @@ module RuboCop
341
342
  heredocs.any? { |range, _delimiter| range.cover?(line_number) }
342
343
  end
343
344
 
345
+ def receiver_contains_heredoc?(node)
346
+ return false unless (receiver = node.receiver)
347
+ return true if receiver.any_str_type? && receiver.heredoc?
348
+
349
+ receiver.each_descendant(:any_str).any?(&:heredoc?)
350
+ end
351
+
344
352
  def check_directive_line(line, line_index)
345
353
  length_without_directive = line_length_without_directive(line)
346
354
  return if length_without_directive <= max
@@ -358,11 +366,32 @@ module RuboCop
358
366
  )
359
367
  end
360
368
 
361
- def check_uri_line(line, line_index)
362
- uri_range = find_excessive_uri_range(line)
363
- return if uri_range && allowed_uri_position?(line, uri_range)
369
+ def check_line_for_exemptions(line, line_index)
370
+ uri_range = range_if_applicable(line, :uri)
371
+ qualified_name_range = range_if_applicable(line, :qualified_name)
372
+
373
+ return if allowed_combination?(line, uri_range, qualified_name_range)
374
+
375
+ range = uri_range || qualified_name_range
376
+ register_offense(excess_range(range, line, line_index), line, line_index)
377
+ end
364
378
 
365
- register_offense(excess_range(uri_range, line, line_index), line, line_index)
379
+ def range_if_applicable(line, type)
380
+ return unless type == :uri ? allow_uri? : allow_qualified_name?
381
+
382
+ find_excessive_range(line, type)
383
+ end
384
+
385
+ def allowed_combination?(line, uri_range, qualified_name_range)
386
+ if uri_range && qualified_name_range
387
+ allowed_position?(line, uri_range) && allowed_position?(line, qualified_name_range)
388
+ elsif uri_range
389
+ allowed_position?(line, uri_range)
390
+ elsif qualified_name_range
391
+ allowed_position?(line, qualified_name_range)
392
+ else
393
+ false
394
+ end
366
395
  end
367
396
 
368
397
  def breakable_dstr?(node)
@@ -10,6 +10,8 @@ module RuboCop
10
10
  # condition, an explicit `return` statement, etc. In other contexts, the second operand should
11
11
  # be indented regardless of enforced style.
12
12
  #
13
+ # In both styles, operators should be aligned when an assignment begins on the next line.
14
+ #
13
15
  # @example EnforcedStyle: aligned (default)
14
16
  # # bad
15
17
  # if a +
@@ -100,10 +102,12 @@ module RuboCop
100
102
  return true if begins_its_line?(assignment_rhs.source_range)
101
103
  end
102
104
 
103
- given_style == :aligned &&
104
- (kw_node_with_special_indentation(node) ||
105
- assignment_node ||
106
- argument_in_method_call(node, :with_or_without_parentheses))
105
+ return false unless given_style == :aligned
106
+ return true if kw_node_with_special_indentation(node) || assignment_node
107
+
108
+ node = argument_in_method_call(node, :with_or_without_parentheses)
109
+
110
+ node.respond_to?(:def_modifier?) && !node.def_modifier?
107
111
  end
108
112
 
109
113
  def message(node, lhs, rhs)
@@ -194,6 +194,14 @@ module RuboCop
194
194
  def alignment_location(alignment_node)
195
195
  if begin_end_alignment_style == 'start_of_line'
196
196
  start_line_range(alignment_node)
197
+ elsif alignment_node.any_block_type?
198
+ # If the alignment node is a block, the `rescue`/`ensure` keyword should
199
+ # be aligned to the start of the block. It is possible that the block's
200
+ # `send_node` spans multiple lines, in which case it should align to the
201
+ # start of the last line.
202
+ send_node = alignment_node.send_node
203
+ range = processed_source.buffer.line_range(send_node.last_line)
204
+ range.adjust(begin_pos: range.source =~ /\S/)
197
205
  else
198
206
  alignment_node.source_range
199
207
  end
@@ -16,6 +16,8 @@ module RuboCop
16
16
  #
17
17
  # something = 123if test
18
18
  #
19
+ # return(foo + bar)
20
+ #
19
21
  # # good
20
22
  # something 'test' do |x|
21
23
  # end
@@ -24,6 +26,9 @@ module RuboCop
24
26
  # end
25
27
  #
26
28
  # something = 123 if test
29
+ #
30
+ # return (foo + bar)
31
+ #
27
32
  class SpaceAroundKeyword < Base
28
33
  extend AutoCorrector
29
34
 
@@ -33,7 +38,7 @@ module RuboCop
33
38
  DO = 'do'
34
39
  SAFE_NAVIGATION = '&.'
35
40
  NAMESPACE_OPERATOR = '::'
36
- ACCEPT_LEFT_PAREN = %w[break defined? next not rescue return super yield].freeze
41
+ ACCEPT_LEFT_PAREN = %w[break defined? next not rescue super yield].freeze
37
42
  ACCEPT_LEFT_SQUARE_BRACKET = %w[super yield].freeze
38
43
  ACCEPT_NAMESPACE_OPERATOR = 'super'
39
44
  RESTRICT_ON_SEND = %i[!].freeze
@@ -151,6 +151,14 @@ module RuboCop
151
151
  check_operator(:match_pattern, node.loc.operator, node)
152
152
  end
153
153
 
154
+ def on_match_alt(node)
155
+ check_operator(:match_alt, node.loc.operator, node)
156
+ end
157
+
158
+ def on_match_as(node)
159
+ check_operator(:match_as, node.loc.operator, node)
160
+ end
161
+
154
162
  alias on_or on_binary
155
163
  alias on_and on_binary
156
164
  alias on_lvasgn on_assignment
@@ -22,10 +22,11 @@ module RuboCop
22
22
  RESTRICT_ON_SEND = %i[[] []=].freeze
23
23
 
24
24
  def on_send(node)
25
+ return if node.loc.dot
26
+
25
27
  receiver_end_pos = node.receiver.source_range.end_pos
26
28
  selector_begin_pos = node.loc.selector.begin_pos
27
29
  return if receiver_end_pos >= selector_begin_pos
28
- return if dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
29
30
 
30
31
  range = range_between(receiver_end_pos, selector_begin_pos)
31
32
 
@@ -33,14 +34,6 @@ module RuboCop
33
34
  corrector.remove(range)
34
35
  end
35
36
  end
36
-
37
- private
38
-
39
- def dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
40
- return false unless node.loc.respond_to?(:dot) && (dot = node.loc.dot)
41
-
42
- dot.begin_pos == receiver_end_pos && dot.end_pos == selector_begin_pos
43
- end
44
37
  end
45
38
  end
46
39
  end
@@ -86,6 +86,7 @@ module RuboCop
86
86
  def on_array(node)
87
87
  return if node.array_type? && !node.square_brackets?
88
88
 
89
+ node = find_node_with_brackets(node)
89
90
  tokens, left, right = array_brackets(node)
90
91
  return unless left && right
91
92
 
@@ -102,6 +103,10 @@ module RuboCop
102
103
 
103
104
  private
104
105
 
106
+ def find_node_with_brackets(node)
107
+ node.ancestors.find(&:const_pattern_type?) || node
108
+ end
109
+
105
110
  def autocorrect(corrector, node)
106
111
  tokens, left, right = array_brackets(node)
107
112
 
@@ -119,7 +124,7 @@ module RuboCop
119
124
  def array_brackets(node)
120
125
  tokens = processed_source.tokens_within(node)
121
126
 
122
- left = tokens.find(&:left_array_bracket?)
127
+ left = tokens.find(&:left_bracket?)
123
128
  right = tokens.reverse_each.find(&:right_bracket?)
124
129
 
125
130
  [tokens, left, right]
@@ -192,7 +197,7 @@ module RuboCop
192
197
  if side == :right
193
198
  processed_source.tokens_within(node)[i].right_bracket?
194
199
  else
195
- processed_source.tokens_within(node)[i].left_array_bracket?
200
+ processed_source.tokens_within(node)[i].left_bracket?
196
201
  end
197
202
  end
198
203
 
@@ -113,7 +113,7 @@ module RuboCop
113
113
  return [] unless ast
114
114
 
115
115
  heredocs = []
116
- ast.each_node(:str, :dstr, :xstr) do |node|
116
+ ast.each_node(:any_str) do |node|
117
117
  next unless node.heredoc?
118
118
 
119
119
  body = node.location.heredoc_body
@@ -27,7 +27,9 @@ module RuboCop
27
27
  # @example
28
28
  # # bad
29
29
  # x || 1..2
30
+ # x - 1..2
30
31
  # (x || 1..2)
32
+ # x || 1..y || 2
31
33
  # 1..2.to_a
32
34
  #
33
35
  # # good, unambiguous
@@ -41,6 +43,7 @@ module RuboCop
41
43
  #
42
44
  # # good, ambiguity removed
43
45
  # x || (1..2)
46
+ # (x - 1)..2
44
47
  # (x || 1)..2
45
48
  # (x || 1)..(y || 2)
46
49
  # (1..2).to_a
@@ -96,6 +99,8 @@ module RuboCop
96
99
  # to avoid the ambiguity of `1..2.to_a`.
97
100
  return false if node.receiver&.basic_literal?
98
101
 
102
+ return false if node.operator_method? && !node.method?(:[])
103
+
99
104
  require_parentheses_for_method_chain? || node.receiver.nil?
100
105
  end
101
106
 
@@ -118,8 +118,11 @@ module RuboCop
118
118
 
119
119
  def replacement_args(node)
120
120
  algorithm_constant, = algorithm_const(node)
121
- algorithm_name = algorithm_name(algorithm_constant)
121
+ if algorithm_constant.source == 'OpenSSL::Cipher::Cipher'
122
+ return node.first_argument.source
123
+ end
122
124
 
125
+ algorithm_name = algorithm_name(algorithm_constant)
123
126
  if openssl_class(algorithm_constant) == 'OpenSSL::Cipher'
124
127
  build_cipher_arguments(node, algorithm_name, node.arguments.empty?)
125
128
  else
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # Checks for duplicated instance (or singleton) method
7
7
  # definitions.
8
8
  #
9
+ # NOTE: Aliasing a method to itself is allowed, as it indicates that
10
+ # the developer intends to suppress Ruby's method redefinition warnings.
11
+ # See https://bugs.ruby-lang.org/issues/13574.
12
+ #
9
13
  # @example
10
14
  #
11
15
  # # bad
@@ -40,6 +44,18 @@ module RuboCop
40
44
  #
41
45
  # alias bar foo
42
46
  #
47
+ # # good
48
+ # alias foo foo
49
+ # def foo
50
+ # 1
51
+ # end
52
+ #
53
+ # # good
54
+ # alias_method :foo, :foo
55
+ # def foo
56
+ # 1
57
+ # end
58
+ #
43
59
  # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
44
60
  #
45
61
  # # good
@@ -113,11 +129,13 @@ module RuboCop
113
129
 
114
130
  # @!method method_alias?(node)
115
131
  def_node_matcher :method_alias?, <<~PATTERN
116
- (alias (sym $_name) sym)
132
+ (alias (sym $_name) (sym $_original_name))
117
133
  PATTERN
118
134
 
119
135
  def on_alias(node)
120
- return unless (name = method_alias?(node))
136
+ name, original_name = method_alias?(node)
137
+ return unless name && original_name
138
+ return if name == original_name
121
139
  return if node.ancestors.any?(&:if_type?)
122
140
 
123
141
  found_instance_method(node, name)
@@ -125,7 +143,7 @@ module RuboCop
125
143
 
126
144
  # @!method alias_method?(node)
127
145
  def_node_matcher :alias_method?, <<~PATTERN
128
- (send nil? :alias_method (sym $_name) _)
146
+ (send nil? :alias_method (sym $_name) (sym $_original_name))
129
147
  PATTERN
130
148
 
131
149
  # @!method delegate_method?(node)
@@ -140,7 +158,10 @@ module RuboCop
140
158
  def_node_matcher :sym_name, '(sym $_name)'
141
159
 
142
160
  def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
143
- if (name = alias_method?(node))
161
+ name, original_name = alias_method?(node)
162
+
163
+ if name && original_name
164
+ return if name == original_name
144
165
  return if node.ancestors.any?(&:if_type?)
145
166
 
146
167
  found_instance_method(node, name)
@@ -24,8 +24,6 @@ module RuboCop
24
24
 
25
25
  MSG_REPEATED_ELEMENT = 'Duplicate element inside regexp character class'
26
26
 
27
- OCTAL_DIGITS_AFTER_ESCAPE = 2
28
-
29
27
  def on_regexp(node)
30
28
  each_repeated_character_class_element_loc(node) do |loc|
31
29
  add_offense(loc, message: MSG_REPEATED_ELEMENT) do |corrector|
@@ -40,9 +38,9 @@ module RuboCop
40
38
 
41
39
  seen = Set.new
42
40
  group_expressions(node, expr.expressions) do |group|
43
- group_source = group.map(&:to_s).join
41
+ group_source = group.to_s
44
42
 
45
- yield source_range(group) if seen.include?(group_source)
43
+ yield group.expression if seen.include?(group_source)
46
44
 
47
45
  seen << group_source
48
46
  end
@@ -52,40 +50,13 @@ module RuboCop
52
50
  private
53
51
 
54
52
  def group_expressions(node, expressions)
55
- # Create a mutable list to simplify state tracking while we iterate.
56
- expressions = expressions.to_a
57
-
58
- until expressions.empty?
59
- # With we may need to compose a group of multiple expressions.
60
- group = [expressions.shift]
61
- next if within_interpolation?(node, group.first)
62
-
63
- # With regexp_parser < 2.7 escaped octal sequences may be up to 3
64
- # separate expressions ("\\0", "0", "1").
65
- pop_octal_digits(group, expressions) if escaped_octal?(group.first.to_s)
66
-
67
- yield(group)
68
- end
69
- end
70
-
71
- def pop_octal_digits(current_child, expressions)
72
- OCTAL_DIGITS_AFTER_ESCAPE.times do
73
- next_child = expressions.first
74
- break unless octal?(next_child.to_s)
53
+ expressions.each do |expression|
54
+ next if within_interpolation?(node, expression)
75
55
 
76
- current_child << expressions.shift
56
+ yield(expression)
77
57
  end
78
58
  end
79
59
 
80
- def source_range(children)
81
- return children.first.expression if children.size == 1
82
-
83
- range_between(
84
- children.first.expression.begin_pos,
85
- children.last.expression.begin_pos + children.last.to_s.length
86
- )
87
- end
88
-
89
60
  def skip_expression?(expr)
90
61
  expr.type != :set || expr.token == :intersection
91
62
  end
@@ -99,14 +70,6 @@ module RuboCop
99
70
  interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
100
71
  end
101
72
 
102
- def escaped_octal?(string)
103
- string.length == 2 && string[0] == '\\' && octal?(string[1])
104
- end
105
-
106
- def octal?(char)
107
- ('0'..'7').cover?(char)
108
- end
109
-
110
73
  def interpolation_locs(node)
111
74
  @interpolation_locs ||= {}
112
75
 
@@ -19,7 +19,9 @@ module RuboCop
19
19
  MSG = 'Empty interpolation detected.'
20
20
 
21
21
  def on_interpolation(begin_node)
22
- return unless begin_node.children.empty?
22
+ node_children = begin_node.children.dup
23
+ node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
24
+ return unless node_children.empty?
23
25
 
24
26
  add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
25
27
  end
@@ -94,7 +94,7 @@ module RuboCop
94
94
  when :float
95
95
  true
96
96
  when :send
97
- check_send(node)
97
+ float_send?(node)
98
98
  when :begin
99
99
  float?(node.children.first)
100
100
  else
@@ -108,18 +108,18 @@ module RuboCop
108
108
  (node.numeric_type? && node.value.zero?) || node.nil_type?
109
109
  end
110
110
 
111
- def check_send(node)
111
+ def float_send?(node)
112
112
  if node.arithmetic_operation?
113
113
  float?(node.receiver) || float?(node.first_argument)
114
114
  elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
115
115
  true
116
116
  elsif node.receiver&.float_type?
117
117
  FLOAT_INSTANCE_METHODS.include?(node.method_name) ||
118
- check_numeric_returning_method(node)
118
+ numeric_returning_method?(node)
119
119
  end
120
120
  end
121
121
 
122
- def check_numeric_returning_method(node)
122
+ def numeric_returning_method?(node)
123
123
  return false unless node.receiver
124
124
 
125
125
  case node.method_name
@@ -11,39 +11,43 @@ module RuboCop
11
11
  # @example
12
12
  # # bad
13
13
  # foo.object_id == bar.object_id
14
+ # foo.object_id != baz.object_id
14
15
  #
15
16
  # # good
16
17
  # foo.equal?(bar)
18
+ # !foo.equal?(baz)
17
19
  #
18
20
  class IdentityComparison < Base
19
21
  extend AutoCorrector
20
22
 
21
- MSG = 'Use `equal?` instead `==` when comparing `object_id`.'
22
- RESTRICT_ON_SEND = %i[==].freeze
23
+ MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
24
+ RESTRICT_ON_SEND = %i[== !=].freeze
25
+
26
+ # @!method object_id_comparison(node)
27
+ def_node_matcher :object_id_comparison, <<~PATTERN
28
+ (send
29
+ (send
30
+ _lhs_receiver :object_id) ${:== :!=}
31
+ (send
32
+ _rhs_receiver :object_id))
33
+ PATTERN
23
34
 
24
35
  def on_send(node)
25
- return unless compare_between_object_id_by_double_equal?(node)
36
+ return unless (comparison_method = object_id_comparison(node))
26
37
 
27
- add_offense(node) do |corrector|
38
+ bang = comparison_method == :== ? '' : '!'
39
+ add_offense(node,
40
+ message: format(MSG, comparison_method: comparison_method,
41
+ bang: bang)) do |corrector|
28
42
  receiver = node.receiver.receiver
29
43
  argument = node.first_argument.receiver
30
44
  return unless receiver && argument
31
45
 
32
- replacement = "#{receiver.source}.equal?(#{argument.source})"
46
+ replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
33
47
 
34
48
  corrector.replace(node, replacement)
35
49
  end
36
50
  end
37
-
38
- private
39
-
40
- def compare_between_object_id_by_double_equal?(node)
41
- object_id_method?(node.receiver) && object_id_method?(node.first_argument)
42
- end
43
-
44
- def object_id_method?(node)
45
- node.send_type? && node.method?(:object_id)
46
- end
47
51
  end
48
52
  end
49
53
  end