mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Extend UnreachableCode rule: handle control flow (#83)
This commit is contained in:
parent
eca0f3f350
commit
0fd5890738
11 changed files with 880 additions and 101 deletions
|
@ -5,42 +5,37 @@ module Ameba::AST
|
|||
describe "#initialize" do
|
||||
it "creates a new flow expression" do
|
||||
node = as_node("return 22")
|
||||
parent_node = as_node("def foo; return 22; end")
|
||||
flow_expression = FlowExpression.new node, parent_node
|
||||
flow_expression = FlowExpression.new node, false
|
||||
flow_expression.node.should_not be_nil
|
||||
flow_expression.parent_node.should_not be_nil
|
||||
flow_expression.in_loop?.should eq false
|
||||
end
|
||||
|
||||
describe "#delegation" do
|
||||
it "delegates to_s to @node" do
|
||||
node = as_node("return 22")
|
||||
parent_node = as_node("def foo; return 22; end")
|
||||
flow_expression = FlowExpression.new node, parent_node
|
||||
flow_expression = FlowExpression.new node, false
|
||||
flow_expression.to_s.should eq node.to_s
|
||||
end
|
||||
|
||||
it "delegates location to @node" do
|
||||
node = as_node %(break if true)
|
||||
parent_node = as_node("def foo; return 22 if true; end")
|
||||
flow_expression = FlowExpression.new node, parent_node
|
||||
flow_expression = FlowExpression.new node, false
|
||||
flow_expression.location.should eq node.location
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_unreachable_node" do
|
||||
it "returns first unreachable node" do
|
||||
describe "#unreachable_nodes" do
|
||||
it "returns unreachable nodes" do
|
||||
nodes = as_nodes %(
|
||||
def foobar
|
||||
return
|
||||
a = 1
|
||||
a + 1
|
||||
a = 2
|
||||
end
|
||||
)
|
||||
node = nodes.control_expression_nodes.first
|
||||
assign_node = nodes.assign_nodes.first
|
||||
def_node = nodes.def_nodes.first
|
||||
flow_expression = FlowExpression.new node, def_node
|
||||
flow_expression.find_unreachable_node.should eq assign_node
|
||||
node = nodes.expressions_nodes.first
|
||||
flow_expression = FlowExpression.new node, false
|
||||
flow_expression.unreachable_nodes.should eq nodes.assign_nodes
|
||||
end
|
||||
|
||||
it "returns nil if there is no unreachable node" do
|
||||
|
@ -50,10 +45,9 @@ module Ameba::AST
|
|||
return a
|
||||
end
|
||||
)
|
||||
node = nodes.control_expression_nodes.first
|
||||
def_node = nodes.def_nodes.first
|
||||
flow_expression = FlowExpression.new node, def_node
|
||||
flow_expression.find_unreachable_node.should eq nil
|
||||
node = nodes.expressions_nodes.first
|
||||
flow_expression = FlowExpression.new node, false
|
||||
flow_expression.unreachable_nodes.empty?.should eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,5 +71,242 @@ module Ameba::AST
|
|||
])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#flow_command?" do
|
||||
it "returns true if this is return" do
|
||||
node = as_node("return 22")
|
||||
subject.flow_command?(node, false).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is a break in a loop" do
|
||||
node = as_node("break")
|
||||
subject.flow_command?(node, true).should eq true
|
||||
end
|
||||
|
||||
it "returns false if this is a break out of loop" do
|
||||
node = as_node("break")
|
||||
subject.flow_command?(node, false).should eq false
|
||||
end
|
||||
|
||||
it "returns true if this is a next in a loop" do
|
||||
node = as_node("next")
|
||||
subject.flow_command?(node, true).should eq true
|
||||
end
|
||||
|
||||
it "returns false if this is a next out of loop" do
|
||||
node = as_node("next")
|
||||
subject.flow_command?(node, false).should eq false
|
||||
end
|
||||
|
||||
it "returns true if this is raise" do
|
||||
node = as_node("raise e")
|
||||
subject.flow_command?(node, false).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is exit" do
|
||||
node = as_node("exit")
|
||||
subject.flow_command?(node, false).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is abort" do
|
||||
node = as_node("abort")
|
||||
subject.flow_command?(node, false).should eq true
|
||||
end
|
||||
|
||||
it "returns false otherwise" do
|
||||
node = as_node("foobar")
|
||||
subject.flow_command?(node, false).should eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#flow_expression?" do
|
||||
it "returns true if this is a flow command" do
|
||||
node = as_node("return")
|
||||
subject.flow_expression?(node, true).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is if-else consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
if foo
|
||||
return :foo
|
||||
else
|
||||
return :bar
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node, false).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is unless-else consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
unless foo
|
||||
return :foo
|
||||
else
|
||||
return :bar
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is case consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
case
|
||||
when 1
|
||||
return 1
|
||||
when 2
|
||||
return 2
|
||||
else
|
||||
return 3
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is exception handler consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
begin
|
||||
raise "exp"
|
||||
rescue e
|
||||
return e
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this while consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
while true
|
||||
return
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if this while with break" do
|
||||
node = as_node %(
|
||||
while true
|
||||
break
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns true if this until consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
until false
|
||||
return
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if this until with break" do
|
||||
node = as_node %(
|
||||
until false
|
||||
break
|
||||
end
|
||||
)
|
||||
subject.flow_expression?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns true if this expressions consumed by flow expressions" do
|
||||
node = as_node %(
|
||||
exp1
|
||||
exp2
|
||||
return
|
||||
)
|
||||
subject.flow_expression?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false otherwise" do
|
||||
node = as_node %(
|
||||
exp1
|
||||
exp2
|
||||
)
|
||||
subject.flow_expression?(node).should eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#raise?" do
|
||||
it "returns true if this is a raise method call" do
|
||||
node = as_node "raise e"
|
||||
subject.raise?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if it has a receiver" do
|
||||
node = as_node "obj.raise e"
|
||||
subject.raise?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns false if size of the arguments doesn't match" do
|
||||
node = as_node "raise"
|
||||
subject.raise?(node).should eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#exit?" do
|
||||
it "returns true if this is a exit method call" do
|
||||
node = as_node "exit"
|
||||
subject.exit?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is a exit method call with one argument" do
|
||||
node = as_node "exit 1"
|
||||
subject.exit?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if it has a receiver" do
|
||||
node = as_node "obj.exit"
|
||||
subject.exit?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns false if size of the arguments doesn't match" do
|
||||
node = as_node "exit 1, 1"
|
||||
subject.exit?(node).should eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#abort?" do
|
||||
it "returns true if this is an abort method call" do
|
||||
node = as_node "abort"
|
||||
subject.abort?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is an abort method call with one argument" do
|
||||
node = as_node "abort \"message\""
|
||||
subject.abort?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns true if this is an abort method call with two arguments" do
|
||||
node = as_node "abort \"message\", 1"
|
||||
subject.abort?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if it has a receiver" do
|
||||
node = as_node "obj.abort"
|
||||
subject.abort?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns false if size of the arguments doesn't match" do
|
||||
node = as_node "abort 1, 1, 1"
|
||||
subject.abort?(node).should eq false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#loop?" do
|
||||
it "returns true if this is a loop method call" do
|
||||
node = as_node "loop"
|
||||
subject.loop?(node).should eq true
|
||||
end
|
||||
|
||||
it "returns false if it has a receiver" do
|
||||
node = as_node "obj.loop"
|
||||
subject.loop?(node).should eq false
|
||||
end
|
||||
|
||||
it "returns false if size of the arguments doesn't match" do
|
||||
node = as_node "loop 1"
|
||||
subject.loop?(node).should eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ module Ameba::AST
|
|||
end
|
||||
end
|
||||
)
|
||||
rule.expressions.size.should eq 2
|
||||
rule.expressions.size.should eq 3
|
||||
end
|
||||
|
||||
it "properly creates nested flow expressions" do
|
||||
|
@ -40,7 +40,7 @@ module Ameba::AST
|
|||
)
|
||||
end
|
||||
)
|
||||
rule.expressions.size.should eq 3
|
||||
rule.expressions.size.should eq 4
|
||||
end
|
||||
|
||||
it "creates an expression for break" do
|
||||
|
|
|
@ -5,14 +5,12 @@ module Ameba::AST
|
|||
source = Source.new ""
|
||||
|
||||
describe NodeVisitor do
|
||||
{% for name in NODES %}
|
||||
describe "{{name}}" do
|
||||
it "allow to visit {{name}} node" do
|
||||
visitor = NodeVisitor.new rule, source
|
||||
nodes = Crystal::Parser.new("").parse
|
||||
nodes.accept visitor
|
||||
end
|
||||
describe "visit" do
|
||||
it "allow to visit ASTNode" do
|
||||
visitor = NodeVisitor.new rule, source
|
||||
nodes = Crystal::Parser.new("").parse
|
||||
nodes.accept visitor
|
||||
end
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue