Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[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 #10885

Merged
merged 1 commit into from Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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