solargraph 0.59.0.dev.2 → 0.59.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +3 -1
  3. data/.github/workflows/plugins.yml +8 -2
  4. data/.github/workflows/rspec.yml +6 -40
  5. data/.github/workflows/typecheck.yml +2 -1
  6. data/.rubocop.yml +6 -1
  7. data/.rubocop_todo.yml +3 -0
  8. data/CHANGELOG.md +15 -0
  9. data/lib/solargraph/api_map/constants.rb +0 -1
  10. data/lib/solargraph/api_map/index.rb +6 -0
  11. data/lib/solargraph/api_map/store.rb +6 -0
  12. data/lib/solargraph/api_map.rb +20 -4
  13. data/lib/solargraph/complex_type/type_methods.rb +2 -1
  14. data/lib/solargraph/complex_type/unique_type.rb +2 -4
  15. data/lib/solargraph/complex_type.rb +1 -1
  16. data/lib/solargraph/doc_map.rb +370 -131
  17. data/lib/solargraph/gem_pins.rb +16 -17
  18. data/lib/solargraph/library.rb +44 -66
  19. data/lib/solargraph/logging.rb +0 -2
  20. data/lib/solargraph/parser/flow_sensitive_typing.rb +0 -2
  21. data/lib/solargraph/parser/parser_gem/class_methods.rb +0 -2
  22. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +0 -1
  23. data/lib/solargraph/pin/base.rb +0 -2
  24. data/lib/solargraph/pin/method.rb +3 -0
  25. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  26. data/lib/solargraph/pin/reference.rb +1 -0
  27. data/lib/solargraph/pin_cache.rb +66 -480
  28. data/lib/solargraph/position.rb +7 -4
  29. data/lib/solargraph/rbs_map/conversions.rb +18 -18
  30. data/lib/solargraph/rbs_map.rb +2 -3
  31. data/lib/solargraph/shell.rb +163 -15
  32. data/lib/solargraph/source/chain.rb +3 -1
  33. data/lib/solargraph/source_map/mapper.rb +0 -2
  34. data/lib/solargraph/type_checker.rb +1 -2
  35. data/lib/solargraph/version.rb +1 -1
  36. data/lib/solargraph/workspace/config.rb +1 -1
  37. data/lib/solargraph/workspace/gemspecs.rb +2 -2
  38. data/lib/solargraph/workspace.rb +32 -129
  39. data/lib/solargraph/yard_map.rb +17 -18
  40. data/lib/solargraph/yardoc.rb +26 -33
  41. data/lib/solargraph.rb +2 -0
  42. data/solargraph.gemspec +2 -2
  43. metadata +6 -11
@@ -1,16 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
4
3
  require 'pathname'
5
4
  require 'observer'
6
5
  require 'open3'
7
6
 
8
- # @!parse
9
- # class ::Gem::Specification
10
- # # @return [String]
11
- # def name; end
12
- # end
13
-
14
7
  module Solargraph
15
8
  # A Library handles coordination between a Workspace and an ApiMap.
16
9
  #
@@ -40,7 +33,6 @@ module Solargraph
40
33
  # @type [Source, nil]
41
34
  @current = nil
42
35
  @sync_count = 0
43
- @cache_progress = nil
44
36
  end
45
37
 
46
38
  def inspect
@@ -65,12 +57,11 @@ module Solargraph
65
57
  # @param source [Source, nil]
66
58
  # @return [void]
67
59
  def attach source
68
- # @sg-ignore Need to add nil check here
69
- if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
70
- # @sg-ignore Need to add nil check here
71
- source_map_hash.delete @current.filename
72
- # @sg-ignore Need to add nil check here
73
- source_map_external_require_hash.delete @current.filename
60
+ # @type [String, nil]
61
+ current_filename = @current&.filename
62
+ if @current && (!source || current_filename != source.filename) && current_filename && source_map_hash.key?(current_filename) && !workspace.has_file?(current_filename)
63
+ source_map_hash.delete current_filename
64
+ source_map_external_require_hash.delete current_filename
74
65
  @external_requires = nil
