Skip to content

Commit

Permalink
[Fix rubocop#10883] Fix Style/RedundantParentheses to be able to de…
Browse files Browse the repository at this point in the history
…tect offenses and properly correct when the end parentheses and comma are on their own line.
  • Loading branch information
dvandersluis committed Aug 9, 2022
1 parent b806ff2 commit 838ec41
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 43 deletions.
1 change: 1 addition & 0 deletions changelog/fix_fix_styleredundantparentheses_to_be_able.md
@@ -0,0 +1 @@
* [#10883](https://github.com/rubocop/rubocop/issues/10883): Fix `Style/RedundantParentheses` to be able to detect offenses and properly correct when the end parentheses and comma are on their own line. ([@dvandersluis][])
28 changes: 28 additions & 0 deletions lib/rubocop/cop/correctors/parentheses_corrector.rb
Expand Up @@ -5,9 +5,13 @@ module Cop
# This autocorrects parentheses
class ParenthesesCorrector
class << self
include RangeHelp

def correct(corrector, node)
corrector.remove(node.loc.begin)
corrector.remove(node.loc.end)
handle_orphaned_comma(corrector, node)

return unless ternary_condition?(node) && next_char_is_question_mark?(node)

corrector.insert_after(node.loc.end, ' ')
Expand All @@ -22,6 +26,30 @@ def ternary_condition?(node)
def next_char_is_question_mark?(node)
node.loc.last_column == node.parent.loc.question.column
end

def only_closing_paren_before_comma?(node)
source_buffer = node.source_range.source_buffer
line_range = source_buffer.line_range(node.loc.end.line)

line_range.source.start_with?(/\s*\)\s*,/)
end

# If removing parentheses leaves a comma on its own line, remove all the whitespace
# preceding it to prevent a syntax error.
def handle_orphaned_comma(corrector, node)
return unless only_closing_paren_before_comma?(node)

range = range_with_surrounding_space(
range: node.loc.end,
buffer: node.source_range.source_buffer,
side: :left,
newlines: true,
whitespace: true,
continuations: true
)

corrector.remove(range)
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/rubocop/cop/mixin/range_help.rb
Expand Up @@ -54,11 +54,11 @@ def range_with_surrounding_comma(range, side = :both)
NOT_GIVEN = Module.new
def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
range: NOT_GIVEN, side: :both, newlines: true,
whitespace: false, continuations: false)
whitespace: false, continuations: false,
buffer: @processed_source.buffer)

range = range_positional unless range_positional == NOT_GIVEN

buffer = @processed_source.buffer
src = buffer.source

go_left, go_right = directions(side)
Expand Down
21 changes: 0 additions & 21 deletions lib/rubocop/cop/style/redundant_parentheses.rb
Expand Up @@ -57,7 +57,6 @@ def ignore_syntax?(node)
def allowed_expression?(node)
allowed_ancestor?(node) ||
allowed_method_call?(node) ||
allowed_array_or_hash_element?(node) ||
allowed_multiple_expression?(node) ||
allowed_ternary?(node)
end
Expand Down Expand Up @@ -167,26 +166,6 @@ def keyword_ancestor?(node)
node.parent&.keyword?
end

def allowed_array_or_hash_element?(node)
# Don't flag
# ```
# { a: (1
# ), }
# ```
hash_or_array_element?(node) && only_closing_paren_before_comma?(node)
end

def hash_or_array_element?(node)
node.each_ancestor(:array, :hash).any?
end

def only_closing_paren_before_comma?(node)
source_buffer = node.source_range.source_buffer
line_range = source_buffer.line_range(node.loc.end.line)

/^\s*\)\s*,/.match?(line_range.source)
end

def disallowed_literal?(begin_node, node)
node.literal? && !node.range_type? && !raised_to_power_negative_numeric?(begin_node, node)
end
Expand Down
126 changes: 106 additions & 20 deletions spec/rubocop/cop/style/redundant_parentheses_spec.rb
Expand Up @@ -218,25 +218,80 @@
RUBY
end

it_behaves_like 'plausible', "[(1\n),]"

it_behaves_like 'plausible', <<~RUBY
[
(
1
),
2
]
RUBY

it_behaves_like 'plausible', <<~RUBY
[
x = (
1
),
y = 2
]
RUBY
context 'literals in an array' do
context 'when there is a comma on the same line as the closing parentheses' do
it 'registers an offense and corrects when there is no subsequent item' do
expect_offense(<<~RUBY)
[
(
^ Don't use parentheses around a literal.
1
)
]
RUBY

expect_correction(<<~RUBY)
[
#{trailing_whitespace * 2}
1
#{trailing_whitespace * 2}
]
RUBY
end

it 'registers an offense and corrects when there is a trailing comma' do
expect_offense(<<~RUBY)
[(1
^^ Don't use parentheses around a literal.
),]
RUBY

expect_correction(<<~RUBY)
[1,]
RUBY
end

it 'registers an offense and corrects when there is a subsequent item' do
expect_offense(<<~RUBY)
[
(
^ Don't use parentheses around a literal.
1
),
2
]
RUBY

expect_correction(<<~RUBY)
[
#{trailing_whitespace * 2}
1,
2
]
RUBY
end

it 'registers an offense and corrects when there is assignment' do
expect_offense(<<~RUBY)
[
x = (
^ Don't use parentheses around a literal.
1
),
y = 2
]
RUBY

expect_correction(<<~RUBY)
[
x =#{trailing_whitespace}
1,
y = 2
]
RUBY
end
end
end

it 'registers an offense for parens around a literal hash value' do
expect_offense(<<~RUBY)
Expand All @@ -262,7 +317,18 @@
RUBY
end

it_behaves_like 'plausible', "{a: (1\n),}"
it 'registers an offense and corrects for a parenthesized item in a hash where ' \
'the comma is on a line with the closing parens' do
expect_offense(<<~RUBY)
{ a: (1
^^ Don't use parentheses around a literal.
),}
RUBY

expect_correction(<<~RUBY)
{ a: 1,}
RUBY
end

it 'registers an offense for parens around an integer exponentiation base' do
expect_offense(<<~RUBY)
Expand Down Expand Up @@ -507,4 +573,24 @@ def x
})
RUBY
end

it 'registers an offense and corrects when method arguments are unnecessarily parenthesized' do
expect_offense(<<~RUBY)
foo(
(
^ Don't use parentheses around a literal.
1
),
2
)
RUBY

expect_correction(<<~RUBY)
foo(
#{trailing_whitespace * 2}
1,
2
)
RUBY
end
end

0 comments on commit 838ec41

Please sign in to comment.