rubocop 1.50.1 → 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +20 -3
  4. data/lib/rubocop/config.rb +4 -0
  5. data/lib/rubocop/config_obsoletion.rb +2 -2
  6. data/lib/rubocop/cop/base.rb +4 -0
  7. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  8. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -1
  9. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  10. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  11. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +25 -34
  12. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +7 -19
  13. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +42 -52
  14. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +38 -55
  15. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  16. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +8 -27
  17. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +7 -26
  18. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -21
  19. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +6 -30
  20. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  21. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +12 -1
  22. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  23. data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -2
  24. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -2
  25. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  26. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  27. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  28. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  29. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  30. data/lib/rubocop/cop/lint/useless_assignment.rb +56 -1
  31. data/lib/rubocop/cop/lint/void.rb +62 -6
  32. data/lib/rubocop/cop/mixin/comments_help.rb +6 -2
  33. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  34. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  35. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
  36. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  37. data/lib/rubocop/cop/style/attr.rb +11 -1
  38. data/lib/rubocop/cop/style/collection_compact.rb +13 -6
  39. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  40. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  41. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  42. data/lib/rubocop/cop/style/copyright.rb +5 -2
  43. data/lib/rubocop/cop/style/documentation.rb +1 -1
  44. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  45. data/lib/rubocop/cop/style/exact_regexp_match.rb +62 -0
  46. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  47. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  48. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  49. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  50. data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
  51. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  52. data/lib/rubocop/cop/style/redundant_fetch_block.rb +6 -4
  53. data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -1
  54. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  55. data/lib/rubocop/cop/style/require_order.rb +9 -4
  56. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  57. data/lib/rubocop/cop/style/special_global_vars.rb +2 -2
  58. data/lib/rubocop/cop/team.rb +1 -1
  59. data/lib/rubocop/cop/variable_force/assignment.rb +4 -0
  60. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  61. data/lib/rubocop/result_cache.rb +1 -1
  62. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  63. data/lib/rubocop/target_ruby.rb +3 -2
  64. data/lib/rubocop/version.rb +3 -3
  65. data/lib/rubocop.rb +1 -0
  66. metadata +5 -4
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Ensures that each key in a multi-line hash
7
7
  # starts on a separate line.
8
8
  #
9
- # @example AllowMultilineFinalElement: false (default)
9
+ # @example
10
10
  #
11
11
  # # bad
12
12
  # {
@@ -14,11 +14,6 @@ module RuboCop
14
14
  # c: 3
15
15
  # }
16
16
  #
17
- # # bad
18
- # { a: 1, b: {
19
- # c: 3,
20
- # }}
21
- #
22
17
  # # good
23
18
  # {
24
19
  # a: 1,
@@ -34,34 +29,20 @@ module RuboCop
34
29
  # }
35
30
  # }
36
31
  #
37
- # @example AllowMultilineFinalElement: true
32
+ # @example AllowMultilineFinalElement: false (default)
38
33
  #
39
34
  # # bad
40
- # {
41
- # a: 1, b: 2,
42
- # c: 3
43
- # }
44
- #
45
- # # good
46
35
  # { a: 1, b: {
47
36
  # c: 3,
48
37
  # }}
49
38
  #
50
- # # good
51
- # {
52
- # a: 1,
53
- # b: 2,
54
- # c: 3
55
- # }
56
- #
39
+ # @example AllowMultilineFinalElement: true
57
40
  #
58
41
  # # good
59
- # {
60
- # a: 1,
61
- # b: {
62
- # c: 3,
63
- # }
64
- # }
42
+ # { a: 1, b: {
43
+ # c: 3,
44
+ # }}
45
+ #
65
46
  class MultilineHashKeyLineBreaks < Base
66
47
  include MultilineElementLineBreaks