75
66
  end
76
67
  changed = source && @current != source
@@ -193,14 +184,12 @@ module Solargraph
193
184
  if cursor.comment?
194
185
  source = read(filename)
195
186
  offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
196
- # @sg-ignore Need to add nil check here
197
187
  # @type [MatchData, nil]
198
- lft = source.code[0..(offset - 1)].match(/\[[a-z0-9_:<, ]*?([a-z0-9_:]*)\z/i)
199
- # @sg-ignore Need to add nil check here
188
+ lft = source.code[0..(offset - 1)]&.match(/\[[a-z0-9_:<, ]*?([a-z0-9_:]*)\z/i)
200
189
  # @type [MatchData, nil]
201
- rgt = source.code[offset..].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
190
+ rgt = source.code[offset..]&.match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
202
191
  if lft && rgt
203
- # @sg-ignore Need to add nil check here
192
+ # @sg-ignore lft and rgt are checked for nil above
204
193
  tag = (lft[1] + rgt[1]).sub(/:+$/, '')
205
194
  clip = mutex.synchronize { api_map.clip(cursor) }
206
195
  clip.translate tag
@@ -262,6 +251,7 @@ module Solargraph
262
251
  clip = mutex.synchronize { api_map.clip(cursor) }
263
252
  pin = clip.define.first
264
253
  return [] unless pin
254
+
265
255
  result = []
266
256
  files = if only
267
257
  [api_map.source_map(filename)]
@@ -271,19 +261,15 @@ module Solargraph
271
261
  files.uniq(&:filename).each do |source|
272
262
  found = source.references(pin.name)
273
263
  found.select! do |loc|
274
- # @sg-ignore Need to add nil check here
275
- # @type [Solargraph::Pin::Base, nil]
276
- referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
264
+ referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)&.first
277
265
  referenced&.path == pin.path
278
266
  end
279
267
  if pin.path == 'Class#new'
280
- # @todo flow sensitive typing should allow shadowing of Kernel#caller
281
268
  caller = cursor.chain.base.infer(api_map, clip.send(:closure), clip.locals).first
282
269
  if caller.defined?
283
270
  found.select! do |loc|
284
271
  clip = api_map.clip_at(loc.filename, loc.range.start)
285
272
  other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:closure), clip.locals).first
286
- # @todo flow sensitive typing should allow shadowing of Kernel#caller
287
273
  caller == other
288
274
  end
289
275
  else
@@ -293,13 +279,13 @@ module Solargraph
293
279
  # HACK: for language clients that exclude special characters from the start of variable names
294
280
  if strip && (match = cursor.word.match(/^[^a-z0-9_]+/i))
295
281
  found.map! do |loc|
296
- Solargraph::Location.new(loc.filename,
297
- # @sg-ignore flow sensitive typing needs to handle if foo = bar
298
- Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line,
299
- loc.range.ending.column))
282
+ # @sg-ignore Unresolved call to []
283
+ Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
300
284
  end
301
285
  end
302
- result.concat(found.sort { |a, b| a.range.start.line <=> b.range.start.line })
286
+ result.concat(found.sort do |a, b|
287
+ a.range.start.line <=> b.range.start.line
288
+ end)
303
289
  end
304
290
  result.uniq
305
291
  end
@@ -320,12 +306,13 @@ module Solargraph
320
306
  def locate_ref location
321
307
  map = source_map_hash[location.filename]
322
308
  return if map.nil?
323
- # @sg-ignore Need to add nil check here
324
- pin = map.requires.select { |p| p.location.range.contain?(location.range.start) }.first
309
+ pin = map.requires.select { |p| p.location&.range&.contain?(location.range.start) }.first
325
310
  return nil if pin.nil?
326
311
  # @param full [String]
327
312
  return_if_match = proc do |full|
328
- return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0)) if source_map_hash.key?(full)
313
+ if source_map_hash.key?(full)
314
+ return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
315
+ end
329
316
  end
330
317
  workspace.require_paths.each do |path|
