Module: Rubocop::Cop::VariableInspector

Included in:
Lint::ShadowingOuterLocalVariable, Lint::UnusedLocalVariable
Defined in:
lib/rubocop/cop/variable_inspector.rb

Overview

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.

Defined Under Namespace

Classes: NodeScanner, Scope, VariableEntry, VariableTable

Constant Summary collapse

VARIABLE_ASSIGNMENT_TYPES =
[:lvasgn, :match_with_lvasgn].freeze
ARGUMENT_DECLARATION_TYPES =
[
  :arg, :optarg, :restarg, :blockarg,
  :kwarg, :kwoptarg, :kwrestarg,
  :shadowarg
].freeze
VARIABLE_DECLARATION_TYPES =
(VARIABLE_ASSIGNMENT_TYPES + ARGUMENT_DECLARATION_TYPES).freeze
VARIABLE_USE_TYPES =
[:lvar].freeze
SCOPE_TYPES =
[:module, :class, :sclass, :def, :defs, :block].freeze

Instance Method Summary collapse

Instance Method Details

#after_declaring_variable(variable_entry) ⇒ Object



316
317
# File 'lib/rubocop/cop/variable_inspector.rb', line 316

def after_declaring_variable(variable_entry)
end

#after_entering_scope(scope) ⇒ Object



304
305
# File 'lib/rubocop/cop/variable_inspector.rb', line 304

def after_entering_scope(scope)
end

#after_leaving_scope(scope) ⇒ Object



310
311
# File 'lib/rubocop/cop/variable_inspector.rb', line 310

def after_leaving_scope(scope)
end

#before_declaring_variable(variable_entry) ⇒ Object



313
314
# File 'lib/rubocop/cop/variable_inspector.rb', line 313

def before_declaring_variable(variable_entry)
end

#before_entering_scope(scope) ⇒ Object

Hooks



301
302
# File 'lib/rubocop/cop/variable_inspector.rb', line 301

def before_entering_scope(scope)
end

#before_leaving_scope(scope) ⇒ Object



307
308
# File 'lib/rubocop/cop/variable_inspector.rb', line 307

def before_leaving_scope(scope)
end

#inspect_variables(root_node) ⇒ Object

Starting point.



233
234
235
236
237
238
239
240
241
242
# File 'lib/rubocop/cop/variable_inspector.rb', line 233

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) ⇒ Object

This is called for each scope recursively.



245
246
247
248
249
250
251
252
253
254
# File 'lib/rubocop/cop/variable_inspector.rb', line 245

def inspect_variables_in_scope(scope_node)
  variable_table.push_scope(scope_node)

  NodeScanner.scan_nodes_in_scope(scope_node) do |node|
    # puts "scope:#{variable_table.current_scope_level} node:#{node}"
    process_node(node)
  end

  variable_table.pop_scope
end

#process_named_captures(match_with_lvasgn_node) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
# File 'lib/rubocop/cop/variable_inspector.rb', line 287

def process_named_captures(match_with_lvasgn_node)
  regexp_string = match_with_lvasgn_node.children[0]
                                        .children[0]
                                        .children[0]
  regexp = Regexp.new(regexp_string)
  variable_names = regexp.named_captures.keys

  variable_names.each do |name|
    process_variable_assignment(match_with_lvasgn_node, name)
  end
end

#process_node(node) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/rubocop/cop/variable_inspector.rb', line 256

def process_node(node)
  case node.type
  when *ARGUMENT_DECLARATION_TYPES
    variable_table.add_variable_entry(node)
  when :lvasgn
    variable_name = node.children.first
    process_variable_assignment(node, variable_name)
  when :match_with_lvasgn
    process_named_captures(node)
  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 *SCOPE_TYPES
    inspect_variables_in_scope(node)
  end
end

#process_variable_assignment(node, name) ⇒ Object



278
279
280
281
282
283
284
285
# File 'lib/rubocop/cop/variable_inspector.rb', line 278

def process_variable_assignment(node, name)
  entry = variable_table.find_variable_entry(name)
  if entry
    entry.used = true
  else
    variable_table.add_variable_entry(node, name)
  end
end

#variable_tableObject



228
229
230
# File 'lib/rubocop/cop/variable_inspector.rb', line 228

def variable_table
  @variable_table ||= VariableTable.new(self)
end