solargraph 0.25.1 → 0.26.0

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +18 -16
  3. data/lib/solargraph/api_map.rb +100 -161
  4. data/lib/solargraph/api_map/source_to_yard.rb +9 -9
  5. data/lib/solargraph/api_map/store.rb +50 -13
  6. data/lib/solargraph/basic_type.rb +33 -0
  7. data/lib/solargraph/basic_type_methods.rb +111 -0
  8. data/lib/solargraph/complex_type.rb +51 -89
  9. data/lib/solargraph/core_fills.rb +12 -8
  10. data/lib/solargraph/diagnostics/type_not_defined.rb +2 -2
  11. data/lib/solargraph/language_server.rb +3 -0
  12. data/lib/solargraph/language_server/completion_item_kinds.rb +2 -0
  13. data/lib/solargraph/language_server/error_codes.rb +2 -0
  14. data/lib/solargraph/language_server/host.rb +53 -6
  15. data/lib/solargraph/language_server/message.rb +13 -0
  16. data/lib/solargraph/language_server/message/text_document/definition.rb +4 -6
  17. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -1
  18. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -1
  19. data/lib/solargraph/language_server/message_types.rb +2 -0
  20. data/lib/solargraph/language_server/request.rb +4 -0
  21. data/lib/solargraph/language_server/symbol_kinds.rb +28 -26
  22. data/lib/solargraph/language_server/transport.rb +3 -0
  23. data/lib/solargraph/language_server/uri_helpers.rb +2 -0
  24. data/lib/solargraph/library.rb +12 -7
  25. data/lib/solargraph/pin.rb +1 -1
  26. data/lib/solargraph/pin/attribute.rb +5 -5
  27. data/lib/solargraph/pin/base.rb +51 -16
  28. data/lib/solargraph/pin/base_variable.rb +25 -7
  29. data/lib/solargraph/pin/block.rb +18 -1
  30. data/lib/solargraph/pin/block_parameter.rb +42 -5
  31. data/lib/solargraph/pin/conversions.rb +4 -2
  32. data/lib/solargraph/pin/method.rb +6 -6
  33. data/lib/solargraph/pin/method_parameter.rb +6 -6
  34. data/lib/solargraph/pin/namespace.rb +7 -2
  35. data/lib/solargraph/pin/proxy_type.rb +39 -0
  36. data/lib/solargraph/pin/symbol.rb +20 -12
  37. data/lib/solargraph/pin/yard_pin/method.rb +2 -2
  38. data/lib/solargraph/source.rb +89 -38
  39. data/lib/solargraph/source/call_chainer.rb +273 -0
  40. data/lib/solargraph/source/chain.rb +104 -0
  41. data/lib/solargraph/source/chain/call.rb +72 -0
  42. data/lib/solargraph/source/chain/class_variable.rb +11 -0
  43. data/lib/solargraph/source/chain/constant.rb +17 -0
  44. data/lib/solargraph/source/chain/definition.rb +16 -0
  45. data/lib/solargraph/source/chain/global_variable.rb +11 -0
  46. data/lib/solargraph/source/chain/head.rb +20 -0
  47. data/lib/solargraph/source/chain/instance_variable.rb +11 -0
  48. data/lib/solargraph/source/chain/link.rb +33 -0
  49. data/lib/solargraph/source/chain/literal.rb +21 -0
  50. data/lib/solargraph/source/chain/variable.rb +11 -0
  51. data/lib/solargraph/source/change.rb +3 -1
  52. data/lib/solargraph/{api_map → source}/completion.rb +3 -1
  53. data/lib/solargraph/source/encoding_fixes.rb +21 -0
  54. data/lib/solargraph/source/fragment.rb +139 -284
  55. data/lib/solargraph/source/mapper.rb +27 -16
  56. data/lib/solargraph/source/node_chainer.rb +94 -0
  57. data/lib/solargraph/source/node_methods.rb +2 -2
  58. data/lib/solargraph/source/position.rb +4 -0
  59. data/lib/solargraph/source/range.rb +10 -2
  60. data/lib/solargraph/version.rb +1 -1
  61. data/lib/solargraph/yard_map.rb +13 -2
  62. metadata +20 -6
  63. data/lib/solargraph/api_map/probe.rb +0 -251
  64. data/lib/solargraph/api_map/type_methods.rb +0 -40
  65. data/lib/solargraph/pin/proxy_method.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bd332c0e24354eee990335169e5d861e470714cf3f3431b41c5d7e184f33035
