123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::VariableForce::Variable Private

Relationships & Source Files
Inherits: Object
Defined in: lib/rubocop/cop/variable_force/variable.rb

Overview

A Variable represents existence of a local variable. This holds a variable declaration node and some states of the variable.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(name, declaration_node, scope) ⇒ Variable

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 15

def initialize(name, declaration_node, scope)
  unless VARIABLE_DECLARATION_TYPES.include?(declaration_node.type)
    raise ArgumentError,
          "Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " \
          "passed #{declaration_node.type}"
  end

  @name = name.to_sym
  @declaration_node = declaration_node
  @scope = scope

  @assignments = []
  @references = []
  @captured_by_block = false
end

Instance Attribute Details

#argument?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 94

def argument?
  ARGUMENT_DECLARATION_TYPES.include?(@declaration_node.type)
end

#assignments (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#block_argument?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 102

def block_argument?
  argument? && @scope.node.block_type?
end

#captured_by_block? (readonly)

Alias for #captured_by_block.

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 13

alias captured_by_block? captured_by_block

#declaration_node (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#explicit_block_local_variable?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 110

def explicit_block_local_variable?
  @declaration_node.shadowarg_type?
end

#keyword_argument?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 106

def keyword_argument?
  %i[kwarg kwoptarg].include?(@declaration_node.type)
end

#method_argument?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 98

def method_argument?
  argument? && %i[def defs].include?(@scope.node.type)
end

#name (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#referenced?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 35

def referenced?
  !@references.empty?
end

#references (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#scope (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#should_be_unused?Boolean (readonly)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 90

def should_be_unused?
  name.to_s.start_with?('_')
end

#used?Boolean (readonly)

This is a convenient way to check whether the variable is used in its entire variable lifetime. For more precise usage check, refer Assignment#used?.

Once the variable is captured by a block, we have no idea when, where, and how many times the block would be invoked. This means we cannot track the usage of the variable. So we consider it’s used to suppress false positive offenses.

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 86

def used?
  @captured_by_block || referenced?
end

Instance Method Details

#assign(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 31

def assign(node)
  @assignments << Assignment.new(node, self)
end

#capture_with_block!

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 74

def capture_with_block!
  @captured_by_block = true
end

#captured_by_block (readonly) Also known as: #captured_by_block?

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 11

attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block

#in_modifier_conditional?(assignment) ⇒ Boolean

Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 66

def in_modifier_conditional?(assignment)
  parent = assignment.node.parent
  parent = parent.parent if parent&.begin_type?
  return false if parent.nil?

  (parent.if_type? || parent.while_type? || parent.until_type?) && parent.modifier_form?
end

#reference!(node)

Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

[ GitHub ]

  
# File 'lib/rubocop/cop/variable_force/variable.rb', line 40

def reference!(node)
  reference = Reference.new(node, @scope)
  @references << reference
  consumed_branches = nil

  @assignments.reverse_each do |assignment|
    next if consumed_branches&.include?(assignment.branch)

    assignment.reference!(node) unless assignment.run_exclusively_with?(reference)

    # Modifier if/unless conditions are special. Assignments made in
    # them do not put the assigned variable in scope to the left of the
    # if/unless keyword. A preceding assignment is needed to put the
    # variable in scope. For this reason we skip to the next assignment
    # here.
    next if in_modifier_conditional?(assignment)

    break if !assignment.branch || assignment.branch == reference.branch

    unless assignment.branch.may_run_incompletely?
      (consumed_branches ||= Set.new) << assignment.branch
    end
  end
end