331
318
  full = File.join path, pin.name
@@ -423,17 +410,17 @@ module Solargraph
423
410
  workspace.config.reporters.each do |line|
424
411
  if line == 'all!'
425
412
  Diagnostics.reporters.each do |reporter_name|
426
- # @sg-ignore Need to add nil check here
427
- repargs[Diagnostics.reporter(reporter_name)] ||= []
413
+ r = Diagnostics.reporter(reporter_name)
414
+ repargs[r] ||= [] if r
428
415
  end
429
416
  else
430
417
  args = line.split(':').map(&:strip)
431
418
  name = args.shift
432
419
  reporter = Diagnostics.reporter(name)
433
420
  raise DiagnosticsError, "Diagnostics reporter #{name} does not exist" if reporter.nil?
434
- # @sg-ignore flow sensitive typing needs to handle 'raise if'
421
+ # @sg-ignore Hash errors
435
422
  repargs[reporter] ||= []
436
- # @sg-ignore flow sensitive typing needs to handle 'raise if'
423
+ # @sg-ignore Hash errors
437
424
  repargs[reporter].concat args
438
425
  end
439
426
  end
@@ -456,7 +443,7 @@ module Solargraph
456
443
  source_maps: source_map_hash.values,
457
444
  workspace: workspace,
458
445
  external_requires: external_requires,
459
- # @sg-ignore Need to add nil check here
446
+ # @sg-ignore OK if @current.filename is nil
460
447
  live_map: @current ? source_map_hash[@current.filename] : nil
461
448
  )
462
449
  end
@@ -493,13 +480,12 @@ module Solargraph
493
480
  # @return [SourceMap, Boolean]
494
481
  def next_map
495
482
  return false if mapped?
496
- # @sg-ignore Need to add nil check here
497
483
  src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
498
484
  if src
499
485
  Logging.logger.debug "Mapping #{src.filename}"
500
- # @sg-ignore Need to add nil check here
486
+ # @sg-ignore OK if src.filename is nil
501
487
  source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
502
- # @sg-ignore Need to add nil check here
488
+ # @sg-ignore OK if src.filename is nil
503
489
  source_map_hash[src.filename]
504
490
  else
505
491
  false
@@ -509,9 +495,9 @@ module Solargraph
509
495
  # @return [self]
510
496
  def map!
511
497
  workspace.sources.each do |src|
512
- # @sg-ignore Need to add nil check here
498
+ # @sg-ignore OK if src.filename is nil
513
499
  source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
514
- # @sg-ignore Need to add nil check here
500
+ # @sg-ignore OK if src.filename is nil
515
501
  find_external_requires source_map_hash[src.filename]
516
502
  end
517
503
  self
@@ -529,11 +515,6 @@ module Solargraph
529
515
 
530
516
  private
531
517
 
532
- # @return [PinCache]
533
- def pin_cache
534
- workspace.pin_cache
535
- end
536
-
537
518
  # @return [Hash{String => Array<String>}]
538
519
  def source_map_external_require_hash
539
520
  @source_map_external_require_hash ||= {}
@@ -544,10 +525,9 @@ module Solargraph
544
525
  def find_external_requires source_map
545
526
  # @type [Set<String>]
546
527
  new_set = source_map.requires.to_set(&:name)
547
- # return if new_set == source_map_external_require_hash[source_map.filename]
548
528
  _filenames = nil
549
529
  filenames = -> { _filenames ||= workspace.filenames.to_set }
550
- # @sg-ignore Need to add nil check here
530
+ # @sg-ignore OK if source_map.filename is nil
551
531
  source_map_external_require_hash[source_map.filename] = new_set.reject do |path|
552
532
  workspace.require_paths.any? do |base|
553
533
  full = File.join(base, path)
@@ -594,15 +574,14 @@ module Solargraph
594
574
  # @return [void]
595
575
  def maybe_map source
596
576
  return unless source
597
- # @sg-ignore Need to add nil check here
577
+ # @sg-ignore Wrong argument type for Solargraph::Workspace#has_file?: filename expected String, received String, nil
598
578
  return unless @current == source || workspace.has_file?(source.filename)
