solargraph 0.58.2 → 0.59.0.dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +40 -36
  5. data/.github/workflows/rspec.yml +45 -13
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.gitignore +0 -1
  8. data/.rubocop_todo.yml +27 -49
  9. data/CHANGELOG.md +1 -7
  10. data/README.md +3 -3
  11. data/Rakefile +1 -0
  12. data/lib/solargraph/api_map/cache.rb +3 -3
  13. data/lib/solargraph/api_map/constants.rb +13 -3
  14. data/lib/solargraph/api_map/index.rb +22 -11
  15. data/lib/solargraph/api_map/source_to_yard.rb +13 -1
  16. data/lib/solargraph/api_map/store.rb +11 -8
  17. data/lib/solargraph/api_map.rb +105 -50
  18. data/lib/solargraph/complex_type/conformance.rb +176 -0
  19. data/lib/solargraph/complex_type/type_methods.rb +16 -2
  20. data/lib/solargraph/complex_type/unique_type.rb +170 -20
  21. data/lib/solargraph/complex_type.rb +119 -14
  22. data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
  23. data/lib/solargraph/convention/data_definition.rb +4 -1
  24. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  25. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
  26. data/lib/solargraph/convention/struct_definition.rb +5 -1
  27. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  28. data/lib/solargraph/diagnostics/rubocop.rb +1 -0
  29. data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
  30. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  31. data/lib/solargraph/doc_map.rb +134 -373
  32. data/lib/solargraph/equality.rb +1 -1
  33. data/lib/solargraph/gem_pins.rb +14 -15
  34. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  35. data/lib/solargraph/language_server/host/dispatch.rb +1 -0
  36. data/lib/solargraph/language_server/host/message_worker.rb +2 -1
  37. data/lib/solargraph/language_server/host/sources.rb +1 -0
  38. data/lib/solargraph/language_server/host.rb +6 -1
  39. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
  40. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
  42. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  43. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
  44. data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
  49. data/lib/solargraph/library.rb +59 -13
  50. data/lib/solargraph/location.rb +9 -4
  51. data/lib/solargraph/logging.rb +21 -1
  52. data/lib/solargraph/parser/comment_ripper.rb +7 -0
  53. data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
  54. data/lib/solargraph/parser/node_processor/base.rb +32 -2
  55. data/lib/solargraph/parser/node_processor.rb +7 -6
  56. data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
  57. data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
  58. data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
  59. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  60. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
  61. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
  63. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
  64. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  65. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
  66. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
  73. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
  74. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  75. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
  76. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  77. data/lib/solargraph/parser/region.rb +9 -3
  78. data/lib/solargraph/parser/snippet.rb +1 -1
  79. data/lib/solargraph/pin/base.rb +53 -21
  80. data/lib/solargraph/pin/base_variable.rb +312 -20
  81. data/lib/solargraph/pin/block.rb +26 -4
  82. data/lib/solargraph/pin/breakable.rb +5 -1
  83. data/lib/solargraph/pin/callable.rb +50 -3
  84. data/lib/solargraph/pin/closure.rb +2 -6
  85. data/lib/solargraph/pin/common.rb +20 -5
  86. data/lib/solargraph/pin/compound_statement.rb +55 -0
  87. data/lib/solargraph/pin/conversions.rb +2 -1
  88. data/lib/solargraph/pin/delegated_method.rb +15 -4
  89. data/lib/solargraph/pin/documenting.rb +1 -0
  90. data/lib/solargraph/pin/instance_variable.rb +5 -1
  91. data/lib/solargraph/pin/keyword.rb +0 -4
  92. data/lib/solargraph/pin/local_variable.rb +13 -57
  93. data/lib/solargraph/pin/method.rb +90 -42
  94. data/lib/solargraph/pin/method_alias.rb +8 -0
  95. data/lib/solargraph/pin/namespace.rb +7 -1
  96. data/lib/solargraph/pin/parameter.rb +76 -13
  97. data/lib/solargraph/pin/proxy_type.rb +2 -1
  98. data/lib/solargraph/pin/reference/override.rb +1 -1
  99. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  100. data/lib/solargraph/pin/reference.rb +2 -0
  101. data/lib/solargraph/pin/search.rb +1 -0
  102. data/lib/solargraph/pin/signature.rb +8 -0
  103. data/lib/solargraph/pin/symbol.rb +1 -1
  104. data/lib/solargraph/pin/until.rb +1 -1
  105. data/lib/solargraph/pin/while.rb +1 -1
  106. data/lib/solargraph/pin.rb +2 -0
  107. data/lib/solargraph/pin_cache.rb +477 -57
  108. data/lib/solargraph/position.rb +12 -26
  109. data/lib/solargraph/range.rb +6 -6
  110. data/lib/solargraph/rbs_map/conversions.rb +33 -10
  111. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  112. data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
  113. data/lib/solargraph/rbs_map.rb +74 -20
  114. data/lib/solargraph/shell.rb +73 -28
  115. data/lib/solargraph/source/chain/call.rb +52 -17
  116. data/lib/solargraph/source/chain/constant.rb +2 -0
  117. data/lib/solargraph/source/chain/hash.rb +1 -0
  118. data/lib/solargraph/source/chain/if.rb +1 -0
  119. data/lib/solargraph/source/chain/instance_variable.rb +22 -1
  120. data/lib/solargraph/source/chain/literal.rb +5 -0
  121. data/lib/solargraph/source/chain/or.rb +9 -1
  122. data/lib/solargraph/source/chain.rb +25 -22
  123. data/lib/solargraph/source/change.rb +9 -2
  124. data/lib/solargraph/source/cursor.rb +7 -1
  125. data/lib/solargraph/source/source_chainer.rb +13 -3
  126. data/lib/solargraph/source/updater.rb +4 -0
  127. data/lib/solargraph/source.rb +33 -7
  128. data/lib/solargraph/source_map/clip.rb +13 -2
  129. data/lib/solargraph/source_map/data.rb +4 -1
  130. data/lib/solargraph/source_map/mapper.rb +24 -1
  131. data/lib/solargraph/source_map.rb +14 -6
  132. data/lib/solargraph/type_checker/problem.rb +3 -1
  133. data/lib/solargraph/type_checker/rules.rb +75 -2
  134. data/lib/solargraph/type_checker.rb +111 -30
  135. data/lib/solargraph/version.rb +1 -1
  136. data/lib/solargraph/workspace/config.rb +3 -1
  137. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  138. data/lib/solargraph/workspace/require_paths.rb +1 -0
  139. data/lib/solargraph/workspace.rb +158 -16
  140. data/lib/solargraph/yard_map/helpers.rb +2 -1
  141. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
  142. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  143. data/lib/solargraph/yard_map/mapper.rb +5 -0
  144. data/lib/solargraph/yardoc.rb +33 -23
  145. data/lib/solargraph.rb +24 -3
  146. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  147. data/rbs/fills/tuple/tuple.rbs +28 -0
  148. data/rbs/shims/ast/0/node.rbs +1 -1
  149. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  150. data/solargraph.gemspec +2 -1
  151. metadata +12 -7
  152. data/lib/solargraph/type_checker/checks.rb +0 -124
  153. data/lib/solargraph/type_checker/param_def.rb +0 -37
  154. data/lib/solargraph/yard_map/to_method.rb +0 -89
@@ -3,6 +3,7 @@
3
3
  require 'benchmark'
4
4
  require 'thor'
5
5
  require 'yard'
6
+ require 'yaml'
6
7
 
7
8
  module Solargraph
8
9
  class Shell < Thor
@@ -104,9 +105,8 @@ module Solargraph
104
105
  # @param gem [String]
105
106
  # @param version [String, nil]
106
107
  def cache gem, version = nil
107
- api_map = Solargraph::ApiMap.load(Dir.pwd)
108
- spec = Gem::Specification.find_by_name(gem, version)
109
- api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
108
+ gems(gem + (version ? "=#{version}" : ''))
109
+ # '
110
110
  end
111
111
 
112
112
  desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
@@ -119,39 +119,83 @@ module Solargraph
119
119
  # @return [void]
120
120
  def uncache *gems
121
121
  raise ArgumentError, 'No gems specified.' if gems.empty?
122
+ workspace = Solargraph::Workspace.new(Dir.pwd)
123
+
122
124
  gems.each do |gem|
123
125
  if gem == 'core'
124
- PinCache.uncache_core
126
+ PinCache.uncache_core(out: $stdout)
125
127
  next
126
128
  end
127
129
 
128
130
  if gem == 'stdlib'
129
- PinCache.uncache_stdlib
131
+ PinCache.uncache_stdlib(out: $stdout)
130
132
  next
131
133
  end
132
134
 
