Skip to content

Commit

Permalink
Add new Style/RedundantArrayConstructor cop
Browse files Browse the repository at this point in the history
Follow up #11874 (comment).

Checks for the instantiation of array using redundant `Array` constructor.
Autocorrect replaces to array literal which is the simplest and fastest.

```ruby
# bad
Array.new([])
Array[]
Array([])
Array.new(['foo', 'foo', 'foo'])
Array['foo', 'foo', 'foo']
Array(['foo', 'foo', 'foo'])

# good
[]
['foo', 'foo', 'foo']
Array.new(3, 'foo')
Array.new(3) { 'foo' }
```
  • Loading branch information
koic authored and bbatsov committed Jun 2, 2023
1 parent 356fc46 commit a01fd9c
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#11886](https://github.com/rubocop/rubocop/pull/11886): Add new `Style/RedundantArrayConstructor` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4806,6 +4806,11 @@ Style/RedundantArgument:
# String#chomp!
chomp!: "\n"

Style/RedundantArrayConstructor:
Description: 'Checks for the instantiation of array using redundant `Array` constructor.'
Enabled: pending
VersionAdded: '<<next>>'

Style/RedundantAssignment:
Description: 'Checks for redundant assignment before returning.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@
require_relative 'rubocop/cop/style/numbered_parameters'
require_relative 'rubocop/cop/style/open_struct_use'
require_relative 'rubocop/cop/style/operator_method_call'
require_relative 'rubocop/cop/style/redundant_array_constructor'
require_relative 'rubocop/cop/style/redundant_assignment'
require_relative 'rubocop/cop/style/redundant_constant_base'
require_relative 'rubocop/cop/style/redundant_double_splat_hash_braces'
Expand Down
77 changes: 77 additions & 0 deletions lib/rubocop/cop/style/redundant_array_constructor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# Checks for the instantiation of array using redundant `Array` constructor.
# Autocorrect replaces to array literal which is the simplest and fastest.
#
# @example
#
# # bad
# Array.new([])
# Array[]
# Array([])
# Array.new(['foo', 'foo', 'foo'])
# Array['foo', 'foo', 'foo']
# Array(['foo', 'foo', 'foo'])
#
# # good
# []
# ['foo', 'foo', 'foo']
# Array.new(3, 'foo')
# Array.new(3) { 'foo' }
#
class RedundantArrayConstructor < Base
extend AutoCorrector

MSG = 'Remove the redundant `Array` constructor.'

RESTRICT_ON_SEND = %i[new [] Array].freeze

# @!method redundant_array_constructor(node)
def_node_matcher :redundant_array_constructor, <<~PATTERN
{
(send
(const {nil? cbase} :Array) :new
$(array ...))
(send
(const {nil? cbase} :Array) :[]
$...)
(send
nil? :Array
$(array ...))
}
PATTERN

def on_send(node)
return unless (array_literal = redundant_array_constructor(node))

receiver = node.receiver
selector = node.loc.selector

if node.method?(:new)
range = receiver.source_range.join(selector)
replacement = array_literal
elsif node.method?(:Array)
range = selector
replacement = array_literal
else
range = receiver
replacement = selector.begin.join(node.source_range.end)
end

register_offense(range, node, replacement)
end

private

def register_offense(range, node, replacement)
add_offense(range) do |corrector|
corrector.replace(node, replacement.source)
end
end
end
end
end
end
121 changes: 121 additions & 0 deletions spec/rubocop/cop/style/redundant_array_constructor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Style::RedundantArrayConstructor, :config do
it 'registers an offense when using an empty array literal argument for `Array.new`' do
expect_offense(<<~RUBY)
Array.new([])
^^^^^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
[]
RUBY
end

it 'registers an offense when using an empty array literal argument for `::Array.new`' do
expect_offense(<<~RUBY)
::Array.new([])
^^^^^^^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
[]
RUBY
end

it 'registers an offense when using an empty array literal argument for `Array[]`' do
expect_offense(<<~RUBY)
Array[]
^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
[]
RUBY
end

it 'registers an offense when using an empty array literal argument for `::Array[]`' do
expect_offense(<<~RUBY)
::Array[]
^^^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
[]
RUBY
end

it 'registers an offense when using an empty array literal argument for `Array([])`' do
expect_offense(<<~RUBY)
Array([])
^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
[]
RUBY
end

it 'registers an offense when using an array literal with some elements as an argument for `Array.new`' do
expect_offense(<<~RUBY)
Array.new(['foo', 'bar', 'baz'])
^^^^^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
['foo', 'bar', 'baz']
RUBY
end

it 'registers an offense when using an array literal with some elements as an argument for `Array[]`' do
expect_offense(<<~RUBY)
Array['foo', 'bar', 'baz']
^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
['foo', 'bar', 'baz']
RUBY
end

it 'registers an offense when using an array literal with some elements as an argument for `Array([])`' do
expect_offense(<<~RUBY)
Array(['foo', 'bar', 'baz'])
^^^^^ Remove the redundant `Array` constructor.
RUBY

expect_correction(<<~RUBY)
['foo', 'bar', 'baz']
RUBY
end

it 'does not register an offense when using an array literal' do
expect_no_offenses(<<~RUBY)
[]
RUBY
end

it 'does not register an offense when using single argument for `Array.new`' do
expect_no_offenses(<<~RUBY)
Array.new(array)
RUBY
end

it 'does not register an offense when using single argument for `Array()`' do
expect_no_offenses(<<~RUBY)
Array(array)
RUBY
end

it 'does not register an offense when using two argument for `Array.new`' do
expect_no_offenses(<<~RUBY)
Array.new(3, 'foo')
RUBY
end

it 'does not register an offense when using block argument for `Array.new`' do
expect_no_offenses(<<~RUBY)
Array.new(3) { 'foo' }
RUBY
end
end

0 comments on commit a01fd9c

Please sign in to comment.