module Rubocop::Cop::VariableInspector

def after_declaring_variable(variable_variable)

def after_declaring_variable(variable_variable)
end

def after_entering_scope(scope)

def after_entering_scope(scope)
end

def after_leaving_scope(scope)

def after_leaving_scope(scope)
end

def before_declaring_variable(variable_variable)

def before_declaring_variable(variable_variable)
end

def before_entering_scope(scope)

def before_entering_scope(scope)
end

def before_leaving_scope(scope)

def before_leaving_scope(scope)
end

def dispatch_node(node)

def dispatch_node(node)
  case node.type
  when *DECLARATION_TYPES
    process_variable_declaration(node)
  when VARIABLE_ASSIGNMENT_TYPE
    process_variable_assignment(node)
  when REGEXP_NAMED_CAPTURE_TYPE
    process_regexp_named_captures(node)
  when *OPERATOR_ASSIGNMENT_TYPES
    process_variable_operator_assignment(node)
  when MULTIPLE_ASSIGNMENT_TYPE
    process_variable_multiple_assignment(node)
  when VARIABLE_REFERENCE_TYPE
    process_variable_referencing(node)
  when *LOOP_TYPES
    process_loop(node)
  when RESCUE_TYPE
    process_rescue(node)
  when ZERO_ARITY_SUPER_TYPE
    process_zero_arity_super(node)
  when *SCOPE_TYPES
    process_scope(node)
  end
end

def inspect_variables(root_node)

Starting point.
def inspect_variables(root_node)
  return unless root_node
  # Wrap with begin node if it's standalone node.
  unless root_node.type == :begin
    root_node = Parser::AST::Node.new(:begin, [root_node])
  end
  inspect_variables_in_scope(root_node)
end

def inspect_variables_in_scope(scope_node)

This is called for each scope recursively.
def inspect_variables_in_scope(scope_node)
  variable_table.push_scope(scope_node)
  process_children(scope_node)
  variable_table.pop_scope
end

def mark_assignments_as_referenced_in_loop(node)

in next iteration.
as referenced by ignoring AST order since they would be referenced
Mark all assignments which are referenced in the same loop
def mark_assignments_as_referenced_in_loop(node)
  referenced_variable_names_in_loop = []
  assignment_nodes_in_loop = []
  # #scan does not consider scope,
  # but we don't need to care about it here.
  scan(node) do |scanning_node|
    case scanning_node.type
    when :lvar
      referenced_variable_names_in_loop << scanning_node.children.first
    when :lvasgn
      assignment_nodes_in_loop << scanning_node
    end
  end
  referenced_variable_names_in_loop.each do |name|
    variable = variable_table.find_variable(name)
    # Non related references which are catched in the above scan
    # would be skipped here.
    next unless variable
    variable.assignments.each do |assignment|
      next if assignment_nodes_in_loop.none? do |assignment_node|
                assignment_node.equal?(assignment.node)
              end
      assignment.reference!
    end
  end
end

def process_children(origin_node)

def process_children(origin_node)
  origin_node.children.each do |child|
    next unless child.is_a?(Parser::AST::Node)
    next if scanned_node?(child)
    process_node(child)
  end
end

def process_loop(node)

def process_loop(node)
  if POST_CONDITION_LOOP_TYPES.include?(node.type)
    # See the comment at the end of file for this behavior.
    condition_node, body_node = *node
    process_node(body_node)
    process_node(condition_node)
  else
    process_children(node)
  end
  mark_assignments_as_referenced_in_loop(node)
  skip_children!
end

def process_node(node)

def process_node(node)
  catch(:skip_children) do
    dispatch_node(node)
    process_children(node)
  end
end

def process_regexp_named_captures(node)

def process_regexp_named_captures(node)
  regexp_node, rhs_node = *node
  regexp_string = regexp_node.children[0].children[0]
  regexp = Regexp.new(regexp_string)
  variable_names = regexp.named_captures.keys
  variable_names.each do |name|
    unless variable_table.variable_exist?(name)
      variable_table.declare_variable(name, node)
    end
  end
  process_node(rhs_node)
  process_node(regexp_node)
  variable_names.each do |name|
    variable_table.assign_to_variable(name, node)
  end
  skip_children!