133
- spec = Gem::Specification.find_by_name(gem)
134
- PinCache.uncache_gem(spec, out: $stdout)
135
+ spec = workspace.find_gem(gem)
136
+ raise Thor::InvocationError, "Gem '#{gem}' not found" if spec.nil?
137
+
138
+ # @sg-ignore flow sensitive typing needs to handle 'raise if'
139
+ workspace.uncache_gem(spec, out: $stdout)
135
140
  end
136
141
  end
137
142
 
138
- desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
143
+ desc 'gems [GEM[=VERSION]...] [STDLIB...] [core]', 'Cache documentation for
144
+ installed libraries'
145
+ long_desc %( This command will cache the
146
+ generated type documentation for the specified libraries. While
147
+ Solargraph will generate this on the fly when needed, it takes
148
+ time. This command will generate it in advance, which can be
149
+ useful for CI scenarios.
150
+
151
+ With no arguments, it will cache all libraries in the current
152
+ workspace. If a gem or standard library name is specified, it
153
+ will cache that library's type documentation.
154
+
155
+ An equals sign after a gem will allow a specific gem version
156
+ to be cached.
157
+
158
+ The 'core' argument can be used to cache the type
159
+ documentation for the core Ruby libraries.
160
+
161
+ If the library is already cached, it will be rebuilt if the
162
+ --rebuild option is set.
163
+
164
+ Cached documentation is stored in #{PinCache.base_dir}, which
165
+ can be stored between CI runs.
166
+ )
139
167
  option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
140
168
  # @param names [Array<String>]
141
169
  # @return [void]
142
170
  def gems *names
143
- api_map = ApiMap.load('.')
171
+ # print time with ms
172
+ workspace = Solargraph::Workspace.new('.')
173
+
144
174
  if names.empty?
145
- Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
146
- STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
175
+ workspace.cache_all_for_workspace!($stdout, rebuild: options[:rebuild])
147
176
  else
177
+ $stderr.puts("Caching these gems: #{names}")
148
178
  names.each do |name|
149
- spec = Gem::Specification.find_by_name(*name.split('='))
150
- do_cache spec, api_map
179
+ if name == 'core'
180
+ PinCache.cache_core(out: $stdout) if !PinCache.core? || options[:rebuild]
181
+ next
182
+ end
183
+
184
+ gemspec = workspace.find_gem(*name.split('='))
185
+ if gemspec.nil?
186
+ warn "Gem '#{name}' not found"
187
+ else
188
+ workspace.cache_gem(gemspec, rebuild: options[:rebuild], out: $stdout)
189
+ end
151
190
  rescue Gem::MissingSpecError
152
191
  warn "Gem '#{name}' not found"
192
+ rescue Gem::Requirement::BadRequirementError => e
193
+ warn "Gem '#{name}' failed while loading"
194
+ warn e.message
195
+ # @sg-ignore Need to add nil check here
196
+ warn e.backtrace.join("\n")
153
197
  end
154
- STDERR.puts "Documentation cached for #{names.count} gems."
198
+ $stderr.puts "Documentation cached for #{names.count} gems."
155
199
  end
156
200
  end
157
201
 
@@ -176,7 +220,10 @@ module Solargraph
176
220
  workspace = Solargraph::Workspace.new(directory)
177
221
  level = options[:level].to_sym
178
222
  rules = workspace.rules(level)
179
- api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
223
+ api_map =
224
+ Solargraph::ApiMap.load_with_cache(directory, $stdout,
225
+ loose_unions:
226
+ !rules.require_all_unique_types_support_call?)
180
227
  probcount = 0
181
228
  if files.empty?
182
229
  files = api_map.source_maps.map(&:filename)
@@ -184,10 +231,9 @@ module Solargraph
184
231
  files.map! { |file| File.realpath(file) }
185
232
  end
186
233
  filecount = 0
187
-
188
234
  time = Benchmark.measure {
189
235
  files.each do |file|
190
- checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym, workspace: workspace)
236
+ checker = TypeChecker.new(file, api_map: api_map, rules: rules, level: options[:level].to_sym, workspace: workspace)
191
237
  problems = checker.problems
192
238
  next if problems.empty?
193
239
  problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
@@ -195,7 +241,6 @@ module Solargraph
195
241
  filecount += 1
196
242
  probcount += problems.length
197
243
  end
198
- # "
199
244
  }
200
245
  puts "Typecheck finished in #{time.real} seconds."
201
246
  puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
@@ -219,19 +264,25 @@ module Solargraph
219
264
  api_map = nil