4
- data.tar.gz: a4ce050c8e2e9ef1990c9be69dc2a4a6457cf27bc9b7ba85168014c30da77480
3
+ metadata.gz: 6faf5ac32f43c83b6d510ed61cac764185616fc4420198ed7adf6b9285ce7d77
4
+ data.tar.gz: 4d7a0abf2e8dd321dbefc90932766c97167caad8291739ed4ca4dc1537ea381e
5
5
  SHA512:
6
- metadata.gz: 9cd5cfb006e654069b88c596dea33d6be250bda7569a1193c834336345fa927d0b28b48fdfa5c37f68f3ce56ffc6cf6e647cda4e6184cbb566e8ad68ef3ac339
7
- data.tar.gz: 9846d874b79d01132a0fdb8ad7dd6f0cf81682a1fb9e1f3d72602d8ca3330380fba455f9c4d7f9e624bb40b2dff21d39fcef42c4273832c549b296c4a98b4a24
6
+ metadata.gz: '08ea817581e66ecc51b4cb19ccb2f5fa7dbb414375b3c1461ce680fa5c382ff2faa46da58e4a297c8a81ffd5782cb6aef9a8eecd74b8804f0e2c6addd56205d6'
7
+ data.tar.gz: 73f36e26202c49869b8afcf4cfd77971f3614863e74dd8f5f6c386fe5fa5d844e62e2995ffa198b4468645577d936b97c4bbf9fdab65b0a8956c95036acfee2b
@@ -24,21 +24,23 @@ module Solargraph
24
24
  end
25
25
  end
26
26
 
27
- autoload :Shell, 'solargraph/shell'
28
- autoload :Source, 'solargraph/source'
29
- autoload :ApiMap, 'solargraph/api_map'
30
- autoload :YardMap, 'solargraph/yard_map'
31
- autoload :Pin, 'solargraph/pin'
32
- autoload :LiveMap, 'solargraph/live_map'
33
- autoload :ServerMethods, 'solargraph/server_methods'
34
- autoload :Plugin, 'solargraph/plugin'
35
- autoload :CoreFills, 'solargraph/core_fills'
36
- autoload :LanguageServer, 'solargraph/language_server'
37
- autoload :Workspace, 'solargraph/workspace'
38
- autoload :Page, 'solargraph/page'
39
- autoload :Library, 'solargraph/library'
40
- autoload :Diagnostics, 'solargraph/diagnostics'
41
- autoload :ComplexType, 'solargraph/complex_type'
27
+ autoload :Shell, 'solargraph/shell'
28
+ autoload :Source, 'solargraph/source'
29
+ autoload :ApiMap, 'solargraph/api_map'
30
+ autoload :YardMap, 'solargraph/yard_map'
31
+ autoload :Pin, 'solargraph/pin'
32
+ autoload :LiveMap, 'solargraph/live_map'
33
+ autoload :ServerMethods, 'solargraph/server_methods'
34
+ autoload :Plugin, 'solargraph/plugin'
35
+ autoload :CoreFills, 'solargraph/core_fills'
36
+ autoload :LanguageServer, 'solargraph/language_server'
37
+ autoload :Workspace, 'solargraph/workspace'
38
+ autoload :Page, 'solargraph/page'
39
+ autoload :Library, 'solargraph/library'
40
+ autoload :Diagnostics, 'solargraph/diagnostics'
41
+ autoload :BasicTypeMethods, 'solargraph/basic_type_methods'
42
+ autoload :BasicType, 'solargraph/basic_type'
43
+ autoload :ComplexType, 'solargraph/complex_type'
42
44
 
