rubocop 1.57.2 → 1.58.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +37 -2
  4. data/lib/rubocop/config_obsoletion.rb +11 -8
  5. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  6. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  7. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  8. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  9. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  10. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  11. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  12. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  13. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
  14. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  15. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  16. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  17. data/lib/rubocop/cop/layout/single_line_block_chain.rb +4 -0
  18. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  19. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  20. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  21. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  22. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  23. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  24. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +64 -0
  25. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  26. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +43 -0
  27. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  28. data/lib/rubocop/cop/lint/self_assignment.rb +37 -0
  29. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  30. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  31. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  32. data/lib/rubocop/cop/lint/void.rb +14 -1
  33. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  34. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  35. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/naming/block_forwarding.rb +2 -2
  37. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  38. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  39. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  40. data/lib/rubocop/cop/style/arguments_forwarding.rb +68 -6
  41. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  42. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  43. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  44. data/lib/rubocop/cop/style/case_like_if.rb +4 -4
  45. data/lib/rubocop/cop/style/combinable_loops.rb +2 -7
  46. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  47. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  48. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  49. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  50. data/lib/rubocop/cop/style/hash_each_methods.rb +58 -10
  51. data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
  52. data/lib/rubocop/cop/style/map_to_hash.rb +9 -4
  53. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  54. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  55. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  56. data/lib/rubocop/cop/style/redundant_argument.rb +2 -2
  57. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  58. data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -0
  59. data/lib/rubocop/cop/style/redundant_parentheses.rb +11 -3
  60. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  61. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  62. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  63. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  64. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  65. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  66. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  67. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  68. data/lib/rubocop/formatter/html_formatter.rb +1 -2
  69. data/lib/rubocop/result_cache.rb +0 -1
  70. data/lib/rubocop/runner.rb +1 -1
  71. data/lib/rubocop/version.rb +1 -1
  72. data/lib/rubocop.rb +3 -0
  73. metadata +10 -6
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
7
+ # them to use `arr.first` and `arr.instead`.
8
+ #
9
+ # The cop is disabled by default due to safety concerns.
10
+ #
11
+ # @safety
12
+ # This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
13
+ # which returns a value for `0` or `-1` key, but changing these to use
14
+ # `.first` or `.last` will return first/last tuple instead. Also, String
15
+ # does not implement `first`/`last` methods.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # arr[0]
20
+ # arr[-1]
21
+ #
22
+ # # good
23
+ # arr.first
24
+ # arr.last
25
+ # arr[0] = 2
26
+ # arr[0][-2]
27
+ #
28
+ class ArrayFirstLast < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<preferred>s`.'
32
+ RESTRICT_ON_SEND = %i[[]].freeze
33
+
34
+ # rubocop:disable Metrics/AbcSize
35
+ def on_send(node)
36
+ return unless node.arguments.size == 1 && node.first_argument.int_type?
37
+
38
+ value = node.first_argument.value
39
+ return unless [0, -1].include?(value)
40
+
41
+ node = innermost_braces_node(node)
42
+ return if node.parent && brace_method?(node.parent)
43
+
44
+ preferred = (value.zero? ? 'first' : 'last')
45
+ add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
46
+ corrector.replace(node.loc.selector, ".#{preferred}")
47
+ end
48
+ end
49
+ # rubocop:enable Metrics/AbcSize
50
+
51
+ private
52
+
53
+ def innermost_braces_node(node)
54
+ node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
55
+ node
56
+ end
57
+
58
+ def brace_method?(node)
59
+ node.send_type? && (node.method?(:[]) || node.method?(:[]=))
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -16,31 +16,38 @@ module RuboCop
16
16
  # File.open('file') do |f|
17
17
  # # ...
18
18
  # end
19
+ #
20
+ # # bad
21
+ # f = Tempfile.open('temp')
22
+ #
23
+ # # good
24
+ # Tempfile.open('temp') do |f|
25
+ # # ...
26
+ # end
19
27
  class AutoResourceCleanup < Base
20
- MSG = 'Use the block version of `%<class>s.%<method>s`.'
21
-
22
- TARGET_METHODS = { File: :open }.freeze
28
+ MSG = 'Use the block version of `%<current>s`.'
29
+ RESTRICT_ON_SEND = %i[open].freeze
23
30
 
24
- RESTRICT_ON_SEND = TARGET_METHODS.values.freeze
31
+ # @!method file_open_method?(node)
32
+ def_node_matcher :file_open_method?, <<~PATTERN
33
+ (send (const {nil? cbase} {:File :Tempfile}) :open ...)
34
+ PATTERN
25
35
 
26
36
  def on_send(node)
27
- TARGET_METHODS.each do |target_class, target_method|
28
- next if node.method_name != target_method
37
+ return if !file_open_method?(node) || cleanup?(node)
29
38
 
30
- target_receiver = s(:const, nil, target_class)
31
- next if node.receiver != target_receiver
39
+ current = node.receiver.source_range.begin.join(node.selector.end).source
32
40
 
33
- next if cleanup?(node)
34
-
35
- add_offense(node, message: format(MSG, class: target_class, method: target_method))
36
- end
41
+ add_offense(node, message: format(MSG, current: current))
37
42
  end
38
43
 
39
44
  private
40
45
 
41
46
  def cleanup?(node)
42
- parent = node.parent
43
- node.block_argument? || (parent && (parent.block_type? || !parent.lvasgn_type?))
47
+ return true if node.block_argument?
48
+ return false unless (parent = node.parent)
49
+
50
+ parent.block_type? || !parent.lvasgn_type?
44
51
  end
45
52
  end
46
53
  end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def on_class(class_node)
34
34
  @macros_to_rewrite[class_node] = Set.new
35
35
 
36
- find_macros(class_node.body).each do |_visibility, macros|
36
+ find_macros(class_node.body).each_value do |macros|
37
37
  bisected = find_bisection(macros)
38
38
  next unless bisected.any?
39
39
 
@@ -74,7 +74,7 @@ module RuboCop
74
74
  def find_macros(class_def)
75
75
  # Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
76
76
  # and turn them into `Macro` objects so that they can be processed.
77
- return [] if !class_def || class_def.def_type?
77
+ return {} if !class_def || class_def.def_type?
78
78
 
79
79
  send_nodes =
80
80
  if class_def.send_type?
@@ -125,7 +125,7 @@ module RuboCop
125
125
  when :==, :eql?, :equal?
126
126
  find_target_in_equality_node(node)
127
127
  when :===
128
- node.arguments.first
128
+ node.first_argument
129
129
  when :include?, :cover?
130
130
  find_target_in_include_or_cover_node(node)
131
131
  when :match, :match?, :=~
@@ -134,7 +134,7 @@ module RuboCop
134
134
  end
135
135
 
136
136
  def find_target_in_equality_node(node)
137
- argument = node.arguments.first
137
+ argument = node.first_argument
138
138
  receiver = node.receiver
139
139
  return unless argument && receiver
140
140
 
@@ -152,7 +152,7 @@ module RuboCop
152
152
  end
153
153
 
154
154
  def find_target_in_match_node(node)
155
- argument = node.arguments.first
155
+ argument = node.first_argument
156
156
  receiver = node.receiver
157
157
  return unless receiver
158
158
 
@@ -185,7 +185,7 @@ module RuboCop
185
185
  def condition_from_send_node(node, target)
186
186
  case node.method_name
187
187
  when :is_a?
188
- node.arguments.first if node.receiver == target
188
+ node.first_argument if node.receiver == target
189
189
  when :==, :eql?, :equal?
190
190
  condition_from_equality_node(node, target)
191
191
  when :=~, :match, :match?
@@ -59,8 +59,6 @@ module RuboCop
59
59
  class CombinableLoops < Base
60
60
  extend AutoCorrector
61
61
 
62
- include RangeHelp
63
-
64
62
  MSG = 'Combine this loop with the previous loop.'
65
63
 
66
64
  def on_block(node)
@@ -105,11 +103,8 @@ module RuboCop
105
103
  end
106
104
 
107
105
  def combine_with_left_sibling(corrector, node)
108
- corrector.replace(
109
- node.left_sibling.body,
110
- "#{node.left_sibling.body.source}\n#{node.body.source}"
111
- )
112
- corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
106
+ corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
107
+ corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
113
108
  end
114
109
  end
115
110
  end
@@ -534,7 +534,7 @@ module RuboCop
534
534
  end
535
535
 
536
536
  def element_assignment?(node)
537
- node.send_type? && node.method_name != :[]=
537
+ node.send_type? && !node.method?(:[]=)
538
538
  end
539
539
 
540
540
  def extract_branches(node)
@@ -83,7 +83,7 @@ module RuboCop
83
83
  parent = node.parent
84
84
  return false unless parent && %i[send super zsuper].include?(parent.type)
85
85
 
86
- node.equal?(parent.arguments.first) && !parentheses?(node.parent)
86
+ node.equal?(parent.first_argument) && !parentheses?(node.parent)
87
87
  end
88
88
 
89
89
  def replacement_range(node)
@@ -84,7 +84,7 @@ module RuboCop
84
84
  # are considered.
85
85
  return if node.method?(:eval) && !valid_eval_receiver?(node.receiver)
86
86
 
87
- code = node.arguments.first
87
+ code = node.first_argument
88
88
  return unless code && (code.str_type? || code.dstr_type?)
89
89
 
90
90
  check_location(node, code)
@@ -165,7 +165,7 @@ module RuboCop
165
165
  end
166
166
 
167
167
  def check_line(node, code)
168
- line_node = node.arguments.last
168
+ line_node = node.last_argument
169
169
  line_diff = line_difference(line_node, code)
170
170
  if line_diff.zero?
171
171
  add_offense_for_same_line(node, line_node)
@@ -227,7 +227,7 @@ module RuboCop
227
227
  end
228
228
 
229
229
  def missing_line(node, code)
230
- line_diff = line_difference(node.arguments.last, code)
230
+ line_diff = line_difference(node.last_argument, code)
231
231
  sign = line_diff.positive? ? :+ : :-
232
232
  expected_line(sign, line_diff)
233
233
  end
@@ -86,7 +86,7 @@ module RuboCop
86
86
 
87
87
  def extract_block_name(def_node)
88
88
  if def_node.block_argument?
89
- def_node.arguments.last.name
89
+ def_node.last_argument.name
90
90
  else
91
91
  'block'
92
92
  end
@@ -127,7 +127,7 @@ module RuboCop
127
127
  end
128
128
 
129
129
  def insert_argument(node, corrector, block_name)
130
- last_arg = node.arguments.last
130
+ last_arg = node.last_argument
131
131
  arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
132
132
  replacement = " &#{block_name}"
133
133
  replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
@@ -17,10 +17,16 @@ module RuboCop
17
17
  # @example
18
18
  # # bad
19
19
  # hash.keys.each { |k| p k }
20
- # hash.values.each { |v| p v }
20
+ # hash.each { |k, unused_value| p k }
21
21
  #
22
22
  # # good
23
23
  # hash.each_key { |k| p k }
24
+ #
25
+ # # bad
26
+ # hash.values.each { |v| p v }
27
+ # hash.each { |unused_key, v| p v }
28
+ #
29
+ # # good
24
30
  # hash.each_value { |v| p v }
25
31
  #
26
32
  # @example AllowedReceivers: ['execute']
@@ -33,22 +39,44 @@ module RuboCop
33
39
  extend AutoCorrector
34
40
 
35
41
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
42
+ UNUSED_BLOCK_ARG_MSG = "#{MSG.chop} and remove the unused `%<unused_code>s` block argument."
36
43
 
37
44
  # @!method kv_each(node)
38
45
  def_node_matcher :kv_each, <<~PATTERN
39
- ({block numblock} $(send (send _ ${:keys :values}) :each) ...)
46
+ ({block numblock} $(call (call _ ${:keys :values}) :each) ...)
47
+ PATTERN
48
+
49
+ # @!method each_arguments(node)
50
+ def_node_matcher :each_arguments, <<~PATTERN
51
+ (block (call _ :each)(args $_key $_value) ...)
40
52
  PATTERN
41
53
 
42
54
  # @!method kv_each_with_block_pass(node)
43
55
  def_node_matcher :kv_each_with_block_pass, <<~PATTERN
44
- (send $(send _ ${:keys :values}) :each (block_pass (sym _)))
56
+ (call $(call _ ${:keys :values}) :each (block_pass (sym _)))
45
57
  PATTERN
46
58
 
59
+ # rubocop:disable Metrics/AbcSize
47
60
  def on_block(node)
48
61
  kv_each(node) do |target, method|
49
- register_kv_offense(target, method)
62
+ register_kv_offense(target, method) and return
63
+ end
64
+
65
+ return unless (key, value = each_arguments(node))
66
+
67
+ if unused_block_arg_exist?(node, value.source)
68
+ message = message('each_key', node.method_name, value.source)
69
+ unused_range = key.source_range.end.join(value.source_range.end)
70
+
71
+ register_each_args_offense(node, message, 'each_key', unused_range)
72
+ elsif unused_block_arg_exist?(node, key.source)
73
+ message = message('each_value', node.method_name, key.source)
74
+ unused_range = key.source_range.begin.join(value.source_range.begin)
75
+
76
+ register_each_args_offense(node, message, 'each_value', unused_range)
50
77
  end
51
78
  end
79
+ # rubocop:enable Metrics/AbcSize
52
80
 
53
81
  alias on_numblock on_block
54
82
 
@@ -64,23 +92,43 @@ module RuboCop
64
92
  return unless (parent_receiver = target.receiver.receiver)
65
93
  return if allowed_receiver?(parent_receiver)
66
94
 
67
- add_offense(kv_range(target), message: format_message(method)) do |corrector|
95
+ current = target.receiver.loc.selector.join(target.source_range.end).source
96
+
97
+ add_offense(kv_range(target), message: format_message(method, current)) do |corrector|
68
98
  correct_key_value_each(target, corrector)
69
99
  end
70
100
  end
71
101
 
102
+ def unused_block_arg_exist?(node, block_arg_source)
103
+ node.body.each_descendant(:lvar).map(&:source).none?(block_arg_source)
104
+ end
105
+
106
+ def message(prefer, method_name, unused_code)
107
+ format(
108
+ UNUSED_BLOCK_ARG_MSG, prefer: prefer, current: method_name, unused_code: unused_code
109
+ )
110
+ end
111
+
112
+ def register_each_args_offense(node, message, prefer, unused_range)
113
+ add_offense(node, message: message) do |corrector|
114
+ corrector.replace(node.send_node.loc.selector, prefer)
115
+ corrector.remove(unused_range)
116
+ end
117
+ end
118
+
72
119
  def register_kv_with_block_pass_offense(node, target, method)
73
120
  return unless (parent_receiver = node.parent.receiver.receiver)
74
121
  return if allowed_receiver?(parent_receiver)
75
122
 
76
- range = target.loc.selector.with(end_pos: node.parent.loc.selector.end_pos)
77
- add_offense(range, message: format_message(method)) do |corrector|
123
+ range = target.loc.selector.join(node.parent.loc.selector.end)
124
+
125
+ add_offense(range, message: format_message(method, range.source)) do |corrector|
78
126
  corrector.replace(range, "each_#{method[0..-2]}")
79
127
  end
80
128
  end
81
129
 
82
- def format_message(method_name)
83
- format(MSG, prefer: "each_#{method_name[0..-2]}", current: "#{method_name}.each")
130
+ def format_message(method_name, current)
131
+ format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
84
132
  end
85
133
 
86
134
  def check_argument(variable)
@@ -103,7 +151,7 @@ module RuboCop
103
151
  name = "each_#{node.receiver.method_name.to_s.chop}"
104
152
  return correct_implicit(node, corrector, name) unless receiver
105
153
 
106
- new_source = receiver.source + ".#{name}"
154
+ new_source = receiver.source + "#{node.loc.dot.source}#{name}"
107
155
  corrector.replace(node, new_source)
108
156
  end
109
157
 
@@ -60,17 +60,17 @@ module RuboCop
60
60
  # @!method inverse_candidate?(node)
61
61
  def_node_matcher :inverse_candidate?, <<~PATTERN
62
62
  {
63
- (send $(send $(...) $_ $...) :!)
64
- (send ({block numblock} $(send $(...) $_) $...) :!)
65
- (send (begin $(send $(...) $_ $...)) :!)
63
+ (send $(call $(...) $_ $...) :!)
64
+ (send ({block numblock} $(call $(...) $_) $...) :!)
65
+ (send (begin $(call $(...) $_ $...)) :!)
66
66
  }
67
67
  PATTERN
68
68
 
69
69
  # @!method inverse_block?(node)
70
70
  def_node_matcher :inverse_block?, <<~PATTERN
71
- ({block numblock} $(send (...) $_) ... { $(send ... :!)
71
+ ({block numblock} $(call (...) $_) ... { $(call ... :!)
72
72
  $(send (...) {:!= :!~} ...)
73
- (begin ... $(send ... :!))
73
+ (begin ... $(call ... :!))
74
74
  (begin ... $(send (...) {:!= :!~} ...))
75
75
  })
76
76
  PATTERN
@@ -87,6 +87,7 @@ module RuboCop
87
87
  end
88
88
  end
89
89
  end
90
+ alias on_csend on_send
90
91
 
91
92
  def on_block(node)
92
93
  inverse_block?(node) do |_method_call, method, block|
@@ -34,21 +34,25 @@ module RuboCop
34
34
 
35
35
  minimum_target_ruby_version 2.6
36
36
 
37
- MSG = 'Pass a block to `to_h` instead of calling `%<method>s.to_h`.'
37
+ MSG = 'Pass a block to `to_h` instead of calling `%<method>s%<dot>sto_h`.'
38
38
  RESTRICT_ON_SEND = %i[to_h].freeze
39
39
 
40
40
  # @!method map_to_h?(node)
41
41
  def_node_matcher :map_to_h?, <<~PATTERN
42
42
  {
43
- $(send ({block numblock} $(send _ {:map :collect}) ...) :to_h)
44
- $(send $(send _ {:map :collect} (block_pass sym)) :to_h)
43
+ $(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
44
+ $(call $(call _ {:map :collect} (block_pass sym)) :to_h)
45
45
  }
46
46
  PATTERN
47
47
 
48
+ def self.autocorrect_incompatible_with
49
+ [Layout::SingleLineBlockChain]
50
+ end
51
+
48
52
  def on_send(node)
49
53
  return unless (to_h_node, map_node = map_to_h?(node))
50
54
 
51
- message = format(MSG, method: map_node.loc.selector.source)
55
+ message = format(MSG, method: map_node.loc.selector.source, dot: map_node.loc.dot.source)
52
56
  add_offense(map_node.loc.selector, message: message) do |corrector|
53
57
  # If the `to_h` call already has a block, do not autocorrect.
54
58
  next if to_h_node.block_node
@@ -56,6 +60,7 @@ module RuboCop
56
60
  autocorrect(corrector, to_h_node, map_node)
57
61
  end
58
62
  end
63
+ alias on_csend on_send
59
64
 
60
65
  private
61
66
 
@@ -239,7 +239,7 @@ module RuboCop
239
239
  def args_parenthesized?(node)
240
240
  return false unless node.arguments.one?
241
241
 
242
- first_node = node.arguments.first
242
+ first_node = node.first_argument
243
243
  first_node.begin_type? && first_node.parenthesized_call?
244
244
  end
245
245
  end
@@ -170,7 +170,7 @@ module RuboCop
170
170
  return true if node.arguments.any? do |arg|
171
171
  arg.forward_arg_type? || arg.restarg_type? || arg.kwrestarg_type?
172
172
  end
173
- return false unless (last_argument = node.arguments.last)
173
+ return false unless (last_argument = node.last_argument)
174
174
 
175
175
  last_argument.blockarg_type? && last_argument.name.nil?
176
176
  end
@@ -7,12 +7,12 @@ module RuboCop
7
7
  # defining `respond_to_missing?`.
8
8
  #
9
9
  # @example
10
- # #bad
10
+ # # bad
11
11
  # def method_missing(name, *args)
12
12
  # # ...
13
13
  # end
14
14
  #
15
- # #good
15
+ # # good
16
16
  # def respond_to_missing?(name, include_private)
17
17
  # # ...
18
18
  # end
@@ -67,7 +67,7 @@ module RuboCop
67
67
  return unless redundant_argument?(node)
68
68
 
69
69
  offense_range = argument_range(node)
70
- message = format(MSG, arg: node.arguments.first.source)
70
+ message = format(MSG, arg: node.first_argument.source)
71
71
 
72
72
  add_offense(offense_range, message: message) do |corrector|
73
73
  corrector.remove(offense_range)
@@ -80,7 +80,7 @@ module RuboCop
80
80
  redundant_argument = redundant_arg_for_method(node.method_name.to_s)
81
81
  return false if redundant_argument.nil?
82
82
 
83
- node.arguments.first == redundant_argument
83
+ node.first_argument == redundant_argument
84
84
  end
85
85
 
86
86
  def redundant_arg_for_method(method_name)
@@ -25,20 +25,20 @@ module RuboCop
25
25
  MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
26
26
  MERGE_METHODS = %i[merge merge!].freeze
27
27
 
28
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
28
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
29
29
  def on_hash(node)
30
30
  return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
31
31
  return unless (parent = node.parent)
32
32
  return unless parent.call_type? || parent.kwsplat_type?
33
33
  return unless mergeable?(parent)
34
34
  return unless (kwsplat = node.each_ancestor(:kwsplat).first)
35
- return if allowed_double_splat_receiver?(kwsplat)
35
+ return if !node.braces? || allowed_double_splat_receiver?(kwsplat)
36
36
 
37
37
  add_offense(kwsplat) do |corrector|
38
38
  autocorrect(corrector, node, kwsplat)
39
39
  end
40
40
  end
41
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
41
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
42
42
 
43
43
  private
44
44
 
@@ -107,6 +107,8 @@ module RuboCop
107
107
 
108
108
  def inside_string_literal_or_method_with_argument?(range)
109
109
  processed_source.tokens.each_cons(2).any? do |token, next_token|
110
+ next if token.line == next_token.line
111
+
110
112
  inside_string_literal?(range, token) || method_with_argument?(token, next_token)
111
113
  end
112
114
  end
@@ -17,6 +17,8 @@ module RuboCop
17
17
  include Parentheses
18
18
  extend AutoCorrector
19
19
 
20
+ ALLOWED_NODE_TYPES = %i[and or send splat kwsplat].freeze
21
+
20
22
  # @!method square_brackets?(node)
21
23
  def_node_matcher :square_brackets?, '(send {(send _recv _msg) str array hash} :[] ...)'
22
24
 
@@ -136,23 +138,29 @@ module RuboCop
136
138
  check_send(begin_node, node) if node.call_type?
137
139
  end
138
140
 
139
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
141
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
140
142
  def find_offense_message(begin_node, node)
141
143
  return 'a keyword' if keyword_with_redundant_parentheses?(node)
142
144
  return 'a literal' if disallowed_literal?(begin_node, node)
143
145
  return 'a variable' if node.variable?
144
146
  return 'a constant' if node.const_type?
147
+ return 'an expression' if node.lambda_or_proc?
145
148
  return 'an interpolated expression' if interpolation?(begin_node)
146
149
 
147
- return if begin_node.chained? || !begin_node.parent.nil?
150
+ return if begin_node.chained?
148
151
 
149
152
  if node.and_type? || node.or_type?
153
+ return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
154
+ return if begin_node.parent&.if_type? && begin_node.parent&.ternary?
155
+
150
156
  'a logical expression'
151
157
  elsif node.respond_to?(:comparison_method?) && node.comparison_method?
158
+ return unless begin_node.parent.nil?
159
+
152
160
  'a comparison expression'
153
161
  end
154
162
  end
155
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
163
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
156
164
 
157
165
  # @!method interpolation?(node)
158
166
  def_node_matcher :interpolation?, '[^begin ^^dstr]'
@@ -58,7 +58,7 @@ module RuboCop
58
58
 
59
59
  MSG = 'Redundant `return` detected.'
60
60
  MULTI_RETURN_MSG = 'To return multiple values, use an array.'
61
- RESTRICT_ON_SEND = %i[define_method define_singleton_method].freeze
61
+ RESTRICT_ON_SEND = %i[define_method define_singleton_method lambda].freeze
62
62
 
63
63
  def on_send(node)
64
64
  return unless (parent = node.parent) && parent.block_type?
@@ -180,7 +180,7 @@ module RuboCop
180
180
  end
181
181
 
182
182
  def arg_node(node)
183
- node.arguments.first
183
+ node.first_argument
184
184
  end
185
185
 
186
186
  def arg_value(node)
@@ -133,7 +133,7 @@ module RuboCop
133
133
  end
134
134
 
135
135
  def percent_array_literal?(node)
136
- (percent_w_literal?(node) || percent_w_upper_literal?(node))
136
+ percent_w_literal?(node) || percent_w_upper_literal?(node)
137
137
  end
138
138
 
139
139
  def heredoc_with_disabled_interpolation?(node)
@@ -146,7 +146,7 @@ module RuboCop
146
146
  return node.child_nodes.first if node.match_with_lvasgn_type?
147
147
 
148
148
  if node.receiver.lvar_type? &&
149
- (block.numblock_type? || node.receiver.source == block.arguments.first.source)
149
+ (block.numblock_type? || node.receiver.source == block.first_argument.source)
150
150
  node.first_argument
151
151
  elsif node.first_argument.lvar_type?
152
152
  node.receiver
@@ -16,7 +16,7 @@ module RuboCop
16
16
  extend AutoCorrector
17
17
 
18
18
  MSG = 'Use self-assignment shorthand `%<method>s=`.'
19
- OPS = %i[+ - * ** / | &].freeze
19
+ OPS = %i[+ - * ** / % ^ << >> | &].freeze
20
20
 
21
21
  def self.autocorrect_incompatible_with
22
22
  [Layout::SpaceAroundOperators]