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
@@ -17,24 +17,24 @@ module RuboCop
17
17
  #
18
18
  # @example
19
19
  # # bad
20
- # if some_var = true
20
+ # if some_var = value
21
21
  # do_something
22
22
  # end
23
23
  #
24
24
  # # good
25
- # if some_var == true
25
+ # if some_var == value
26
26
  # do_something
27
27
  # end
28
28
  #
29
29
  # @example AllowSafeAssignment: true (default)
30
30
  # # good
31
- # if (some_var = true)
31
+ # if (some_var = value)
32
32
  # do_something
33
33
  # end
34
34
  #
35
35
  # @example AllowSafeAssignment: false
36
36
  # # bad
37
- # if (some_var = true)
37
+ # if (some_var = value)
38
38
  # do_something
39
39
  # end
40
40
  #
@@ -66,6 +66,7 @@ module RuboCop
66
66
  # end
67
67
  class Debugger < Base
68
68
  MSG = 'Remove debugger entry point `%<source>s`.'
69
+ BLOCK_TYPES = %i[block numblock kwbegin].freeze
69
70
 
70
71
  def on_send(node)
71
72
  return if !debugger_method?(node) || assumed_usage_context?(node)
@@ -98,7 +99,7 @@ module RuboCop
98
99
  return true if assumed_argument?(node)
99
100
 
100
101
  node.each_ancestor.none? do |ancestor|
101
- ancestor.block_type? || ancestor.numblock_type? || ancestor.lambda_or_proc?
102
+ BLOCK_TYPES.include?(ancestor.type) || ancestor.lambda_or_proc?
102
103
  end
103
104
  end
104
105
 
@@ -253,7 +253,7 @@ module RuboCop
253
253
  # Assume that if a method definition is inside any block call which
254
254
  # we can't identify, it could be a DSL
255
255
  node.each_ancestor(:block).any? do |ancestor|
256
- ancestor.method_name != :class_eval && !ancestor.class_constructor?
256
+ !ancestor.method?(:class_eval) && !ancestor.class_constructor?
257
257
  end
258
258
  end
259
259
 
@@ -106,7 +106,7 @@ module RuboCop
106
106
  private
107
107
 
108
108
  def autocorrect(corrector, node)
109
- str_arg = node.arguments[0].source
109
+ str_arg = node.first_argument.source
110
110
 
111
111
  kwargs = build_kwargs(node)
112
112
  overridden_kwargs = override_by_legacy_args(kwargs, node)
@@ -121,11 +121,11 @@ module RuboCop
121
121
  end
122
122
 
123
123
  def build_kwargs(node)
124
- return [nil, nil] unless node.arguments.last.hash_type?
124
+ return [nil, nil] unless node.last_argument.hash_type?
125
125
 
126
126
  trim_mode_arg, eoutvar_arg = nil
127
127
 
128
- node.arguments.last.pairs.each do |pair|
128
+ node.last_argument.pairs.each do |pair|
129
129
  case pair.key.source
130
130
  when 'trim_mode'
131
131
  trim_mode_arg = "trim_mode: #{pair.value.source}"
@@ -18,6 +18,10 @@ module RuboCop
18
18
  # # good - using BigDecimal
19
19
  # x.to_d == 0.1.to_d
20
20
  #
21
+ # # good - comparing against zero
22
+ # x == 0.0
23
+ # x != 0.0
24
+ #
21
25
  # # good
22
26
  # (x - 0.1).abs < Float::EPSILON
23
27
  #
@@ -39,6 +43,8 @@ module RuboCop
39
43
 
40
44
  def on_send(node)
41
45
  lhs, _method, rhs = *node
46
+ return if literal_zero?(lhs) || literal_zero?(rhs)
47
+
42
48
  add_offense(node) if float?(lhs) || float?(rhs)
43
49
  end
44
50
 
@@ -59,6 +65,10 @@ module RuboCop
59
65
  end
