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 #9955] Fix Style/ExplicitBlockArgument adding a second set of parentheses #9967

Merged
merged 1 commit into from Aug 3, 2021
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_styleexplicitblockargument_adding_a.md
@@ -0,0 +1 @@
* [#9955](https://github.com/rubocop/rubocop/issues/9955): Fix `Style/ExplicitBlockArgument` adding a second set of parentheses. ([@dvandersluis][])
39 changes: 32 additions & 7 deletions lib/rubocop/cop/style/explicit_block_argument.rb
Expand Up @@ -93,18 +93,43 @@ def yielding_arguments?(block_args, yield_args)

def add_block_argument(node, corrector)
if node.arguments?
last_arg = node.arguments.last
arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
replacement = ' &block'
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
elsif node.call_type? || node.zsuper_type?
corrector.insert_after(node, '(&block)')
insert_argument(node, corrector)
elsif empty_arguments?(node)
corrector.replace(node.arguments, '(&block)')
elsif call_like?(node)
correct_call_node(node, corrector)
else
corrector.insert_after(node.loc.name, '(&block)')
end
end

def empty_arguments?(node)
# Is there an arguments node with only parentheses?
node.arguments.is_a?(RuboCop::AST::Node) && node.arguments.loc.begin
end

def call_like?(node)
node.call_type? || node.zsuper_type? || node.super_type?
end

def insert_argument(node, corrector)
last_arg = node.arguments.last
arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
replacement = ' &block'
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
end

def correct_call_node(node, corrector)
corrector.insert_after(node, '(&block)')
return unless node.parenthesized?

args_begin = Util.args_begin(node)
args_end = Util.args_end(node)
range = range_between(args_begin.begin_pos, args_end.end_pos)
corrector.remove(range)
end

def block_body_range(block_node, send_node)
range_between(send_node.loc.expression.end_pos, block_node.loc.end.end_pos)
end
Expand Down
9 changes: 7 additions & 2 deletions lib/rubocop/cop/util.rb
Expand Up @@ -46,8 +46,13 @@ def add_parentheses(node, corrector)

def args_begin(node)
loc = node.loc
selector =
node.super_type? || node.yield_type? ? loc.keyword : loc.selector
selector = if node.super_type? || node.yield_type?
loc.keyword
elsif node.def_type? || node.defs_type?
loc.name
else
loc.selector
end
selector.end.resize(1)
end

Expand Down
45 changes: 45 additions & 0 deletions spec/rubocop/cop/style/explicit_block_argument_spec.rb
Expand Up @@ -191,4 +191,49 @@ def m
end
RUBY
end

it 'does not add extra parens when correcting' do
expect_offense(<<~RUBY)
def my_method()
foo() { yield }
^^^^^^^^^^^^^^^ Consider using explicit block argument in the surrounding method's signature over `yield`.
end
RUBY

expect_correction(<<~RUBY, loop: false)
def my_method(&block)
foo(&block)
end
RUBY
end

it 'does not add extra parens to `super` when correcting' do
expect_offense(<<~RUBY)
def my_method
super() { yield }
^^^^^^^^^^^^^^^^^ Consider using explicit block argument in the surrounding method's signature over `yield`.
end
RUBY

expect_correction(<<~RUBY, loop: false)
def my_method(&block)
super(&block)
end
RUBY
end

it 'adds to the existing arguments when correcting' do
expect_offense(<<~RUBY)
def my_method(x)
foo(x) { yield }
^^^^^^^^^^^^^^^^ Consider using explicit block argument in the surrounding method's signature over `yield`.
end
RUBY

expect_correction(<<~RUBY)
def my_method(x, &block)
foo(x, &block)
end
RUBY
end
end