Class: Tapioca::Gem::Pipeline

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Includes:
RBIHelper, Runtime::Reflection
Defined in:
lib/tapioca/gem/pipeline.rb

Constant Summary collapse

IGNORED_SYMBOLS =
T.let(["YAML", "MiniTest", "Mutex"], T::Array[String])
EVAL_SOURCE_FILE_PATTERN =

this looks something like: “(eval at /path/to/file.rb:123)” and we are just interested in the “/path/to/file.rb” part

T.let(/\(eval at (.+):\d+\)/, Regexp)

Constants included from SorbetHelper

SorbetHelper::FEATURE_REQUIREMENTS, SorbetHelper::SORBET_BIN, SorbetHelper::SORBET_EXE_PATH_ENV_VAR, SorbetHelper::SORBET_GEM_SPEC, SorbetHelper::SORBET_PAYLOAD_URL, SorbetHelper::SPOOM_CONTEXT

Constants included from Runtime::Reflection

Runtime::Reflection::ANCESTORS_METHOD, Runtime::Reflection::CLASS_METHOD, Runtime::Reflection::CONSTANTS_METHOD, Runtime::Reflection::EQUAL_METHOD, Runtime::Reflection::METHOD_METHOD, Runtime::Reflection::NAME_METHOD, Runtime::Reflection::OBJECT_ID_METHOD, Runtime::Reflection::PRIVATE_INSTANCE_METHODS_METHOD, Runtime::Reflection::PROTECTED_INSTANCE_METHODS_METHOD, Runtime::Reflection::PUBLIC_INSTANCE_METHODS_METHOD, Runtime::Reflection::REQUIRED_FROM_LABELS, Runtime::Reflection::SINGLETON_CLASS_METHOD, Runtime::Reflection::SUPERCLASS_METHOD, Runtime::Reflection::UNDEFINED_CONSTANT

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RBIHelper

#as_nilable_type, #create_block_param, #create_kw_opt_param, #create_kw_param, #create_kw_rest_param, #create_opt_param, #create_param, #create_rest_param, #create_typed_param, #sanitize_signature_types, serialize_type_variable, #valid_method_name?, #valid_parameter_name?

Methods included from SorbetHelper

#sorbet, #sorbet_path, #sorbet_supports?

Methods included from Runtime::Reflection

#abstract_type_of, #ancestors_of, #are_equal?, #class_of, #constant_defined?, #constantize, #constants_of, #descendants_of, #file_candidates_for, #final_module?, #inherited_ancestors_of, #method_of, #name_of_type, #object_id_of, #private_instance_methods_of, #protected_instance_methods_of, #public_instance_methods_of, #qualified_name_of, #resolve_loc, #sealed_module?, #signature_of, #singleton_class_of, #superclass_of

Methods included from Runtime::AttachedClassOf

#attached_class_of

Constructor Details

#initialize(gem, include_doc: false, include_loc: false) ⇒ Pipeline

Returns a new instance of Pipeline.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/tapioca/gem/pipeline.rb', line 17

def initialize(gem, include_doc: false, include_loc: false)
  @root = T.let(RBI::Tree.new, RBI::Tree)
  @gem = gem
  @seen = T.let(Set.new, T::Set[String])
  @alias_namespace = T.let(Set.new, T::Set[String])

  @events = T.let([], T::Array[Gem::Event])

  @payload_symbols = T.let(Static::SymbolLoader.payload_symbols, T::Set[String])
  @bootstrap_symbols = T.let(load_bootstrap_symbols(@gem), T::Set[String])

  @bootstrap_symbols.each { |symbol| push_symbol(symbol) }

  @node_listeners = T.let([], T::Array[Gem::Listeners::Base])
  @node_listeners << Gem::Listeners::SorbetTypeVariables.new(self)
  @node_listeners << Gem::Listeners::Mixins.new(self)
  @node_listeners << Gem::Listeners::DynamicMixins.new(self)
  @node_listeners << Gem::Listeners::Methods.new(self)
  @node_listeners << Gem::Listeners::SorbetHelpers.new(self)
  @node_listeners << Gem::Listeners::SorbetEnums.new(self)
  @node_listeners << Gem::Listeners::SorbetProps.new(self)
  @node_listeners << Gem::Listeners::SorbetRequiredAncestors.new(self)
  @node_listeners << Gem::Listeners::SorbetSignatures.new(self)
  @node_listeners << Gem::Listeners::Subconstants.new(self)
  @node_listeners << Gem::Listeners::YardDoc.new(self) if include_doc
  @node_listeners << Gem::Listeners::ForeignConstants.new(self)
  @node_listeners << Gem::Listeners::SourceLocation.new(self) if include_loc
  @node_listeners << Gem::Listeners::RemoveEmptyPayloadScopes.new(self)
