class RubyLint::VirtualMachine

{RubyLint::VirtualMachine} is the heart of ruby-lint. It takes a AST generated by {RubyLint::Parser}, iterates it and builds various definitions of methods, variables, etc.

The virtual machine is a stack based virtual machine. Whenever certain expressions are processed their values are stored in a stack which is then later used for creating definitions (where applicable). For example, when creating a new class a definition for the class is pushed on to a stack. All code defined in this class is then stored in the definition at the end of the stack.

After a certain AST has been processed the VM will enter a read-only state to prevent code from modifying it (either on purpose or by accident).

## Stacks

The virtual machine uses two stacks:

The value stack is used for storing raw values (e.g. integers) while the variable stack is used for storing variable definitions (which in turn store their values inside themselves).

## Definitions

Built definitions are stored in {RubyLint::VirtualMachine#definitions} as a single root definition called “root”. This definition in turn contains everything defined in a block of code that was processed by the VM.

## Associations

The VM also keeps track of various nodes and their corresponding definitions to make it easier to retrieve them later on. These are only nodes/definitions related to a new scope such as a class or method definition node.

These associations are stored as a Hash in {RubyLint::VirtualMachine#associations} with the keys set to the nodes and the values to the corresponding definitions.

## Options

The following extra options can be set in the constructor:

@!attribute [r] associations

@return [Hash]

@!attribute [r] comments

@return [Hash]

@!attribute [r] definitions

@return [RubyLint::Definition::RubyObject]

@!attribute [r] extra_definitions

@return [Array]

@!attribute [r] value_stack

@return [RubyLint::NestedStack]

@!attribute [r] variable_stack

@return [RubyLint::NestedStack]

@!attribute [r] docstring_tags

@return [RubyLint::Docstring::Mapping]

Constants

ARGUMENT_TYPES

Array containing the various argument types of method definitions.

@return [Array]

ASSIGNMENT_TYPES

Hash containing variable assignment types and the corresponding variable reference types.

@return [Hash]

ASSIGN_GLOBAL

List of variable types that should be assigned in the global scope.

@return [Array]

EXPORT_VARIABLES

The types of variables to export outside of a method definition.

@return [Array]

PRIMITIVES

Collection of primitive value types.

@return [Array]

SEND_MAPPING

Returns a Hash containing the method call evaluators to use for `(send)` nodes.

@return [Hash]

VISIBILITIES

The available method visibilities.

@return [Array]

Attributes

associations[R]
comments[R]
definitions[R]
docstring_tags[R]
value_stack[R]
variable_stack[R]

Public Instance Methods

after_alias(node) click to toggle source

Processes calls to `alias`. Two types of data can be aliased:

  1. Methods (using the syntax `alias ALIAS SOURCE`)

  2. Global variables

This method dispatches the alias process to two possible methods:

  • on_alias_sym: aliasing methods (using symbols)

  • on_alias_gvar: aliasing global variables

# File lib/ruby-lint/virtual_machine.rb, line 750
def after_alias(node)
  arguments = value_stack.pop
  evaluator = MethodCall::Alias.new(node, self)

  evaluator.evaluate(arguments, current_scope)
end
after_and_asgn() click to toggle source

Processes an `and` assignment in the form of `variable &&= value`.

# File lib/ruby-lint/virtual_machine.rb, line 327
def after_and_asgn
  variable = variable_stack.pop.first
  value    = value_stack.pop.first

  conditional_assignment(variable, value)
end
after_array(node) click to toggle source

Builds an Array.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 387
def after_array(node)
  builder = DefinitionBuilder::RubyArray.new(
    node,
    self,
    :values => value_stack.pop
  )

  push_value(builder.build)
end
after_assign(node) click to toggle source

@see on_assign

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 231
def after_assign(node)
  type  = ASSIGNMENT_TYPES[node.type]
  name  = node.children[0].to_s
  value = value_stack.pop.first

  if !value and assignment_value
    value = assignment_value
  end

  assign_variable(type, name, value, node)
end
after_block() click to toggle source

Pops the scope created by the block.

# File lib/ruby-lint/virtual_machine.rb, line 521
def after_block
  pop_scope
end
after_casgn(node) click to toggle source

@see on_casgn

# File lib/ruby-lint/virtual_machine.rb, line 264
def after_casgn(node)
  values = value_stack.pop
  scope  = current_scope

  if node.children[0]
    scope = ConstantPath.new(node.children[0]).resolve(current_scope)

    return unless scope
  end

  variable = Definition::RubyObject.new(
    :type          => :const,
    :name          => node.children[1].to_s,
    :value         => values.first,
    :instance_type => :instance
  )

  add_variable(variable, scope)
end
after_class() click to toggle source

Pops the scope created by the class.

# File lib/ruby-lint/virtual_machine.rb, line 500
def after_class
  pop_scope
end
after_def() click to toggle source

Exports various variables to the outer scope of the method definition.

# File lib/ruby-lint/virtual_machine.rb, line 594
def after_def
  previous = pop_scope
  current  = current_scope

  reset_docstring_tags

  EXPORT_VARIABLES.each do |type|
    current.copy(previous, type)
  end
end
Also aliased as: after_defs
after_defs()
Alias for: after_def
after_hash(node) click to toggle source

Builds a Hash.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 409
def after_hash(node)
  builder = DefinitionBuilder::RubyHash.new(
    node,
    self,
    :values => value_stack.pop
  )

  push_value(builder.build)
end
after_initialize() click to toggle source

Called after a new instance of the virtual machine has been created.

# File lib/ruby-lint/virtual_machine.rb, line 165
def after_initialize
  @comments ||= {}

  @associations    = {}
  @definitions     = initial_definitions
  @constant_loader = ConstantLoader.new(:definitions => @definitions)
  @scopes          = [@definitions]
  @value_stack     = NestedStack.new
  @variable_stack  = NestedStack.new
  @ignored_nodes   = []
  @visibility      = :public

  reset_docstring_tags
  reset_method_type

  @constant_loader.bootstrap
end
after_masgn() click to toggle source

Processes a mass variable assignment using the stacks created by {#on_masgn}.

# File lib/ruby-lint/virtual_machine.rb, line 292
def after_masgn
  variables = variable_stack.pop
  values    = value_stack.pop.first
  values    = values && values.value ? values.value : []

  variables.each_with_index do |variable, index|
    variable.value = values[index].value if values[index]

    current_scope.add(variable.type, variable.name, variable)
  end
end
after_module() click to toggle source

Pops the scope created by the module.

# File lib/ruby-lint/virtual_machine.rb, line 472
def after_module
  pop_scope
end
after_or_asgn() click to toggle source

Processes an `or` assignment in the form of `variable ||= value`.

# File lib/ruby-lint/virtual_machine.rb, line 311
def after_or_asgn
  variable = variable_stack.pop.first
  value    = value_stack.pop.first

  if variable and value
    conditional_assignment(variable, value, false)
  end
end
after_pair() click to toggle source

@see on_pair

# File lib/ruby-lint/virtual_machine.rb, line 429
def after_pair
  key, value = value_stack.pop

  return unless key

  member = Definition::RubyObject.new(
    :name  => key.value.to_s,
    :type  => :member,
    :value => value
  )

  push_value(member)
end
after_sclass() click to toggle source

Pops the scope created by the `sclass` block and resets the method definition/send type.

# File lib/ruby-lint/virtual_machine.rb, line 548
def after_sclass
  reset_method_type
  pop_scope
end
after_send(node) click to toggle source

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 653
    def after_send(node)
      receiver, name, _ = *node

      receiver    = unpack_block(receiver)
      name        = name.to_s
      args_length = node.children[2..-1].length
      values      = value_stack.pop
      arguments   = values.pop(args_length)
      block       = nil

      receiver_definition = values.first

      if arguments.length != args_length
        raise <<-EOF
Not enough argument definitions for #{node.inspect_oneline}.
Location: #{node.file} on line #{node.line}, column #{node.column}
Expected: #{args_length}
Received: #{arguments.length}
        EOF
      end

      # Associate the argument definitions with their nodes.
      arguments.each_with_index do |obj, index|
        arg_node = unpack_block(node.children[2 + index])

        associate_node(arg_node, obj)
      end

      # If the receiver doesn't exist there's no point in associating a context
      # with it.
      if receiver and !receiver_definition
        push_unknown_value

        return
      end

      if receiver and receiver_definition
        context = receiver_definition
      else
        context = current_scope

        # `parser` wraps (block) nodes around (send) calls which is a bit
        # inconvenient
        if context.block?
          block   = context
          context = previous_scope
        end
      end

      if SEND_MAPPING[name]
        evaluator = SEND_MAPPING[name].new(node, self)

        evaluator.evaluate(arguments, context, block)
      end

      # Associate the receiver node with the context so that it becomes
      # easier to retrieve later on.
      if receiver and context
        associate_node(receiver, context)
      end

      if context and context.method_defined?(name)
        retval = context.call_method(name)

        retval ? push_value(retval) : push_unknown_value

        # Track the method call
        track_method_call(context, name, node)
      else
        push_unknown_value
      end
    end
current_scope() click to toggle source

@return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 760
def current_scope
  return @scopes.last
end
evaluate_node(node) click to toggle source

Evaluates and returns the value of the given node.

@param [RubyLint::AST::Node] node @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 795
def evaluate_node(node)
  value_stack.add_stack

  iterate(node)

  return value_stack.pop.first
end
freeze() click to toggle source

Freezes the VM along with all the instance variables.

Calls superclass method
# File lib/ruby-lint/virtual_machine.rb, line 203
def freeze
  @associations.freeze
  @definitions.freeze
  @scopes.freeze

  super
end
global_constant(name) click to toggle source

@param [String] name @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 776
def global_constant(name)
  found = definitions.lookup(:const, name)

  # Didn't find it? Lets see if the constant loader knows about it.
  unless found
    @constant_loader.load_constant(name)

    found = definitions.lookup(:const, name)
  end

  return found
end
on_alias() click to toggle source

Adds a new value stack for the values of an alias.

# File lib/ruby-lint/virtual_machine.rb, line 735
def on_alias
  value_stack.add_stack
end
on_and_asgn() click to toggle source
# File lib/ruby-lint/virtual_machine.rb, line 320
def on_and_asgn
  add_stacks
end
on_array() click to toggle source

Adds a new stack for Array values.

# File lib/ruby-lint/virtual_machine.rb, line 378
def on_array
  value_stack.add_stack
end
on_assign() click to toggle source

Processes a regular variable assignment.

# File lib/ruby-lint/virtual_machine.rb, line 221
def on_assign
  reset_assignment_value
  value_stack.add_stack
end
on_block(node) click to toggle source

Builds the definition for a block.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 509
def on_block(node)
  builder    = DefinitionBuilder::RubyBlock.new(node, self)
  definition = builder.build

  associate_node(node, definition)

  push_scope(definition)
end
on_casgn(node) click to toggle source

Processes the assignment of a constant.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 253
def on_casgn(node)
  # Don't push values for the receiver constant.
  @ignored_nodes << node.children[0] if node.children[0]

  reset_assignment_value
  value_stack.add_stack
end
on_class(node) click to toggle source

Creates the definition for a class.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 481
def on_class(node)
  parent      = nil
  parent_node = node.children[1]

  if parent_node
    parent = evaluate_node(parent_node)

    if !parent or !parent.const?
      # FIXME: this should use `definitions` instead.
      parent = current_scope.lookup(:const, 'Object')
    end
  end

  define_module(node, DefinitionBuilder::RubyClass, :parent => parent)
end
on_const(node) click to toggle source

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 366
def on_const(node)
  increment_reference_amount(node)
  push_variable_value(node)

  # The root node is also used in such a way that it processes child (=
  # receiver) constants.
  skip_child_nodes!(node)
end
on_def(node) click to toggle source

Creates the definition for a method definition.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 558
def on_def(node)
  receiver = nil

  if node.type == :defs
    receiver = evaluate_node(node.children[0])
  end

  builder = DefinitionBuilder::RubyMethod.new(
    node,
    self,
    :type       => @method_type,
    :receiver   => receiver,
    :visibility => @visibility
  )

  definition = builder.build

  builder.scope.add_definition(definition)

  associate_node(node, definition)

  buffer_docstring_tags(node)

  if docstring_tags and docstring_tags.return_tag
    assign_return_value_from_tag(
      docstring_tags.return_tag,
      definition
    )
  end

  push_scope(definition)
end
Also aliased as: on_defs
on_defs(node)
Alias for: on_def
on_hash() click to toggle source

Adds a new stack for Hash values.

# File lib/ruby-lint/virtual_machine.rb, line 400
def on_hash
  value_stack.add_stack
end
on_masgn() click to toggle source
# File lib/ruby-lint/virtual_machine.rb, line 284
def on_masgn
  add_stacks
end
on_module(node) click to toggle source

Creates the definition for a module.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 465
def on_module(node)
  define_module(node, DefinitionBuilder::RubyModule)
end
on_nth_ref(node) click to toggle source

Called whenever a magic regexp global variable is referenced (e.g. `$1`).

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 355
def on_nth_ref(node)
  var = definitions.lookup(:gvar, "$#{node.children[0]}")
  # If the number is not found, then add it as there is no limit for them
  var = definitions.define_global_variable(node.children[0]) if !var && node.children[0].is_a?(Fixnum)

  push_value(var.value)
end
on_or_asgn() click to toggle source
# File lib/ruby-lint/virtual_machine.rb, line 304
def on_or_asgn
  add_stacks
end
on_pair() click to toggle source

Adds a new value stack for key/value pairs.

# File lib/ruby-lint/virtual_machine.rb, line 422
def on_pair
  value_stack.add_stack
end
on_root(node) click to toggle source

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 214
def on_root(node)
  associate_node(node, current_scope)
end
on_sclass(node) click to toggle source

Processes an sclass block. Sclass blocks look like the following:

class << self

end

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 534
def on_sclass(node)
  parent       = node.children[0]
  definition   = evaluate_node(parent)
  @method_type = definition.method_call_type

  associate_node(node, definition)

  push_scope(definition)
end
on_self() click to toggle source

Pushes the value of `self` onto the current stack.

# File lib/ruby-lint/virtual_machine.rb, line 446
def on_self
  scope  = current_scope
  method = scope.lookup(scope.method_call_type, 'self')

  push_value(method.return_value)
end
on_send(node) click to toggle source

Processes a method call. If a certain method call has its own dedicated callback that one will be called as well.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 640
def on_send(node)
  name     = node.children[1].to_s
  name     = SEND_MAPPING.fetch(name, name)
  callback = "on_send_#{name}"

  value_stack.add_stack

  execute_callback(callback, node)
end
on_yield() click to toggle source

Pushes the return value of the block yielded to, that is, an unknown one.

# File lib/ruby-lint/virtual_machine.rb, line 456
def on_yield
  push_unknown_value
end
previous_scope() click to toggle source

@return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 768
def previous_scope
  return @scopes[-2]
end
run(ast) click to toggle source

Processes the given AST or a collection of AST nodes.

@see iterate @param [Array|RubyLint::AST::Node] ast

# File lib/ruby-lint/virtual_machine.rb, line 189
def run(ast)
  ast = [ast] unless ast.is_a?(Array)

  # pre-load all the built-in definitions.
  @constant_loader.run(ast)

  ast.each { |node| iterate(node) }

  freeze
end

Private Instance Methods

add_stacks() click to toggle source

Adds a new variable and value stack.

# File lib/ruby-lint/virtual_machine.rb, line 927
def add_stacks
  variable_stack.add_stack
  value_stack.add_stack
end
add_variable(variable, scope = current_scope) click to toggle source

Adds a variable to the current scope of, if a the variable stack is not empty, add it to the stack instead.

@param [RubyLint::Definition::RubyObject] variable @param [RubyLint::Definition::RubyObject] scope

# File lib/ruby-lint/virtual_machine.rb, line 992
def add_variable(variable, scope = current_scope)
  if variable_stack.empty?
    scope.add(variable.type, variable.name, variable)
  else
    variable_stack.push(variable)
  end
end
assign_return_value_from_tag(tag, definition) click to toggle source

@param [RubyLint::Docstring::ReturnTag] tag @param [RubyLint::Definition::RubyMethod] definition

# File lib/ruby-lint/virtual_machine.rb, line 1195
def assign_return_value_from_tag(tag, definition)
  definitions = definitions_for_types(tag.types)

  # THINK: currently ruby-lint assumes methods always return a single type
  # but YARD allows you to specify multiple ones. For now we'll take the
  # first one but there should be a nicer way to do this.
  definition.returns(definitions[0].instance) if definitions[0]
end
assign_variable(type, name, value, node) click to toggle source

Assigns a basic variable.

@param [Symbol] type The type of variable. @param [String] name The name of the variable @param [RubyLint::Definition::RubyObject] value @param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 940
def assign_variable(type, name, value, node)
  scope    = assignment_scope(type)
  variable = scope.lookup(type, name)

  # If there's already a variable we'll just update it.
  if variable
    variable.reference_amount += 1

    # `value` is not for conditional assignments as those are handled
    # manually.
    variable.value = value if value
  else
    variable = Definition::RubyObject.new(
      :type             => type,
      :name             => name,
      :value            => value,
      :instance_type    => :instance,
      :reference_amount => 0,
      :line             => node.line,
      :column           => node.column,
      :file             => node.file
    )
  end

  buffer_assignment_value(value)

  # Primarily used by #after_send to support variable assignments as method
  # call arguments.
  if value and !value_stack.empty?
    value_stack.push(variable.value)
  end

  add_variable(variable, scope)
end
assignment_scope(type) click to toggle source

Determines the scope to use for a variable assignment.

@param [Symbol] type @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 981
def assignment_scope(type)
  return ASSIGN_GLOBAL.include?(type) ? definitions : current_scope
end
assignment_value() click to toggle source

Returns the value of the last assignment.

# File lib/ruby-lint/virtual_machine.rb, line 1022
def assignment_value
  return @assignment_value
end
associate_node(node, definition) click to toggle source

Associates the given node and defintion with each other.

@param [RubyLint::AST::Node] node @param [RubyLint::Definition::RubyObject] definition

# File lib/ruby-lint/virtual_machine.rb, line 861
def associate_node(node, definition)
  @associations[node] = definition
end
buffer_assignment_value(value) click to toggle source

Stores the value as the last assigned value.

@param [RubyLint::Definition::RubyObject] value

# File lib/ruby-lint/virtual_machine.rb, line 1031
def buffer_assignment_value(value)
  @assignment_value = value
end
buffer_docstring_tags(node) click to toggle source

Extracts all the docstring tags from the documentation of the given node, retrieves the corresponding types and stores them for later use.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 1113
def buffer_docstring_tags(node)
  return unless comments[node]

  parser = Docstring::Parser.new
  tags   = parser.parse(comments[node].map(&:text))

  @docstring_tags = Docstring::Mapping.new(tags)
end
conditional_assignment(variable, value, bool = true) click to toggle source

Performs a conditional assignment.

@param [RubyLint::Definition::RubyObject] variable @param [RubyLint::Definition::RubyValue] value @param [TrueClass|FalseClass] bool When set to `true` existing variables

will be overwritten.
# File lib/ruby-lint/virtual_machine.rb, line 1050
def conditional_assignment(variable, value, bool = true)
  variable.reference_amount += 1

  if current_scope.has_definition?(variable.type, variable.name) == bool
    variable.value = value

    current_scope.add_definition(variable)

    buffer_assignment_value(variable.value)
  end
end
create_primitive(node, options = {}) click to toggle source

Creates a primitive value such as an integer.

@param [RubyLint::AST::Node] node @param [Hash] options

# File lib/ruby-lint/virtual_machine.rb, line 1006
def create_primitive(node, options = {})
  builder = DefinitionBuilder::Primitive.new(node, self, options)

  return builder.build
end
create_unknown_with_method(name) click to toggle source

Creates an “unknown” definition with the given method in it.

@param [String] name The name of the method to add. @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 1148
def create_unknown_with_method(name)
  definition = Definition::RubyObject.create_unknown

  definition.send("define_#{@method_type}", name)

  return definition
end
define_module(node, definition_builder, options = {}) click to toggle source

Defines a new module/class based on the supplied node.

@param [RubyLint::Node] node @param [RubyLint::DefinitionBuilder::Base] definition_builder @param [Hash] options

# File lib/ruby-lint/virtual_machine.rb, line 834
def define_module(node, definition_builder, options = {})
  builder    = definition_builder.new(node, self, options)
  definition = builder.build
  scope      = builder.scope
  existing   = scope.lookup(definition.type, definition.name, false)

  if existing
    definition = existing

    inherit_definition(definition, current_scope)
  else
    definition.add_definition(definition)

    scope.add_definition(definition)
  end

  associate_node(node, definition)

  push_scope(definition)
end
definition_for_node(node) click to toggle source

Returns the definition for the given node.

@param [RubyLint::AST::Node] node @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 1068
def definition_for_node(node)
  if node.const? and node.children[0]
    definition = ConstantPath.new(node).resolve(current_scope)
  else
    definition = current_scope.lookup(node.type, node.name)
  end

  definition = Definition::RubyObject.create_unknown unless definition

  return definition
end
definitions_for_types(types) click to toggle source

Returns a collection of definitions for a set of YARD types.

@param [Array] types @return [Array]

# File lib/ruby-lint/virtual_machine.rb, line 1162
def definitions_for_types(types)
  definitions = []

  # There are basically two type signatures: either the name(s) of a
  # constant or a method in the form of `#method_name`.
  types.each do |type|
    if type[0] == '#'
      found = create_unknown_with_method(type[1..-1])
    else
      found = lookup_type_definition(type)
    end

    definitions << found if found
  end

  return definitions
end
increment_reference_amount(node) click to toggle source

Increments the reference amount of a node's definition unless the definition is frozen.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 1086
def increment_reference_amount(node)
  definition = definition_for_node(node)

  if definition and !definition.frozen?
    definition.reference_amount += 1
  end
end
inherit_definition(definition, inherit) click to toggle source

Includes the definition `inherit` in the list of parent definitions of `definition`.

@param [RubyLint::Definition::RubyObject] definition @param [RubyLint::Definition::RubyObject] inherit

# File lib/ruby-lint/virtual_machine.rb, line 1101
def inherit_definition(definition, inherit)
  unless definition.parents.include?(inherit)
    definition.parents << inherit
  end
end
initial_definitions() click to toggle source

Returns the initial set of definitions to use.

@return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 810
def initial_definitions
  definitions = Definition::RubyObject.new(
    :name          => 'root',
    :type          => :root,
    :instance_type => :instance,
    :inherit_self  => false
  )

  definitions.parents = [
    definitions.constant_proxy('Object', RubyLint.registry)
  ]

  definitions.define_self

  return definitions
end
lookup_type_definition(name) click to toggle source

Tries to look up the given type/constant in the current scope and falls back to the global scope if it couldn't be found in the former.

@param [String] name @return [RubyLint::Definition::RubyObject]

# File lib/ruby-lint/virtual_machine.rb, line 1187
def lookup_type_definition(name)
  return current_scope.lookup(:const, name) || global_constant(name)
end
pop_scope() click to toggle source

Removes a scope from the list.

# File lib/ruby-lint/virtual_machine.rb, line 885
def pop_scope
  raise 'Trying to pop an empty scope' if @scopes.empty?

  @scopes.pop
end
push_scope(definition) click to toggle source

Pushes a new scope on the list of available scopes.

@param [RubyLint::Definition::RubyObject] definition

# File lib/ruby-lint/virtual_machine.rb, line 870
def push_scope(definition)
  unless definition.is_a?(RubyLint::Definition::RubyObject)
    raise(
      ArgumentError,
      "Expected a RubyLint::Definition::RubyObject but got " \
        "#{definition.class} instead"
    )
  end

  @scopes << definition
end
push_unknown_value() click to toggle source

Pushes an unknown value object onto the value stack.

# File lib/ruby-lint/virtual_machine.rb, line 920
def push_unknown_value
  push_value(Definition::RubyObject.create_unknown)
end
push_value(definition) click to toggle source

Pushes a definition (of a value) onto the value stack.

@param [RubyLint::Definition::RubyObject] definition

# File lib/ruby-lint/virtual_machine.rb, line 913
def push_value(definition)
  value_stack.push(definition) if definition && !value_stack.empty?
end
push_variable_value(node) click to toggle source

Pushes the value of a variable onto the value stack.

@param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 896
def push_variable_value(node)
  return if value_stack.empty? || @ignored_nodes.include?(node)

  definition = definition_for_node(node)

  if definition
    value = definition.value ? definition.value : definition

    push_value(value)
  end
end
reset_assignment_value() click to toggle source

Resets the variable used for storing the last assignment value.

# File lib/ruby-lint/virtual_machine.rb, line 1015
def reset_assignment_value
  @assignment_value = nil
end
reset_docstring_tags() click to toggle source

Resets the docstring tags collection back to its initial value.

# File lib/ruby-lint/virtual_machine.rb, line 1125
def reset_docstring_tags
  @docstring_tags = nil
end
reset_method_type() click to toggle source

Resets the method assignment/call type.

# File lib/ruby-lint/virtual_machine.rb, line 1038
def reset_method_type
  @method_type = :instance_method
end
track_method_call(definition, name, node) click to toggle source

Tracks a method call.

@param [RubyLint::Definition::RubyMethod] definition @param [String] name @param [RubyLint::AST::Node] node

# File lib/ruby-lint/virtual_machine.rb, line 1211
def track_method_call(definition, name, node)
  method   = definition.lookup(definition.method_call_type, name)
  current  = current_scope
  location = {
    :line   => node.line,
    :column => node.column,
    :file   => node.file
  }

  # Add the call to the current scope if we're dealing with a writable
  # method definition.
  if current.respond_to?(:calls) and !current.frozen?
    current.calls.push(
      MethodCallInfo.new(location.merge(:definition => method))
    )
  end

  # Add the caller to the called method, this allows for inverse lookups.
  unless method.frozen?
    method.callers.push(
      MethodCallInfo.new(location.merge(:definition => definition))
    )
  end
end
update_parents_from_tag(tag, definition) click to toggle source

Updates the parents of a definition according to the types of a `@param` tag.

@param [RubyLint::Docstring::ParamTag] tag @param [RubyLint::Definition::RubyObject] definition

# File lib/ruby-lint/virtual_machine.rb, line 1136
def update_parents_from_tag(tag, definition)
  extra_parents = definitions_for_types(tag.types)

  definition.parents.concat(extra_parents)
end