solargraph 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
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