solargraph 0.53.4 → 0.54.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/lib/solargraph/api_map/cache.rb +2 -12
  4. data/lib/solargraph/api_map/store.rb +11 -6
  5. data/lib/solargraph/api_map.rb +53 -17
  6. data/lib/solargraph/complex_type/type_methods.rb +62 -30
  7. data/lib/solargraph/complex_type/unique_type.rb +117 -66
  8. data/lib/solargraph/complex_type.rb +41 -25
  9. data/lib/solargraph/doc_map.rb +19 -3
  10. data/lib/solargraph/gem_pins.rb +9 -1
  11. data/lib/solargraph/language_server/host/dispatch.rb +8 -1
  12. data/lib/solargraph/language_server/host/sources.rb +1 -61
  13. data/lib/solargraph/language_server/host.rb +21 -68
  14. data/lib/solargraph/language_server/message/base.rb +1 -1
  15. data/lib/solargraph/language_server/message/initialize.rb +14 -0
  16. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  17. data/lib/solargraph/language_server/progress.rb +118 -0
  18. data/lib/solargraph/language_server.rb +1 -0
  19. data/lib/solargraph/library.rb +136 -96
  20. data/lib/solargraph/parser/node_processor/base.rb +3 -2
  21. data/lib/solargraph/parser/node_processor.rb +1 -0
  22. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
  23. data/lib/solargraph/parser/parser_gem/node_methods.rb +0 -4
  24. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  25. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
  26. data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
  27. data/lib/solargraph/pin/base_variable.rb +34 -5
  28. data/lib/solargraph/pin/block.rb +55 -0
  29. data/lib/solargraph/pin/delegated_method.rb +5 -1
  30. data/lib/solargraph/pin/documenting.rb +2 -0
  31. data/lib/solargraph/pin/method.rb +3 -1
  32. data/lib/solargraph/pin/parameter.rb +5 -28
  33. data/lib/solargraph/rbs_map/conversions.rb +10 -6
  34. data/lib/solargraph/rbs_map.rb +11 -3
  35. data/lib/solargraph/shell.rb +18 -13
  36. data/lib/solargraph/source/chain.rb +20 -0
  37. data/lib/solargraph/source/updater.rb +1 -0
  38. data/lib/solargraph/source.rb +0 -44
  39. data/lib/solargraph/source_map/mapper.rb +3 -2
  40. data/lib/solargraph/source_map.rb +10 -0
  41. data/lib/solargraph/type_checker.rb +43 -18
  42. data/lib/solargraph/version.rb +1 -1
  43. data/lib/solargraph/workspace/config.rb +2 -1
  44. data/lib/solargraph/workspace.rb +13 -0
  45. metadata +4 -3
  46. data/lib/solargraph/language_server/host/cataloger.rb +0 -57
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ # Progress notification handling for language server hosts.
8
+ #
9
+ class Progress
10
+ WAITING = :waiting
11
+ CREATED = :created
12
+ FINISHED = :finished
13
+
14
+ # @return [String]
15
+ attr_reader :uuid
16
+
17
+ # @return [String]
18
+ attr_reader :title
19
+
20
+ # @return [String, nil]
21
+ attr_reader :kind
22
+
23
+ # @return [String, nil]
24
+ attr_reader :message
25
+
26
+ # @return [Integer]
27
+ attr_reader :percentage
28
+
29
+ # @return [Symbol]
30
+ attr_reader :status
31
+
32
+ # @param title [String]
33
+ def initialize title
34
+ @title = title
35
+ @uuid = SecureRandom.uuid
36
+ @percentage = 0
37
+ @status = WAITING
38
+ end
39
+
40
+ # @param message [String]
41
+ # @param percentage [Integer]
42
+ def begin message, percentage
43
+ @kind = 'begin'
44
+ @message = message
45
+ @percentage = percentage
46
+ end
47
+
48
+ # @param message [String]
49
+ # @param percentage [Integer]
50
+ def report message, percentage
51
+ @kind = 'report'
52
+ @message = message
53
+ @percentage = percentage
54
+ end
55
+
56
+ # @param message [String]
57
+ def finish message
58
+ @kind = 'end'
59
+ @message = message
60
+ @percentage = 100
61
+ true
62
+ end
63
+
64
+ # @param host [Solargraph::LanguageServer::Host]
65
+ def send host
66
+ return unless host.client_supports_progress? && !finished?
67
+
68
+ message = build
69
+
70
+ create(host) unless created?
71
+ host.send_notification '$/progress', message
72
+ @status = FINISHED if kind == 'end'
73
+ end
74
+
75
+ def created?
76
+ [CREATED, FINISHED].include?(status)
77
+ end
78
+
79
+ def finished?
80
+ status == FINISHED
81
+ end
82
+
83
+ private
84
+
85
+ # @param host [Solargraph::LanguageServer::Host]
86
+ # @return [void]
87
+ def create host
88
+ return if created?
89
+
90
+ host.send_request 'window/workDoneProgress/create', { token: uuid }
91
+ @status = CREATED
92
+ end
93
+
94
+ def build
95
+ {
96
+ token: uuid,
97
+ value: {
98
+ kind: kind,
99
+ cancellable: false
100
+ }.merge(build_value)
101
+ }
102
+ end
103
+
104
+ def build_value
105
+ case kind
106
+ when 'begin'
107
+ { title: title, message: message, percentage: percentage }
108
+ when 'report'
109
+ { message: message, percentage: percentage }
110
+ when 'end'
111
+ { message: message }
112
+ else
113
+ raise "Invalid progress kind #{kind}"
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -15,5 +15,6 @@ module Solargraph
15
15
  autoload :MessageTypes, 'solargraph/language_server/message_types'