43
45
  YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
44
46
  YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
@@ -47,4 +49,4 @@ end
47
49
 
48
50
  Solargraph::YardMap::CoreDocs.require_minimum
49
51
  # Change YARD log IO to avoid sending unexpected messages to STDOUT
50
- YARD::Logger.instance.io = STDERR
52
+ YARD::Logger.instance.io = File.new(File::NULL, 'w')
@@ -9,14 +9,10 @@ module Solargraph
9
9
  class ApiMap
10
10
  autoload :Cache, 'solargraph/api_map/cache'
11
11
  autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
12
- autoload :Completion, 'solargraph/api_map/completion'
13
- autoload :Probe, 'solargraph/api_map/probe'
14
12
  autoload :Store, 'solargraph/api_map/store'
15
- autoload :TypeMethods, 'solargraph/api_map/type_methods'
16
13
 
17
14
  include Solargraph::ApiMap::SourceToYard
18
15
  include CoreFills
19
- include TypeMethods
20
16
 
21
17
  # The workspace to analyze and process.
22
18
  #
@@ -141,7 +137,7 @@ module Solargraph
141
137
  #
142
138
  # @return [Array<Solargraph::Pin::Keyword>]
143
139
  def self.keywords
144
- @keyword_suggestions ||= KEYWORDS.map{ |s|
140
+ @keywords ||= KEYWORDS.map{ |s|
145
141
  Pin::Keyword.new(s)
146
142
  }.freeze
147
143
  end
@@ -207,6 +203,13 @@ module Solargraph
207
203
  result
208
204
  end
209
205
 
206
+ def fragment_at(location)
207
+ @sources.each do |source|
208
+ return source.fragment_at(location.range.start.line, location.range.start.column) if source.filename == location.filename
209
+ end
210
+ nil
211
+ end
212
+
210
213
  # @deprecated Use #qualify instead
211
214
  # @param namespace [String]
212
215
  # @param context [String]
@@ -238,6 +241,14 @@ module Solargraph
238
241
  store.get_symbols
239
242
  end
240
243
 
244
+ # @todo Make this better
245
+ def get_source filename
246
+ @sources.each do |s|
247
+ return s if s.filename == filename
248
+ end
249
+ nil
250
+ end
251
+
241
252
  # @return [Array<Solargraph::Pin::GlobalVariable>]
242
253
  def get_global_variable_pins
243
254
  globals = []
@@ -261,8 +272,8 @@ module Solargraph
261
272
  skip = []
262
273
  if fqns == ''
263
274
  domains.each do |domain|
264
- namespace, scope = extract_namespace_and_scope(domain)
265
- result.concat inner_get_methods(namespace, scope, [:public], deep, skip)
275
+ type = ComplexType.parse(domain).first
276
+ result.concat inner_get_methods(type.name, type.scope, [:public], deep, skip)
266
277
  end
267
278
  result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
268
279
  result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
@@ -279,140 +290,55 @@ module Solargraph
279
290
  result
280
291
  end
281
292
 
282
- # Get a stack of method pins for a method name in a namespace. The order
283
- # of the pins corresponds to the ancestry chain, with highest precedence
284
- # first.
293
+ # Get an array of public methods for a complex type.
285
294
  #
286
- # @param fqns [String]
287
- # @param name [String]
288
- # @param scope [Symbol] :instance or :class
295
+ # @param type [Solargraph::ComplexType]
296
+ # @param context [String]
289
297
  # @return [Array<Solargraph::Pin::Base>]
290
- def get_method_stack fqns, name, scope: :instance
291
- # cached = cache.get_method_stack(fqns, name, scope)
292
- # return cached.clone unless cached.nil?
293
- result = get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
294
- # cache.set_method_stack(fqns, name, scope, result)
295
- result
296
- end
297
-
298
- # Get a set of available completions for the specified fragment. The
299
- # resulting Completion object contains an array of pins and the range of
300
- # text to replace in the source.
301
- #
302
- # @param fragment [Solargraph::Source::Fragment]
303
- # @return [ApiMap::Completion]
304
- def complete fragment
305
- return Completion.new([], fragment.whole_word_range) if fragment.string? or fragment.comment?
298
+ def get_complex_type_methods type, context = '', internal = false
299
+ return [] if type.undefined? or type.void?
306
300
  result = []
307
- if !fragment.signature.include?('.') and !fragment.base_literal?
308
- if fragment.signature.start_with?('@@')
309
- result.concat get_class_variable_pins(fragment.namespace)
310
- elsif fragment.signature.start_with?('@')
311
- result.concat get_instance_variable_pins(fragment.namespace, fragment.scope)
312
- elsif fragment.signature.start_with?('$')
313
- result.concat get_global_variable_pins
314
- elsif fragment.signature.start_with?(':') and !fragment.signature.start_with?('::')
315
- result.concat get_symbols
316
- else
317
- unless fragment.signature.include?('::')
318
- result.concat prefer_non_nil_variables(fragment.locals)
319
- result.concat get_methods(fragment.namespace, scope: fragment.scope, visibility: [:public, :private, :protected])
320
- result.concat get_methods('Kernel')
321
- result.concat ApiMap.keywords
322
- end
323
- result.concat get_constants(fragment.base, fragment.namespace)
301
+ if type.duck_type?
302
+ type.select(&:duck_type?).each do |t|
303
+ result.push Pin::DuckMethod.new(nil, t.tag[1..-1])
324
304
  end
325
305
  else
326
- if fragment.base_literal?
327
- pin = get_path_suggestions(fragment.base_literal).select{|pin| pin.kind == Pin::NAMESPACE}.first
328
- unless pin.nil?
329
- if fragment.base.empty?
330
- result.concat get_methods(pin.path)
331
- else
332
- type = probe.infer_signature_type("#{pin.path}.new.#{fragment.base}", pin, fragment.locals)
333
- unless type.nil?
334
- namespace, scope = extract_namespace_and_scope(type)
335
- result.concat get_methods(namespace, scope: scope)
336
- end
337
- end
306
+ unless type.nil? or type.name == 'void'
307
+ namespace = qualify(type.namespace, context)
308
+ if ['Class', 'Module'].include?(namespace) and !type.subtypes.empty?
309
+ subtype = qualify(type.subtypes.first.name, context)
310
+ result.concat get_methods(subtype, scope: :class)
338
311
  end
339
- elsif fragment.signature.include?('::') and !fragment.signature.include?('.')
340
- result.concat get_constants(fragment.base, fragment.namespace)
341
- else
342
- pins = probe.infer_signature_pins(fragment.base, fragment.named_path, fragment.locals)
343
- unless pins.empty?
344
- pin = pins.first
345
- if pin.variable? and pin.return_type.nil? and !pin.signature.nil?
346
- type = probe.infer_signature_type(pin.signature, pin.context, fragment.locals)
347
- result.concat(get_methods(type)) unless type.nil?
348
- elsif pin.return_complex_types.any? and pin.return_complex_types.first.duck_type?
349
- pin.return_complex_types.each do |t|
350
- next unless t.duck_type?
351
- result.push Pin::DuckMethod.new(pin.location, t.tag[1..-1])
352
- end
353
- result.concat(get_methods('Object', scope: :instance))
354
- end
355
- if result.empty?
356
- pins.each do |pin|
357
- type = pin.return_type
358
- unless type.nil? or type == 'void'
359
- docns, scope = extract_namespace_and_scope(type)
360
- namespace = qualify(docns, pin.namespace)
361
- result.concat get_methods(namespace, scope: scope)
362
- break
363
- end
364
- end
365
- end
312
+ visibility = [:public]
313
+ if namespace == context or super_and_sub?(namespace, context)
314
+ visibility.push :protected
315
+ visibility.push :private if internal
366
316
  end
317
+ result.concat get_methods(namespace, scope: type.scope, visibility: visibility)
367
318
  end
368
319
  end
369
- frag_start = fragment.word.to_s.downcase
370
- filtered = result.uniq(&:identifier).select{|s| s.name.downcase.start_with?(frag_start) and (s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))}.sort_by.with_index{ |x, idx| [x.name, idx] }
371
- Completion.new(filtered, fragment.whole_word_range)
372
- end
373
-
374
- # Get an array of pins that describe the symbol at the specified fragment.
375
- #
376
- # @param fragment [Solargraph::Source::Fragment]
377
- # @return [Array<Solargraph::Pin::Base>]
378
- def define fragment
379
- return get_path_suggestions(fragment.namespace) if fragment.whole_signature == 'self'
380
- return [] if fragment.string? or fragment.comment? or fragment.literal? or KEYWORDS.include?(fragment.whole_signature)
381
- if fragment.base_literal?
382
- probe.infer_signature_pins fragment.whole_signature, Pin::ProxyMethod.new(fragment.base_literal), fragment.locals
383
- else
384
- probe.infer_signature_pins fragment.whole_signature, fragment.named_path, fragment.locals
385
- end
386
- end
387
-
388
- # Infer a return type from a fragment. This method will attempt to resolve
389
- # signatures.
390
- #
391
- # @param fragment [Solargraph::Source::Fragment]
392
- # @return [String]
393
- def infer_type fragment
394
- return nil if fragment.string? or fragment.comment?
395
- probe.infer_signature_type fragment.whole_signature, fragment.named_path, fragment.locals
320
+ result
396
321
  end
397
322
 
398
- # Get an array of pins that describe the method being called by the
399
- # argument list where the fragment is located. This is useful for queries
400
- # that need to know what parameters the current method expects to receive.
323
+ # Get a stack of method pins for a method name in a namespace. The order
324
+ # of the pins corresponds to the ancestry chain, with highest precedence
325
+ # first.
401
326
  #
402
- # If the fragment is not inside an argument list, return an empty array.
327
+ # @example
328
+ # api_map.get_method_stack('Subclass', 'method_name')
329
+ # #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]
403
330
  #
404
- # @param fragment [Solargraph::Source::Fragment]
331
+ # @param fqns [String]
332
+ # @param name [String]
333
+ # @param scope [Symbol] :instance or :class
405
334
  # @return [Array<Solargraph::Pin::Base>]
406
- def signify fragment
407
- return [] unless fragment.argument?
408
- return [] if fragment.recipient.whole_signature.nil? or fragment.recipient.whole_signature.empty?
409
- result = []
410
- if fragment.recipient.base_literal?
411
- result.concat probe.infer_signature_pins(fragment.recipient.whole_signature, Pin::ProxyMethod.new(fragment.recipient.base_literal), fragment.locals)
412
- else
413
- result.concat probe.infer_signature_pins(fragment.recipient.whole_signature, fragment.named_path, fragment.locals)
414
- end
415
- result.select{ |pin| pin.kind == Pin::METHOD }
335
+ def get_method_stack fqns, name, scope: :instance
336
+ # @todo Caches don't work on this query
337
+ # cached = cache.get_method_stack(fqns, name, scope)
338
+ # return cached.clone unless cached.nil?
339
+ result = get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select{|p| p.name == name}
340
+ # cache.set_method_stack(fqns, name, scope, result)
341
+ result
416
342
  end
