rubocop 1.6.1 → 1.9.1

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -3
  4. data/config/default.yml +145 -19
  5. data/lib/rubocop.rb +16 -1
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  7. data/lib/rubocop/comment_config.rb +6 -6
  8. data/lib/rubocop/config.rb +13 -7
  9. data/lib/rubocop/config_loader.rb +11 -14
  10. data/lib/rubocop/config_loader_resolver.rb +21 -4
  11. data/lib/rubocop/config_obsoletion.rb +5 -3
  12. data/lib/rubocop/config_store.rb +12 -1
  13. data/lib/rubocop/cop/base.rb +2 -1
  14. data/lib/rubocop/cop/exclude_limit.rb +26 -0
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  16. data/lib/rubocop/cop/generator.rb +1 -3
  17. data/lib/rubocop/cop/internal_affairs.rb +6 -1
  18. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  19. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  21. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  22. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  24. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +56 -20
  25. data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
  27. data/lib/rubocop/cop/layout/line_length.rb +2 -1
  28. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  29. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  30. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  31. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  32. data/lib/rubocop/cop/layout/space_before_brackets.rb +67 -0
  33. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  34. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  35. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  36. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  37. data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
  38. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  39. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  40. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  41. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  42. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  43. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  45. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  46. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  47. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  48. data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
  49. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  50. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  51. data/lib/rubocop/cop/message_annotator.rb +4 -1
  52. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  53. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  54. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  55. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  56. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  57. data/lib/rubocop/cop/mixin/code_length.rb +3 -1
  58. data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
  59. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  60. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  61. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
  62. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  63. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  64. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  65. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  66. data/lib/rubocop/cop/naming/variable_number.rb +2 -9
  67. data/lib/rubocop/cop/registry.rb +10 -0
  68. data/lib/rubocop/cop/severity.rb +3 -3
  69. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  70. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  71. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  72. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  73. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  74. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  75. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  76. data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
  77. data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
  78. data/lib/rubocop/cop/style/float_division.rb +3 -0
  79. data/lib/rubocop/cop/style/for.rb +2 -0
  80. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  81. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  82. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  83. data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
  84. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
  85. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  86. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  87. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  88. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  89. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  90. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  91. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  92. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  93. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  94. data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
  95. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  96. data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
  97. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  98. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  99. data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
  100. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  101. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  102. data/lib/rubocop/cop/style/single_line_methods.rb +36 -2
  103. data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
  104. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  105. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  106. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  107. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  108. data/lib/rubocop/cop/util.rb +3 -1
  109. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  110. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
  111. data/lib/rubocop/magic_comment.rb +30 -1
  112. data/lib/rubocop/options.rb +10 -10
  113. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  114. data/lib/rubocop/rspec/expect_offense.rb +37 -22
  115. data/lib/rubocop/runner.rb +17 -1
  116. data/lib/rubocop/target_finder.rb +4 -2
  117. data/lib/rubocop/target_ruby.rb +47 -11
  118. data/lib/rubocop/util.rb +16 -0
  119. data/lib/rubocop/version.rb +8 -2
  120. metadata +27 -7
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks uses of lambda without a literal block.
7
+ # It emulates the following warning in Ruby 3.0:
8
+ #
9
+ # % ruby -vwe 'lambda(&proc {})'
10
+ # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
11
+ # -e:1: warning: lambda without a literal block is deprecated; use the proc without
12
+ # lambda instead
13
+ #
14
+ # This way, proc object is never converted to lambda.
15
+ # Auto-correction replaces with compatible proc argument.
16
+ #
17
+ # @example
18
+ #
19
+ # # bad
20
+ # lambda(&proc { do_something })
21
+ # lambda(&Proc.new { do_something })
22
+ #
23
+ # # good
24
+ # proc { do_something }
25
+ # Proc.new { do_something }
26
+ # lambda { do_something } # If you use lambda.
27
+ #
28
+ class LambdaWithoutLiteralBlock < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'lambda without a literal block is deprecated; use the proc without lambda instead.'
32
+ RESTRICT_ON_SEND = %i[lambda].freeze
33
+
34
+ def on_send(node)
35
+ return if node.parent&.block_type? || !node.first_argument
36
+
37
+ add_offense(node) do |corrector|
38
+ corrector.replace(node, node.first_argument.source.delete('&'))
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -11,6 +11,11 @@ module RuboCop
11
11
  # that are hard to debug. To ensure this doesn't happen,
12
12
  # always sort the list.
13
13
  #