67
48
  extend AutoCorrector
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodArgumentLineBreak`.
11
11
  #
12
- # @example AllowMultilineFinalElement: false (default)
12
+ # @example
13
13
  #
14
14
  # # bad
15
15
  # foo(a, b,
@@ -31,6 +31,8 @@ module RuboCop
31
31
  # # good
32
32
  # foo(a, b, c)
33
33
  #
34
+ # @example AllowMultilineFinalElement: false (default)
35
+ #
34
36
  # # good
35
37
  # foo(
36
38
  # a,
@@ -42,26 +44,6 @@ module RuboCop
42
44
  #
43
45
  # @example AllowMultilineFinalElement: true
44
46
  #
45
- # # bad
46
- # foo(a, b,
47
- # c
48
- # )
49
- #
50
- # # good
51
- # foo(a, b, {
52
- # foo: "bar",
53
- # })
54
- #
55
- # # good
56
- # foo(
57
- # a,
58
- # b,
59
- # c
60
- # )
61
- #
62
- # # good
63
- # foo(a, b, c)
64
- #
65
47
  # # good
66
48
  # foo(
67
49
  # a,
@@ -70,6 +52,7 @@ module RuboCop
70
52
  # foo: "bar",
71
53
  # }
72
54
  # )
55
+ #
73
56
  class MultilineMethodArgumentLineBreaks < Base
74
57
  include MultilineElementLineBreaks
75
58
  extend AutoCorrector
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodParameterLineBreak`.
11
11
  #
12
- # @example AllowMultilineFinalElement: false (default)
12
+ # @example
13
13
  #
14
14
  # # bad
15
15
  # def foo(a, b,
@@ -17,12 +17,6 @@ module RuboCop
17
17
  # )
18
18
  # end
19
19
  #
20
- # # bad
21
- # def foo(a, b = {
22
- # foo: "bar",
23
- # })
24
- # end
25
- #
26
20
  # # good
27
21
  # def foo(
28
22
  # a,
@@ -44,40 +38,22 @@ module RuboCop
44
38
  # def foo(a, b, c)
45
39
  # end
46
40
  #
47
- # @example AllowMultilineFinalElement: true
41
+ # @example AllowMultilineFinalElement: false (default)
48
42
  #
49
43
  # # bad
50
- # def foo(a, b,
51
- # c
52
- # )
53
- # end
54
- #
55
- # # good
56
44
  # def foo(a, b = {
57
45
  # foo: "bar",
58
46
  # })
59
47
  # end
60
48
  #
61
- # # good
62
- # def foo(
63
- # a,
64
- # b,
65
- # c
66
- # )
67
- # end
49
+ # @example AllowMultilineFinalElement: true
68
50
  #
69
51
  # # good
70
- # def foo(
71
- # a,
72
- # b = {
73
- # foo: "bar",
74
- # }
75
- # )
52
+ # def foo(a, b = {
53
+ # foo: "bar",
54
+ # })
76
55
  # end
77
56
  #
78
- # # good
79
- # def foo(a, b, c)
80
- # end
81
57
  class MultilineMethodParameterLineBreaks < Base
82
58
  include MultilineElementLineBreaks
83
59
  extend AutoCorrector
@@ -236,6 +236,8 @@ module RuboCop
236
236
  end
237
237
 
238
238
  def offense(begin_pos, end_pos, msg, style_param = 'EnforcedStyle')
239
+ return if begin_pos > end_pos
240
+
239
241
  range = range_between(begin_pos, end_pos)
240
242
  add_offense(range, message: msg) do |corrector|
241
243
  case range.source
@@ -52,6 +52,8 @@ module RuboCop
52
52
  # expect { do_something }.to not_change { object.attribute }
53
53
  #
54
54
  class AmbiguousBlockAssociation < Base
55
+ extend AutoCorrector
56
+
55
57
  include AllowedMethods
56
58
  include AllowedPattern
57
59
 
@@ -68,7 +70,9 @@ module RuboCop
68
70
 
69
71
  message = message(node)
70
72
 
71
- add_offense(node, message: message)
73
+ add_offense(node, message: message) do |corrector|
74
+ wrap_in_parentheses(corrector, node)
75
+ end
72
76
  end