417
343
 
418
344
  # Get an array of all suggestions that match the specified path.
@@ -423,7 +349,6 @@ module Solargraph
423
349
  return [] if path.nil?
424
350
  result = []
425
351
  result.concat store.get_path_pins(path)
426
- # result.concat yard_map.objects(path)
427
352
  if result.empty?
428
353
  lp = live_map.get_path_pin(path)
429
354
  result.push lp unless lp.nil?
@@ -439,7 +364,7 @@ module Solargraph
439
364
  # @param query [String] The text to match
440
365
  # @return [Array<String>]
441
366
  def search query
442
- rake_yard(@sources) if @yard_stale
367
+ rake_yard(store) if @yard_stale
443
368
  @yard_stale = false
444
369
  found = []
445
370
  code_object_paths.each do |k|
@@ -458,11 +383,10 @@ module Solargraph
458
383
  # @param path [String] The path to find
459
384
  # @return [Array<YARD::CodeObject::Base>]
460
385
  def document path
461
- rake_yard(@sources) if @yard_stale
386
+ rake_yard(store) if @yard_stale
462
387
  @yard_stale = false
463
388
  docs = []
464
389
  docs.push code_object_at(path) unless code_object_at(path).nil?
465
- # docs.concat yard_map.document(path)
466
390
  docs