end

def process_rescue(node)

def process_rescue(node)
  resbody_nodes = node.children.select do |child|
    next false unless child.is_a?(Parser::AST::Node)
    child.type == :resbody
  end
  contain_retry = resbody_nodes.any? do |resbody_node|
    scan(resbody_node) do |node_in_resbody|
      break true if node_in_resbody.type == :retry
    end
  end
  # Treat begin..rescue..end with retry as a loop.
  process_loop(node) if contain_retry
end

def process_scope(node)

def process_scope(node)
  if TWISTED_SCOPE_TYPES.include?(node.type)
    # See the comment at the end of file for this behavior.
    twisted_nodes = [node.children[0]]
    twisted_nodes << node.children[1] if node.type == :class
    twisted_nodes.compact!
    twisted_nodes.each do |twisted_node|
      process_node(twisted_node)
      scanned_nodes << twisted_node
    end
  end
  inspect_variables_in_scope(node)
  skip_children!
end

def process_variable_assignment(node)

def process_variable_assignment(node)
  name = node.children.first
  unless variable_table.variable_exist?(name)
    variable_table.declare_variable(name, node)
  end
  # Need to scan rhs before assignment so that we can mark previous
  # assignments as referenced if rhs has referencing to the variable
  # itself like:
  #
  #   foo = 1
  #   foo = foo + 1
  process_children(node)
  variable_table.assign_to_variable(name, node)
  skip_children!
end

def process_variable_declaration(node)

def process_variable_declaration(node)
  # restarg would have no name:
  #
  #   def initialize(*)
  #   end
  return if node.type == :restarg && node.children.empty?
  variable_name = node.children.first
  variable_table.declare_variable(variable_name, node)
end

def process_variable_multiple_assignment(node)

def process_variable_multiple_assignment(node)
  lhs_node, rhs_node = *node
  process_node(rhs_node)
  process_node(lhs_node)
  skip_children!
end

def process_variable_operator_assignment(node)

def process_variable_operator_assignment(node)
  if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
    asgn_node, rhs_node = *node
  else
    asgn_node, _operator, rhs_node = *node
  end
  return unless asgn_node.type == :lvasgn
  name = asgn_node.children.first
  unless variable_table.variable_exist?(name)
    variable_table.declare_variable(name, asgn_node)
  end
  # The following statements:
  #
  #   foo = 1
  #   foo += foo = 2
  #   # => 3
  #
  # are equivalent to:
  #
  #   foo = 1
  #   foo = foo + (foo = 2)
  #   # => 3
  #
  # So, at operator assignment node, we need to reference the variable
  # before processing rhs nodes.
  variable_table.reference_variable(name, node)
  process_node(rhs_node)
  variable_table.assign_to_variable(name, asgn_node)
  skip_children!
end

def process_variable_referencing(node)

def process_variable_referencing(node)
  name = node.children.first
  variable_table.reference_variable(name, node)
end

def process_zero_arity_super(node)

def process_zero_arity_super(node)
  variable_table.accessible_variables.each do |variable|
    next unless variable.method_argument?
    variable.reference!(node)
  end
end

def scan(node, &block)

Simple recursive scan
def scan(node, &block)
  node.children.each do |child|
    next unless child.is_a?(Parser::AST::Node)
    yield child
    scan(child, &block)
  end
  nil
end

def scanned_node?(node)

Use Node#equal? for accurate check.
def scanned_node?(node)
  scanned_nodes.any? do |scanned_node|
    scanned_node.equal?(node)
  end
end

def scanned_nodes

def scanned_nodes
  @scanned_nodes ||= []
end

def skip_children!

def skip_children!
  throw :skip_children
end

def variable_table

def variable_table
  @variable_table ||= VariableTable.new(self)
end