220
265
  time = Benchmark.measure {
221
266
  api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
267
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
222
268
  api_map.pins.each do |pin|
223
269
  begin
224
270
  puts pin_description(pin) if options[:verbose]
225
271
  pin.typify api_map
226
272
  pin.probe api_map
227
273
  rescue StandardError => e
274
+ # @todo to add nil check here
275
+ # @todo should warn on nil dereference below
228
276
  STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
229
277
  STDERR.puts "[#{e.class}]: #{e.message}"
278
+ # @todo Need to add nil check here
279
+ # @todo flow sensitive typing should be able to handle redefinition
230
280
  STDERR.puts e.backtrace.join("\n")
231
281
  exit 1
232
282
  end
233
283
  end
234
284
  }
285
+ # @sg-ignore Need to add nil check here
235
286
  puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
236
287
  end
237
288
 
@@ -279,6 +330,7 @@ module Solargraph
279
330
  exit 1
280
331
  when Pin::Namespace
281
332
  if options[:references]
333
+ # @sg-ignore Need to add nil check here
282
334
  superclass_tag = api_map.qualify_superclass(pin.return_type.tag)
283
335
  superclass_pin = api_map.get_path_pins(superclass_tag).first if superclass_tag
284
336
  references[:superclass] = superclass_pin if superclass_pin
@@ -309,6 +361,7 @@ module Solargraph
309
361
  def pin_description pin
310
362
  desc = if pin.path.nil? || pin.path.empty?
311
363
  if pin.closure
364
+ # @sg-ignore Need to add nil check here
312
365
  "#{pin.closure.path} | #{pin.name}"
313
366
  else
314
367
  "#{pin.context.namespace} | #{pin.name}"
@@ -316,20 +369,12 @@ module Solargraph
316
369
  else
317
370
  pin.path
318
371
  end
372
+ # @sg-ignore Need to add nil check here
319
373
  desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
320
374
  desc
321
375
  end
322
376
 
323
- # @param gemspec [Gem::Specification]
324
- # @param api_map [ApiMap]
325
- # @return [void]
326
- def do_cache gemspec, api_map
327
- # @todo if the rebuild: option is passed as a positional arg,
328
- # typecheck doesn't complain on the below line
329
- api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
330
- end
331
-
332
- # @param type [ComplexType]
377
+ # @param type [ComplexType, ComplexType::UniqueType]
333
378
  # @return [void]
334
379
  def print_type(type)
335
380
  if options[:rbs]
@@ -37,6 +37,7 @@ module Solargraph
37
37
 
38
38
  # @sg-ignore Fix "Not enough arguments to Module#protected"
39
39
  protected def equality_fields
40
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
40
41
  super + [arguments, block]
41
42
  end
42
43
 
@@ -50,24 +51,35 @@ module Solargraph
50
51
  def resolve api_map, name_pin, locals
51
52
  return super_pins(api_map, name_pin) if word == 'super'
52
53
  return yield_pins(api_map, name_pin) if word == 'yield'
53
- found = if head?
54
- api_map.visible_pins(locals, word, name_pin, location)
55
- else
56
- []
57
- end
58
- return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
59
- pins = name_pin.binder.each_unique_type.flat_map do |context|
54
+ found = api_map.var_at_location(locals, word, name_pin, location) if head?
55
+
56
+ return inferred_pins([found], api_map, name_pin, locals) unless found.nil?
57
+ binder = name_pin.binder
58
+ # this is a q_call - i.e., foo&.bar - assume result of call
59
+ # will be nil or result as if binder were not nil -
60
+ # chain.rb#maybe_nil will add the nil type later, we just
61
+ # need to worry about the not-nil case
62
+
63
+ # @sg-ignore Need to handle duck-typed method calls on union types
64
+ binder = binder.without_nil if nullable?
65
+ # @sg-ignore Need to handle duck-typed method calls on union types
66
+ pin_groups = binder.each_unique_type.map do |context|
60
67
  ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
61
68
  stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
62
69
  [stack.first].compact
63
70
  end
71
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
72
+ if !api_map.loose_unions && pin_groups.any? { |pins| pins.empty? }
73
+ pin_groups = []
74
+ end
75
+ pins = pin_groups.flatten.uniq(&:path)
64
76
  return [] if pins.empty?
65
77
  inferred_pins(pins, api_map, name_pin, locals)
66
78
  end
67
79
 
68
80
  private
69
81
 
70
- # @param pins [::Enumerable<Pin::Method>]
82
+ # @param pins [::Enumerable<Pin::Base>]
71
83
  # @param api_map [ApiMap]
72
84
  # @param name_pin [Pin::Base]
73
85
  # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
@@ -84,9 +96,13 @@ module Solargraph
84
96
  # reject it regardless
85
97
 
86
98
  with_block, without_block = overloads.partition(&:block?)
99
+ # @sg-ignore flow sensitive typing should handle is_a? and next
100
+ # @type Array<Pin::Signature>
87
101
  sorted_overloads = with_block + without_block
88
102
  # @type [Pin::Signature, nil]
89
103
  new_signature_pin = nil
104
+ # @sg-ignore flow sensitive typing should handle is_a? and next
105
+ # @param ol [Pin::Signature]
90
106
  sorted_overloads.each do |ol|
91
107
  next unless ol.arity_matches?(arguments, with_block?)
92
108
  match = true
@@ -99,6 +115,7 @@ module Solargraph
99
115
  break
100
116
  end
101
117
  arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
118
+ closure: name_pin.closure,
102
119
  gates: name_pin.gates,
103
120
  source: :chain)
104
121
  atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
@@ -110,6 +127,7 @@ module Solargraph
110
127
  if match
111
128
  if ol.block && with_block?
112
129
  block_atypes = ol.block.parameters.map(&:return_type)
130
+ # @todo Need to add nil check here
113
131
  if block.links.map(&:class) == [BlockSymbol]
114
132
  # like the bar in foo(&:bar)
115
133
  blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
@@ -140,6 +158,7 @@ module Solargraph
140
158
  #
141
159
  # qualify(), however, happens in the namespace where
142
160
  # the docs were written - from the method pin.
161
+ # @todo Need to add nil check here
143
162
  type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, *p.gates) if new_return_type.defined?
144
163
  type ||= ComplexType::UNDEFINED
145
164
  end
@@ -149,9 +168,11 @@ module Solargraph
149
168
  next p.proxy(type) if type.defined?
150
169
  if !p.macros.empty?
151
170
  result = process_macro(p, api_map, name_pin.context, locals)
171
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
152
172
  next result unless result.return_type.undefined?
153
173
  elsif !p.directives.empty?
154
174
  result = process_directive(p, api_map, name_pin.context, locals)
175
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
155
176
  next result unless result.return_type.undefined?
156
177
  end
157
178
  p
@@ -162,8 +183,11 @@ module Solargraph
162
183
  reduced_context = name_pin.binder.reduce_class_type
163
184
  pin.proxy(reduced_context)
164
185
  else
186
+ # @sg-ignore Need to add nil check here
165
187
  next pin if pin.return_type.undefined?
188
+ # @sg-ignore Need to add nil check here
166
189
  selfy = pin.return_type.self_to_type(name_pin.binder)
190
+ # @sg-ignore Need to add nil check here
167
191
  selfy == pin.return_type ? pin : pin.proxy(selfy)
168
192
  end
169
193
  end
@@ -171,7 +195,7 @@ module Solargraph
171
195
 
172
196
  # @param pin [Pin::Base]
173
197
  # @param api_map [ApiMap]
174
- # @param context [ComplexType]
198
+ # @param context [ComplexType, ComplexType::UniqueType]
175
199
  # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
176
200
  # @return [Pin::Base]
177
201
  def process_macro pin, api_map, context, locals
@@ -190,7 +214,7 @@ module Solargraph
190
214
 
191
215
  # @param pin [Pin::Method]
192
216
  # @param api_map [ApiMap]
193
- # @param context [ComplexType]
217
+ # @param context [ComplexType, ComplexType::UniqueType]
194
218
  # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
195
219
  # @return [Pin::ProxyType]
196
220
  def process_directive pin, api_map, context, locals
@@ -206,21 +230,24 @@ module Solargraph
206
230
  # @param pin [Pin::Base]
207
231
  # @param macro [YARD::Tags::MacroDirective]
208
232
  # @param api_map [ApiMap]
209
- # @param context [ComplexType]
233
+ # @param context [ComplexType, ComplexType::UniqueType]
210
234
  # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
211
235
  # @return [Pin::ProxyType]
212
236
  def inner_process_macro pin, macro, api_map, context, locals
213
237
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
214
238
  txt = macro.tag.text.clone
239
+ # @sg-ignore Need to add nil check here
215
240
  if txt.empty? && macro.tag.name
216
241
  named = api_map.named_macro(macro.tag.name)
217
242
  txt = named.tag.text.clone if named
218
243
  end
219
244
  i = 1
220
245
  vals.each do |v|