16
16
  autoload :Request, 'solargraph/language_server/request'
17
17
  autoload :Transport, 'solargraph/language_server/transport'
18
+ autoload :Progress, 'solargraph/language_server/progress'
18
19
  end
19
20
  end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'pathname'
4
+ require 'observer'
4
5
 
5
6
  module Solargraph
6
7
  # A Library handles coordination between a Workspace and an ApiMap.
7
8
  #
8
9
  class Library
9
10
  include Logging
11
+ include Observable
10
12
 
11
13
  # @return [Solargraph::Workspace]
12
14
  attr_reader :workspace
@@ -17,12 +19,19 @@ module Solargraph
17
19
  # @return [Source, nil]
18
20
  attr_reader :current
19
21
 
22
+ # @return [LanguageServer::Progress, nil]
23
+ attr_reader :cache_progress
24
+
20
25
  # @param workspace [Solargraph::Workspace]
21
26
  # @param name [String, nil]
22
27
  def initialize workspace = Solargraph::Workspace.new, name = nil
23
28
  @workspace = workspace
24
29
  @name = name
25
- @synchronized = false
30
+ @threads = []
31
+ # @type [Integer, nil]
32
+ @total = nil
33
+ # @type [Source, nil]
34
+ @current = nil
26
35
  end
27
36
 
28
37
  def inspect
@@ -35,7 +44,7 @@ module Solargraph
35
44
  #
36
45
  # @return [Boolean]
37
46
  def synchronized?
38
- @synchronized
47
+ !mutex.locked?
39
48
  end
40
49
 
41
50
  # Attach a source to the library.
@@ -47,17 +56,15 @@ module Solargraph
47
56
  # @param source [Source, nil]
48
57
  # @return [void]
49
58
  def attach source
50
- mutex.synchronize do
51
- if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
52
- source_map_hash.delete @current.filename
53
- source_map_external_require_hash.delete @current.filename
54
- @external_requires = nil
55
- @synchronized = false
56
- end
57
- @current = source
58
- maybe_map @current
59
- catalog_inlock
59
+ if @current && (!source || @current.filename != source.filename) && source_map_hash.key?(@current.filename) && !workspace.has_file?(@current.filename)
60
+ source_map_hash.delete @current.filename
61
+ source_map_external_require_hash.delete @current.filename
62
+ @external_requires = nil
60
63
  end
64
+ changed = source && @current != source
65
+ @current = source
66
+ maybe_map @current
67
+ catalog if changed
61
68
  end
62
69
 
63
70
  # True if the specified file is currently attached.
@@ -95,15 +102,10 @@ module Solargraph
95
102
  # @param text [String] The contents of the file
96
103
  # @return [Boolean] True if the file was added to the workspace.
97
104
  def create filename, text
