rubocop 1.78.0 → 1.81.6

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -3
  3. data/config/default.yml +46 -21
  4. data/exe/rubocop +1 -8
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  6. data/lib/rubocop/cli.rb +6 -2
  7. data/lib/rubocop/config_loader.rb +3 -1
  8. data/lib/rubocop/config_store.rb +5 -0
  9. data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
  10. data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
  11. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  12. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  13. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  14. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  15. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  16. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  17. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  18. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  19. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  20. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  21. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  22. data/lib/rubocop/cop/layout/hash_alignment.rb +0 -5
  23. data/lib/rubocop/cop/layout/line_length.rb +9 -1
  24. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
  26. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  27. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  28. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  29. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  30. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
  31. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  32. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  33. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  34. data/lib/rubocop/cop/lint/literal_as_condition.rb +12 -0
  35. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
  36. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  37. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  38. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  39. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  40. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  41. data/lib/rubocop/cop/lint/self_assignment.rb +6 -5
  42. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  43. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  44. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  45. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  46. data/lib/rubocop/cop/lint/void.rb +7 -0
  47. data/lib/rubocop/cop/message_annotator.rb +1 -1
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  49. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  50. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  51. data/lib/rubocop/cop/naming/method_name.rb +40 -1
  52. data/lib/rubocop/cop/naming/predicate_method.rb +19 -3
  53. data/lib/rubocop/cop/security/json_load.rb +33 -11
  54. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  55. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  56. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  57. data/lib/rubocop/cop/style/array_intersect.rb +99 -35
  58. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  59. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  60. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  61. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -4
  62. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  63. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  64. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  65. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  66. data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
  67. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  68. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  69. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  70. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  71. data/lib/rubocop/cop/style/it_block_parameter.rb +2 -0
  72. data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
  73. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  74. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
  75. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  76. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  77. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  78. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  79. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  80. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  81. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  82. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  83. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  84. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  85. data/lib/rubocop/cop/style/redundant_parentheses.rb +29 -11
  86. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  87. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  88. data/lib/rubocop/cop/style/safe_navigation.rb +20 -1
  89. data/lib/rubocop/cop/style/semicolon.rb +20 -5
  90. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  91. data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
  92. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  93. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  94. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  95. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  96. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  97. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  98. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  99. data/lib/rubocop/cop/variable_force.rb +25 -8
  100. data/lib/rubocop/cops_documentation_generator.rb +5 -4
  101. data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
  102. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  103. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  104. data/lib/rubocop/lsp/diagnostic.rb +21 -20
  105. data/lib/rubocop/lsp/routes.rb +65 -9
  106. data/lib/rubocop/lsp/runtime.rb +2 -2
  107. data/lib/rubocop/lsp/server.rb +2 -2
  108. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  109. data/lib/rubocop/result_cache.rb +14 -12
  110. data/lib/rubocop/runner.rb +6 -4
  111. data/lib/rubocop/target_finder.rb +9 -9
  112. data/lib/rubocop/target_ruby.rb +10 -1
  113. data/lib/rubocop/version.rb +1 -1
  114. data/lib/rubocop.rb +3 -0
  115. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  116. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  117. metadata +9 -6
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Layout
6
+ # Checks for an empty line after a module inclusion method (`extend`,
7
+ # `include` and `prepend`), or a group of them.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class Foo
12
+ # include Bar
13
+ # attr_reader :baz
14
+ # end
15
+ #
16
+ # # good
17
+ # class Foo
18
+ # include Bar
19
+ #
20
+ # attr_reader :baz
21
+ # end
22
+ #
23
+ # # also good - multiple module inclusions grouped together
24
+ # class Foo
25
+ # extend Bar
26
+ # include Baz
27
+ # prepend Qux
28
+ # end
29
+ #
30
+ class EmptyLinesAfterModuleInclusion < Base
31
+ include RangeHelp
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Add an empty line after module inclusion.'
35
+
36
+ MODULE_INCLUSION_METHODS = %i[include extend prepend].freeze
37
+
38
+ RESTRICT_ON_SEND = MODULE_INCLUSION_METHODS
39
+
40
+ def on_send(node)
41
+ return if node.receiver || node.arguments.empty?
42
+ return if node.parent&.type?(:send, :any_block)
43
+
44
+ return if next_line_empty_or_enable_directive_comment?(node.last_line)
45
+
46
+ next_line_node = next_line_node(node)
47
+ return unless require_empty_line?(next_line_node)
48
+
49
+ add_offense(node) { |corrector| autocorrect(corrector, node) }
50
+ end
51
+
52
+ private
53
+
54
+ def autocorrect(corrector, node)
55
+ node_range = range_by_whole_lines(node.source_range)
56
+
57
+ next_line = node_range.last_line + 1
58
+ if enable_directive_comment?(next_line)
59
+ node_range = processed_source.comment_at_line(next_line)
60
+ end
61
+
62
+ corrector.insert_after(node_range, "\n")
63
+ end
64
+
65
+ def next_line_empty_or_enable_directive_comment?(line)
66
+ line_empty?(line) || (enable_directive_comment?(line + 1) && line_empty?(line + 1))
67
+ end
68
+
69
+ def enable_directive_comment?(line)
70
+ return false unless (comment = processed_source.comment_at_line(line))
71
+
72
+ DirectiveComment.new(comment).enabled?
73
+ end
74
+
75
+ def line_empty?(line)
76
+ processed_source[line].nil? || processed_source[line].blank?
77
+ end
78
+
79
+ def require_empty_line?(node)
80
+ return false unless node
81
+
82
+ !allowed_method?(node)
83
+ end
84
+
85
+ def allowed_method?(node)
86
+ node = node.body if node.respond_to?(:modifier_form?) && node.modifier_form?
87
+
88
+ return false unless node.send_type?
89
+
90
+ MODULE_INCLUSION_METHODS.include?(node.method_name)
91
+ end
92
+
93
+ def next_line_node(node)
94
+ return if node.parent.if_type?
95
+
96
+ node.right_sibling
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -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
@@ -193,7 +193,6 @@ module RuboCop
193
193
  SEPARATOR_ALIGNMENT_STYLES = %w[EnforcedColonStyle EnforcedHashRocketStyle].freeze