246
+ # @sg-ignore Need to add nil check here
221
247
  txt.gsub!(/\$#{i}/, v.context.namespace)
222
248
  i += 1
223
249
  end
250
+ # @sg-ignore Need to add nil check here
224
251
  docstring = Solargraph::Source.parse_docstring(txt).to_docstring
225
252
  tag = docstring.tag(:return)
226
253
  unless tag.nil? || tag.types.nil?
@@ -246,6 +273,7 @@ module Solargraph
246
273
  def find_method_pin(name_pin)
247
274
  method_pin = name_pin
248
275
  until method_pin.is_a?(Pin::Method)
276
+ # @sg-ignore Need to support this in flow sensitive typing
249
277
  method_pin = method_pin.closure
250
278
  return if method_pin.nil?
251
279
  end
@@ -271,13 +299,14 @@ module Solargraph
271
299
 
272
300
  # @param signature_pin [Pin::Signature]
273
301
  method_pin.signatures.map(&:block).compact.map do |signature_pin|
302
+ # @sg-ignore Need to add nil check here
274
303
  return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
275
304
  signature_pin.proxy(return_type)
276
305
  end
277
306
  end
278
307
 
279
308
  # @param type [ComplexType]
280
- # @param context [ComplexType]
309
+ # @param context [ComplexType, ComplexType::UniqueType]
281
310
  # @return [ComplexType]
282
311
  def with_params type, context
283
312
  return type unless type.to_s.include?('$')
@@ -291,13 +320,14 @@ module Solargraph
291
320
  end
292
321
 
293
322
  # @param api_map [ApiMap]
294
- # @param context [ComplexType]
323
+ # @param context [ComplexType, ComplexType::UniqueType]
295
324
  # @param block_parameter_types [::Array<ComplexType>]
296
325
  # @param locals [::Array<Pin::LocalVariable>]
297
326
  # @return [ComplexType, nil]
298
327
  def block_symbol_call_type(api_map, context, block_parameter_types, locals)
299
328
  # Ruby's shorthand for sending the passed in method name
300
329
  # to the first yield parameter with no arguments
330
+ # @sg-ignore Need to add nil check here
301
331
  block_symbol_name = block.links.first.word
302
332
  block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
303
333
  callee = api_map.get_path_pins(block_symbol_call_path).first
@@ -305,6 +335,7 @@ module Solargraph
305
335
  # @todo: Figure out why we get unresolved generics at
306
336
  # this point and need to assume method return types
307
337
  # based on the generic type
338
+ # @sg-ignore Need to add nil check here
308
339
  return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
309
340
  return_type || ComplexType::UNDEFINED
310
341
  end
@@ -312,9 +343,11 @@ module Solargraph
312
343
  # @param api_map [ApiMap]
313
344
  # @return [Pin::Block, nil]
314
345
  def find_block_pin(api_map)
346
+ # @sg-ignore Need to add nil check here
315
347
  node_location = Solargraph::Location.from_node(block.node)
316
- return if node_location.nil?
348
+ return if node_location.nil?
317
349
  block_pins = api_map.get_block_pins
350
+ # @sg-ignore Need to add nil check here
318
351
  block_pins.find { |pin| pin.location.contain?(node_location) }
319
352
  end
320
353
 
@@ -326,10 +359,12 @@ module Solargraph
326
359
  def block_call_type(api_map, name_pin, locals)
327
360
  return nil unless with_block?
328
361
 
329
- block_context_pin = name_pin
330
362
  block_pin = find_block_pin(api_map)
331
- block_context_pin = block_pin.closure if block_pin
332
- block.infer(api_map, block_context_pin, locals)
363
+ # We use the block pin as the closure, as the parameters
364
+ # here will only be defined inside the block itself and we
365
+ # need to be able to see them
366
+ # @sg-ignore Need to add nil check here
367
+ block.infer(api_map, block_pin, locals)
333
368
  end
334
369
  end
335
370
  end
@@ -17,7 +17,9 @@ module Solargraph
17
17
  base = word
18
18
  gates = name_pin.gates
19
19
  end
20
+ # @sg-ignore Need to add nil check here
20
21
  fqns = api_map.resolve(base, gates)
22
+ # @sg-ignore Need to add nil check here
21
23
  api_map.get_path_pins(fqns)
22
24
  end
23
25
  end
@@ -14,6 +14,7 @@ module Solargraph
14
14
 
15
15
  # @sg-ignore Fix "Not enough arguments to Module#protected"
16
16
  protected def equality_fields
17
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
17
18
  super + [@splatted]
18
19
  end
19
20
 
@@ -15,6 +15,7 @@ module Solargraph
15
15
 
16
16
  # @sg-ignore Fix "Not enough arguments to Module#protected"
17
17
  protected def equality_fields
18
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
18
19
  super + [@links]
19
20
  end
20
21
 
@@ -4,9 +4,30 @@ module Solargraph
4
4
  class Source
5
5
  class Chain
6
6
  class InstanceVariable < Link
7
+ # @param word [String]
8
+ # @param node [Parser::AST::Node, nil] The node representing the variable
9
+ # @param location [Location, nil] The location of the variable reference in the source
10
+ def initialize word, node, location
11
+ super(word)
12
+ @node = node
13
+ @location = location
14
+ end
15
+
16
+ # @sg-ignore Declared return type
17
+ # ::Array<::Solargraph::Pin::Base> does not match inferred
18
+ # type ::Array<::Solargraph::Pin::BaseVariable, ::NilClass>
19
+ # for Solargraph::Source::Chain::InstanceVariable#resolve
7
20
  def resolve api_map, name_pin, locals
8
- api_map.get_instance_variable_pins(name_pin.binder.namespace, name_pin.binder.scope).select{|p| p.name == word}
21
+ ivars = api_map.get_instance_variable_pins(name_pin.context.namespace, name_pin.context.scope).select{|p| p.name == word}
22
+ out = api_map.var_at_location(ivars, word, name_pin, location)
23
+ [out].compact
9
24
  end
25
+
26
+ private
27
+
28
+ # @todo: Missed nil violation
29
+ # @return [Location]
30
+ attr_reader :location
10
31
  end
11
32
  end
12
33
  end
@@ -16,11 +16,15 @@ module Solargraph
16
16
  # @param node [Parser::AST::Node, Object]
17
17
  def initialize type, node
18
18
  if node.is_a?(::Parser::AST::Node)
19
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
19
20
  if node.type == :true
20
21
  @value = true
22
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
21
23
  elsif node.type == :false
22
24
  @value = false
25
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
23
26
  elsif [:int, :sym].include?(node.type)
27
+ # @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
24
28
  @value = node.children.first
25
29
  end
26
30
  end
@@ -31,6 +35,7 @@ module Solargraph
31
35
 
32
36
  # @sg-ignore Fix "Not enough arguments to Module#protected"
33
37
  protected def equality_fields
38
+ # @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
34
39
  super + [@value, @type, @literal_type, @complex_type]
35
40
  end
36
41
 
@@ -8,6 +8,8 @@ module Solargraph
8
8
  '<or>'
9
9
  end
10
10
 
11
+ attr_reader :links
12
+
11
13
  # @param links [::Array<Chain>]
12
14
  def initialize links
13
15
  @links = links
@@ -15,7 +17,13 @@ module Solargraph
15
17
 
16
18
  def resolve api_map, name_pin, locals
17
19
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq), source: :chain)]
20
+ combined_type = Solargraph::ComplexType.new(types)
21
+ unless types.all?(&:nullable?)
22
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
23
+ combined_type = combined_type.without_nil
24
+ end
25
+
26
+ [Solargraph::Pin::ProxyType.anonymous(combined_type, source: :chain)]
19
27
  end
