Skip to content

Commit

Permalink
[Fix #9290] Fix a false positive for Layout/SpaceBeforeBrackets
Browse files Browse the repository at this point in the history
Fixes #9290.

This PR fixes a false positive for `Layout/SpaceBeforeBrackets`
when using array literal argument for method call.

If receiver is a method call, it is difficult to prevent false positives.
Therefore, This PR change behaviour to detect only when receiver is a variable.

As a result, safe detection is possible.
  • Loading branch information
koic authored and bbatsov committed Dec 27, 2020
1 parent c1b7dce commit 4114691
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9290](https://github.com/rubocop-hq/rubocop/issues/9290): Fix a false positive for `Layout/SpaceBeforeBrackets` when using array literal method argument. ([@koic][])
1 change: 0 additions & 1 deletion config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,6 @@ Layout/SpaceBeforeBrackets:
StyleGuide: '#space-in-brackets-access'
Enabled: pending
VersionAdded: '1.7'
Safe: false

Layout/SpaceBeforeComma:
Description: 'No spaces before commas.'
Expand Down
22 changes: 10 additions & 12 deletions lib/rubocop/cop/layout/space_before_brackets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ module Layout
# Checks for space between the name of a receiver and a left
# brackets.
#
# This cop is marked as unsafe because it can occur false positives
# for `do_something [this_is_an_array_literal_argument]` that take
# an array without parentheses as an argument.
#
# @example
#
# # bad
Expand All @@ -25,21 +21,23 @@ class SpaceBeforeBrackets < Base
MSG = 'Remove the space before the opening brackets.'

def on_send(node)
return if node.parenthesized? || node.parent&.send_type?
return unless (first_argument = node.first_argument)

begin_pos = first_argument.source_range.begin_pos

return unless (range = offense_range(node, first_argument, begin_pos))
return unless (range = offense_range(node, begin_pos))

register_offense(range)
end

private

def offense_range(node, first_argument, begin_pos)
if space_before_brackets?(node, first_argument)
range_between(node.loc.selector.end_pos, begin_pos)
def offense_range(node, begin_pos)
if reference_variable_with_brackets?(node)
receiver_end_pos = node.receiver.source_range.end_pos
selector_begin_pos = node.loc.selector.begin_pos
return if receiver_end_pos >= selector_begin_pos

range_between(receiver_end_pos, selector_begin_pos)
elsif node.method?(:[]=)
end_pos = node.receiver.source_range.end_pos

Expand All @@ -55,8 +53,8 @@ def register_offense(range)
end
end

def space_before_brackets?(node, first_argument)
node.receiver.nil? && first_argument.array_type? && node.arguments.size == 1
def reference_variable_with_brackets?(node)
node.receiver&.variable? && node.method?(:[]) && node.arguments.size == 1
end
end
end
Expand Down
66 changes: 63 additions & 3 deletions spec/rubocop/cop/layout/space_before_brackets_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,74 @@
subject(:cop) { described_class.new(config) }

context 'when referencing' do
it 'registers an offense and corrects when using space between receiver and left brackets' do
it 'registers an offense and corrects when using space between lvar receiver and left brackets' do
expect_offense(<<~RUBY)
collection = do_something
collection [index_or_key]
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
collection = do_something
collection[index_or_key]
RUBY
end

it 'does not register an offense when not using space between receiver and left brackets' do
it 'registers an offense and corrects when using space between ivar receiver and left brackets' do
expect_offense(<<~RUBY)
@collection [index_or_key]
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
@collection[index_or_key]
RUBY
end

it 'registers an offense and corrects when using space between cvar receiver and left brackets' do
expect_offense(<<~RUBY)
@@collection [index_or_key]
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
@@collection[index_or_key]
RUBY
end

it 'registers an offense and corrects when using space between gvar receiver and left brackets' do
expect_offense(<<~RUBY)
$collection [index_or_key]
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
$collection[index_or_key]
RUBY
end

it 'does not register an offense when using space between method call and left brackets' do
expect_no_offenses(<<~RUBY)
do_something [item_of_array_literal]
RUBY
end

it 'does not register an offense when not using space between variable receiver and left brackets' do
expect_no_offenses(<<~RUBY)
collection = do_something
collection[index_or_key]
RUBY
end

it 'does not register an offense when not using space between method call and left brackets' do
expect_no_offenses(<<~RUBY)
do_something[item_of_array_literal]
RUBY
end

it 'does not register an offense when array literal argument is enclosed in parentheses' do
expect_no_offenses(<<~RUBY)
collection([index_or_key])
do_something([item_of_array_literal])
RUBY
end

Expand Down Expand Up @@ -70,4 +118,16 @@
task.options = ['--no-output']
RUBY
end

it 'does not register an offense when using array literal argument without parentheses' do
expect_no_offenses(<<~RUBY)
before_validation { to_downcase ['email'] }
RUBY
end

it 'does not register an offense when using percent array literal argument without parentheses' do
expect_no_offenses(<<~RUBY)
before_validation { to_downcase %w[email] }
RUBY
end
end

0 comments on commit 4114691

Please sign in to comment.