class RuboCop::Cop::VariableForce::Variable
This holds a variable declaration node and some states of the variable.
A Variable represents existence of a local variable.
def argument?
def argument? ARGUMENT_DECLARATION_TYPES.include?(@declaration_node.type) end
def assign(node)
def assign(node) @assignments << Assignment.new(node, self) end
def block_argument?
def block_argument? argument? && @scope.node.block_type? end
def capture_with_block!
def capture_with_block! @captured_by_block = true end
def explicit_block_local_variable?
def explicit_block_local_variable? @declaration_node.shadowarg_type? end
def in_modifier_if?(assignment)
def in_modifier_if?(assignment) parent = assignment.node.parent parent = parent.parent if parent&.begin_type? parent&.if_type? && parent&.modifier_form? end
def initialize(name, declaration_node, scope)
def initialize(name, declaration_node, scope) unless VARIABLE_DECLARATION_TYPES.include?(declaration_node.type) raise ArgumentError, "Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " \ "passed #{declaration_node.type}" end @name = name.to_sym @declaration_node = declaration_node @scope = scope @assignments = [] @references = [] @captured_by_block = false end
def keyword_argument?
def keyword_argument? %i[kwarg kwoptarg].include?(@declaration_node.type) end
def method_argument?
def method_argument? argument? && %i[def defs].include?(@scope.node.type) end
def reference!(node)
def reference!(node) reference = Reference.new(node, @scope) @references << reference consumed_branches = nil @assignments.reverse_each do |assignment| next if consumed_branches&.include?(assignment.branch) assignment.reference!(node) unless assignment.run_exclusively_with?(reference) # Modifier if/unless conditions are special. Assignments made in # them do not put the assigned variable in scope to the left of the # if/unless keyword. A preceding assignment is needed to put the # variable in scope. For this reason we skip to the next assignment # here. next if in_modifier_if?(assignment) break if !assignment.branch || assignment.branch == reference.branch unless assignment.branch.may_run_incompletely? (consumed_branches ||= Set.new) << assignment.branch end end end
def referenced?
def referenced? !@references.empty? end
def should_be_unused?
def should_be_unused? name.to_s.start_with?('_') end
def used?
This means we cannot track the usage of the variable.
when, where, and how many times the block would be invoked.
Once the variable is captured by a block, we have no idea
For more precise usage check, refer Assignment#used?.
in its entire variable lifetime.
This is a convenient way to check whether the variable is used
def used? @captured_by_block || referenced? end