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
-
VARIABLE_DECLARATION_TYPES =
# File 'lib/rubocop/cop/variable_force/variable.rb', line 9(VARIABLE_ASSIGNMENT_TYPES + ARGUMENT_DECLARATION_TYPES).freeze
Class Method Summary
- .new(name, declaration_node, scope) ⇒ Variable constructor Internal use only
Instance Attribute Summary
- #argument? ⇒ Boolean readonly Internal use only
- #assignments readonly Internal use only
- #block_argument? ⇒ Boolean readonly Internal use only
-
#captured_by_block?
readonly
Alias for #captured_by_block.
- #declaration_node readonly Internal use only
- #explicit_block_local_variable? ⇒ Boolean readonly Internal use only
- #keyword_argument? ⇒ Boolean readonly Internal use only
- #method_argument? ⇒ Boolean readonly Internal use only
- #name readonly Internal use only
- #referenced? ⇒ Boolean readonly Internal use only
- #references readonly Internal use only
- #scope readonly Internal use only
- #should_be_unused? ⇒ Boolean readonly Internal use only
-
#used? ⇒ Boolean
readonly
Internal use only
This is a convenient way to check whether the variable is used in its entire variable lifetime.
Instance Method Summary
- #assign(node) Internal use only
- #capture_with_block! Internal use only
- #captured_by_block (also: #captured_by_block?) readonly Internal use only
- #covers?(container, node) ⇒ Boolean Internal use only
- #in_modifier_conditional?(assignment, reference_node) ⇒ Boolean Internal use only
- #mark_last_as_reassigned!(assignment) Internal use only
- #modifier_conditional_of(node) Internal use only
-
#reference!(node)
Internal use only
rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
Constructor Details
.new(name, declaration_node, scope) ⇒ Variable
# 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)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 116
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)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 124
def block_argument? argument? && @scope.node.block_type? end
#captured_by_block? (readonly)
Alias for #captured_by_block.
# 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)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 132
def explicit_block_local_variable? @declaration_node.shadowarg_type? end
#keyword_argument? ⇒ Boolean (readonly)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 128
def keyword_argument? %i[kwarg kwoptarg].include?(@declaration_node.type) end
#method_argument? ⇒ Boolean (readonly)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 120
def method_argument? argument? && @scope.node.any_def_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)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 46
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)
# File 'lib/rubocop/cop/variable_force/variable.rb', line 112
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.
# File 'lib/rubocop/cop/variable_force/variable.rb', line 108
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) mark_last_as_reassigned!(assignment) @assignments << assignment end
#capture_with_block!
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable.rb', line 96
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
#covers?(container, node) ⇒ Boolean
# 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
#in_modifier_conditional?(assignment, reference_node) ⇒ Boolean
# 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
#mark_last_as_reassigned!(assignment)
[ GitHub ]# 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
#modifier_conditional_of(node)
[ GitHub ]# 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)
rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# 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