98
- result = false
99
- mutex.synchronize do
100
- next unless contain?(filename) || open?(filename)
101
- @synchronized = false
102
- source = Solargraph::Source.load_string(text, filename)
103
- workspace.merge(source)
104
- result = true
105
- end
106
- result
105
+ return false unless contain?(filename) || open?(filename)
106
+ source = Solargraph::Source.load_string(text, filename)
107
+ workspace.merge(source)
108
+ true
107
109
  end
108
110
 
109
111
  # Create file sources from files on disk. A file is ignored if it is
@@ -112,14 +114,11 @@ module Solargraph
112
114
  # @param filenames [Array<String>]
113
115
  # @return [Boolean] True if at least one file was added to the workspace.
114
116
  def create_from_disk *filenames
115
- result = false
116
- mutex.synchronize do
117
- sources = filenames
118
- .reject { |filename| File.directory?(filename) || !File.exist?(filename) }
119
- .map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
120
- result = workspace.merge(*sources)
121
- sources.each { |source| maybe_map source }
122
- end
117
+ sources = filenames
118
+ .reject { |filename| File.directory?(filename) || !File.exist?(filename) }
119
+ .map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
120
+ result = workspace.merge(*sources)
121
+ sources.each { |source| maybe_map source }
123
122
  result
124
123
  end
125
124
 
@@ -133,10 +132,7 @@ module Solargraph
133
132
  result = false
134
133
  filenames.each do |filename|
135
134
  detach filename
136
- mutex.synchronize do
137
- result ||= workspace.remove(filename)
138
- @synchronized = !result if synchronized?
139
- end
135
+ result ||= workspace.remove(filename)
140
136
  end
141
137
  result
142
138
  end
@@ -147,11 +143,10 @@ module Solargraph
147
143
  # @param filename [String]
148
144
  # @return [void]
149
145
  def close filename
150
- mutex.synchronize do
151
- @synchronized = false
152
- @current = nil if @current && @current.filename == filename
153
- catalog
154
- end
146
+ return unless @current&.filename == filename
147
+
148
+ @current = nil
149
+ catalog unless workspace.has_file?(filename)
155
150
  end
156
151
 
157
152
  # Get completion suggestions at the specified file and location.
@@ -162,9 +157,10 @@ module Solargraph
162
157
  # @return [SourceMap::Completion, nil]
163
158
  # @todo Take a Location instead of filename/line/column
164
159
  def completions_at filename, line, column
160
+ sync_catalog
165
161
  position = Position.new(line, column)
166
162
  cursor = Source::Cursor.new(read(filename), position)
167
- api_map.clip(cursor).complete
163
+ mutex.synchronize { api_map.clip(cursor).complete }
168
164
  rescue FileNotFoundError => e
169
165
  handle_file_not_found filename, e
170
166
  end
@@ -180,6 +176,7 @@ module Solargraph
180
176
  def definitions_at filename, line, column
181
177
  position = Position.new(line, column)
182
178
  cursor = Source::Cursor.new(read(filename), position)
179
+ sync_catalog
183
180
  if cursor.comment?
184
181
  source = read(filename)
185
182
  offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
@@ -187,13 +184,13 @@ module Solargraph
187
184
  rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
188
185
  if lft && rgt
189
186
  tag = (lft[1] + rgt[1]).sub(/:+$/, '')
190
- clip = api_map.clip(cursor)
187
+ clip = mutex.synchronize { api_map.clip(cursor) }
191
188
  clip.translate tag
192
189
  else
193
190
  []
194
191
  end
195
192
  else
196
- api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
193
+ mutex.synchronize { api_map.clip(cursor).define.map { |pin| pin.realize(api_map) } }
197
194
  end
198
195
  rescue FileNotFoundError => e
199
196
  handle_file_not_found(filename, e)
@@ -210,7 +207,8 @@ module Solargraph
210
207
  def type_definitions_at filename, line, column
211
208
  position = Position.new(line, column)
212
209
  cursor = Source::Cursor.new(read(filename), position)
213
- api_map.clip(cursor).types
210
+ sync_catalog
211
+ mutex.synchronize { api_map.clip(cursor).types }
214
212
  rescue FileNotFoundError => e
215
213
  handle_file_not_found filename, e
216
214
  end
@@ -226,7 +224,8 @@ module Solargraph
226
224
  def signatures_at filename, line, column
227
225
  position = Position.new(line, column)
228
226
  cursor = Source::Cursor.new(read(filename), position)
