mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Prevent false positiveness cause by macro literals
https://github.com/crystal-lang/crystal/pull/6055#issuecomment-386376227
This commit is contained in:
parent
6579c8f573
commit
415432713a
5 changed files with 47 additions and 25 deletions
|
@ -820,6 +820,37 @@ module Ameba::Rule
|
||||||
)
|
)
|
||||||
subject.catch(s).should be_valid
|
subject.catch(s).should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "doesn't report if assignment is referenced in macro def" do
|
||||||
|
s = Source.new %(
|
||||||
|
macro macro_call
|
||||||
|
puts x
|
||||||
|
end
|
||||||
|
|
||||||
|
def foo
|
||||||
|
x = 1
|
||||||
|
macro_call
|
||||||
|
end
|
||||||
|
)
|
||||||
|
subject.catch(s).should be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "reports if assignment is referenced in macro def in a different scope" do
|
||||||
|
s = Source.new %(
|
||||||
|
class Foo
|
||||||
|
def foo
|
||||||
|
x = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Bar
|
||||||
|
macro macro_call
|
||||||
|
puts x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
subject.catch(s).should_not be_valid
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,9 @@ module Ameba::AST
|
||||||
# The actual AST node that represents a current scope.
|
# The actual AST node that represents a current scope.
|
||||||
getter node : Crystal::ASTNode
|
getter node : Crystal::ASTNode
|
||||||
|
|
||||||
|
# Macro literals in current scope
|
||||||
|
getter macro_literals = [] of Crystal::MacroLiteral
|
||||||
|
|
||||||
delegate to_s, to: node
|
delegate to_s, to: node
|
||||||
delegate location, to: node
|
delegate location, to: node
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ module Ameba::AST
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if the current assignment is referenced in
|
# Returns true if the current var is referenced in
|
||||||
# in the block. For example this variable is captured
|
# in the block. For example this variable is captured
|
||||||
# by block:
|
# by block:
|
||||||
#
|
#
|
||||||
|
@ -113,6 +113,16 @@ module Ameba::AST
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns true if current variable potentially referenced in a macro literal,
|
||||||
|
# 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) }
|
||||||
|
end
|
||||||
|
return true if (outer_scope = scope.outer_scope) && used_in_macro?(outer_scope)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
# Returns true if the variable is a target (on the left) of the assignment,
|
# Returns true if the variable is a target (on the left) of the assignment,
|
||||||
# false otherwise.
|
# false otherwise.
|
||||||
def target_of?(assign)
|
def target_of?(assign)
|
||||||
|
|
|
@ -120,7 +120,7 @@ module Ameba::AST
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
def visit(node : Crystal::MacroLiteral)
|
def visit(node : Crystal::MacroLiteral)
|
||||||
MacroLiteralVarVisitor.new(node).vars.each { |var| visit(var) }
|
@current_scope.macro_literals << node
|
||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
@ -134,26 +134,4 @@ module Ameba::AST
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private class MacroLiteralVarVisitor < Crystal::Visitor
|
|
||||||
getter vars = [] of Crystal::Var
|
|
||||||
|
|
||||||
def initialize(literal)
|
|
||||||
Crystal::Parser.new(literal.value).parse.accept self
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def visit(node : Crystal::ASTNode)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def visit(node : Crystal::Var)
|
|
||||||
vars << node
|
|
||||||
end
|
|
||||||
|
|
||||||
def visit(node : Crystal::Call)
|
|
||||||
vars << Crystal::Var.new(node.name).at(node.location)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Ameba::Rule
|
||||||
|
|
||||||
def test(source, node, scope : AST::Scope)
|
def test(source, node, scope : AST::Scope)
|
||||||
scope.variables.each do |var|
|
scope.variables.each do |var|
|
||||||
next if var.captured_by_block?
|
next if var.captured_by_block? || var.used_in_macro?
|
||||||
|
|
||||||
var.assignments.each do |assign|
|
var.assignments.each do |assign|
|
||||||
next if assign.referenced?
|
next if assign.referenced?
|
||||||
|
|
Loading…
Reference in a new issue