module Rubocop::Cop::VariableInspector
This module provides a way to track local variables and scopes of Ruby. This is intended to be used as mix-in, and the user class may override some of hook methods.
Constants
- ARGUMENT_DECLARATION_TYPES
- SCOPE_TYPES
- VARIABLE_ASSIGNMENT_TYPES
- VARIABLE_DECLARATION_TYPES
- VARIABLE_USE_TYPES
Public Instance Methods
after_declaring_variable(variable_entry)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 276 def after_declaring_variable(variable_entry) end
after_entering_scope(scope)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 264 def after_entering_scope(scope) end
after_leaving_scope(scope)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 270 def after_leaving_scope(scope) end
before_declaring_variable(variable_entry)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 273 def before_declaring_variable(variable_entry) end
before_entering_scope(scope)
click to toggle source
Hooks
# File lib/rubocop/cop/variable_inspector.rb, line 261 def before_entering_scope(scope) end
before_leaving_scope(scope)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 267 def before_leaving_scope(scope) end
inspect_variables(root_node)
click to toggle source
Starting point.
# File lib/rubocop/cop/variable_inspector.rb, line 156 def inspect_variables(root_node) return unless root_node # Wrap with begin node if it's standalone node. unless root_node.type == :begin root_node = Parser::AST::Node.new(:begin, [root_node]) end inspect_variables_in_scope(root_node) end
inspect_variables_in_scope(scope_node)
click to toggle source
This is called for each scope recursively.
# File lib/rubocop/cop/variable_inspector.rb, line 168 def inspect_variables_in_scope(scope_node) variable_table.push_scope(scope_node) NodeScanner.scan_nodes_in_scope(scope_node) do |node, index| if scope_node.type == :block && index == 0 && node.type == :send # Avoid processing method argument nodes of outer scope # in current block scope. # See #process_node. throw :skip_children elsif [:sclass, :defs].include?(scope_node.type) && index == 0 throw :skip_children end process_node(node) end variable_table.pop_scope end
process_node(node)
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 187 def process_node(node) case node.type when *ARGUMENT_DECLARATION_TYPES variable_table.add_variable_entry(node) when *VARIABLE_ASSIGNMENT_TYPES variable_name = node.children.first variable_entry = variable_table.find_variable_entry(variable_name) if variable_entry variable_entry.used = true else variable_table.add_variable_entry(node) end when *VARIABLE_USE_TYPES variable_name = node.children.first variable_entry = variable_table.find_variable_entry(variable_name) unless variable_entry fail "Using undeclared local variable \"#{variable_name}\" " + "at #{node.loc.expression}, #{node.inspect}" end variable_entry.used = true when :block # The variable foo belongs to the top level scope, # but in AST, it's under the block node. # # Ruby: # some_method(foo = 1) do # end # puts foo # # AST: # (begin # (block # (send nil :some_method # (lvasgn :foo # (int 1))) # (args) nil) # (send nil :puts # (lvar :foo))) # # So the nodes of the method argument need to be processed # in current scope before dive into the block scope. NodeScanner.scan_nodes_in_scope(node.children.first) do |n| process_node(n) end # Now go into the block scope. inspect_variables_in_scope(node) when :sclass, :defs # Same thing. # # Ruby: # instance = Object.new # class << instance # foo = 1 # end # # AST: # (begin # (lvasgn :instance # (send # (const nil :Object) :new)) # (sclass # (lvar :instance) # (begin # (lvasgn :foo # (int 1)) process_node(node.children.first) inspect_variables_in_scope(node) when *SCOPE_TYPES inspect_variables_in_scope(node) end end
variable_table()
click to toggle source
# File lib/rubocop/cop/variable_inspector.rb, line 151 def variable_table @variable_table ||= VariableTable.new(self) end