229
- api_map.clip(cursor).signify
227
+ sync_catalog
228
+ mutex.synchronize { api_map.clip(cursor).signify }
230
229
  end
231
230
 
232
231
  # @param filename [String]
@@ -237,8 +236,9 @@ module Solargraph
237
236
  # @return [Array<Solargraph::Range>]
238
237
  # @todo Take a Location instead of filename/line/column
239
238
  def references_from filename, line, column, strip: false, only: false
240
- cursor = api_map.cursor_at(filename, Position.new(line, column))
241
- clip = api_map.clip(cursor)
239
+ sync_catalog
240
+ cursor = Source::Cursor.new(read(filename), [line, column])
241
+ clip = mutex.synchronize { api_map.clip(cursor) }
242
242
  pin = clip.define.first
243
243
  return [] unless pin
244
244
  result = []
@@ -283,7 +283,8 @@ module Solargraph
283
283
  # @param location [Location]
284
284
  # @return [Array<Solargraph::Pin::Base>]
285
285
  def locate_pins location
286
- api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
286
+ sync_catalog
287
+ mutex.synchronize { api_map.locate_pins(location).map { |pin| pin.realize(api_map) } }
287
288
  end
288
289
 
289
290
  # Match a require reference to a file.
@@ -316,19 +317,22 @@ module Solargraph
316
317
  # @param path [String]
317
318
  # @return [Enumerable<Solargraph::Pin::Base>]
318
319
  def get_path_pins path
319
- api_map.get_path_suggestions(path)
320
+ sync_catalog
321
+ mutex.synchronize { api_map.get_path_suggestions(path) }
320
322
  end
321
323
 
322
324
  # @param query [String]
323
325
  # @return [Enumerable<YARD::CodeObjects::Base>]
324
326
  def document query
325
- api_map.document query
327
+ sync_catalog
328
+ mutex.synchronize { api_map.document query }
326
329
  end
327
330
 
328
331
  # @param query [String]
329
332
  # @return [Array<String>]
330
333
  def search query
331
- api_map.search query
334
+ sync_catalog
335
+ mutex.synchronize { api_map.search query }
332
336
  end
333
337
 
334
338
  # Get an array of all symbols in the workspace that match the query.
@@ -336,7 +340,8 @@ module Solargraph
336
340
  # @param query [String]
337
341
  # @return [Array<Pin::Base>]
338
342
  def query_symbols query
339
- api_map.query_symbols query
343
+ sync_catalog
344
+ mutex.synchronize { api_map.query_symbols query }
340
345
  end
341
346
 
342
347
  # Get an array of document symbols.
@@ -348,13 +353,15 @@ module Solargraph
348
353
  # @param filename [String]
349
354
  # @return [Array<Solargraph::Pin::Base>]
350
355
  def document_symbols filename
351
- api_map.document_symbols(filename)
356
+ sync_catalog
357
+ mutex.synchronize { api_map.document_symbols(filename) }
352
358
  end
353
359
 
354
360
  # @param path [String]
355
361
  # @return [Enumerable<Solargraph::Pin::Base>]
356
362
  def path_pins path
357
- api_map.get_path_suggestions(path)
363
+ sync_catalog
364
+ mutex.synchronize { api_map.get_path_suggestions(path) }
358
365
  end
359
366
 
360
367
  # @return [Array<SourceMap>]
@@ -380,10 +387,10 @@ module Solargraph
380
387
  # everything in the workspace should get diagnosed, or if there should
381
388
  # be an option to do so.
382
389
  #
390
+ sync_catalog
383
391
  return [] unless open?(filename)
384
392
  result = []
385
393
  source = read(filename)
386
- catalog
387
394
  repargs = {}
388
395
  workspace.config.reporters.each do |line|
389
396
  if line == 'all!'
@@ -409,21 +416,20 @@ module Solargraph
409
416
  #
410
417
  # @return [void]
411
418
  def catalog
412
- mutex.synchronize do
413
- catalog_inlock
414
- end
415
- end
416
-
417
- # @return [void]
418
- private def catalog_inlock
419
- return if synchronized?
419
+ @threads.delete_if(&:stop?)
420
+ @threads.push(Thread.new do
421
+ sleep 0.05 if RUBY_PLATFORM =~ /mingw/
422
+ next unless @threads.last == Thread.current
420
423
 
421
- logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
422
- api_map.catalog bench
423
- @synchronized = true
424
- logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
425
- logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
426
- cache_next_gemspec
424
+ mutex.synchronize do
425
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
426
+ api_map.catalog bench
427
+ logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
428
+ logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
429
+ cache_next_gemspec
430
+ end
431
+ end)
432
+ @threads.last.run if RUBY_PLATFORM =~ /mingw/
427
433
  end