599
- # @sg-ignore Need to add nil check here
600
579
  if source_map_hash.key?(source.filename)
601
580
  new_map = Solargraph::SourceMap.map(source)
602
- # @sg-ignore Need to add nil check here
581
+ # @sg-ignore OK if source.filename is nil
603
582
  source_map_hash[source.filename] = new_map
604
583
  else
605
- # @sg-ignore Need to add nil check here
584
+ # @sg-ignore OK if source.filename is nil
606
585
  source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
607
586
  end
608
587
  end
@@ -621,7 +600,7 @@ module Solargraph
621
600
 
622
601
  pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
623
602
 
624
- if pin_cache.yardoc_processing?(spec)
603
+ if Yardoc.processing?(spec)
625
604
  logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)"
626
605
  queued_gemspec_cache.push(spec)
627
606
  return if pending - queued_gemspec_cache.length < 1
@@ -632,10 +611,7 @@ module Solargraph
632
611
  logger.info "Caching #{spec.name} #{spec.version}"
633
612
  Thread.new do
634
613
  report_cache_progress spec.name, pending
635
- kwargs = {}
636
- kwargs[:chdir] = workspace.directory.to_s if workspace.directory && !workspace.directory.empty?
637
- _o, e, s = Open3.capture3(workspace.command_path, 'cache', spec.name, spec.version.to_s,
638
- **kwargs)
614
+ _o, e, s = Open3.capture3(workspace.command_path, 'cache', spec.name, spec.version.to_s)
639
615
  if s.success?
640
616
  logger.info "Cached #{spec.name} #{spec.version}"
641
617
  else
@@ -652,7 +628,8 @@ module Solargraph
652
628
 
653
629
  # @return [Array<Gem::Specification>]
654
630
  def cacheable_specs
655
- cacheable = api_map.uncached_gemspecs +
631
+ cacheable = api_map.uncached_yard_gemspecs +
632
+ api_map.uncached_rbs_collection_gemspecs -
656
633
  queued_gemspec_cache -
657
634
  cache_errors.to_a
658
635
  return cacheable unless cacheable.empty?
@@ -670,15 +647,15 @@ module Solargraph
670
647
  # @return [void]
671
648
  def report_cache_progress gem_name, pending
672
649
  @total ||= pending
673
- # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
650
+ # @sg-ignore Wrong argument type for Integer#>: arg_0 expected Numeric, received Integer, nil
674
651
  @total = pending if pending > @total
675
- # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
652
+ # @sg-ignore Unresolved call to - on Integer, nil
676
653
  finished = @total - pending
677
- # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
654
+ # @sg-ignore @total should always be an Integer
678
655
  pct = if @total.zero?
679
656
  0
680
657
  else
681
- # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
658
+ # @sg-ignore Unresolved call to to_f
682
659
  ((finished.to_f / @total) * 100).to_i
683
660
  end
