Class: Semdiff::TypeVisitor

Inherits:
Prism::Visitor
  • Object
show all
Includes:
Typeguard::TypeModel::Definitions
Defined in:
lib/semdiff/type_visitor.rb

Overview

This visitor is responsible for mapping AST nodes to type information. Returns a Hash of node_id => flags : {10 => 7, 11 => 7}

Constant Summary collapse

UNSAFE_NUMERIC_CLASSES =
%i[Date::Infinity].freeze
NUMERIC_CLASSES =
%i[Numeric Integer Float Rational Complex].freeze
ENUMERABLE_CLASSES =
%i[
  Enumerable ARGF Array Dir Enumerator ENV Hash
  IO Range Struct CSV CSV::Table CSV::Row Set
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(types) ⇒ TypeVisitor

Returns a new instance of TypeVisitor.



18
19
20
21
22
23
24
25
26
# File 'lib/semdiff/type_visitor.rb', line 18

def initialize(types)
  @types = types
  @mods = map_mods(@types)
  @scope = []
  @mod = nil
  @method = nil
  @node_types = {}
  super()
end

Instance Method Details

#visit_call_node(node) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/semdiff/type_visitor.rb', line 85

def visit_call_node(node)
  if node.variable_call? || node.receiver&.type == :self_node
    # In the case where a singleton method is defined on the
    # current mod: `class << self; attr_reader :a; end` we
    # might have type information (a var) on the mod.
    types = find_var_types(:self, node.name)
    store_node_types(node, types)
  end
  super
end

#visit_class_node(node) ⇒ Object



37
38
39
# File 'lib/semdiff/type_visitor.rb', line 37

def visit_class_node(node)
  process_mod_node(node)
end

#visit_class_variable_read_node(node) ⇒ Object



58
59
60
61
62
# File 'lib/semdiff/type_visitor.rb', line 58

def visit_class_variable_read_node(node)
  types = find_var_types(:class, node.name)
  store_node_types(node, types)
  super
end

#visit_constant_read_node(node) ⇒ Object



64
65
66
67
68
# File 'lib/semdiff/type_visitor.rb', line 64

def visit_constant_read_node(node)
  types = find_var_types(:constant, node.name)
  store_node_types(node, types)
  super
end

#visit_def_node(node) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/semdiff/type_visitor.rb', line 41

def visit_def_node(node)
  # Either look in the current mod or root
  haystack = @mod&.children || (@types if @scope.empty?)
  # NOTE: If an explicit receiver is provided, we look
  # for singleton methods on the current mod,
  # assuming that the receiver is self. Could be
  # expanded by resolving the receiver if not self.
  scope = node.receiver ? :class : :instance
  needle = node.name
  method = haystack.find do |e|
    e.is_a?(MethodDefinition) && e.name == needle && e.scope == scope
  end
  @method = method
  super
  @method = nil
end

#visit_instance_variable_read_node(node) ⇒ Object



70
71
72
73
74
# File 'lib/semdiff/type_visitor.rb', line 70

def visit_instance_variable_read_node(node)
  types = find_var_types(:instance, node.name)
  store_node_types(node, types)
  super
end

#visit_local_variable_read_node(node) ⇒ Object



76
77
78
79
80
81
82
83
# File 'lib/semdiff/type_visitor.rb', line 76

def visit_local_variable_read_node(node)
  unless @method.nil? || @method.parameters.empty?
    params = @method.parameters.find { |p| p.name == node.name }
    types = params&.types
    store_node_types(node, types)
  end
  super
end

#visit_module_node(node) ⇒ Object



33
34
35
# File 'lib/semdiff/type_visitor.rb', line 33

def visit_module_node(node)
  process_mod_node(node)
end

#visit_program_node(node) ⇒ Object



28
29
30
31
# File 'lib/semdiff/type_visitor.rb', line 28

def visit_program_node(node)
  super
  @node_types
end