Skip to content

Commit

Permalink
Merge pull request #10885 from dvandersluis/issue/10883
Browse files Browse the repository at this point in the history
[Fix #10883] Fix `Style/RedundantParentheses` to be able to detect offenses and properly correct when the end parentheses and comma are on their own line
  • Loading branch information
koic committed Aug 9, 2022
2 parents eaec469 + 838ec41 commit 67f3055
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 67f3055

Please sign in to comment.