60
66
  end
61
67
 
68
+ def literal_zero?(node)
69
+ node&.numeric_type? && node.value.zero?
70
+ end
71
+
62
72
  # rubocop:disable Metrics/PerceivedComplexity
63
73
  def check_send(node)
64
74
  if node.arithmetic_operation?
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for literal assignments in the conditions of `if`, `while`, and `until`.
7
+ # It emulates the following Ruby warning:
8
+ #
9
+ # [source,console]
10
+ # ----
11
+ # $ ruby -we 'if x = true; end'
12
+ # -e:1: warning: found `= literal' in conditional, should be ==
13
+ # ----
14
+ #
15
+ # As a lint cop, it cannot be determined if `==` is appropriate as intended,
16
+ # therefore this cop does not provide autocorrection.
17
+ #
18
+ # @example
19
+ #
20
+ # # bad
21
+ # if x = 42
22
+ # do_something
23
+ # end
24
+ #
25
+ # # good
26
+ # if x == 42
27
+ # do_something
28
+ # end
29
+ #
30
+ # # good
31
+ # if x = y
32
+ # do_something
33
+ # end
34
+ #
35
+ class LiteralAssignmentInCondition < Base
36
+ MSG = "Don't use literal assignment `= %<literal>s` in conditional, " \
37
+ 'should be `==` or non-literal operand.'
38
+
39
+ def on_if(node)
40
+ traverse_node(node.condition) do |asgn_node|
41
+ next unless asgn_node.loc.operator
42
+
43
+ rhs = asgn_node.to_a.last
44
+ next unless rhs.respond_to?(:literal?) && rhs.literal?
45
+
46
+ range = asgn_node.loc.operator.join(rhs.source_range.end)
47
+
48
+ add_offense(range, message: format(MSG, literal: rhs.source))
49
+ end
50
+ end
51
+ alias on_while on_if
52
+ alias on_until on_if
53
+
54
+ private
55
+
56
+ def traverse_node(node, &block)
57
+ yield node if AST::Node::EQUALS_ASSIGNMENTS.include?(node.type)
58
+
59
+ node.each_child_node { |child| traverse_node(child, &block) }
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -94,7 +94,7 @@ module RuboCop
94
94
  parent_node = node.parent
95
95
 
96
96
  add_offense(parent_node) do |corrector|
97
- if parent_node.arguments.last&.block_pass_type?
97
+ if parent_node.last_argument&.block_pass_type?
98
98
  correct_block_pass(corrector, parent_node)
99
99
  else
100
100
  correct_block(corrector, parent_node)
@@ -116,7 +116,7 @@ module RuboCop
116
116
 
117
117
  def correct_block_pass(corrector, node)
118
118
  if unsorted_dir_glob_pass?(node)
119
- block_arg = node.arguments.last
119
+ block_arg = node.last_argument
120
120
 
121
121
  corrector.remove(last_arg_range(node))
122
122
  corrector.insert_after(node, ".sort.each(#{block_arg.source})")
@@ -130,9 +130,7 @@ module RuboCop
130
130
  # @return [Parser::Source::Range]
131
131
  #
132
132
  def last_arg_range(node)
133
- node.arguments.last.source_range.with(
134
- begin_pos: node.arguments[-2].source_range.end_pos
135
- )
133
+ node.last_argument.source_range.with(begin_pos: node.arguments[-2].source_range.end_pos)
136
134
  end
137
135
 
138
136
  def unsorted_dir_loop?(node)
@@ -50,6 +50,22 @@ module RuboCop
50
50
  # # good - without `&.` this will always return `true`
51
51
  # foo&.respond_to?(:to_a)
52
52
  #