14
+ # `Dir.glob` and `Dir[]` sort globbed results by default in Ruby 3.0.
15
+ # So all bad cases are acceptable when Ruby 3.0 or higher are used.
16
+ #
17
+ # This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.
18
+ #
14
19
  # @example
15
20
  #
16
21
  # # bad
@@ -23,8 +28,6 @@ module RuboCop
23
28
  # require file
24
29
  # end
25
30
  #
26
- # @example
27
- #
28
31
  # # bad
29
32
  # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')) do |file|
30
33
  # require file
@@ -35,28 +38,28 @@ module RuboCop
35
38
  # require file
36
39
  # end
37
40
  #
38
- # @example
39
- #
40
41
  # # bad
41
42
  # Dir['./lib/**/*.rb'].each(&method(:require))
42
43
  #
43
44
  # # good
44
45
  # Dir['./lib/**/*.rb'].sort.each(&method(:require))
45
46
  #
46
- # @example
47
- #
48
47
  # # bad
49
48
  # Dir.glob(Rails.root.join('test', '*.rb'), &method(:require))
50
49
  #
51
50
  # # good
52
51
  # Dir.glob(Rails.root.join('test', '*.rb')).sort.each(&method(:require))
53
52
  #
53
+ # # good - Respect intent if `sort` keyword option is specified in Ruby 3.0 or higher.
54
+ # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb'), sort: false).each(&method(:require))
55
+ #
54
56
  class NonDeterministicRequireOrder < Base
55
57
  extend AutoCorrector
56
58
 
57
59
  MSG = 'Sort files before requiring them.'
58
60
 
59
61
  def on_block(node)
62
+ return if target_ruby_version >= 3.0
60
63
  return unless node.body
61
64
  return unless unsorted_dir_loop?(node.send_node)
62
65
 
@@ -70,6 +73,7 @@ module RuboCop
70
73
  end
71
74
 
72
75
  def on_block_pass(node)
76
+ return if target_ruby_version >= 3.0
73
77
  return unless method_require?(node)
74
78
  return unless unsorted_dir_pass?(node.parent)
75
79
 
@@ -25,12 +25,18 @@ module RuboCop
25
25
  # '10'.to_i
26
26
  # '10.2'.to_f
27
27
  # '10'.to_c
28
+ # ['1', '2', '3'].map(&:to_i)
29
+ # foo.try(:to_f)
30
+ # bar.send(:to_c)
28
31
  #
29
32
  # # good
30
33
  #
31
34
  # Integer('10', 10)
32
35
  # Float('10.2')
33
36
  # Complex('10')
37
+ # ['1', '2', '3'].map { |i| Integer(i, 10) }
38
+ # foo.try { |i| Float(i) }
39
+ # bar.send { |i| Complex(i) }
34
40
  #
35
41
  # @example IgnoredMethods: [minutes]
36
42
  #
@@ -52,22 +58,33 @@ module RuboCop
52
58
  }.freeze
53
59
  MSG = 'Replace unsafe number conversion with number '\
54
60
  'class parsing, instead of using '\
55
- '%<number_object>s.%<to_method>s, use stricter '\
61
+ '%<current>s, use stricter '\
56
62
  '%<corrected_method>s.'
57
- RESTRICT_ON_SEND = CONVERSION_METHOD_CLASS_MAPPING.keys.freeze
63
+ METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
58
64
 
59
65
  def_node_matcher :to_method, <<~PATTERN
