forked from rubocop/rubocop
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fix rubocop#4508] Added return nil cop
- Loading branch information
Showing
8 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Style | ||
# This cop enforces consistency between 'return nil' and 'return'. | ||
# | ||
# Supported styles are: return, return_nil. | ||
# | ||
# @example | ||
# | ||
# # EnforcedStyle: return (default) | ||
# | ||
# # bad | ||
# def foo(arg) | ||
# return nil if arg | ||
# end | ||
# | ||
# # good | ||
# def foo(arg) | ||
# return if arg | ||
# end | ||
# | ||
# # EnforcedStyle: return_nil | ||
# | ||
# # bad | ||
# def foo(arg) | ||
# return if arg | ||
# end | ||
# | ||
# # good | ||
# def foo(arg) | ||
# return nil if arg | ||
# end | ||
class ReturnNil < Cop | ||
include ConfigurableEnforcedStyle | ||
|
||
RETURN_MSG = 'Use `return` instead of `return nil`.'.freeze | ||
RETURN_NIL_MSG = 'Use `return nil` instead of `return`.'.freeze | ||
|
||
def_node_matcher :return_node?, '(return)' | ||
# TODO: fix (return nil) on the NodePattern class | ||
# def_node_matcher :return_nil_node?, '(return nil)' | ||
|
||
def on_return(node) | ||
# Check Lint/NonLocalExitFromIterator first before this cop | ||
node.each_ancestor(:block, :def, :defs) do |n| | ||
break if scoped_node?(n) | ||
|
||
send_node, args_node, _body_node = *n | ||
|
||
# if a proc is passed to `Module#define_method` or | ||
# `Object#define_singleton_method`, `return` will not cause a | ||
# non-local exit error | ||
break if define_method?(send_node) | ||
|
||
next if args_node.children.empty? | ||
|
||
return nil if chained_send?(send_node) | ||
end | ||
|
||
add_offense(node) unless correct_style?(node) | ||
end | ||
|
||
private | ||
|
||
def autocorrect(node) | ||
lambda do |corrector| | ||
corrected = style == :return ? 'return' : 'return nil' | ||
corrector.replace(node.source_range, corrected) | ||
end | ||
end | ||
|
||
def message(_node) | ||
style == :return ? RETURN_MSG : RETURN_NIL_MSG | ||
end | ||
|
||
def correct_style?(node) | ||
style == :return && !return_nil_node?(node) || | ||
style == :return_nil && !return_node?(node) | ||
end | ||
|
||
def return_nil_node?(node) | ||
!node.children.empty? && node.children.first.nil_type? | ||
end | ||
|
||
def scoped_node?(node) | ||
node.def_type? || node.defs_type? || node.lambda? | ||
end | ||
|
||
def_node_matcher :chained_send?, '(send !nil ...)' | ||
def_node_matcher :define_method?, <<-PATTERN | ||
(send _ {:define_method :define_singleton_method} _) | ||
PATTERN | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# frozen_string_literal: true | ||
|
||
describe RuboCop::Cop::Style::ReturnNil do | ||
subject(:cop) { described_class.new(config) } | ||
|
||
context 'when enforced style is `return`' do | ||
let(:config) do | ||
RuboCop::Config.new( | ||
'Style/ReturnNil' => { | ||
'EnforcedStyle' => 'return', | ||
'SupportedStyles' => %w[return return_nil] | ||
} | ||
) | ||
end | ||
|
||
it 'registers an offense for return nil' do | ||
expect_offense(<<-RUBY.strip_indent) | ||
return nil | ||
^^^^^^^^^^ Use `return` instead of `return nil`. | ||
RUBY | ||
end | ||
|
||
it 'auto-corrects `return nil` into `return`' do | ||
expect(autocorrect_source('return nil')).to eq 'return' | ||
end | ||
|
||
it 'does not register an offense for return' do | ||
expect_no_offenses('return') | ||
end | ||
|
||
it 'does not register an offense for returning others' do | ||
expect_no_offenses('return 2') | ||
end | ||
|
||
it 'does not register an offense for return nil from iterators' do | ||
expect_no_offenses(<<-RUBY) | ||
loop do | ||
return if x | ||
end | ||
RUBY | ||
end | ||
end | ||
|
||
context 'when enforced style is `return_nil`' do | ||
let(:config) do | ||
RuboCop::Config.new( | ||
'Style/ReturnNil' => { | ||
'EnforcedStyle' => 'return_nil', | ||
'SupportedStyles' => %w[return return_nil] | ||
} | ||
) | ||
end | ||
|
||
it 'registers an offense for return' do | ||
expect_offense(<<-RUBY.strip_indent) | ||
return | ||
^^^^^^ Use `return nil` instead of `return`. | ||
RUBY | ||
end | ||
|
||
it 'auto-corrects `return` into `return nil`' do | ||
expect(autocorrect_source('return')).to eq 'return nil' | ||
end | ||
|
||
it 'does not register an offense for return nil' do | ||
expect_no_offenses('return nil') | ||
end | ||
|
||
it 'does not register an offense for returning others' do | ||
expect_no_offenses('return 2') | ||
end | ||
end | ||
end |