53
+ # # bad - for `nil`s conversion methods return default values for the type
54
+ # foo&.to_h || {}
55
+ # foo&.to_h { |k, v| [k, v] } || {}
56
+ # foo&.to_a || []
57
+ # foo&.to_i || 0
58
+ # foo&.to_f || 0.0
59
+ # foo&.to_s || ''
60
+ #
61
+ # # good
62
+ # foo.to_h
63
+ # foo.to_h { |k, v| [k, v] }
64
+ # foo.to_a
65
+ # foo.to_i
66
+ # foo.to_f
67
+ # foo.to_s
68
+ #
53
69
  # @example AllowedMethods: [nil_safe_method]
54
70
  # # bad
55
71
  # do_something if attrs&.nil_safe_method(:[])
@@ -64,6 +80,7 @@ module RuboCop
64
80
  extend AutoCorrector
65
81
 
66
82
  MSG = 'Redundant safe navigation detected.'
83
+ MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
67
84
 
68
85
  NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
69
86
 
@@ -74,6 +91,18 @@ module RuboCop
74
91
  (csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
75
92
  PATTERN
76
93
 
94
+ # @!method conversion_with_default?(node)
95
+ def_node_matcher :conversion_with_default?, <<~PATTERN
96
+ {
97
+ (or $(csend _ :to_h) (hash))
98
+ (or (block $(csend _ :to_h) ...) (hash))
99
+ (or $(csend _ :to_a) (array))
100
+ (or $(csend _ :to_i) (int 0))
101
+ (or $(csend _ :to_f) (float 0.0))
102
+ (or $(csend _ :to_s) (str empty?))
103
+ }
104
+ PATTERN
105
+
77
106
  # rubocop:disable Metrics/AbcSize
78
107
  def on_csend(node)
79
108
  unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
@@ -84,6 +113,20 @@ module RuboCop
84
113
  range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
85
114
  add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
86
115
  end
116
+
117
+ def on_or(node)
118
+ conversion_with_default?(node) do |send_node|
119
+ range = range_between(send_node.loc.dot.begin_pos, node.source_range.end_pos)
120
+
121
+ add_offense(range, message: MSG_LITERAL) do |corrector|
122
+ corrector.replace(send_node.loc.dot, '.')
123
+
124
+ range_with_default = range_between(node.lhs.source_range.end.begin_pos,
125
+ node.source_range.end.end_pos)
126
+ corrector.remove(range_with_default)
127
+ end
128
+ end
129
+ end
87
130
  # rubocop:enable Metrics/AbcSize
88
131
 
89
132
  private
@@ -45,10 +45,9 @@ module RuboCop
45
45
  bad_method?(node) do |safe_nav, method|
46
46
  return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
47
47
 
48
- location =
49
- Parser::Source::Range.new(node.source_range.source_buffer,
50
- safe_nav.source_range.end_pos,
51
- node.source_range.end_pos)
48
+ begin_range = node.loc.dot || safe_nav.source_range.end
49
+ location = begin_range.join(node.source_range.end)
50
+
52
51
  add_offense(location) do |corrector|
53
52
  autocorrect(corrector, offense_range: location, send_node: node)
54
53
  end
@@ -10,11 +10,18 @@ module RuboCop
10
10
  # foo = foo
11
11
  # foo, bar = foo, bar
12
12
  # Foo = Foo
13
+ # hash['foo'] = hash['foo']
14
+ # obj.attr = obj.attr
13
15
  #
14
16
  # # good
15
17
  # foo = bar
16
18
  # foo, bar = bar, foo
17
19
  # Foo = Bar
20
+ # hash['foo'] = hash['bar']
21
+ # obj.attr = obj.attr2
22
+ #
23
+ # # good (method calls possibly can return different results)
24
+ # hash[foo] = hash[foo]
18
25
  #
19
26
  class SelfAssignment < Base
20
27
  MSG = 'Self-assignment detected.'
@@ -26,6 +33,15 @@ module RuboCop
26
33
  gvasgn: :gvar
27
34
  }.freeze
28
35
 
