Class: RuboCop::Cop::VariableForce Private
Do not use. This class is for internal use only.
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Force
|
|
|
Instance Chain:
self,
Force
|
|
| Inherits: |
RuboCop::Cop::Force
|
| Defined in: | lib/rubocop/cop/variable_force.rb, lib/rubocop/cop/variable_force/assignment.rb, lib/rubocop/cop/variable_force/branch.rb, lib/rubocop/cop/variable_force/branchable.rb, lib/rubocop/cop/variable_force/reference.rb, lib/rubocop/cop/variable_force/scope.rb, lib/rubocop/cop/variable_force/variable.rb, lib/rubocop/cop/variable_force/variable_table.rb |
Overview
This force provides a way to track local variables and scopes of Ruby. Cops interact with this force need to override some of the hook methods.
def before_entering_scope(scope, variable_table)
end
def after_entering_scope(scope, variable_table)
end
def before_leaving_scope(scope, variable_table)
end
def after_leaving_scope(scope, variable_table)
end
def before_declaring_variable(variable, variable_table)
end
def after_declaring_variable(variable, variable_table)
end
Constant Summary
-
ARGUMENT_DECLARATION_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 35[ :arg, :optarg, :restarg, :kwarg, :kwoptarg, :kwrestarg, :blockarg, # This doesn't mean block argument, it's block-pass (&block). :shadowarg # This means block local variable (obj.each { |arg; this| }). ].freeze
-
BRANCH_NODES =
# File 'lib/rubocop/cop/variable_force.rb', line 74%i[if case case_match rescue].freeze
-
LOGICAL_OPERATOR_ASSIGNMENT_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 42%i[or_asgn and_asgn].freeze
-
LOOP_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 51(POST_CONDITION_LOOP_TYPES + %i[while until for]).freeze
-
MULTIPLE_ASSIGNMENT_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 45:masgn
-
NODE_HANDLER_METHOD_NAMES =
private
# File 'lib/rubocop/cop/variable_force.rb', line 117[ [VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment], [REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures], [PATTERN_MATCH_VARIABLE_TYPE, :process_pattern_match_variable], [MULTIPLE_ASSIGNMENT_TYPE, :process_variable_multiple_assignment], [VARIABLE_REFERENCE_TYPE, :process_variable_referencing], [RESCUE_TYPE, :process_rescue], [ZERO_ARITY_SUPER_TYPE, :process_zero_arity_super], [SEND_TYPE, :process_send], *ARGUMENT_DECLARATION_TYPES.product([:process_variable_declaration]), *OPERATOR_ASSIGNMENT_TYPES.product([:process_variable_operator_assignment]), *LOOP_TYPES.product([:process_loop]), *SCOPE_TYPES.product([:process_scope]) ].to_h.freeze
-
OPERATOR_ASSIGNMENT_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 43(LOGICAL_OPERATOR_ASSIGNMENT_TYPES + [:op_asgn]).freeze
-
PATTERN_MATCH_VARIABLE_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 30:match_var
-
POST_CONDITION_LOOP_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 50%i[while_post until_post].freeze
-
REGEXP_NAMED_CAPTURE_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 29:match_with_lvasgn
-
RESCUE_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 53:rescue
-
REST_ASSIGNMENT_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 46:splat
-
SCOPE_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 58(TWISTED_SCOPE_TYPES + [:def]).freeze
-
SEND_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 60:send
-
TWISTED_SCOPE_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 57%i[block numblock itblock class sclass defs module].freeze
-
VARIABLE_ASSIGNMENT_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 28:lvasgn
-
VARIABLE_ASSIGNMENT_TYPES =
# File 'lib/rubocop/cop/variable_force.rb', line 31[ VARIABLE_ASSIGNMENT_TYPE, REGEXP_NAMED_CAPTURE_TYPE, PATTERN_MATCH_VARIABLE_TYPE ].freeze
-
VARIABLE_REFERENCE_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 48:lvar
-
ZERO_ARITY_SUPER_TYPE =
# File 'lib/rubocop/cop/variable_force.rb', line 55:zsuper
Class Method Summary
Force - Inherited
Instance Attribute Summary
Instance Method Summary
-
#investigate(processed_source)
Internal use only
Starting point.
- #process_node(node) Internal use only
- #variable_table Internal use only
- #descendant_reference(node) private Internal use only
- #each_descendant_reference(loop_node) private Internal use only
- #find_variables_in_loop(loop_node) private Internal use only
-
#inspect_variables_in_scope(scope_node)
private
Internal use only
This is called for each scope recursively.
-
#mark_assignments_as_referenced_in_loop(node)
private
Internal use only
Mark last assignments which are referenced in the same loop as referenced by ignoring AST order since they would be referenced in next iteration.
- #node_handler_method_name(node) private Internal use only
- #process_children(origin_node) private Internal use only
- #process_loop(node) private Internal use only
- #process_pattern_match_variable(node) private Internal use only
- #process_regexp_named_captures(node) private Internal use only
- #process_rescue(node) private Internal use only
- #process_scope(node) private Internal use only
- #process_send(node) private Internal use only
- #process_variable_assignment(node) private Internal use only
- #process_variable_declaration(node) private Internal use only
- #process_variable_multiple_assignment(node) private Internal use only
- #process_variable_operator_assignment(node) private Internal use only
- #process_variable_referencing(node) private Internal use only
- #process_zero_arity_super(node) private Internal use only
- #reference_assignments(loop_assignments, loop_node) private Internal use only
- #regexp_captured_names(node) private Internal use only
- #scanned_node?(node) ⇒ Boolean private Internal use only
- #scanned_nodes private Internal use only
- #skip_children! private Internal use only
- #twisted_nodes(node) private Internal use only
Force - Inherited
Constructor Details
This class inherits a constructor from RuboCop::Cop::Force
Instance Method Details
#descendant_reference(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 352
def descendant_reference(node) case node.type when :lvar VariableReference.new(node.children.first) when :lvasgn AssignmentReference.new(node) when *OPERATOR_ASSIGNMENT_TYPES VariableReference.new(node.lhs.name) if node.lhs.lvasgn_type? end end
#each_descendant_reference(loop_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 342
def each_descendant_reference(loop_node) # #each_descendant does not consider scope, # but we don't need to care about it here. loop_node.each_descendant do |node| reference = descendant_reference(node) yield reference if reference end end
#find_variables_in_loop(loop_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 327
def find_variables_in_loop(loop_node) referenced_variable_names_in_loop = [] assignment_nodes_in_loop = [] each_descendant_reference(loop_node) do |reference| if reference.assignment? assignment_nodes_in_loop << reference.node else referenced_variable_names_in_loop << reference.name end end [referenced_variable_names_in_loop, assignment_nodes_in_loop] end
#inspect_variables_in_scope(scope_node) (private)
This is called for each scope recursively.
# File 'lib/rubocop/cop/variable_force.rb', line 99
def inspect_variables_in_scope(scope_node) variable_table.push_scope(scope_node) process_children(scope_node) variable_table.pop_scope end
#investigate(processed_source)
Starting point.
# File 'lib/rubocop/cop/variable_force.rb', line 81
def investigate(processed_source) root_node = processed_source.ast return unless root_node variable_table.push_scope(root_node) process_node(root_node) variable_table.pop_scope end
#mark_assignments_as_referenced_in_loop(node) (private)
Mark last assignments which are referenced in the same loop as referenced by ignoring AST order since they would be referenced in next iteration.
# File 'lib/rubocop/cop/variable_force.rb', line 309
def mark_assignments_as_referenced_in_loop(node) referenced_variable_names_in_loop, assignment_nodes_in_loop = find_variables_in_loop(node) referenced_variable_names_in_loop.each do |name| variable = variable_table.find_variable(name) # Non related references which are caught in the above scan # would be skipped here. next unless variable loop_assignments = variable.assignments.select do |assignment| assignment_nodes_in_loop.include?(assignment.node) end next unless loop_assignments.any? reference_assignments(loop_assignments, node) end end
#node_handler_method_name(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 132
def node_handler_method_name(node) NODE_HANDLER_METHOD_NAMES[node.type] end
#process_children(origin_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 105
def process_children(origin_node) origin_node.each_child_node do |child_node| next if scanned_node?(child_node) process_node(child_node) end end
#process_loop(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 240
def process_loop(node) if node.post_condition_loop? # See the comment at the end of file for this behavior. condition_node, body_node = *node process_node(body_node) process_node(condition_node) elsif node.for_type? # In `for item in items` the rightmost expression is evaluated first. process_node(node.collection) process_node(node.variable) process_node(node.body) if node.body else process_children(node) end mark_assignments_as_referenced_in_loop(node) skip_children! end
#process_node(node)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 90
def process_node(node) method_name = node_handler_method_name(node) retval = send(method_name, node) if method_name process_children(node) unless retval == :skip_children end
#process_pattern_match_variable(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 184
def process_pattern_match_variable(node) name = node.children.first variable_table.declare_variable(name, node) unless variable_table.variable_exist?(name) skip_children! end
#process_regexp_named_captures(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 166
def process_regexp_named_captures(node) regexp_node, rhs_node = *node variable_names = regexp_captured_names(regexp_node) variable_names.each do |name| next if variable_table.variable_exist?(name) variable_table.declare_variable(name, node) end process_node(rhs_node) process_node(regexp_node) variable_names.each { |name| variable_table.assign_to_variable(name, node) } skip_children! end
#process_rescue(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 260
def process_rescue(node) resbody_nodes = node.each_child_node(:resbody) contain_retry = resbody_nodes.any? do |resbody_node| resbody_node.each_descendant.any?(&:retry_type?) end # Treat begin..rescue..end with retry as a loop. process_loop(node) if contain_retry end
#process_scope(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 279
def process_scope(node) if TWISTED_SCOPE_TYPES.include?(node.type) # See the comment at the end of file for this behavior. twisted_nodes(node).each do |twisted_node| process_node(twisted_node) scanned_nodes << twisted_node end end inspect_variables_in_scope(node) skip_children! end
#process_send(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 298
def process_send(node) _receiver, method_name, args = *node return unless method_name == :binding return if args && !args.children.empty? variable_table.accessible_variables.each { |variable| variable.reference!(node) } end
#process_variable_assignment(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 148
def process_variable_assignment(node) name = node.children.first variable_table.declare_variable(name, node) unless variable_table.variable_exist?(name) # Need to scan rhs before assignment so that we can mark previous # assignments as referenced if rhs has referencing to the variable # itself like: # # foo = 1 # foo = foo + 1 process_children(node) variable_table.assign_to_variable(name, node) skip_children! end
#process_variable_declaration(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 136
def process_variable_declaration(node) variable_name = node.children.first # restarg and kwrestarg would have no name: # # def initialize(*) # end return unless variable_name variable_table.declare_variable(variable_name, node) end
#process_variable_multiple_assignment(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 228
def process_variable_multiple_assignment(node) lhs_node, rhs_node = *node process_node(rhs_node) process_node(lhs_node) skip_children! end
#process_variable_operator_assignment(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 198
def process_variable_operator_assignment(node) asgn_node = node.lhs return unless asgn_node.lvasgn_type? name = asgn_node.name variable_table.declare_variable(name, asgn_node) unless variable_table.variable_exist?(name) # The following statements: # # foo = 1 # foo += foo = 2 # # => 3 # # are equivalent to: # # foo = 1 # foo = foo + (foo = 2) # # => 3 # # So, at operator assignment node, we need to reference the variable # before processing rhs nodes. variable_table.reference_variable(name, node) process_node(node.rhs) variable_table.assign_to_variable(name, asgn_node) skip_children! end
#process_variable_referencing(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 235
def process_variable_referencing(node) name = node.children.first variable_table.reference_variable(name, node) end
#process_zero_arity_super(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 271
def process_zero_arity_super(node) variable_table.accessible_variables.each do |variable| next unless variable.method_argument? variable.reference!(node) end end
#reference_assignments(loop_assignments, loop_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 363
def reference_assignments(loop_assignments, loop_node) # If inside a branching statement, mark all as referenced. # Otherwise, mark only the last assignment as referenced. # Note that `rescue` must be considered as branching because of # the `retry` keyword. loop_assignments.each do |assignment| assignment.reference!(loop_node) if assignment.node.each_ancestor(*BRANCH_NODES).any? end loop_assignments.last&.reference!(loop_node) end
#regexp_captured_names(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 192
def regexp_captured_names(node) regexp = node.to_regexp regexp.named_captures.keys end
#scanned_node?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/variable_force.rb', line 374
def scanned_node?(node) scanned_nodes.include?(node) end
#scanned_nodes (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 378
def scanned_nodes @scanned_nodes ||= Set.new.compare_by_identity end
#skip_children! (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 113
def skip_children! :skip_children end
#twisted_nodes(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 292
def twisted_nodes(node) twisted_nodes = [node.children[0]] twisted_nodes << node.children[1] if node.class_type? twisted_nodes.compact end
#variable_table
[ GitHub ]# File 'lib/rubocop/cop/variable_force.rb', line 76
def variable_table @variable_table ||= VariableTable.new(self) end