428
434
 
429
435
  # @return [Bench]
@@ -462,12 +468,8 @@ module Solargraph
462
468
  # @return [Boolean] True if the source was merged into the workspace.
463
469
  def merge source
464
470
  Logging.logger.debug "Merging source: #{source.filename}"
465
- result = false
466
- mutex.synchronize do
467
- result = workspace.merge(source)
468
- maybe_map source
469
- end
470
- # catalog
471
+ result = workspace.merge(source)
472
+ maybe_map source
471
473
  result
472
474
  end
473
475
 
@@ -483,17 +485,14 @@ module Solargraph
483
485
  # @return [SourceMap, Boolean]
484
486
  def next_map
485
487
  return false if mapped?
486
- mutex.synchronize do
487
- @synchronized = false
488
- src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
489
- if src
490
- Logging.logger.debug "Mapping #{src.filename}"
491
- source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
492
- find_external_requires(source_map_hash[src.filename])
493
- source_map_hash[src.filename]
494
- else
495
- false
496
- end
488
+ src = workspace.sources.find { |s| !source_map_hash.key?(s.filename) }
489
+ if src
490
+ Logging.logger.debug "Mapping #{src.filename}"
491
+ source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
492
+ find_external_requires(source_map_hash[src.filename])
493
+ source_map_hash[src.filename]
494
+ else
495
+ false
497
496
  end
498
497
  end
499
498
 
@@ -575,7 +574,7 @@ module Solargraph
575
574
  end
576
575
  end
577
576
 
578
- # @param source [Source]
577
+ # @param source [Source, nil]
579
578
  # @return [void]
580
579
  def maybe_map source
581
580
  return unless source
@@ -589,7 +588,6 @@ module Solargraph
589
588
  unless source_map_hash[source.filename].try_merge!(new_map)
590
589
  source_map_hash[source.filename] = new_map
591
590
  find_external_requires(source_map_hash[source.filename])
592
- @synchronized = false
593
591
  end
594
592
  else
595
593
  # @todo Smelly instance variable access
@@ -598,7 +596,6 @@ module Solargraph
598
596
  else
599
597
  source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
600
598
  find_external_requires(source_map_hash[source.filename])
601
- @synchronized = false
602
599
  end
603
600
  end
604
601
 
@@ -609,25 +606,68 @@ module Solargraph
609
606
 
610
607
  # @return [void]
611
608
  def cache_next_gemspec
612
- return if @cache_pid
613
- spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec)}
614
- return unless spec
609
+ return if @cache_progress
610
+ spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec) }
611
+ return end_cache_progress unless spec
615
612
 
613
+ pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
616
614
  logger.info "Caching #{spec.name} #{spec.version}"
617
615
  Thread.new do
618
- @cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
619
- Process.wait(@cache_pid)
616
+ cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
617
+ report_cache_progress spec.name, pending
618
+ Process.wait(cache_pid)
620
619
  logger.info "Cached #{spec.name} #{spec.version}"
621
- @synchronized = false
622
- rescue Errno::EINVAL => e
620
+ rescue Errno::EINVAL => _e
623
621
  logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
624
- @synchronized = false
625
622
  rescue StandardError => e
626
623
  cache_errors.add spec
627
624
  Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
628
625
  ensure