36
+ def on_send(node)
37
+ if node.method?(:[]=)
38
+ handle_key_assignment(node) if node.arguments.size == 2
39
+ elsif node.assignment_method?
40
+ handle_attribute_assignment(node) if node.arguments.size == 1
41
+ end
42
+ end
43
+ alias on_csend on_send
44
+
29
45
  def on_lvasgn(node)
30
46
  lhs, rhs = *node
31
47
  return unless rhs
@@ -72,6 +88,27 @@ module RuboCop
72
88
  rhs.type == ASSIGNMENT_TYPE_TO_RHS_TYPE[lhs.type] &&
73
89
  rhs.children.first == lhs.children.first
74
90
  end
91
+
92
+ def handle_key_assignment(node)
93
+ value_node = node.arguments[1]
94
+
95
+ if value_node.send_type? && value_node.method?(:[]) &&
96
+ node.receiver == value_node.receiver &&
97
+ !node.first_argument.call_type? &&
98
+ node.first_argument == value_node.first_argument
99
+ add_offense(node)
100
+ end
101
+ end
102
+
103
+ def handle_attribute_assignment(node)
104
+ first_argument = node.first_argument
105
+
106
+ if first_argument.call_type? &&
107
+ node.receiver == first_argument.receiver &&
108
+ first_argument.method_name.to_s == node.method_name.to_s.delete_suffix('=')
109
+ add_offense(node)
110
+ end
111
+ end
75
112
  end
76
113
  end
77
114
  end
@@ -19,6 +19,7 @@ module RuboCop
19
19
  # 'underscored_string'.to_sym
20
20
  # :'underscored_symbol'
21
21
  # 'hyphenated-string'.to_sym
22
+ # "string_#{interpolation}".to_sym
22
23
  #
23
24
  # # good
24
25
  # :string
@@ -26,6 +27,7 @@ module RuboCop
26
27
  # :underscored_string
27
28
  # :underscored_symbol
28
29
  # :'hyphenated-string'
30
+ # :"string_#{interpolation}"
29
31
  #
30
32
  # @example EnforcedStyle: strict (default)
31
33
  #
@@ -75,9 +77,12 @@ module RuboCop
75
77
 
76
78
  def on_send(node)
77
79
  return unless node.receiver
78
- return unless node.receiver.str_type? || node.receiver.sym_type?
79
80
 
80
- register_offense(node, correction: node.receiver.value.to_sym.inspect)
81
+ if node.receiver.str_type? || node.receiver.sym_type?
82
+ register_offense(node, correction: node.receiver.value.to_sym.inspect)
83
+ elsif node.receiver.dstr_type?
84
+ register_offense(node, correction: ":\"#{node.receiver.value.to_sym}\"")
85
+ end
81
86
  end
82
87
 
83
88
  def on_sym(node)
@@ -34,7 +34,7 @@ module RuboCop
34
34
  MSG = 'Avoid leaving a trailing comma in attribute declarations.'
35
35
 
36
36
  def on_send(node)
37
- return unless node.attribute_accessor? && node.arguments.last.def_type?
37
+ return unless node.attribute_accessor? && node.last_argument.def_type?
38
38
 
39
39
  trailing_comma = trailing_comma_range(node)
40
40
 
@@ -256,7 +256,7 @@ module RuboCop
256
256
 
257
257
  def any_method_definition?(child)
258
258
  cop_config.fetch('MethodCreatingMethods', []).any? do |m|
259
- matcher_name = "#{m}_method?".to_sym
259
+ matcher_name = :"#{m}_method?"
260
260
  unless respond_to?(matcher_name)
261
261
  self.class.def_node_matcher matcher_name, <<~PATTERN