194
194
 
195
195
  def on_send(node)
196
- return if double_splat?(node)
197
196
  return unless node.arguments?
198
197
 
199
198
  last_argument = node.last_argument
@@ -241,10 +240,6 @@ module RuboCop
241
240
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
242
241
  end
243
242
 
244
- def double_splat?(node)
245
- node.children.last.is_a?(Symbol)
246
- end
247
-
248
243
  def check_pairs(node)
249
244
  first_pair = node.pairs.first
250
245
  reset!
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -31,7 +31,7 @@ module RuboCop
31
31
 
32
32
  # @!method overwritten_constant(node)
33
33
  def_node_matcher :overwritten_constant, <<~PATTERN
34
- (resbody nil? (casgn nil? $_) nil?)
34
+ (resbody nil? $(casgn _ _) nil?)
35
35
  PATTERN
36
36
 
37
37
  def self.autocorrect_incompatible_with
@@ -41,7 +41,8 @@ module RuboCop
41
41
  def on_resbody(node)
42
42
  return unless (constant = overwritten_constant(node))
43
43
 
44
- add_offense(node.loc.assoc, message: format(MSG, constant: constant)) do |corrector|
44
+ message = format(MSG, constant: constant.source)
45
+ add_offense(node.loc.assoc, message: message) do |corrector|
45
46
  corrector.remove(range_between(node.loc.keyword.end_pos, node.loc.assoc.end_pos))
46
47
  end
47
48
  end
@@ -13,28 +13,34 @@ module RuboCop
13
13
  # @example
14
14
  # # bad
15
15
  # # rubocop:disable Layout/LineLength Style/Encoding
16
- # # ^ missing comma
16
+ #
17
+ # # good
18
+ # # rubocop:disable Layout/LineLength, Style/Encoding
17
19
  #
18
20
  # # bad
19
21
  # # rubocop:disable
20
22
  #
23
+ # # good
24
+ # # rubocop:disable all
25
+ #
21
26
  # # bad
22
27
  # # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
23
28
  #
29
+ # # good
30
+ # # rubocop:disable Layout/LineLength
31
+ # # rubocop:disable Style/Encoding
32
+ #
24
33
  # # bad
25
34
  # # rubocop:wrongmode Layout/LineLength
26
35
  #
27
36
  # # good
28
37
  # # rubocop:disable Layout/LineLength
29
38
  #
30
- # # good
31
- # # rubocop:disable Layout/LineLength, Style/Encoding
32
- #
33
- # # good
34
- # # rubocop:disable all
39
+ # # bad
40
+ # # rubocop:disable Layout/LineLength comment
35
41
  #
36
42
  # # good
37
- # # rubocop:disable Layout/LineLength -- This is a good comment.
43
+ # # rubocop:disable Layout/LineLength -- comment
38
44
  #
39
45
  class CopDirectiveSyntax < Base
40
46
  COMMON_MSG = 'Malformed directive comment detected.'
@@ -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
@@ -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,12 +19,23 @@ module RuboCop
19
19
  MSG = 'Empty interpolation detected.'
20
20
 
21
21
  def on_interpolation(begin_node)
22
+ return if in_percent_literal_array?(begin_node)
23
+
22
24
  node_children = begin_node.children.dup
23
25
  node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
24
26
  return unless node_children.empty?
25
27
 
26
28
  add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
27
29
  end
30
+
31
+ private
32
+
33
+ def in_percent_literal_array?(begin_node)
34
+ array_node = begin_node.each_ancestor(:array).first
35
+ return false unless array_node
36
+
37
+ array_node.percent_literal?
38
+ end
28
39
  end
29
40
  end
30
41
  end
@@ -54,6 +54,18 @@ module RuboCop
54
54
  end
55
55
  end
56
56
 
57
+ def on_or(node)
58
+ return unless node.lhs.falsey_literal?
59
+
60
+ add_offense(node.lhs) do |corrector|
61
+ # Don't autocorrect `'foo' && return` because having `return` as
62
+ # the leftmost node can lead to a void value expression syntax error.
63
+ next if node.rhs.type?(:return, :break, :next)
64
+
65
+ corrector.replace(node, node.rhs.source)
66
+ end
67
+ end
68
+
57
69
  def on_if(node)
58
70
  cond = condition(node)
59
71
 
@@ -52,10 +52,9 @@ module RuboCop
52
52
  each_missing_enable do |cop, line_range|
53
53
  next if acceptable_range?(cop, line_range)
54
54
 
55
- range = source_range(processed_source.buffer, line_range.min, 0..0)
56
55
  comment = processed_source.comment_at_line(line_range.begin)
57
56
 
58
- add_offense(range, message: message(cop, comment))
57
+ add_offense(comment, message: message(cop, comment))
59
58
  end
60
59
  end
61
60
 
@@ -45,6 +45,7 @@ module RuboCop
45
45
  #
46
46
  class NumericOperationWithConstantResult < Base
47
47
  extend AutoCorrector
48
+
48
49
  MSG = 'Numeric operation with a constant result detected.'
49
50
  RESTRICT_ON_SEND = %i[* / **].freeze
50
51