684
661
  message = "#{gem_name}#{" (+#{pending})" if pending.positive?}"
@@ -687,12 +664,12 @@ module Solargraph
687
664
  @cache_progress = LanguageServer::Progress.new('Caching gem')
688
665
  # If we don't send both a begin and a report, the progress notification
689
666
  # might get stuck in the status bar forever
690
- # @sg-ignore flow sensitive typing should be able to handle redefinition
667
+ # @sg-ignore Unresolved call to begin
691
668
  @cache_progress.begin(message, pct)
692
669
  changed
693
670
  notify_observers @cache_progress
694
671
  end
695
- # @sg-ignore flow sensitive typing should be able to handle redefinition
672
+ # @sg-ignore Unresolved call to report
696
673
  @cache_progress.report(message, pct)
697
674
  changed
698
675
  notify_observers @cache_progress
@@ -715,7 +692,8 @@ module Solargraph
715
692
  source_map_hash.each_value { |map| find_external_requires(map) }
716
693
  api_map.catalog bench
717
694
  logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
718
- logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
695
+ logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
696
+ logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
719
697
  cache_next_gemspec
720
698
  @sync_count = 0
721
699
  end
@@ -47,8 +47,6 @@ module Solargraph
47
47
  new_log_level = LOG_LEVELS[log_level.to_s]
48
48
  logger = Logger.new($stderr, level: new_log_level)
49
49
 
50
- # @sg-ignore Wrong argument type for Logger#formatter=: arg_0
51
- # expected nil, received Logger::_Formatter, nil
52
50
  logger.formatter = @@logger.formatter
53
51
  logger
54
52
  end
@@ -275,7 +275,6 @@ module Solargraph
275
275
  end
276
276
  # or like this:
277
277
  # (lvar :repr)
278
- # @sg-ignore Need to look at Tuple#include? handling
279
278
  variable_name = call_receiver.children[0].to_s if %i[lvar ivar].include?(call_receiver&.type)
280
279
  return unless variable_name
281
280
 
@@ -463,7 +462,6 @@ module Solargraph
463
462
  # @param clause_node [Parser::AST::Node, nil]
464
463
  def always_leaves_compound_statement? clause_node
465
464
  # https://docs.ruby-lang.org/en/2.2.0/keywords_rdoc.html
466
- # @sg-ignore Need to look at Tuple#include? handling
467
465
  %i[return raise next redo retry].include?(clause_node&.type)
468
466
  end
469
467
 
@@ -34,9 +34,7 @@ module Solargraph
34
34
  # @return [::Parser::Base]
35
35
  def parser
36
36
  @parser ||= Prism::Translation::Parser.new(FlawedBuilder.new).tap do |parser|
37
- # @sg-ignore Unresolved call to diagnostics on Prism::Translation::Parser
38
37
  parser.diagnostics.all_errors_are_fatal = true
39
- # @sg-ignore Unresolved call to diagnostics on Prism::Translation::Parser
40
38
  parser.diagnostics.ignore_warnings = true
41
39
  end
42
40
  end
@@ -36,7 +36,6 @@ module Solargraph
36
36
  def other_class_eval?
37
37
  node.children[0].type == :send &&
38
38
  node.children[0].children[1] == :class_eval &&
39
- # @sg-ignore Need to add nil check here
40
39
  %i[cbase const].include?(node.children[0].children[0]&.type)
41
40
  end
42
41
  end
@@ -241,8 +241,6 @@ module Solargraph
241
241
  results = [self, other].map(&attr).compact
242
242
  # true and false are different classes and can't be sorted
243
243
 
244
- # @sg-ignore Wrong argument type for Array#include?: object
245
- # expected Boolean, received Proc
246
244
  return true if results.any? { |r| [true, false].include?(r) }
247
245
  return results.first if results.any? { |r| r.is_a? AST::Node }
248
246
  results.min
@@ -505,6 +505,9 @@ module Solargraph
505
505
  #
506
506
  # @return [Array<Pin::Signature>]
507
507
  def combine_same_type_arity_signatures same_type_arity_signatures
508
+ # @todo Stubbing this method while we debug an infinite loop bug in Ruby 3.x
509
+ return same_type_arity_signatures
510
+
508
511
  # This is an O(n^2) operation, so bail out if n is not small
509
512
  return same_type_arity_signatures if same_type_arity_signatures.length > 10
510
513
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Reference
6
+ class TypeAlias < Reference
7
+ # @param return_type [ComplexType]
8
+ # @param [Hash{Symbol => Object}] splat
9
+ def initialize return_type:, **splat
10
+ super(**splat)
11
+ @return_type = return_type
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -9,6 +9,7 @@ module Solargraph
9
9
  autoload :Prepend, 'solargraph/pin/reference/prepend'
10
10
  autoload :Extend, 'solargraph/pin/reference/extend'
11
11
  autoload :Override, 'solargraph/pin/reference/override'
12
+ autoload :TypeAlias, 'solargraph/pin/reference/type_alias'
12
13
 
13
14
  attr_reader :generic_values
14
15