rubocop 1.57.2 → 1.58.0

Sign up to get free protection for your applications and to get access to all the features.
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]