629
- @cache_pid = nil
626
+ end_cache_progress
627
+ catalog
628
+ end
629
+ end
630
+
631
+ # @param gem_name [String]
632
+ # @param pending [Integer]
633
+ # @return [void]
634
+ def report_cache_progress gem_name, pending
635
+ @total ||= pending
636
+ @total = pending if pending > @total
637
+ finished = @total - pending
638
+ pct = if @total.zero?
639
+ 0
640
+ else
641
+ ((finished.to_f / @total.to_f) * 100).to_i
642
+ end
643
+ message = "#{gem_name}#{pending > 0 ? " (+#{pending})" : ''}"
644
+ # "
645
+ if @cache_progress
646
+ @cache_progress.report(message, pct)
647
+ else
648
+ @cache_progress = LanguageServer::Progress.new('Caching gem')
649
+ # If we don't send both a begin and a report, the progress notification
650
+ # might get stuck in the status bar forever
651
+ @cache_progress.begin(message, pct)
652
+ changed
653
+ notify_observers @cache_progress
654
+ @cache_progress.report(message, pct)
630
655
  end
656
+ changed
657
+ notify_observers @cache_progress
658
+ end
659
+
660
+ # @return [void]
661
+ def end_cache_progress
662
+ changed if @cache_progress&.finish('done')
663
+ notify_observers @cache_progress
664
+ @cache_progress = nil
665
+ @total = nil
666
+ end
667
+
668
+ def sync_catalog
669
+ @threads.delete_if(&:stop?)
670
+ .last&.join
631
671
  end
632
672
  end
633
673
  end
@@ -13,7 +13,7 @@ module Solargraph
13
13
  # @return [Array<Pin::Base>]
14
14
  attr_reader :pins
15
15
 
16
- # @return [Array<Pin::Base>]
16
+ # @return [Array<Pin::BaseVariable>]
17
17
  attr_reader :locals
18
18
 
19
19
  # @param node [Parser::AST::Node]
@@ -62,7 +62,7 @@ module Solargraph
62
62
  end
63
63
 
64
64
  # @param position [Solargraph::Position]
65
- # @return [Pin::Base, nil]
65
+ # @return [Pin::Closure, nil]
66
66
  def named_path_pin position
67
67
  pins.select{|pin| pin.is_a?(Pin::Closure) && pin.path && !pin.path.empty? && pin.location.range.contain?(position)}.last
68
68
  end
@@ -71,6 +71,7 @@ module Solargraph
71
71
  # @param position [Solargraph::Position]
72
72
  # @return [Pin::Closure, nil]
73
73
  def block_pin position
74
+ # @todo determine if this can return a Pin::Block
74
75
  pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
75
76
  end
76
77
 
@@ -24,6 +24,7 @@ module Solargraph
24
24
  # @param node [Parser::AST::Node]
25
25
  # @param region [Region]
26
26
  # @param pins [Array<Pin::Base>]
27
+ # @param locals [Array<Pin::BaseVariable>]
27
28
  # @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
28
29
  def self.process node, region = Region.new, pins = [], locals = []
29
30
  if pins.empty?
@@ -48,12 +48,6 @@ module Solargraph
48
48
  NodeProcessor.process(source.node, Region.new(source: source))
49
49
  end
50
50
 
51
- # @param node [Parser::AST::Node]
52
- # @return [Array<Parser::AST::Node>]
53
- def returns_from node
54
- NodeMethods.returns_from(node)
55
- end
56
-
57
51
  # @param source [Source]
58
52
  # @param name [String]
59
53
  # @return [Array<Location>]
@@ -62,10 +56,12 @@ module Solargraph
62
56
  reg = /#{Regexp.escape name[0..-2]}\s*=/
63
57
  # @param code [String]
64
58
  # @param offset [Integer]
59
+ # @return [Array(Integer, Integer), Array(nil, nil)]
65
60
  extract_offset = ->(code, offset) { reg.match(code, offset).offset(0) }
66
61
  else
67
62
  # @param code [String]
68
63
  # @param offset [Integer]
64
+ # @return [Array(Integer, Integer), Array(nil, nil)]
69
65
  extract_offset = ->(code, offset) { [soff = code.index(name, offset), soff + name.length] }
70
66
  end
71
67
  inner_node_references(name, source.node).map do |n|
@@ -115,7 +111,7 @@ module Solargraph
115
111
  NodeMethods.infer_literal_node_type node
116
112
  end
117
113
 
118
- # @return [void]
114
+ # @return [Integer]
119
115
  def version
120
116
  parser.version
121
117
  end
@@ -181,10 +181,6 @@ module Solargraph
181
181
  elsif [:super, :zsuper].include?(node.type)
182
182
  result.push node
183
183
  node.children.each { |child| result.concat call_nodes_from(child) }
184
- elsif node.type == :masgn
185
- # @todo We're treating a mass assignment as a call node, but the
186
- # type checker still needs the logic to handle it.
187
- result.push node
188
184
  else
189
185
  node.children.each { |child| result.concat call_nodes_from(child) }
190
186
  end