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 98

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 106

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 114

def explicit_block_local_variable?
  @declaration_node.shadowarg_type?
end

#keyword_argument?Boolean (readonly)

[ GitHub ]

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

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 102

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 39

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 94

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 90

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)
  assignment = Assignment.new(node, self)

  @assignments.last&.reassigned! unless captured_by_block?

  @assignments << assignment
end

#capture_with_block!

[ GitHub ]

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

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 70

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 44

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