Variable scope & useless assignments (#41)

* 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?
This commit is contained in:
V. Elenhaupt 2018-05-03 18:57:47 +03:00 committed by GitHub
parent 60c1b86890
commit 6475c2bb25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 2521 additions and 124 deletions

View file

@ -0,0 +1,18 @@
require "../../../spec_helper"
module Ameba::AST
rule = DummyRule.new
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
end
{% end %}
end
end

View file

@ -0,0 +1,58 @@
require "../../../spec_helper"
module Ameba::AST
describe ScopeVisitor do
it "creates a scope for the def" do
rule = ScopeRule.new
ScopeVisitor.new rule, Source.new %(
def method
end
)
rule.scopes.size.should eq 1
end
it "creates a scope for the proc" do
rule = ScopeRule.new
ScopeVisitor.new rule, Source.new %(
-> {}
)
rule.scopes.size.should eq 1
end
it "creates a scope for the block" do
rule = ScopeRule.new
ScopeVisitor.new rule, Source.new %(
3.times {}
)
rule.scopes.size.should eq 2
end
context "inner scopes" do
it "creates scope for block inside def" do
rule = ScopeRule.new
ScopeVisitor.new rule, Source.new %(
def method
3.times {}
end
)
rule.scopes.size.should eq 2
rule.scopes.last.outer_scope.should_not be_nil
rule.scopes.first.outer_scope.should eq rule.scopes.last
end
it "creates scope for block inside block" do
rule = ScopeRule.new
ScopeVisitor.new rule, Source.new %(
3.times do
2.times {}
end
)
rule.scopes.size.should eq 3
inner_block = rule.scopes.first
outer_block = rule.scopes.last
inner_block.outer_scope.should_not eq outer_block
outer_block.outer_scope.should be_nil
end
end
end
end