123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Lint::Utils::NilReceiverChecker

Relationships & Source Files
Inherits: Object
Defined in: lib/rubocop/cop/lint/utils/nil_receiver_checker.rb

Overview

Utility class that checks if the receiver can’t be nil.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(receiver, additional_nil_methods) ⇒ NilReceiverChecker

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 11

def initialize(receiver, additional_nil_methods)
  @receiver = receiver
  @additional_nil_methods = additional_nil_methods
  @checked_nodes = {}.compare_by_identity
end

Instance Attribute Details

#cant_be_nil?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 17

def cant_be_nil?
  sole_condition_of_parent_if?(@receiver) || _cant_be_nil?(@receiver.parent, @receiver)
end

Instance Method Details

#_cant_be_nil?(node, receiver) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 24

def _cant_be_nil?(node, receiver)
  return false unless node

  # For some nodes, we check their parent and then some children for these parents.
  # This is added to avoid infinite loops.
  return false if @checked_nodes.key?(node)

  @checked_nodes[node] = true

  case node.type
  when :def, :class, :module, :sclass
    return false
  when :send
    return non_nil_method?(node.method_name) if node.receiver == receiver

    node.arguments.each do |argument|
      return true if _cant_be_nil?(argument, receiver)
    end

    return true if _cant_be_nil?(node.receiver, receiver)
  when :begin
    return true if _cant_be_nil?(node.children.first, receiver)
  when :if, :case
    return true if _cant_be_nil?(node.condition, receiver)
  when :and, :or
    return true if _cant_be_nil?(node.lhs, receiver)
  when :pair
    if _cant_be_nil?(node.key, receiver) ||
       _cant_be_nil?(node.value, receiver)
      return true
    end
  when :when
    node.each_condition do |condition|
      return true if _cant_be_nil?(condition, receiver)
    end
  when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
    return true if _cant_be_nil?(node.expression, receiver)
  end

  # Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
  # using left_siblings will not work correctly for them.
  if !else_branch?(node) || (node.if_type? && !node.elsif?)
    node.left_siblings.reverse_each do |sibling|
      next unless sibling.is_a?(AST::Node)

      return true if _cant_be_nil?(sibling, receiver)
    end
  end

  if node.parent
    _cant_be_nil?(node.parent, receiver)
  else
    false
  end
end

#else_branch?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 108

def else_branch?(node)
  node.parent&.if_type? && node.parent.else_branch == node
end

#find_top_if(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 112

def find_top_if(node)
  node = node.parent while node.elsif?

  node
end

#non_nil_method?(method_name) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 81

def non_nil_method?(method_name)
  !NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
end

#sole_condition_of_parent_if?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/lint/utils/nil_receiver_checker.rb', line 86

def sole_condition_of_parent_if?(node)
  parent = node.parent

  while parent
    if parent.if_type?
      if parent.condition == node
        return true
      elsif parent.elsif?
        parent = find_top_if(parent)
      end
    elsif else_branch?(parent)
      # Find the top `if` for `else`.
      parent = parent.parent
    end

    parent = parent&.parent
  end

  false
end