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

Update Style/NilLambda to handle procs as well #9776

Merged
merged 1 commit into from May 7, 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
@@ -0,0 +1 @@
* [#9776](https://github.com/rubocop/rubocop/pull/9776): Update `Style/NilLambda` to handle procs as well. ([@dvandersluis][])
41 changes: 29 additions & 12 deletions lib/rubocop/cop/style/nil_lambda.rb
Expand Up @@ -3,8 +3,8 @@
module RuboCop
module Cop
module Style
# This cop checks for lambdas that always return nil, which can be replaced
# with an empty lambda instead.
# This cop checks for lambdas and procs that always return nil,
# which can be replaced with an empty lambda or proc instead.
#
# @example
# # bad
Expand All @@ -14,6 +14,12 @@ module Style
# next nil
# end
#
# proc { nil }
#
# Proc.new do
# break nil
# end
#
# # good
# -> {}
#
Expand All @@ -22,31 +28,42 @@ module Style
#
# -> (x) { nil if x }
#
# proc {}
#
# Proc.new { nil if x }
#
class NilLambda < Base
extend AutoCorrector
include RangeHelp

MSG = 'Use an empty lambda instead of always returning nil.'
MSG = 'Use an empty %<type>s instead of always returning nil.'

# @!method nil_return?(node)
def_node_matcher :nil_return?, <<~PATTERN
{ ({return next break} nil) (nil) }
PATTERN

def on_block(node)
return unless node.lambda?
return unless node.lambda? || node.proc?
return unless nil_return?(node.body)

add_offense(node) do |corrector|
range = if node.single_line?
range_with_surrounding_space(range: node.body.loc.expression)
else
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
end

corrector.remove(range)
message = format(MSG, type: node.lambda? ? 'lambda' : 'proc')
add_offense(node, message: message) do |corrector|
autocorrect(corrector, node)
end
end

private

def autocorrect(corrector, node)
range = if node.single_line?
range_with_surrounding_space(range: node.body.loc.expression)
else
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
end

corrector.remove(range)
end
end
end
end
Expand Down
198 changes: 198 additions & 0 deletions spec/rubocop/cop/style/nil_lambda_spec.rb
Expand Up @@ -171,4 +171,202 @@
RUBY
end
end

context 'proc' do
it 'registers an offense when returning nil implicitly' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `return`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
return nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `break`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
break nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `next`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
next nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'does not register an offense when not returning nil' do
expect_no_offenses(<<~RUBY)
proc do
6
end
RUBY
end

it 'does not register an offense when doing more than returning nil' do
expect_no_offenses(<<~RUBY)
proc do |x|
x ? x.method : nil
end
RUBY
end

it 'does not remove block params or change spacing' do
expect_offense(<<~RUBY)
fn = proc do |x|
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
fn = proc do |x|
end
RUBY
end

it 'properly corrects single line' do
expect_offense(<<~RUBY)
proc { nil }
^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
RUBY

expect_correction(<<~RUBY)
proc {}
RUBY
end
end

context 'Proc.new' do
it 'registers an offense when returning nil implicitly' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `return`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
return nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `break`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
break nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `next`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
next nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'does not register an offense when not returning nil' do
expect_no_offenses(<<~RUBY)
Proc.new do
6
end
RUBY
end

it 'does not register an offense when doing more than returning nil' do
expect_no_offenses(<<~RUBY)
Proc.new do |x|
x ? x.method : nil
end
RUBY
end

it 'does not remove block params or change spacing' do
expect_offense(<<~RUBY)
fn = Proc.new do |x|
^^^^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
fn = Proc.new do |x|
end
RUBY
end

it 'properly corrects single line' do
expect_offense(<<~RUBY)
Proc.new { nil }
^^^^^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
RUBY

expect_correction(<<~RUBY)
Proc.new {}
RUBY
end
end
end