mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
6475c2bb25
* AST::Visitor -> AST::NodeVisitor * Scope & ScopeVisitor * Useless assignment rule * Instance vars and useless assignments * Multiple assigns one by one * Support outer scope * Variable used in the useless assignment * Support OpAssign & MultiAssign * Captured by block * Variable, Assignment, Reference & Refactoring * Variable has references, Assignment can be referenced * Branch entity * Handle useless assignments in branches * Handle assignments in a loop * Handle branch equality * Handle special var `$?` assignment * Improve captured by block stuff * Avoid assignments in property definitions (UselessAssign rule reports an warning) * Support MacroIf and MacroFor branches * Handle assignments with shadowed vars in inner scopes * Add method arguments as scope variables * Handle case if branch is blank * Top level scope * Handle case when branch is nop?
364 lines
9.2 KiB
Crystal
364 lines
9.2 KiB
Crystal
require "../../spec_helper"
|
|
|
|
private def branch_of_assign_in_def(source)
|
|
nodes = as_nodes source
|
|
Ameba::AST::Branch.of(nodes.assign_nodes.first, nodes.def_nodes.first)
|
|
end
|
|
|
|
module Ameba::AST
|
|
describe Branch do
|
|
describe ".of" do
|
|
context "Crystal::If" do
|
|
it "constructs a branch in If.cond" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
if a = get_something # --> Crystal::Assign
|
|
puts a
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = get_something"
|
|
end
|
|
|
|
it "constructs a branch in If.then" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
if true
|
|
a = 2 # --> Crystal::Assign
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 2"
|
|
end
|
|
|
|
it "constructs a branch in If.else" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
if true
|
|
nil
|
|
else
|
|
a = 2 # --> Crystal::Assign
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 2"
|
|
end
|
|
|
|
it "constructs a branch in inline If" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
a = 0 if a == 2 # --> Crystal::Assign
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 0"
|
|
end
|
|
end
|
|
|
|
context "Crystal::Unless" do
|
|
it "constructs a branch in Unless.cond" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
unless a = get_something # --> Crystal::Assign
|
|
puts a
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = get_something"
|
|
end
|
|
|
|
it "constructs a branch in Unless.then" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
unless true
|
|
a = 2 # --> Crystal::Assign
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 2"
|
|
end
|
|
|
|
it "constructs a new branch in Unless.else" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method
|
|
unless true
|
|
nil
|
|
else
|
|
a = 2 # --> Crystal::Assign
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 2"
|
|
end
|
|
|
|
it "constructs a branch in inline Unless" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
(a = 0; b = 3) unless a == 2 # --> Crystal::Expressions
|
|
end
|
|
)
|
|
branch.to_s.should eq "(a = 0\nb = 3)"
|
|
end
|
|
end
|
|
|
|
context "Crystal::BinaryOp" do
|
|
it "constructs a branch in left node" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
(a = 2) && do_something
|
|
end
|
|
)
|
|
branch.to_s.should eq "(a = 2)"
|
|
end
|
|
|
|
it "constructs a branch in right node" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
do_something || (a = 0)
|
|
end
|
|
)
|
|
branch.to_s.should eq "(a = 0)"
|
|
end
|
|
end
|
|
|
|
context "Crystal::Case" do
|
|
# FIXME:
|
|
# https://github.com/crystal-lang/crystal/pull/6032
|
|
# it "constructs a branch in cond" do
|
|
# branch = branch_of_assign_in_def %(
|
|
# def method(a)
|
|
# case (a = 2)
|
|
# when true then nil
|
|
# end
|
|
# end
|
|
# )
|
|
# branch.to_s.should eq "(a = 2)"
|
|
# end
|
|
|
|
it "constructs a branch in when" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
case a
|
|
when a = 3 then nil
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "when a = 3\n nil\n"
|
|
end
|
|
|
|
it "constructs a branch in else" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
case a
|
|
when true then nil
|
|
else a = 4
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 4"
|
|
end
|
|
end
|
|
|
|
context "Crystal::While" do
|
|
it "constructs a branch in cond" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
while a = 1
|
|
nil
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
|
|
it "constructs a branch in body" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
while true
|
|
b = (a = 1)
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "b = (a = 1)"
|
|
end
|
|
end
|
|
|
|
context "Crystal::Until" do
|
|
it "constructs a branch in cond" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
until a = 1
|
|
nil
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
|
|
it "constructs a branch in body" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
until false
|
|
b = (a = 1)
|
|
end
|
|
end
|
|
)
|
|
branch.to_s.should eq "b = (a = 1)"
|
|
end
|
|
end
|
|
|
|
context "Crystal::ExceptionHandler" do
|
|
it "constructs a branch in body" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
a = 1
|
|
rescue
|
|
nil
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
|
|
it "constructs a branch in a rescue" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
rescue
|
|
a = 1
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
|
|
it "constructs a branch in else" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
rescue
|
|
else
|
|
a = 1
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
|
|
it "constructs a branch in ensure" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
rescue
|
|
ensure
|
|
a = 1
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 1"
|
|
end
|
|
end
|
|
|
|
context "Crystal::MacroIf" do
|
|
it "constructs a branch in cond" do
|
|
branch = branch_of_assign_in_def %(
|
|
def method(a)
|
|
{% if a = 2 %}
|
|
{% end %}
|
|
end
|
|
)
|
|
branch.to_s.should eq "a = 2"
|
|
end
|
|
|
|
it "constructs a branch in then" do
|
|
nodes = as_nodes %(
|
|
def method(a)
|
|
{% if true %}
|
|
a = 2
|
|
{% end %}
|
|
end
|
|
)
|
|
branch = Branch.of(nodes.macro_literal_nodes.first, nodes.def_nodes.first)
|
|
branch.to_s.strip.should eq "a = 2"
|
|
end
|
|
end
|
|
|
|
context "Crystal::MacroFor" do
|
|
it "constructs a branch in body" do
|
|
nodes = as_nodes %(
|
|
def method(a)
|
|
{% for x in [1, 2, 3] %}
|
|
a = 2
|
|
{% end %}
|
|
end
|
|
)
|
|
branch = Branch.of(nodes.macro_literal_nodes.first, nodes.def_nodes.first)
|
|
branch.to_s.strip.should eq "a = 2"
|
|
end
|
|
end
|
|
|
|
it "returns nil if branch does not exist" do
|
|
nodes = as_nodes %(
|
|
def method
|
|
a = 2
|
|
end
|
|
)
|
|
branch = Branch.of(nodes.assign_nodes.first, nodes.def_nodes.first)
|
|
branch.should be_nil
|
|
end
|
|
end
|
|
|
|
describe "#initialize" do
|
|
it "creates new branch" do
|
|
nodes = as_nodes %(
|
|
if true
|
|
a = 2
|
|
end
|
|
)
|
|
branchable = Branchable.new nodes.if_nodes.first
|
|
branch = Branch.new nodes.assign_nodes.first, branchable
|
|
branch.node.should_not be_nil
|
|
end
|
|
end
|
|
|
|
describe "delegation" do
|
|
it "delegates to_s to node" do
|
|
nodes = as_nodes %(
|
|
if true
|
|
a = 2
|
|
end
|
|
)
|
|
branchable = Branchable.new nodes.if_nodes.first
|
|
branch = Branch.new nodes.assign_nodes.first, branchable
|
|
branch.to_s.should eq branch.node.to_s
|
|
end
|
|
|
|
it "delegates location to node" do
|
|
nodes = as_nodes %(
|
|
if true
|
|
a = 2
|
|
end
|
|
)
|
|
branchable = Branchable.new nodes.if_nodes.first
|
|
branch = Branch.new nodes.assign_nodes.first, branchable
|
|
branch.location.should eq branch.node.location
|
|
end
|
|
end
|
|
|
|
describe "#in_loop?" do
|
|
it "returns true if branch is in a loop" do
|
|
nodes = as_nodes %(
|
|
while true
|
|
a = 1
|
|
end
|
|
)
|
|
branchable = Branchable.new nodes.while_nodes.first
|
|
branch = Branch.new nodes.assign_nodes.first, branchable
|
|
branch.in_loop?.should be_true
|
|
end
|
|
|
|
it "returns false if branch is not in a loop" do
|
|
nodes = as_nodes %(
|
|
if a > 2
|
|
a = 1
|
|
end
|
|
)
|
|
branchable = Branchable.new nodes.if_nodes.first
|
|
branch = Branch.new nodes.assign_nodes.first, branchable
|
|
branch.in_loop?.should be_false
|
|
end
|
|
end
|
|
end
|
|
end
|