73
77
  alias on_csend on_send
74
78
 
@@ -89,6 +93,13 @@ module RuboCop
89
93
 
90
94
  format(MSG, param: block_param.source, method: block_param.send_node.source)
91
95
  end
96
+
97
+ def wrap_in_parentheses(corrector, node)
98
+ range = node.loc.selector.end.join(node.first_argument.source_range.begin)
99
+
100
+ corrector.replace(range, '(')
101
+ corrector.insert_after(node.last_argument, ')')
102
+ end
92
103
  end
93
104
  end
94
105
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
 
108
108
  def pattern_identity(pattern)
109
109
  pattern_source = if pattern.hash_pattern_type? || pattern.match_alt_type?
110
- pattern.children.map(&:source).sort
110
+ pattern.children.map(&:source).sort.to_s
111
111
  else
112
112
  pattern.source
113
113
  end
@@ -8,9 +8,9 @@ module RuboCop
8
8
  #
9
9
  # [source,console]
10
10
  # ----
11
- # % cat example.rb
11
+ # $ cat example.rb
12
12
  # ERB.new('hi', nil, '-', '@output_buffer')
13
- # % ruby -rerb example.rb
13
+ # $ ruby -rerb example.rb
14
14
  # example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is
15
15
  # deprecated. Do not use it, and specify other arguments as keyword arguments.
16
16
  # example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is
@@ -6,6 +6,9 @@ module RuboCop
6
6
  #
7
7
  # This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
8
8
  #
9
+ # When an array of IO objects waiting for an exception (the third argument of `IO.select`)
10
+ # is used as an argument, there is no alternative API, so offenses are not registered.
11
+ #
9
12
  # NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`,
10
13
  # and the return value of `io.wait_readable` and `io.wait_writable` are `self`.
11
14
  # They are not autocorrected when assigning a return value because these types are different.
@@ -42,8 +45,8 @@ module RuboCop
42
45
  PATTERN
43
46
 
44
47
  def on_send(node)
45
- read, write, _excepts, timeout = *io_select(node)
46
- return unless read
48
+ read, write, excepts, timeout = *io_select(node)
49
+ return if excepts && !excepts.children.empty?
47
50
  return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
48
51
 
49
52
  preferred = preferred_method(read, write, timeout)
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks uses of lambda without a literal block.
7
7
  # It emulates the following warning in Ruby 3.0:
8
8
  #
9
- # % ruby -vwe 'lambda(&proc {})'
9
+ # $ ruby -vwe 'lambda(&proc {})'
10
10
  # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
11
11
  # -e:1: warning: lambda without a literal block is deprecated; use the proc without
12
12
  # lambda instead
@@ -6,13 +6,13 @@ module RuboCop
6
6
  # Checks for uses of numbered parameter assignment.
7
7
  # It emulates the following warning in Ruby 2.7:
8
8
  #
9
- # % ruby -ve '_1 = :value'
9
+ # $ ruby -ve '_1 = :value'
10
10
  # ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
11
11
  # -e:1: warning: `_1' is reserved for numbered parameter; consider another name
12
12
  #
13
13
  # Assigning to a numbered parameter (from `_1` to `_9`) causes an error in Ruby 3.0.
14
14
  #
15
- # % ruby -ve '_1 = :value'
15
+ # $ ruby -ve '_1 = :value'
16
16
  # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
17
17
  # -e:1: _1 is reserved for numbered parameter
18
18
  #
@@ -65,13 +65,13 @@ module RuboCop
65
65
  def on_when(node)
66
66
  regexp_conditions = node.conditions.select(&:regexp_type?)
67
67
 
68
- @valid_ref = regexp_conditions.map { |condition| check_regexp(condition) }.compact.max
68
+ @valid_ref = regexp_conditions.filter_map { |condition| check_regexp(condition) }.max
69
69
  end
70
70
 
71
71
  def on_in_pattern(node)
72
72
  regexp_patterns = regexp_patterns(node)
73
73
 
74
- @valid_ref = regexp_patterns.map { |pattern| check_regexp(pattern) }.compact.max
74
+ @valid_ref = regexp_patterns.filter_map { |pattern| check_regexp(pattern) }.max
75
75
  end
76
76
 
77
77
  def on_nth_ref(node)
@@ -47,7 +47,7 @@ module RuboCop
47
47
  return if node.receiver
48
48
 
49
49
  node.each_child_node(:send) do |child|
50
- next unless child.method?(:to_s)
50
+ next if !child.method?(:to_s) || child.arguments.any?
51
51
 
52
52
  register_offense(child, "`#{node.method_name}`")
53
53
  end
@@ -8,25 +8,39 @@ module RuboCop
8
8
  # always ignored. This is detected automatically since Ruby 2.7.
9
9
  #
10
10
  # @example
11
+ # # bad
12
+ # return 1
11
13
  #
12
- # # Detected since Ruby 2.7
13
- # return 1 # 1 is always ignored.
14
+ # # good
15
+ # return
14
16
  class TopLevelReturnWithArgument < Base
15
- # This cop works by validating the ancestors of the return node. A
16
- # top-level return node's ancestors should not be of block, def, or
17
- # defs type.
17
+ extend AutoCorrector
18
18
 
19
19
  MSG = 'Top level return with argument detected.'
20
20
 
21
21
  def on_return(return_node)
22
- add_offense(return_node) if return_node.arguments? && ancestors_valid?(return_node)
22
+ return unless top_level_return_with_any_argument?(return_node)
23
+
24
+ add_offense(return_node) do |corrector|
25
+ remove_arguments(corrector, return_node)
26
+ end
23
27
  end
24
28
 
25
29
  private
26
30
 
27
- def ancestors_valid?(return_node)
28
- prohibited_ancestors = return_node.each_ancestor(:block, :def, :defs)
29
- prohibited_ancestors.none?
31
+ def top_level_return_with_any_argument?(return_node)
32
+ top_level_return?(return_node) && return_node.arguments?
33
+ end
34
+
35
+ def remove_arguments(corrector, return_node)
36
+ corrector.replace(return_node, 'return')
37
+ end
38
+
39
+ # This cop works by validating the ancestors of the return node. A
40
+ # top-level return node's ancestors should not be of block, def, or
41
+ # defs type.
42
+ def top_level_return?(return_node)
43
+ return_node.each_ancestor(:block, :def, :defs).none?
30
44
  end
31
45
  end
32
46
  end
@@ -13,6 +13,12 @@ module RuboCop
13
13
  # reassignments and properly handles varied cases such as branch, loop,
14
14
  # rescue, ensure, etc.
15
15
  #
16
+ # @safety
17
+ # This cop's autocorrection is unsafe because removing assignment from
18
+ # operator assignment can cause NameError if this assignment has been used to declare
19
+ # local variable. For example, replacing `a ||= 1` to `a || 1` may cause
20
+ # "undefined local variable or method `a' for main:Object (NameError)".
21
+ #
16
22
  # @example
17
23
  #
18
24
  # # bad
@@ -31,6 +37,10 @@ module RuboCop
31
37
  # do_something(some_var)
32
38
  # end
33
39
  class UselessAssignment < Base
40
+ extend AutoCorrector
41
+
42
+ include RangeHelp
43
+
34
44
  MSG = 'Useless assignment to variable - `%<variable>s`.'
35
45
 
36
46
  def self.joining_forces
@@ -55,7 +65,9 @@ module RuboCop
55
65
  assignment.node.loc.name
56
66
  end
57
67
 
58
- add_offense(location, message: message)
68
+ add_offense(location, message: message) do |corrector|
69
+ autocorrect(corrector, assignment)
70
+ end
59
71
  end
60
72
  end
61
73
 
@@ -119,6 +131,49 @@ module RuboCop
119
131
 
