diff --git a/changelog/change_update_stylenillambda_to_handle_procs_as.md b/changelog/change_update_stylenillambda_to_handle_procs_as.md new file mode 100644 index 00000000000..d62e2ba203f --- /dev/null +++ b/changelog/change_update_stylenillambda_to_handle_procs_as.md @@ -0,0 +1 @@ +* [#9776](https://github.com/rubocop/rubocop/pull/9776): Update `Style/NilLambda` to handle procs as well. ([@dvandersluis][]) diff --git a/lib/rubocop/cop/style/nil_lambda.rb b/lib/rubocop/cop/style/nil_lambda.rb index 54c07fcb124..48b923e33c0 100644 --- a/lib/rubocop/cop/style/nil_lambda.rb +++ b/lib/rubocop/cop/style/nil_lambda.rb @@ -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 @@ -14,6 +14,12 @@ module Style # next nil # end # + # proc { nil } + # + # Proc.new do + # break nil + # end + # # # good # -> {} # @@ -22,11 +28,15 @@ 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 %s instead of always returning nil.' # @!method nil_return?(node) def_node_matcher :nil_return?, <<~PATTERN @@ -34,19 +44,26 @@ class NilLambda < Base 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 diff --git a/spec/rubocop/cop/style/nil_lambda_spec.rb b/spec/rubocop/cop/style/nil_lambda_spec.rb index c1ff36f96b0..d88d1ab8477 100644 --- a/spec/rubocop/cop/style/nil_lambda_spec.rb +++ b/spec/rubocop/cop/style/nil_lambda_spec.rb @@ -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