467
391
  end
468
392
 
@@ -483,20 +407,13 @@ module Solargraph
483
407
  def locate_pin location
484
408
  @sources.each do |source|
485
409
  pin = source.locate_pin(location)
486
- unless pin.nil?
487
- return pin
488
- end
410
+ return pin unless pin.nil?
489
411
  end
490
412
  nil
491
413
  end
492
414
 
493
- # @return [Probe]
494
- def probe
495
- @probe ||= Probe.new(self)
496
- end
497
-
415
+ # @return [Array<String>]
498
416
  def unresolved_requires
499
- # return [] if yard_map_changed?
500
417
  yard_map.unresolved_requires
501
418
  end
502
419
 
@@ -549,6 +466,12 @@ module Solargraph
549
466
  @cache ||= Cache.new
550
467
  end
551
468
 
469
+ # @param fqns [String] A fully qualified namespace
470
+ # @param scope [Symbol] :class or :instance
471
+ # @param visibility [Array<Symbol>] :public, :protected, and/or :private
472
+ # @param deep [Boolean]
473
+ # @param skip [Array<String>]
474
+ # @return [Array<Pin::Base>]
552
475
  def inner_get_methods fqns, scope, visibility, deep, skip
553
476
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
554
477
  return [] if skip.include?(reqstr)
@@ -560,23 +483,19 @@ module Solargraph
560
483
  sc = store.get_superclass(fqns)
561
484
  unless sc.nil?
562
485
  fqsc = qualify(sc, fqns)
563
- sc_visi = [:public]
564
- sc_visi.push :protected if visibility.include?(:protected)
565
- result.concat inner_get_methods(fqsc, scope, sc_visi, true, skip) unless fqsc.nil?
486
+ result.concat inner_get_methods(fqsc, scope, visibility, true, skip) unless fqsc.nil?
566
487
  end
567
488
  if scope == :instance
568
489
  store.get_includes(fqns).each do |im|
569
490
  fqim = qualify(im, fqns)
570
491
  result.concat inner_get_methods(fqim, scope, visibility, deep, skip) unless fqim.nil?
571
492
  end
572
- # result.concat yard_map.get_instance_methods(fqns, visibility: visibility)
573
493
  result.concat inner_get_methods('Object', :instance, [:public], deep, skip) unless fqns == 'Object'
574
494
  else
575
495
  store.get_extends(fqns).each do |em|
576
496
  fqem = qualify(em, fqns)
577
497
  result.concat inner_get_methods(fqem, :instance, visibility, deep, skip) unless fqem.nil?
578
498
  end
579
- # result.concat yard_map.get_methods(fqns, '', visibility: visibility)
580
499
  type = get_namespace_type(fqns)
581
500
  result.concat inner_get_methods('Class', :instance, fqns == '' ? [:public] : visibility, deep, skip) if type == :class
