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

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/cop/variable_force/variable.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

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

Constant Summary collapse

VARIABLE_DECLARATION_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

(VARIABLE_ASSIGNMENT_TYPES + ARGUMENT_DECLARATION_TYPES).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, declaration_node, scope) ⇒ Variable

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Variable.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 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

#assignmentsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def assignments
  @assignments
end

#captured_by_blockObject (readonly) Also known as: captured_by_block?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def captured_by_block
  @captured_by_block
end

#declaration_nodeObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def declaration_node
  @declaration_node
end

#nameObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def name
  @name
end

#referencesObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def references
  @references
end

#scopeObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def scope
  @scope
end

Instance Method Details

#argument?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


116
117
118
# File 'lib/rubocop/cop/variable_force/variable.rb', line 116

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

#assign(node) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



31
32
33
34
35
36
37
# File 'lib/rubocop/cop/variable_force/variable.rb', line 31

def assign(node)
  assignment = Assignment.new(node, self)

  mark_last_as_reassigned!(assignment)

  @assignments << assignment
end

#block_argument?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


124
125
126
# File 'lib/rubocop/cop/variable_force/variable.rb', line 124

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

#capture_with_block!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def capture_with_block!
  @captured_by_block = true
end

#covers?(container, node) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


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

def covers?(container, node)
  container.equal?(node) || container.source_range.contains?(node.source_range)
end

#explicit_block_local_variable?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


132
133
134
# File 'lib/rubocop/cop/variable_force/variable.rb', line 132

def explicit_block_local_variable?
  @declaration_node.shadowarg_type?
end

#in_modifier_conditional?(assignment, reference_node) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


76
77
78
79
80
81
82
83
84
# File 'lib/rubocop/cop/variable_force/variable.rb', line 76

def in_modifier_conditional?(assignment, reference_node)
  conditional = modifier_conditional_of(assignment.node)
  return false unless conditional

  # The out-of-scope problem only affects a reference in the modifier body (to the
  # left of the keyword); a reference after the modifier is put in scope by the
  # condition's assignment, so an earlier assignment there is genuinely useless.
  covers?(conditional, reference_node) && !covers?(conditional.condition, reference_node)
end

#keyword_argument?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


128
129
130
# File 'lib/rubocop/cop/variable_force/variable.rb', line 128

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

#mark_last_as_reassigned!(assignment) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



39
40
41
42
43
44
# File 'lib/rubocop/cop/variable_force/variable.rb', line 39

def mark_last_as_reassigned!(assignment)
  return if captured_by_block?
  return unless assignment.branch == @assignments.last&.branch

  @assignments.last&.reassigned!
end

#method_argument?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


120
121
122
# File 'lib/rubocop/cop/variable_force/variable.rb', line 120

def method_argument?
  argument? && @scope.node.any_def_type?
end

#modifier_conditional_of(node) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



86
87
88
89
90
# File 'lib/rubocop/cop/variable_force/variable.rb', line 86

def modifier_conditional_of(node)
  node.each_ancestor(:if, :while, :until).find do |conditional|
    conditional.modifier_form? && covers?(conditional.condition, node)
  end
end

#reference!(node) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rubocop/cop/variable_force/variable.rb', line 51

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, node)

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

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

#referenced?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


46
47
48
# File 'lib/rubocop/cop/variable_force/variable.rb', line 46

def referenced?
  !@references.empty?
end

#should_be_unused?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


112
113
114
# File 'lib/rubocop/cop/variable_force/variable.rb', line 112

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

#used?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.

Returns:

  • (Boolean)


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

def used?
  @captured_by_block || referenced?
end