20
28
  end
21
29
  end
@@ -71,6 +71,7 @@ module Solargraph
71
71
 
72
72
  # @return [Chain]
73
73
  def base
74
+ # @sg-ignore Need to add nil check here
74
75
  @base ||= Chain.new(links[0..-2])
75
76
  end
76
77
 
@@ -78,25 +79,25 @@ module Solargraph
78
79
  #
79
80
  # @param api_map [ApiMap]
80
81
  #
81
- # @param name_pin [Pin::Base] A pin
82
- # representing the place in which expression is evaluated (e.g.,
83
- # a Method pin, or a Module or Class pin if not run within a
84
- # method - both in terms of the closure around the chain, as well
85
- # as the self type used for any method calls in head position.
82
+ # @param name_pin [Pin::Base] A pin representing the closure in
83
+ # which expression is evaluated (e.g., a Method pin, or a
84
+ # Module or Class pin if not run within a method - both in
85
+ # terms of the closure around the chain, as well as the self
86
+ # type used for any method calls in head position.
86
87
  #
87
88
  # Requirements for name_pin:
88
89
  #
89
90
  # * name_pin.context: This should be a type representing the
90
- # namespace where we can look up non-local variables and
91
- # method names. If it is a Class<X>, we will look up
92
- # :class scoped methods/variables.
91
+ # namespace where we can look up non-local variables. If
92
+ # it is a Class<X>, we will look up :class scoped
93
+ # instance variables.
93
94
  #