582
501
  result.concat inner_get_methods('Module', :instance, fqns == '' ? [:public] : visibility, deep, skip) #if type == :module
@@ -585,12 +504,15 @@ module Solargraph
585
504
  result
586
505
  end
587
506
 
507
+ # @param fqns [String]
508
+ # @param visibility [Array<Symbol>]
509
+ # @param skip [Array<String>]
510
+ # @return [Array<Pin::Base>]
588
511
  def inner_get_constants fqns, visibility, skip
589
512
  return [] if skip.include?(fqns)
590
513
  skip.push fqns
591
514
  result = []
592
515
  result.concat store.get_constants(fqns, visibility)
593
- # result.concat yard_map.get_constants(fqns)
594
516
  store.get_includes(fqns).each do |is|
595
517
  fqis = qualify(is, fqns)
596
518
  result.concat inner_get_constants(fqis, [:public], skip) unless fqis.nil?
@@ -603,6 +525,7 @@ module Solargraph
603
525
  # installed gem with a name that starts with "solargraph-" is considered
604
526
  # an extension.
605
527
  #
528
+ # @return [void]
606
529
  def require_extensions
607
530
  Gem::Specification.all_names.select{|n| n.match(/^solargraph\-[a-z0-9_\-]*?\-ext\-[0-9\.]*$/)}.each do |n|
608
531
  STDERR.puts "Loading extension #{n}"
@@ -610,20 +533,6 @@ module Solargraph
610
533
  end
611
534
  end
612
535
 
613
- # @return [Array<Solargraph::Pin::Base>]
614
- def prefer_non_nil_variables pins
615
- result = []
616
- nil_pins = []
617
- pins.each do |pin|
618
- if pin.variable? and pin.nil_assignment?
619
- nil_pins.push pin
620
- else
621
- result.push pin
622
- end
623
- end
624
- result + nil_pins
625
- end
626
-
627
536
  # @return [Hash]
628
537
  def path_macros
629
538
  @path_macros ||= {}
@@ -634,6 +543,9 @@ module Solargraph
634
543
  @sources - [@virtual_source]
635
544
  end
636
545
 
546
+ # @param name [String]
547
+ # @param root [String]
548
+ # @param skip [Array<String>]
637
549
  # @return [String]
638
550
  def inner_qualify name, root, skip
639
551
  return nil if name.nil?
@@ -664,9 +576,10 @@ module Solargraph
664
576
 
665
577
  # Get the namespace's type (Class or Module).
666
578
  #
667
- # @param [String] A fully qualified namespace
579
+ # @param fqns [String] A fully qualified namespace
668
580
  # @return [Symbol] :class, :module, or nil
669
581
  def get_namespace_type fqns
582
+ return nil if fqns.nil?
670
583
  pin = store.get_path_pins(fqns).first
671
584
  return nil if pin.nil?
672
585
  pin.type
@@ -678,5 +591,31 @@ module Solargraph
678
591
  def yard_map
679
592
  @yard_map ||= Solargraph::YardMap.new(required: required, workspace: workspace)
680
593
  end
594
+
595
+ # Sort an array of pins to put nil or undefined variables last.
596
+ #
597
+ # @param pins [Array<Solargraph::Pin::Base>]
598
+ # @return [Array<Solargraph::Pin::Base>]
599
+ def prefer_non_nil_variables pins
600
+ result = []
601
+ nil_pins = []
602
+ pins.each do |pin|
603
+ if pin.variable? and pin.nil_assignment?
604
+ nil_pins.push pin
605
+ else
606
+ result.push pin
607
+ end
608
+ end
609
+ result + nil_pins
610
+ end
611
+
612
+ def super_and_sub?(sup, sub)
613
+ cls = store.get_superclass(sub)
614
+ until cls.nil?
615
+ return true if cls == sup
616
+ cls = store.get_superclass(cls)
617
+ end
618
+ false
619
+ end
681
620
  end
682
621
  end