end

Instance Attribute Details

#gemObject (readonly)

Returns the value of attribute gem.



14
15
16
# File 'lib/tapioca/gem/pipeline.rb', line 14

def gem
  @gem
end

Instance Method Details

#compileObject



48
49
50
51
# File 'lib/tapioca/gem/pipeline.rb', line 48

def compile
  dispatch(next_event) until @events.empty?
  @root
end

#constant_in_gem?(name) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/tapioca/gem/pipeline.rb', line 119

def constant_in_gem?(name)
  return true unless Object.respond_to?(:const_source_location)

  source_file, _ = Object.const_source_location(name)
  return true unless source_file
  # If the source location of the constant is "(eval)", all bets are off.
  return true if source_file == "(eval)"

  # Ruby 3.3 adds automatic definition of source location for evals if
  # `file` and `line` arguments are not provided. This results in the source
  # file being something like `(eval at /path/to/file.rb:123)`. We try to parse
  # this string to get the actual source file.
  source_file = source_file.sub(EVAL_SOURCE_FILE_PATTERN, "\\1")

  gem.contains_path?(source_file)
end

#method_in_gem?(method) ⇒ Boolean

Returns:

  • (Boolean)


137
138
139
140
141
142
# File 'lib/tapioca/gem/pipeline.rb', line 137

def method_in_gem?(method)
  source_location = method.source_location&.first
  return false if source_location.nil?

  @gem.contains_path?(source_location)
end

#name_of(constant) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/tapioca/gem/pipeline.rb', line 147

def name_of(constant)
  name = name_of_proxy_target(constant, super(class_of(constant)))
  return name if name

  name = super(constant)
  return if name.nil?
  return unless are_equal?(constant, constantize(name, inherit: true))

  name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
  name
end

#push_const(symbol, constant, node) ⇒ Object



71
72
73
# File 'lib/tapioca/gem/pipeline.rb', line 71

def push_const(symbol, constant, node)
  @events << Gem::ConstNodeAdded.new(symbol, constant, node)
end

#push_constant(symbol, constant) ⇒ Object



61
62
63
# File 'lib/tapioca/gem/pipeline.rb', line 61

def push_constant(symbol, constant)
  @events << Gem::ConstantFound.new(symbol, constant)
end

#push_foreign_constant(symbol, constant) ⇒ Object



66
67
68
# File 'lib/tapioca/gem/pipeline.rb', line 66

def push_foreign_constant(symbol, constant)
  @events << Gem::ForeignConstantFound.new(symbol, constant)
end

#push_foreign_scope(symbol, constant, node) ⇒ Object



85
86
87
# File 'lib/tapioca/gem/pipeline.rb', line 85

def push_foreign_scope(symbol, constant, node)
  @events << Gem::ForeignScopeNodeAdded.new(symbol, constant, node)
end

#push_method(symbol, constant, method, node, signature, parameters) ⇒ Object

rubocop:disable Metrics/ParameterLists



99
100
101
# File 'lib/tapioca/gem/pipeline.rb', line 99

def push_method(symbol, constant, method, node, signature, parameters) # rubocop:disable Metrics/ParameterLists
  @events << Gem::MethodNodeAdded.new(symbol, constant, method, node, signature, parameters)
end

#push_scope(symbol, constant, node) ⇒ Object



78
79
80
# File 'lib/tapioca/gem/pipeline.rb', line 78

def push_scope(symbol, constant, node)
  @events << Gem::ScopeNodeAdded.new(symbol, constant, node)
end

#push_symbol(symbol) ⇒ Object



56
57
58
# File 'lib/tapioca/gem/pipeline.rb', line 56

def push_symbol(symbol)
  @events << Gem::SymbolFound.new(symbol)
end

#symbol_in_payload?(symbol_name) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
109
110
111
# File 'lib/tapioca/gem/pipeline.rb', line 106

def symbol_in_payload?(symbol_name)
  symbol_name = symbol_name[2..-1] if symbol_name.start_with?("::")
  return false unless symbol_name

  @payload_symbols.include?(symbol_name)
end