Incorrectly reporting shadowingOuterLocalVar within macro included

closes #161
This commit is contained in:
Vitalii Elenhaupt 2020-07-15 10:18:12 +03:00
parent 7f501a1df5
commit d650ca5477
No known key found for this signature in database
GPG key ID: CD0BF17825928BC0
4 changed files with 41 additions and 7 deletions

View file

@ -114,19 +114,30 @@ module Ameba::AST
end
end
describe "#macro?" do
describe "#in_macro?" do
it "returns true if Crystal::Macro" do
nodes = as_nodes %(
macro included
end
)
scope = Scope.new nodes.macro_nodes.first
scope.macro?.should be_true
scope.in_macro?.should be_true
end
it "returns true if node is nested to Crystal::Macro" do
nodes = as_nodes %(
macro included
{{@type.each do |type| a = type end}}
end
)
outer_scope = Scope.new nodes.macro_nodes.first
scope = Scope.new nodes.block_nodes.first, outer_scope
scope.in_macro?.should be_true
end
it "returns false otherwise" do
scope = Scope.new as_node "a = 1"
scope.macro?.should be_false
scope.in_macro?.should be_false
end
end
end

View file

@ -213,6 +213,29 @@ module Ameba::Rule::Lint
)
subject.catch(source).should be_valid
end
it "does not report shadowed vars withing nested macro" do
source = Source.new %(
module Foo
macro included
def foo
{% for ann in instance_vars %}
{% pos_args = ann.args.empty? ? "Tuple.new".id : ann.args %}
{% end %}
end
def bar
{{@type.instance_vars.map do |ivar|
ivar.annotations(Name).each do |ann|
puts ann.args
end
end}}
end
end
end
)
subject.catch(source).should be_valid
end
end
end
end

View file

@ -110,9 +110,9 @@ module Ameba::AST
call.try(&.name) == "spawn"
end
# Returns true if current scope represents a macro.
def macro?
node.is_a?(Crystal::Macro)
# Returns true if current scope sits inside a macro.
def in_macro?
node.is_a?(Crystal::Macro) || !!outer_scope.try(&.in_macro?)
end
# Returns true instance variable assinged in this scope.

View file

@ -54,7 +54,7 @@ module Ameba::Rule::Lint
private def find_shadowing(source, scope)
outer_scope = scope.outer_scope
return if outer_scope.nil? || outer_scope.macro?
return if outer_scope.nil? || outer_scope.in_macro?
scope.arguments.reject(&.ignored?).each do |arg|
variable = outer_scope.find_variable(arg.name)