60
- (send $_ ${:to_i :to_f :to_c})
66
+ (send $_ ${#{METHODS}})
67
+ PATTERN
68
+
69
+ def_node_matcher :to_method_symbol, <<~PATTERN
70
+ {(send _ $_ ${(sym ${#{METHODS}})} ...)
71
+ (send _ $_ ${(block_pass (sym ${#{METHODS}}))} ...)}
61
72
  PATTERN
62
73
 
63
74
  def on_send(node)
75
+ handle_conversion_method(node)
76
+ handle_as_symbol(node)
77
+ end
78
+
79
+ private
80
+
81
+ def handle_conversion_method(node)
64
82
  to_method(node) do |receiver, to_method|
65
83
  next if receiver.nil? || ignore_receiver?(receiver)
66
84
 
67
85
  message = format(
68
86
  MSG,
69
- number_object: receiver.source,
70
- to_method: to_method,
87
+ current: "#{receiver.source}.#{to_method}",
71
88
  corrected_method: correct_method(node, receiver)
72
89
  )
73
90
  add_offense(node, message: message) do |corrector|
@@ -76,13 +93,31 @@ module RuboCop
76
93
  end
77
94
  end
78
95
 
79
- private
96
+ def handle_as_symbol(node)
97
+ to_method_symbol(node) do |receiver, sym_node, to_method|
98
+ next if receiver.nil?
99
+
100
+ message = format(
101
+ MSG,
102
+ current: sym_node.source,
103
+ corrected_method: correct_sym_method(to_method)
104
+ )
105
+ add_offense(node, message: message) do |corrector|
106
+ corrector.replace(sym_node, correct_sym_method(to_method))
107
+ end
108
+ end
109
+ end
80
110
 
81
111
  def correct_method(node, receiver)
82
112
  format(CONVERSION_METHOD_CLASS_MAPPING[node.method_name],
83
113
  number_object: receiver.source)
84
114
  end
85
115
 
116
+ def correct_sym_method(to_method)
117
+ body = format(CONVERSION_METHOD_CLASS_MAPPING[to_method], number_object: 'i')
118
+ "{ |i| #{body} }"
119
+ end
120
+
86
121
  def ignore_receiver?(receiver)
87
122
  if receiver.send_type? && ignored_method?(receiver.method_name)
88
123
  true
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for uses of numbered parameter assignment.
7
+ # It emulates the following warning in Ruby 2.7:
8
+ #
9
+ # % ruby -ve '_1 = :value'
10
+ # ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
11
+ # -e:1: warning: `_1' is reserved for numbered parameter; consider another name
12
+ #
13
+ # Assiging to numbered parameter (from `_1` to `_9`) cause an error in Ruby 3.0.
14
+ #
15
+ # % ruby -ve '_1 = :value'
16
+ # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
17
+ # -e:1: _1 is reserved for numbered parameter
18
+ #
19
+ # NOTE: The parametered parameters are from `_1` to `_9`. This cop checks `_0`, and over `_10`
20
+ # as well to prevent confusion.
21
+ #
22
+ # @example
23
+ #
24
+ # # bad
25
+ # _1 = :value
26
+ #
27
+ # # good
28
+ # non_numbered_parameter_name = :value
29
+ #
30
+ class NumberedParameterAssignment < Base
31
+ NUM_PARAM_MSG = '`_%<number>s` is reserved for numbered parameter; consider another name.'
32
+ LVAR_MSG = '`_%<number>s` is similar to numbered parameter; consider another name.'
33
+ NUMBERED_PARAMETER_RANGE = (1..9).freeze
34
+
35
+ def on_lvasgn(node)
36
+ lhs, _rhs = *node
37
+ return unless /\A_(\d+)\z/ =~ lhs
38
+
39
+ number = Regexp.last_match(1).to_i
40
+ template = NUMBERED_PARAMETER_RANGE.include?(number) ? NUM_PARAM_MSG : LVAR_MSG
41
+
42
+ add_offense(node, message: format(template, number: number))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for unintended or-assignment to a constant.
7
+ #
8
+ # Constants should always be assigned in the same location. And its value
9
+ # should always be the same. If constants are assigned in multiple
10
+ # locations, the result may vary depending on the order of `require`.
11
+ #
12
+ # Also, if you already have such an implementation, auto-correction may
13
+ # change the result.
14
+ #
15
+ # @example
16
+ #
17
+ # # bad
18
+ # CONST ||= 1
19
+ #
20
+ # # good
21
+ # CONST = 1
22
+ #
23
+ class OrAssignmentToConstant < Base
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Avoid using or-assignment with constants.'
27
+
28
+ def on_or_asgn(node)
29
+ lhs, _rhs = *node
30
+ return unless lhs&.casgn_type?
31
+
32
+ add_offense(node.loc.operator) do |corrector|
33
+ corrector.replace(node.loc.operator, '=')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -61,7 +61,8 @@ module RuboCop
61
61
  end
62
62
 
63
63
  def comment_range_with_surrounding_space(range)
64
- if previous_line_blank?(range)
64
+ if previous_line_blank?(range) &&
65
+ processed_source.comment_config.comment_only_line?(range.line)
65
66
  # When the previous line is blank, it should be retained
66
67
  range_with_surrounding_space(range: range, side: :right)
67
68
  else
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Sort globbed results by default in Ruby 3.0.
7
+ # This cop checks for redundant `sort` method to `Dir.glob` and `Dir[]`.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Dir.glob('./lib/**/*.rb').sort.each do |file|
13
+ # end
14
+ #
15
+ # Dir['./lib/**/*.rb'].sort.each do |file|
16
+ # end
17
+ #
18
+ # # good
19
+ # Dir.glob('./lib/**/*.rb').each do |file|
20
+ # end
21
+ #
22
+ # Dir['./lib/**/*.rb'].each do |file|
23
+ # end
24
+ #
25
+ class RedundantDirGlobSort < Base
26
+ extend AutoCorrector
27
+ extend TargetRubyVersion
28
+
29
+ minimum_target_ruby_version 3.0
30
+
31
+ MSG = 'Remove redundant `sort`.'
32
+ RESTRICT_ON_SEND = %i[sort].freeze
33
+ GLOB_METHODS = %i[glob []].freeze
34
+
35
+ def on_send(node)
36
+ return unless (receiver = node.receiver)
37
+ return unless receiver.receiver&.const_type? && receiver.receiver.short_name == :Dir
38
+ return unless GLOB_METHODS.include?(receiver.method_name)
39
+
40
+ selector = node.loc.selector
41
+
42
+ add_offense(selector) do |corrector|
43
+ corrector.remove(selector)
44
+ corrector.remove(node.loc.dot)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -8,47 +8,66 @@ module RuboCop
8
8
  # @example
9
9
  #
10
10
  # # bad
11
- #
12
11
  # a = *[1, 2, 3]
13
12
  # a = *'a'
14
13
  # a = *1
15
- #
16
- # begin
17
- # foo
18
- # rescue *[StandardError, ApplicationError]
19
- # bar
20
- # end
21
- #
22
- # case foo
23
- # when *[1, 2, 3]
24
- # bar
25
- # else
26
- # baz
27
- # end
28
- #
29
- # @example
14
+ # ['a', 'b', *%w(c d e), 'f', 'g']
30
15
  #
31
16
  # # good
32
- #
33
17
  # c = [1, 2, 3]
34
18
  # a = *c
35
19
  # a, b = *c
36
20
  # a, *b = *c
37
21
  # a = *1..10
38
22
  # a = ['a']
23
+ # ['a', 'b', 'c', 'd', 'e', 'f', 'g']
39
24
  #
25
+ # # bad
26
+ # do_something(*['foo', 'bar', 'baz'])
27
+ #
28
+ # # good
29
+ # do_something('foo', 'bar', 'baz')
30
+ #
31
+ # # bad
32
+ # begin
33
+ # foo
34
+ # rescue *[StandardError, ApplicationError]
35
+ # bar
36
+ # end
37
+ #
38
+ # # good
40
39
  # begin
41
40
  # foo
42
41
  # rescue StandardError, ApplicationError
43
42
  # bar
44
43
  # end
45
44
  #
45
+ # # bad
46
+ # case foo
47
+ # when *[1, 2, 3]
48
+ # bar
49
+ # else
50
+ # baz
51
+ # end
52
+ #
53
+ # # good
46
54
  # case foo
47
55
  # when 1, 2, 3
48
56
  # bar
49
57
  # else
50
58
  # baz
51
59
  # end
60
+ #
61
+ # @example AllowPercentLiteralArrayArgument: true (default)
62
+ #
63
+ # # good
64
+ # do_something(*%w[foo bar baz])
65
+ #
66
+ # @example AllowPercentLiteralArrayArgument: false
67
+ #
68
+ # # bad
69
+ # do_something(*%w[foo bar baz])
70
+ #
52
71
  class RedundantSplatExpansion < Base
53
72
  extend AutoCorrector
54
73
 
@@ -75,6 +94,9 @@ module RuboCop
75
94
  redundant_splat_expansion(node) do
76
95
  if array_splat?(node) &&
77
96
  (method_argument?(node) || part_of_an_array?(node))
97
+ return if allow_percent_literal_array_argument? &&
98
+ use_percent_literal_array_argument?(node)
99
+
78
100
  add_offense(node, message: ARRAY_PARAM_MSG) do |corrector|
79
101
  autocorrect(corrector, node)
80
102
  end
@@ -170,6 +192,17 @@ module RuboCop
170
192
  elements.join(', ')
171
193
  end
172
194
  end
195
+
196
+ def use_percent_literal_array_argument?(node)
197
+ argument = node.children.first
198
+
199
+ node.parent.send_type? &&
200
+ (argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
201
+ end
202
+
203
+ def allow_percent_literal_array_argument?
204
+ cop_config.fetch('AllowPercentLiteralArrayArgument', true)
205
+ end
173
206
  end
174
207
  end
175
208
  end