Extend UnreachableCode rule: handle control flow (#83)

This commit is contained in:
V. Elenhaupt 2018-11-22 10:38:32 +02:00 committed by GitHub
parent eca0f3f350
commit 0fd5890738
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 880 additions and 101 deletions

View file

@ -41,6 +41,23 @@ module Ameba::Rule::Lint
subject.catch(s).should be_valid
end
it "doesn't report if there is no else in if" do
s = Source.new %(
if a > 0
return :positive
end
:reachable
)
subject.catch(s).should be_valid
end
it "doesn't report return in on-line if" do
s = Source.new %(
return :positive if a > 0
)
subject.catch(s).should be_valid
end
it "doesn't report if return is used in a block" do
s = Source.new %(
def foo
@ -57,7 +74,7 @@ module Ameba::Rule::Lint
subject.catch(s).should be_valid
end
pending "reports if there is unreachable code after if-then-else" do
it "reports if there is unreachable code after if-then-else" do
s = Source.new %(
def foo
if a > 0
@ -71,7 +88,448 @@ module Ameba::Rule::Lint
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":8:4"
issue.location.to_s.should eq ":8:3"
end
it "reports if there is unreachable code after if-then-else-if" do
s = Source.new %(
def foo
if a > 0
return :positive
elsif a != 0
return :negative
else
return :zero
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":10:3"
end
it "doesn't report if there is no unreachable code after if-then-else" do
s = Source.new %(
def foo
if a > 0
return :positive
else
return :negative
end
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is no unreachable in inner branch" do
s = Source.new %(
def foo
if a > 0
return :positive if a != 1
else
return :negative
end
:not_unreachable
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is no unreachable in exception handler" do
s = Source.new %(
def foo
puts :bar
rescue Exception
raise "Error!"
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is multiple conditions with return" do
s = Source.new %(
if :foo
if :bar
return :foobar
else
return :foobaz
end
elsif :fox
return :foofox
end
return :reachable
)
subject.catch(s).should be_valid
end
it "reports if there is unreachable code after unless" do
s = Source.new %(
unless :foo
return :bar
else
return :foo
end
:unreachable
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":7:1"
end
it "doesn't report if there is no unreachable code after unless" do
s = Source.new %(
unless :foo
return :bar
end
:reachable
)
subject.catch(s).should be_valid
end
end
context "binary op" do
it "reports unreachable code in a binary operator" do
s = Source.new %(
(return 22) && puts "a"
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":1:16"
end
it "reports unreachable code in inner binary operator" do
s = Source.new %(
do_something || (return 22) && puts "a"
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":1:32"
end
it "reports unreachable code after the binary op" do
s = Source.new %(
(return 22) && break
:unreachable
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":2:1"
end
it "doesn't report if return is not the right" do
s = Source.new %(
puts "a" && return
)
subject.catch(s).should be_valid
end
it "doesn't report unreachable code in multiple binary expressions" do
s = Source.new %(
foo || bar || baz
)
subject.catch(s).should be_valid
end
end
context "case" do
it "reports if there is unreachable code after case" do
s = Source.new %(
def foo
case cond
when 1
something
return
when 2
something2
return
else
something3
return
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":13:3"
end
it "doesn't report if case does not have else" do
s = Source.new %(
def foo
case cond
when 1
something
return
when 2
something2
return
end
:reachable
end
)
subject.catch(s).should be_valid
end
it "doesn't report if one when does not return" do
s = Source.new %(
def foo
case cond
when 1
something
return
when 2
something2
else
something3
return
end
:reachable
end
)
subject.catch(s).should be_valid
end
end
context "exception handler" do
it "reports unreachable code if it returns in body and rescues" do
s = Source.new %(
def foo
begin
return false
rescue Error
return false
rescue Exception
return false
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":9:3"
end
it "reports unreachable code if it returns in rescues and else" do
s = Source.new %(
def foo
begin
do_something
rescue Error
return :error
else
return true
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":9:3"
end
it "doesn't report if there is no else and ensure doesn't return" do
s = Source.new %(
def foo
begin
return false
rescue Error
puts "error"
rescue Exception
return false
end
:reachable
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is no else and body doesn't return" do
s = Source.new %(
def foo
begin
do_something
rescue Error
return true
rescue Exception
return false
end
:reachable
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is else and ensure doesn't return" do
s = Source.new %(
def foo
begin
do_something
rescue Error
puts "yo"
else
return true
end
:reachable
end
)
subject.catch(s).should be_valid
end
it "doesn't report if there is else and it doesn't return" do
s = Source.new %(
def foo
begin
do_something
rescue Error
return false
else
puts "yo"
end
:reachable
end
)
subject.catch(s).should be_valid
end
it "reports if there is unreachable code in rescue" do
s = Source.new %(
def method
rescue
return 22
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":4:3"
end
end
context "while/until" do
it "reports if there is unreachable code after while" do
s = Source.new %(
def method
while something
if :foo
return :foo
else
return :foobar
end
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":9:3"
end
it "reports if there is unreachable code after until" do
s = Source.new %(
def method
until something
if :foo
return :foo
else
return :foobar
end
end
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":9:3"
end
it "doesn't report if there is reachable code after while with break" do
s = Source.new %(
while something
break
end
:reachable
)
subject.catch(s).should be_valid
end
end
context "rescue" do
it "reports unreachable code in rescue" do
s = Source.new %(
begin
rescue e
raise e
:unreachable
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":5:3"
end
it "doesn't report if there is no unreachable code in rescue" do
s = Source.new %(
begin
rescue e
raise e
end
)
subject.catch(s).should be_valid
end
end
context "when" do
it "reports unreachable code in when" do
s = Source.new %(
case
when valid?
return 22
:unreachable
else
end
)
subject.catch(s).should_not be_valid
issue = s.issues.first
issue.location.to_s.should eq ":4:3"
end
it "doesn't report if there is no unreachable code in when" do
s = Source.new %(
case
when valid?
return 22
else
end
)
subject.catch(s).should be_valid
end
end