Skip to content

Commit

Permalink
Style/ExplicitBlockArgument: do not assume the block parameter name
Browse files Browse the repository at this point in the history
The autocorector would generate invalid code if the old code
already defined the block parameter with any other name than `&block`.
  • Loading branch information
byroot committed Sep 8, 2021
1 parent 27f2c59 commit e44b0a8
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 14 deletions.
1 change: 1 addition & 0 deletions changelog/fix_hardcoded_block_parameter_name.md
@@ -0,0 +1 @@
* [#10064](https://github.com/rubocop/rubocop/pull/10064): Fix `Style/ExplicitBlockArgument` corrector assuming any existing block argument was named `block`. ([@byroot][])
32 changes: 21 additions & 11 deletions lib/rubocop/cop/style/explicit_block_argument.rb
Expand Up @@ -67,17 +67,27 @@ def on_yield(node)
# so this can cause crashes in haml_lint
return unless def_node

block_name = extract_block_name(def_node)

add_offense(block_node) do |corrector|
corrector.remove(block_body_range(block_node, send_node))

add_block_argument(send_node, corrector)
add_block_argument(def_node, corrector) if @def_nodes.add?(def_node)
add_block_argument(send_node, corrector, block_name)
add_block_argument(def_node, corrector, block_name) if @def_nodes.add?(def_node)
end
end
end

private

def extract_block_name(def_node)
if def_node.block_argument?
def_node.arguments.last.name
else
'block'
end
end

def yielding_arguments?(block_args, yield_args)
yield_args = yield_args.dup.fill(
nil,
Expand All @@ -91,15 +101,15 @@ def yielding_arguments?(block_args, yield_args)
end
end

def add_block_argument(node, corrector)
def add_block_argument(node, corrector, block_name)
if node.arguments?
insert_argument(node, corrector)
insert_argument(node, corrector, block_name)
elsif empty_arguments?(node)
corrector.replace(node.arguments, '(&block)')
corrector.replace(node.arguments, "(&#{block_name})")
elsif call_like?(node)
correct_call_node(node, corrector)
correct_call_node(node, corrector, block_name)
else
corrector.insert_after(node.loc.name, '(&block)')
corrector.insert_after(node.loc.name, "(&#{block_name})")
end
end

Expand All @@ -112,16 +122,16 @@ def call_like?(node)
node.call_type? || node.zsuper_type? || node.super_type?
end

def insert_argument(node, corrector)
def insert_argument(node, corrector, block_name)
last_arg = node.arguments.last
arg_range = range_with_surrounding_comma(last_arg.source_range, :right)
replacement = ' &block'
replacement = " &#{block_name}"
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)')
def correct_call_node(node, corrector, block_name)
corrector.insert_after(node, "(&#{block_name})")
return unless node.parenthesized?

args_begin = Util.args_begin(node)
Expand Down
6 changes: 3 additions & 3 deletions spec/rubocop/cop/style/explicit_block_argument_spec.rb
Expand Up @@ -41,15 +41,15 @@ def m

it 'correctly corrects when method already has an explicit block argument' do
expect_offense(<<~RUBY)
def m(&block)
def m(&blk)
items.something { |i| yield i }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider using explicit block argument in the surrounding method's signature over `yield`.
end
RUBY

expect_correction(<<~RUBY)
def m(&block)
items.something(&block)
def m(&blk)
items.something(&blk)
end
RUBY
end
Expand Down

0 comments on commit e44b0a8

Please sign in to comment.