94
95
  # * name_pin.binder: Used for method call lookups only
95
96
  # (Chain::Call links). For method calls as the first
96
97
  # element in the chain, 'name_pin.binder' should be the
97
98
  # same as name_pin.context above. For method calls later
98
- # in the chain (e.g., 'b' in a.b.c), it should represent
99
- # 'a'.
99
+ # in the chain, it changes. (e.g., for 'b' in a.b.c, it
100
+ # should represent the type of 'a').
100
101
  #
101
102
  # @param locals [::Array<Pin::LocalVariable>] Any local
102
103
  # variables / method parameters etc visible by the statement
@@ -113,6 +114,7 @@ module Solargraph
113
114
  #
114
115
  # @todo ProxyType uses 'type' for the binder, but '
115
116
  working_pin = name_pin
117
+ # @sg-ignore Need to add nil check here
116
118
  links[0..-2].each do |link|
117
119
  pins = link.resolve(api_map, working_pin, locals)
118
120
  type = infer_from_definitions(pins, working_pin, api_map, locals)
@@ -138,7 +140,8 @@ module Solargraph
138
140
  # @return [ComplexType]
139
141
  # @sg-ignore
140
142
  def infer api_map, name_pin, locals
141
- cache_key = [node, node&.location, links, name_pin&.return_type, locals]
143
+ # includes binder as it is mutable in Pin::Block
144
+ cache_key = [node, node&.location, links, name_pin&.return_type, name_pin&.binder, locals]
142
145
  if @@inference_invalidation_key == api_map.hash
143
146
  cached = @@inference_cache[cache_key]
144
147
  return cached if cached
@@ -154,7 +157,7 @@ module Solargraph
154
157
  # @param api_map [ApiMap]
155
158
  # @param name_pin [Pin::Base]
156
159
  # @param locals [::Array<Pin::LocalVariable>]
157
- # @return [ComplexType]
160
+ # @return [ComplexType, ComplexType::UniqueType]
158
161
  def infer_uncached api_map, name_pin, locals
159
162
  pins = define(api_map, name_pin, locals)
160
163
  if pins.empty?
@@ -209,12 +212,12 @@ module Solargraph
209
212
  private
210
213
 
211
214
  # @param pins [::Array<Pin::Base>]
212
- # @param context [Pin::Base]
215
+ # @param name_pin [Pin::Base]
213
216
  # @param api_map [ApiMap]
214
217
  # @param locals [::Enumerable<Pin::LocalVariable>]
215
- # @return [ComplexType]
216
- def infer_from_definitions pins, context, api_map, locals
217
- # @type [::Array<ComplexType>]
218
+ # @return [ComplexType, ComplexType::UniqueType]
219
+ def infer_from_definitions pins, name_pin, api_map, locals
220
+ # @type [::Array<ComplexType, ComplexType::UniqueType>]
218
221
  types = []
219
222
  unresolved_pins = []
220
223
  # @todo this param tag shouldn't be needed to probe the type
@@ -232,7 +235,8 @@ module Solargraph
232
235
  # @todo even at strong, no typechecking complaint
233
236
  # happens when a [Pin::Base,nil] is passed into a method
234
237
  # that accepts only [Pin::Namespace] as an argument
235
- type = type.resolve_generics(pin.closure, context.binder)
238
+ # @sg-ignore Need to add nil check here
239
+ type = type.resolve_generics(pin.closure, name_pin.binder)
236
240
  end
237
241
  types << type
238
242
  else
@@ -271,16 +275,15 @@ module Solargraph
271
275
  else
272
276
  ComplexType.new(types)
273
277
  end
274
- if context.nil? || context.return_type.undefined?
278
+ if name_pin.nil? || name_pin.context.undefined?
275
279
  # up to downstream to resolve self type
276
280
  return type
277
281
  end
278
-
279
- type.self_to_type(context.return_type)
282
+ type.self_to_type(name_pin.context)
280
283
  end
281
284
 
282
- # @param type [ComplexType]
283
- # @return [ComplexType]
285
+ # @param type [ComplexType, ComplexType::UniqueType]
286
+ # @return [ComplexType, ComplexType::UniqueType]
284
287
  def maybe_nil type
285
288
  return type if type.undefined? || type.void? || type.nullable?
286
289
  return type unless nullable?