From bf907ee98b868506438fe39dc6838d0e7021566c Mon Sep 17 00:00:00 2001 From: Vitalii Elenhaupt Date: Sat, 12 May 2018 20:06:52 +0300 Subject: [PATCH] Rework variable references detection in macro --- spec/ameba/rule/useless_assign_spec.cr | 16 ++++++++++++++++ src/ameba/ast/scope.cr | 3 --- src/ameba/ast/variabling/variable.cr | 22 +++++++++++++++++++++- src/ameba/ast/visitors/scope_visitor.cr | 5 ----- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/spec/ameba/rule/useless_assign_spec.cr b/spec/ameba/rule/useless_assign_spec.cr index 0cb27b7b..e86493d3 100644 --- a/spec/ameba/rule/useless_assign_spec.cr +++ b/spec/ameba/rule/useless_assign_spec.cr @@ -851,6 +851,22 @@ module Ameba::Rule ) subject.catch(s).should_not be_valid end + + it "doesn't report if assignment is referenced in a macro below" do + s = Source.new %( + class Foo + def foo + a = 1 + macro_call + end + + macro macro_call + puts a + end + end + ) + subject.catch(s).should be_valid + end end context "uninitialized" do diff --git a/src/ameba/ast/scope.cr b/src/ameba/ast/scope.cr index b2d7ecb1..1a287385 100644 --- a/src/ameba/ast/scope.cr +++ b/src/ameba/ast/scope.cr @@ -19,9 +19,6 @@ module Ameba::AST # The actual AST node that represents a current scope. getter node : Crystal::ASTNode - # Macro literals in current scope - getter macro_literals = [] of Crystal::MacroLiteral - delegate to_s, to: node delegate location, to: node diff --git a/src/ameba/ast/variabling/variable.cr b/src/ameba/ast/variabling/variable.cr index cecb44e8..ae215ba7 100644 --- a/src/ameba/ast/variabling/variable.cr +++ b/src/ameba/ast/variabling/variable.cr @@ -117,7 +117,7 @@ module Ameba::AST # false if not. def used_in_macro?(scope = @scope) scope.inner_scopes.each do |inner_scope| - return true if inner_scope.macro_literals.any? { |literal| literal.value.includes?(name) } + return true if MacroLiteralFinder.new(inner_scope.node).references? node end return true if (outer_scope = scope.outer_scope) && used_in_macro?(outer_scope) false @@ -142,5 +142,25 @@ module Ameba::AST node.name == @node.name && node.location == @node.location end + + private class MacroLiteralFinder < Crystal::Visitor + @macro_literals = [] of Crystal::MacroLiteral + + def initialize(node) + node.accept self + end + + def references?(node : Crystal::Var) + @macro_literals.any? { |literal| literal.value.includes? node.name } + end + + def visit(node : Crystal::ASTNode) + true + end + + def visit(node : Crystal::MacroLiteral) + @macro_literals << node + end + end end end diff --git a/src/ameba/ast/visitors/scope_visitor.cr b/src/ameba/ast/visitors/scope_visitor.cr index 84f06c25..c68544eb 100644 --- a/src/ameba/ast/visitors/scope_visitor.cr +++ b/src/ameba/ast/visitors/scope_visitor.cr @@ -127,11 +127,6 @@ module Ameba::AST end end - # :nodoc: - def visit(node : Crystal::MacroLiteral) - @current_scope.macro_literals << node - end - # :nodoc: def visit(node : Crystal::Call) return true unless node.name == "super" && node.args.empty?