262
262
  {def (send nil? :#{m} ...)}
@@ -279,7 +279,7 @@ module RuboCop
279
279
 
280
280
  def any_context_creating_methods?(child)
281
281
  cop_config.fetch('ContextCreatingMethods', []).any? do |m|
282
- matcher_name = "#{m}_block?".to_sym
282
+ matcher_name = :"#{m}_block?"
283
283
  unless respond_to?(matcher_name)
284
284
  self.class.def_node_matcher matcher_name, <<~PATTERN
285
285
  ({block numblock} (send {nil? const} {:#{m}} ...) ...)
@@ -144,7 +144,7 @@ module RuboCop
144
144
  end
145
145
 
146
146
  def check_literal(node)
147
- return if !node.literal? || node.xstr_type? || node.range_type?
147
+ return if !entirely_literal?(node) || node.xstr_type? || node.range_type?
148
148
 
149
149
  add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
150
150
  autocorrect_void_expression(corrector, node)
@@ -217,6 +217,19 @@ module RuboCop
217
217
  end
218
218
  corrector.replace(send_node.loc.selector, suggestion)
219
219
  end
220
+
221
+ def entirely_literal?(node)
222
+ case node.type
223
+ when :array
224
+ node.each_value.all? { |value| entirely_literal?(value) }
225
+ when :hash
226
+ return false unless node.each_key.all? { |key| entirely_literal?(key) }
227
+
228
+ node.each_value.all? { |value| entirely_literal?(value) }
229
+ else
230
+ node.literal?
231
+ end
232
+ end
220
233
  end
221
234
  end
222
235
  end
@@ -218,7 +218,7 @@ module RuboCop
218
218
 
219
219
  # @api private
220
220
  def already_on_multiple_lines?(node)
221
- return node.first_line != node.arguments.last.last_line if node.def_type?
221
+ return node.first_line != node.last_argument.last_line if node.def_type?
222
222
 
223
223
  !node.single_line?
224
224
  end
@@ -79,7 +79,7 @@ module RuboCop
79
79
  end
80
80
 
81
81
  def aligned_operator?(range, line)
82
- (aligned_identical?(range, line) || aligned_assignment?(range, line))
82
+ aligned_identical?(range, line) || aligned_assignment?(range, line)
83
83
  end
84
84
 
85
85
  def aligned_words?(range, line)
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def space_required_after?(token)
39
- token.left_curly_brace? && space_required_after_lcurly?
39
+ (token.left_curly_brace? || token.type == :tLAMBEG) && space_required_after_lcurly?
40
40
  end
41
41
 
42
42
  def space_required_after_lcurly?
@@ -48,13 +48,13 @@ module RuboCop
48
48
  MSG = 'Use %<style>s block forwarding.'
49
49
 
50
50
  def self.autocorrect_incompatible_with
51
- [Lint::AmbiguousOperator]
51
+ [Lint::AmbiguousOperator, Style::ArgumentsForwarding]
52
52
  end
53
53
 
54
54
  def on_def(node)
55
55
  return if node.arguments.empty?
56
56
 
57
- last_argument = node.arguments.last
57
+ last_argument = node.last_argument
58
58
  return if expected_block_forwarding_style?(node, last_argument)
59
59
 
60
60
  register_offense(last_argument, node)
@@ -203,7 +203,7 @@ module RuboCop
203
203
 
204
204
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
205
205
  def on_defined?(node)
206
- arg = node.arguments.first
206
+ arg = node.first_argument
207
207
  return false unless arg.ivar_type?
208
208
 
209
209
  method_node, method_name = find_definition(node)
@@ -168,12 +168,12 @@ module RuboCop
168
168
 
169
169
  def find_corresponding_def_node(node)
170
170
  if access_modifier_with_symbol?(node)
171
- method_name = node.arguments.first.value
171
+ method_name = node.first_argument.value
172
172
  node.parent.each_child_node(:def).find do |child|
173
173
  child.method?(method_name)
174
174
  end
175
175
  else
176
- node.arguments.first
176
+ node.first_argument
177
177
  end
178
178
  end
179
179
 
@@ -166,7 +166,7 @@ module RuboCop
166
166
  *processed_source.ast_with_comments[arg].map(&:text),
167
167
  "#{node.method_name} #{arg.source}"
168
168
  ]
169
- if arg == node.arguments.first
169
+ if arg == node.first_argument
170
170
  lines
171
171
  else
172
172
  indent = ' ' * node.loc.column
@@ -12,7 +12,16 @@ module RuboCop
12
12
  #
13
13
  # This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
14
14
  # replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
15
- # by setting UseAnonymousForwarding: false.
15
+ # by setting `UseAnonymousForwarding: false`.
16
+ #
17
+ # And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
18
+ # and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
19
+ # that are sufficient for anonymizing meaningless naming.
20
+ #
21
+ # Meaningless names that are commonly used can be anonymized by default:
22
+ # e.g., `*args`, `**options`, `&block`, and so on.
23
+ #
24
+ # Names not on this list are likely to be meaningful and are allowed by default.
16
25
  #
17
26
  # @example
18
27
  # # bad
@@ -72,6 +81,38 @@ module RuboCop
72
81
  # bar(**kwargs)
73
82
  # end
74
83
  #
84
+ # @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
85
+ # # bad
86
+ # def foo(*args)
87
+ # bar(*args)
88
+ # end
89
+ #
90
+ # # good
91
+ # def foo(*)
92
+ # bar(*)
93
+ # end
94
+ #
95
+ # @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
96
+ # # bad
97
+ # def foo(**kwargs)
98
+ # bar(**kwargs)
99
+ # end
100
+ #
101
+ # # good
102
+ # def foo(**)
103
+ # bar(**)
104
+ # end
105
+ #
106
+ # @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
107
+ # # bad
108
+ # def foo(&block)
109
+ # bar(&block)
110
+ # end
111
+ #
112
+ # # good
113
+ # def foo(&)
114
+ # bar(&)
115
+ # end
75
116
  class ArgumentsForwarding < Base
76
117
  include RangeHelp
77
118
  extend AutoCorrector
@@ -86,16 +127,19 @@ module RuboCop
86
127
  ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
87
128
  KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
88
129
 
130
+ def self.autocorrect_incompatible_with
131
+ [Naming::BlockForwarding]
132
+ end
133
+
89
134
  def on_def(node)
90
135
  return unless node.body
91
136
 
92
- forwardable_args = extract_forwardable_args(node.arguments)
137
+ restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
138
+ forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
139
+ send_nodes = node.each_descendant(:send).to_a
93
140
 
94
141
  send_classifications = classify_send_nodes(
95
- node,
96
- node.each_descendant(:send).to_a,
97
- non_splat_or_block_pass_lvar_references(node.body),
98
- forwardable_args
142
+ node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
99
143
  )
100
144
 
101
145
  return if send_classifications.empty?
@@ -115,6 +159,14 @@ module RuboCop
115
159
  [args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
116
160
  end
117
161
 
162
+ def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
163
+ restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
164
+ kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
165
+ blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
166
+
167
+ [restarg_node, kwrestarg_node, blockarg_node]
168
+ end
169
+
118
170
  def only_forwards_all?(send_classifications)
119
171
  send_classifications.all? { |_, c, _, _| c == :all }
120
172
  end
@@ -188,6 +240,16 @@ module RuboCop
188
240
  [classification, classifier.forwarded_rest_arg, classifier.forwarded_kwrest_arg]
189
241
  end
190
242
 
243
+ def redundant_named_arg(arg, config_name, keyword)
244
+ return nil unless arg
245
+
246
+ redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
247
+ "#{keyword}#{redundant_arg_name}"
248
+ end << keyword
249
+
250
+ redundant_arg_names.include?(arg.source) ? arg : nil
251
+ end
252
+
191
253
  def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
192
254
  add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
193
255
  add_parens_if_missing(def_arguments_or_send, corrector)