mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
parent
fde321f7e6
commit
6b56c87e78
5 changed files with 55 additions and 1 deletions
|
@ -151,6 +151,16 @@ module Ameba::Rule::Lint
|
|||
subject.catch(source).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if argument shadows an ivar assignment" do
|
||||
s = Source.new %(
|
||||
def bar(@foo)
|
||||
@foo.try do |foo|
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
source = Source.new %(
|
||||
foo = 1
|
||||
|
|
|
@ -10,6 +10,9 @@ module Ameba::AST
|
|||
# Link to the arguments in current scope
|
||||
getter arguments = [] of Argument
|
||||
|
||||
# Link to the instance variables used in current scope
|
||||
getter ivariables = [] of InstanceVariable
|
||||
|
||||
# Link to the outer scope
|
||||
getter outer_scope : Scope?
|
||||
|
||||
|
@ -44,11 +47,27 @@ module Ameba::AST
|
|||
variables << Variable.new(node, self)
|
||||
end
|
||||
|
||||
# Creates a new argument in the current scope.
|
||||
#
|
||||
# ```
|
||||
# scope = Scope.new(class_node, nil)
|
||||
# scope.add_argument(arg_node)
|
||||
# ```
|
||||
def add_argument(node)
|
||||
add_variable Crystal::Var.new(node.name).at(node)
|
||||
arguments << Argument.new(node, variables.last)
|
||||
end
|
||||
|
||||
# Adds a new instance variable to the current scope.
|
||||
#
|
||||
# ```
|
||||
# scope = Scope.new(class_node, nil)
|
||||
# scope.add_ivariable(ivar_node)
|
||||
# ```
|
||||
def add_ivariable(node)
|
||||
ivariables << InstanceVariable.new(node)
|
||||
end
|
||||
|
||||
# Returns variable by its name or nil if it does not exist.
|
||||
#
|
||||
# ```
|
||||
|
@ -75,6 +94,12 @@ module Ameba::AST
|
|||
node.is_a?(Crystal::Block) || node.is_a?(Crystal::ProcLiteral)
|
||||
end
|
||||
|
||||
# Returns true instance variable assinged in this scope.
|
||||
def assigns_ivar?(name)
|
||||
arguments.find { |arg| arg.name == name } &&
|
||||
ivariables.find { |var| var.name == "@#{name}" }
|
||||
end
|
||||
|
||||
# Returns true if and only if current scope represents some
|
||||
# type definition, for example a class.
|
||||
def type_definition?
|
||||
|
|
13
src/ameba/ast/variabling/ivariable.cr
Normal file
13
src/ameba/ast/variabling/ivariable.cr
Normal file
|
@ -0,0 +1,13 @@
|
|||
module Ameba::AST
|
||||
class InstanceVariable
|
||||
getter node : Crystal::InstanceVar
|
||||
|
||||
delegate location, to: @node
|
||||
delegate end_location, to: @node
|
||||
delegate name, to: @node
|
||||
delegate to_s, to: @node
|
||||
|
||||
def initialize(@node)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -135,6 +135,11 @@ module Ameba::AST
|
|||
@current_scope.add_argument node
|
||||
end
|
||||
|
||||
# :nodoc:
|
||||
def visit(node : Crystal::InstanceVar)
|
||||
@current_scope.add_ivariable(node)
|
||||
end
|
||||
|
||||
# :nodoc:
|
||||
def visit(node : Crystal::Var)
|
||||
variable = @current_scope.find_variable node.name
|
||||
|
|
|
@ -54,7 +54,8 @@ module Ameba::Rule::Lint
|
|||
private def find_shadowing(source, scope)
|
||||
scope.arguments.each do |arg|
|
||||
next if arg.ignored?
|
||||
if scope.outer_scope.try &.find_variable(arg.name)
|
||||
outer_scope = scope.outer_scope
|
||||
if outer_scope && outer_scope.find_variable(arg.name) && !outer_scope.assigns_ivar?(arg.name)
|
||||
issue_for arg.node, MSG % arg.name
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue