module RuboCop::Yast::TrackVariableScope

This module tracks variable usage

Public Instance Methods

on_and_asgn(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 103
def on_and_asgn(node)
  super
  var, value = *node
  bool_op_asgn(var, value, :and)
  node
end
on_block(node) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 117
def on_block(node)
  # ignore body, clean slate
  scope.clear
  node
end
Also aliased as: on_for
on_case(node) click to toggle source

def on_unless Does not exist. ‘unless` is parsed as an `if` with then_body and else_body swapped. Compare with `while` and `until` which cannot do that and thus need distinct node types. end

# File lib/rubocop/yast/track_variable_scope.rb, line 79
def on_case(node)
  expr, *cases = *node
  process(expr)

  cases.each do |case_|
    scopes.with_copy do
      process(case_)
    end
  end

  # clean slate
  scope.clear

  node
end
on_class(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 46
def on_class(node)
  with_new_scope_rescuing_oops(node) { super }
end
on_def(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 29
def on_def(node)
  name, _, _ = *node
  RuboCop::Yast.logger.debug "ONDEF #{name}"
  RuboCop::Yast.logger.debug "CUR SCOPE #{scope.inspect}"
  RuboCop::Yast.backtrace skip_frames: 50 if $DEBUG

  with_new_scope_rescuing_oops(node) { super }
end
on_defs(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 38
def on_defs(node)
  with_new_scope_rescuing_oops(node) { super }
end
on_ensure(node) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 169
def on_ensure(node)
  # (:ensure, guarded-code, ensuring-code)
  # guarded-code may be a :rescue or not

  scope.clear
  node
end
on_for(node)
Alias for: on_block
on_if(node) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 54
def on_if(node)
  cond, then_body, else_body = *node
  process(cond)

  scopes.with_copy do
    process(then_body)
  end

  scopes.with_copy do
    process(else_body)
  end

  # clean slate
  scope.clear

  node
end
on_lvasgn(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 95
def on_lvasgn(node)
  super
  name, value = * node
  return if value.nil? # and-asgn, or-asgn, resbody do this
  scope[name].nice = nice(value)
  node
end
on_module(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 42
def on_module(node)
  with_new_scope_rescuing_oops(node) { super }
end
on_or_asgn(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 110
def on_or_asgn(node)
  super
  var, value = *node
  bool_op_asgn(var, value, :or)
  node
end
on_resbody(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 155
def on_resbody(node)
  # How it is parsed:
  # (:resbody, exception-types-or-nil, exception-variable-or-nil, body)
  # exception-types is an :array
  # exception-variable is a (:lvasgn, name), without a value

  # A rescue means that *some* previous code was skipped.
  # We know nothing. We could process the resbodies individually,
  # and join begin-block with else-block, but it is little worth
  # because they will contain few zombies.
  scope.clear
  super
end
on_rescue(node) click to toggle source

Exceptions: ‘raise` is an ordinary :send for the parser

# File lib/rubocop/yast/track_variable_scope.rb, line 137
def on_rescue(node)
  # (:rescue, begin-block, resbody..., else-block-or-nil)
  begin_body, *rescue_bodies, else_body = *node

  if rescue_bodies.any? { |r| descendant?(r, :retry) }
    # do not process if a retry may cause a loop
    return node
  end

  process(begin_body)
  process(else_body)
  rescue_bodies.each do |r|
    process(r)
  end

  node
end
on_sclass(node) click to toggle source
Calls superclass method
# File lib/rubocop/yast/track_variable_scope.rb, line 50
def on_sclass(node)
  with_new_scope_rescuing_oops(node) { super }
end
on_until(node)
Alias for: on_while
on_while(node) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 124
def on_while(node)
  # ignore both condition and body,
  # with a simplistic scope we cannot handle them

  # clean slate
  scope.clear
  node
end
Also aliased as: on_until
scope() click to toggle source

currently visible scope

# File lib/rubocop/yast/track_variable_scope.rb, line 17
def scope
  scopes.innermost
end
scopes() click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 12
def scopes
  @scopes ||= VariableScopeStack.new
end
with_new_scope_rescuing_oops(node, &block) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 21
def with_new_scope_rescuing_oops(node, &block)
  scopes.with_new do
    block.call if block_given?
  end
rescue => e
  oops(node, e)
end

Private Instance Methods

bool_op_asgn(var, value, op) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 193
def bool_op_asgn(var, value, op)
  return if var.type != :lvasgn
  name = var.children[0]

  case op
  when :and
    scope[name].nice &&= nice(value)
  when :or
    scope[name].nice ||= nice(value)
  else
    raise "Unknown operator: #{op}"
  end
end
descendant?(node, descendant_type) click to toggle source

does node have a particular type as a descendant?

# File lib/rubocop/yast/track_variable_scope.rb, line 180
def descendant?(node, descendant_type)
  on_node(descendant_type, node) do
    return true           # short circuit, returns from the method
  end
  false
end
oops(node, exception) click to toggle source
# File lib/rubocop/yast/track_variable_scope.rb, line 187
def oops(node, exception)
  puts "Node exception @ #{node.loc.expression}"
  puts "Offending node: #{node.inspect}"
  raise exception unless exception.is_a?(TooComplexToTranslateError)
end