module Solargraph::Parser::ParserGem::NodeMethods::DeepInference

def explicit_return_values_from_compound_statement parent

Returns:
  • (Array) -

Parameters:
  • parent (Parser::AST::Node) --
def explicit_return_values_from_compound_statement parent
  return [] unless parent.is_a?(::Parser::AST::Node)
  result = []
  nodes = parent.children.select{|n| n.is_a?(::Parser::AST::Node)}
  nodes.each do |node|
    next if SKIPPABLE.include?(node.type)
    if node.type == :return
      result.concat reduce_to_value_nodes([node.children[0]])
      # Return the result here because the rest of the code is

      # unreachable

      return result
    else
      result.concat explicit_return_values_from_compound_statement(node)
    end
  end
  result
end

def from_method_body node

Returns:
  • (Array) - low-level value nodes from

Parameters:
  • include_explicit_returns (Boolean) -- If true,
  • node (AST::Node) -- a method body compound statement
def from_method_body node
  from_value_position_statement(node, include_explicit_returns: true)
end

def from_value_position_compound_statement parent

Returns:
  • (Array) -

Parameters:
  • parent (Parser::AST::Node) --
def from_value_position_compound_statement parent
  result = []
  nodes = parent.children.select{|n| n.is_a?(AST::Node)}
  nodes.each_with_index do |node, idx|
    if node.type == :block
      result.concat explicit_return_values_from_compound_statement(node.children[2])
    elsif node.type == :rescue
      # body statements

      result.concat from_value_position_statement(node.children[0])
      # rescue statements

      result.concat from_value_position_statement(node.children[1])
    elsif SKIPPABLE.include?(node.type)
      next
    elsif node.type == :resbody
      result.concat reduce_to_value_nodes([node.children[2]])
    elsif node.type == :return
      result.concat reduce_to_value_nodes([node.children[0]])
      # Return here because the rest of the code is

      # unreachable and shouldn't be looked at

      return result
    else
      result.concat explicit_return_values_from_compound_statement(node)
    end
    # handle last line of compound statements, which is in

    # value position.  we already have the explicit values

    # from above; now we need to also gather the value

    # position nodes

    result.concat from_value_position_statement(nodes.last, include_explicit_returns: false) if idx == nodes.length - 1
  end
  result
end

def from_value_position_statement node, include_explicit_returns: true

Returns:
  • (Array) -

Parameters:
  • include_explicit_returns (Boolean) -- If true,
  • node (Parser::AST::Node) -- Statement which is in
def from_value_position_statement node, include_explicit_returns: true
  # STDERR.puts("from_expression called on #{node.inspect}")

  return [] unless node.is_a?(::Parser::AST::Node)
  # @type [Array<Parser::AST::Node>]

  result = []
  if COMPOUND_STATEMENTS.include?(node.type)
    result.concat from_value_position_compound_statement node
  elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
    result.concat reduce_to_value_nodes(node.children[1..-1])
    # result.push NIL_NODE unless node.children[2]

  elsif CONDITIONAL_ALL.include?(node.type)
    result.concat reduce_to_value_nodes(node.children)
  elsif ONLY_ONE_CHILD.include?(node.type)
    result.concat reduce_to_value_nodes([node.children[0]])
  elsif FIRST_TWO_CHILDREN.include?(node.type)
    result.concat reduce_to_value_nodes([node.children[0], node.children[1]])
  elsif FUNCTION_VALUE.include?(node.type)
    # the block itself is a first class value that could be returned

    result.push node
    # @todo any explicit returns actually return from

    #   scope in which the proc is run.  This asssumes

    #   that the function is executed here.

    result.concat explicit_return_values_from_compound_statement(node.children[2]) if include_explicit_returns
  elsif CASE_STATEMENT.include?(node.type)
    node.children[1..-1].each do |cc|
      if cc.nil?
        result.push NIL_NODE
      elsif cc.type == :when
        result.concat reduce_to_value_nodes([cc.children.last])
      else
        # else clause in case

        result.concat reduce_to_value_nodes([cc])
      end
    end
  elsif node.type == :resbody
    result.concat reduce_to_value_nodes([node.children[2]])
  else
    result.push node
  end
  result
end

def reduce_to_value_nodes nodes

Returns:
  • (Array) -

Parameters:
  • nodes (Enumerable) --
def reduce_to_value_nodes nodes
  result = []
  nodes.each do |node|
    if !node.is_a?(::Parser::AST::Node)
      result.push nil
    elsif COMPOUND_STATEMENTS.include?(node.type)
      result.concat from_value_position_compound_statement(node)
    elsif CONDITIONAL_ALL_BUT_FIRST.include?(node.type)
      result.concat reduce_to_value_nodes(node.children[1..-1])
    elsif node.type == :return
      result.concat reduce_to_value_nodes([node.children[0]])
    elsif node.type == :or
      result.concat reduce_to_value_nodes(node.children)
    elsif node.type == :block
      result.concat explicit_return_values_from_compound_statement(node.children[2])
    elsif node.type == :resbody
      result.concat reduce_to_value_nodes([node.children[2]])
    else
      result.push node
    end
  end
  result
end

def value_position_nodes_only(node)

Returns:
  • (Array) - low-level value nodes in

Parameters:
  • node (AST::Node) -- an individual statement, to be
def value_position_nodes_only(node)
  from_value_position_statement(node, include_explicit_returns: false)
end