120
132
  node.receiver.nil? && !node.arguments?
121
133
  end
134
+
135
+ def autocorrect(corrector, assignment)
136
+ if assignment.exception_assignment?
137
+ remove_exception_assignment_part(corrector, assignment.node)
138
+ elsif assignment.multiple_assignment?
139
+ rename_variable_with_underscore(corrector, assignment.node)
140
+ elsif assignment.operator_assignment?
141
+ remove_trailing_character_from_operator(corrector, assignment.node)
142
+ elsif assignment.regexp_named_capture?
143
+ replace_named_capture_group_with_non_capturing_group(corrector, assignment.node,
144
+ assignment.variable.name)
145
+ else
146
+ remove_local_variable_assignment_part(corrector, assignment.node)
147
+ end
148
+ end
149
+
150
+ def remove_exception_assignment_part(corrector, node)
151
+ corrector.remove(
152
+ range_between(
153
+ (node.parent.children.first&.source_range || node.parent.location.keyword).end_pos,
154
+ node.source_range.end_pos
155
+ )
156
+ )
157
+ end
158
+
159
+ def rename_variable_with_underscore(corrector, node)
160
+ corrector.replace(node, '_')
161
+ end
162
+
163
+ def remove_trailing_character_from_operator(corrector, node)
164
+ corrector.remove(node.parent.location.operator.end.adjust(begin_pos: -1))
165
+ end
166
+
167
+ def replace_named_capture_group_with_non_capturing_group(corrector, node, variable_name)
168
+ corrector.replace(
169
+ node.children.first,
170
+ node.children.first.source.sub(/\(\?<#{variable_name}>/, '(?:')
171
+ )
172
+ end
173
+
174
+ def remove_local_variable_assignment_part(corrector, node)
175
+ corrector.replace(node, node.expression.source)
176
+ end
122
177
  end
123
178
  end
124
179
  end
@@ -41,6 +41,10 @@ module RuboCop
41
41
  # do_something(some_array)
42
42
  # end
43
43
  class Void < Base
44
+ extend AutoCorrector
45
+
46
+ include RangeHelp
47
+
44
48
  OP_MSG = 'Operator `%<op>s` used in void context.'
45
49
  VAR_MSG = 'Variable `%<var>s` used in void context.'
46
50
  LIT_MSG = 'Literal `%<lit>s` used in void context.'
@@ -100,31 +104,43 @@ module RuboCop
100
104
  def check_void_op(node)
101
105
  return unless node.send_type? && OPERATORS.include?(node.method_name)
102
106
 
103
- add_offense(node.loc.selector, message: format(OP_MSG, op: node.method_name))
107
+ add_offense(node.loc.selector,
108
+ message: format(OP_MSG, op: node.method_name)) do |corrector|
109
+ autocorrect_void_op(corrector, node)
110
+ end
104
111
  end
105
112
 
106
113
  def check_var(node)
107
114
  return unless node.variable? || node.const_type?
108
115
 
109
- add_offense(node.loc.name, message: format(VAR_MSG, var: node.loc.name.source))
116
+ add_offense(node.loc.name,
117
+ message: format(VAR_MSG, var: node.loc.name.source)) do |corrector|
118
+ autocorrect_void_var(corrector, node)
119
+ end
110
120
  end
111
121
 
112
122
  def check_literal(node)
113
123
  return if !node.literal? || node.xstr_type? || node.range_type?
114
124
 
115
- add_offense(node, message: format(LIT_MSG, lit: node.source))
125
+ add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
126
+ autocorrect_void_literal(corrector, node)
127
+ end
116
128
  end
117
129
 
118
130
  def check_self(node)
119
131
  return unless node.self_type?
120
132
 
121
- add_offense(node, message: SELF_MSG)
133
+ add_offense(node, message: SELF_MSG) do |corrector|
134
+ autocorrect_void_self(corrector, node)
135
+ end
122
136
  end
123
137
 
124
138
  def check_void_expression(node)
125
139
  return unless node.defined_type? || node.lambda_or_proc?
126
140
 
127
- add_offense(node, message: format(EXPRESSION_MSG, expression: node.source))
141
+ add_offense(node, message: format(EXPRESSION_MSG, expression: node.source)) do |corrector|
142
+ autocorrect_void_expression(corrector, node)
143
+ end
128
144
  end
129
145
 
130
146
  def check_nonmutating(node)
@@ -139,7 +155,10 @@ module RuboCop
139
155
  "#{method_name}!"
140
156
  end
141
157
  add_offense(node,
142
- message: format(NONMUTATING_MSG, method: method_name, suggest: suggestion))
158
+ message: format(NONMUTATING_MSG, method: method_name,
159
+ suggest: suggestion)) do |corrector|
160
+ autocorrect_nonmutating_send(corrector, node, suggestion)
161
+ end
143
162
  end
144
163
 
145
164
  def in_void_context?(node)
@@ -149,6 +168,43 @@ module RuboCop
149
168
 
150
169
  VOID_CONTEXT_TYPES.include?(parent.type) && parent.void_context?
151
170
  end
171
+
172
+ def autocorrect_void_op(corrector, node)
173
+ if node.arguments.empty?
174
+ corrector.replace(node, node.receiver.source)
175
+ else
176
+ corrector.replace(
177
+ range_with_surrounding_space(range: node.loc.selector, side: :both,
178
+ newlines: false),
179
+ "\n"
180
+ )
181
+ end
182
+ end
183
+
184
+ def autocorrect_void_var(corrector, node)
185
+ corrector.remove(range_with_surrounding_space(range: node.loc.name, side: :left))
186
+ end
187
+
188
+ def autocorrect_void_literal(corrector, node)
189
+ corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
190
+ end
191
+
192
+ def autocorrect_void_self(corrector, node)
193
+ corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
194
+ end
195
+
196
+ def autocorrect_void_expression(corrector, node)
197
+ corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
198
+ end
199
+
200
+ def autocorrect_nonmutating_send(corrector, node, suggestion)
201
+ send_node = if node.send_type?
202
+ node
203
+ else
204
+ node.send_node
205
+ end
206
+ corrector.replace(send_node.loc.selector, suggestion)
207
+ end
152
208
  end
153
209
  end
154
210
  end
@@ -62,12 +62,16 @@ module RuboCop
62
62
  # Returns the end line of a node, which might be a comment and not part of the AST
63
63
  # End line is considered either the line at which another node starts, or
64
64
  # the line at which the parent node ends.
65
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
65
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Lint/DuplicateBranch
66
66
  def find_end_line(node)
67
67
  if node.if_type? && node.else?
68
68
  node.loc.else.line
69
69
  elsif node.if_type? && node.ternary?
70
70
  node.else_branch.loc.line
71
+ elsif node.if_type? && node.elsif?
72
+ node.each_ancestor(:if).find(&:if?).loc.end.line
73
+ elsif node.block_type? || node.numblock_type?
74
+ node.loc.end.line
71
75
  elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node)
72
76
  next_sibling.loc.line
73
77
  elsif (parent = node.parent)
@@ -76,7 +80,7 @@ module RuboCop
76
80
  node.loc.end.line
77
81
  end
78
82
  end
79
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
83
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Lint/DuplicateBranch
80
84
  end
81
85
  end
82
86
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def allowed_type?(token)
39
- %i[tRPAREN tRBRACK tPIPE].include?(token.type)
39
+ %i[tRPAREN tRBRACK tPIPE tSTRING_DEND].include?(token.type)
40
40
  end
41
41
 
42
42
  def space_forbidden_before_rcurly?
@@ -76,7 +76,7 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def contains_constant?(node)
79
- node.branches.any?(&:const_type?)
79
+ node.branches.compact.any?(&:const_type?)
80
80
  end
81
81
  end
82
82
  end