solargraph 0.54.0 → 0.54.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/solargraph/api_map/store.rb +8 -4
- data/lib/solargraph/api_map.rb +74 -23
- data/lib/solargraph/complex_type/type_methods.rb +17 -11
- data/lib/solargraph/complex_type/unique_type.rb +72 -9
- data/lib/solargraph/complex_type.rb +66 -17
- data/lib/solargraph/language_server/host/message_worker.rb +45 -5
- data/lib/solargraph/language_server/host.rb +10 -10
- data/lib/solargraph/language_server/message/base.rb +18 -11
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +19 -2
- data/lib/solargraph/library.rb +29 -39
- data/lib/solargraph/location.rb +14 -1
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
- data/lib/solargraph/parser.rb +2 -5
- data/lib/solargraph/pin/base.rb +16 -3
- data/lib/solargraph/pin/base_variable.rb +1 -1
- data/lib/solargraph/pin/block.rb +6 -26
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +8 -3
- data/lib/solargraph/pin/common.rb +2 -6
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/method.rb +51 -31
- data/lib/solargraph/pin/namespace.rb +4 -4
- data/lib/solargraph/pin/parameter.rb +9 -11
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/signature.rb +3 -129
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/range.rb +2 -4
- data/lib/solargraph/rbs_map/conversions.rb +76 -37
- data/lib/solargraph/rbs_map/core_fills.rb +6 -6
- data/lib/solargraph/shell.rb +17 -2
- data/lib/solargraph/source/chain/array.rb +6 -5
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +81 -51
- data/lib/solargraph/source/chain/link.rb +9 -0
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +41 -17
- data/lib/solargraph/source/cursor.rb +14 -2
- data/lib/solargraph/source.rb +102 -85
- data/lib/solargraph/source_map/clip.rb +4 -4
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +7 -7
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/solargraph.gemspec +4 -4
- metadata +20 -24
@@ -24,10 +24,8 @@ module Solargraph
|
|
24
24
|
attr_writer :client_capabilities
|
25
25
|
|
26
26
|
def initialize
|
27
|
-
@cancel_semaphore = Mutex.new
|
28
27
|
@buffer_semaphore = Mutex.new
|
29
28
|
@request_mutex = Mutex.new
|
30
|
-
@cancel = []
|
31
29
|
@buffer = String.new
|
32
30
|
@stopped = true
|
33
31
|
@next_request_id = 1
|
@@ -65,7 +63,7 @@ module Solargraph
|
|
65
63
|
# @param id [Integer]
|
66
64
|
# @return [void]
|
67
65
|
def cancel id
|
68
|
-
|
66
|
+
cancelled.push id
|
69
67
|
end
|
70
68
|
|
71
69
|
# True if the host received a request to cancel the method with the
|
@@ -74,9 +72,7 @@ module Solargraph
|
|
74
72
|
# @param id [Integer]
|
75
73
|
# @return [Boolean]
|
76
74
|
def cancel? id
|
77
|
-
|
78
|
-
@cancel_semaphore.synchronize { result = @cancel.include? id }
|
79
|
-
result
|
75
|
+
cancelled.include? id
|
80
76
|
end
|
81
77
|
|
82
78
|
# Delete the specified ID from the list of cancelled IDs if it exists.
|
@@ -84,7 +80,7 @@ module Solargraph
|
|
84
80
|
# @param id [Integer]
|
85
81
|
# @return [void]
|
86
82
|
def clear id
|
87
|
-
|
83
|
+
cancelled.delete id
|
88
84
|
end
|
89
85
|
|
90
86
|
# Called by adapter, to handle the request
|
@@ -101,11 +97,11 @@ module Solargraph
|
|
101
97
|
# @return [Solargraph::LanguageServer::Message::Base, nil] The message handler.
|
102
98
|
def receive request
|
103
99
|
if request['method']
|
104
|
-
logger.info "
|
100
|
+
logger.info "Host received ##{request['id']} #{request['method']}"
|
105
101
|
logger.debug request
|
106
102
|
message = Message.select(request['method']).new(self, request)
|
107
103
|
begin
|
108
|
-
message.process
|
104
|
+
message.process unless cancel?(request['id'])
|
109
105
|
rescue StandardError => e
|
110
106
|
logger.warn "Error processing request: [#{e.class}] #{e.message}"
|
111
107
|
logger.warn e.backtrace.join("\n")
|
@@ -381,7 +377,6 @@ module Solargraph
|
|
381
377
|
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
382
378
|
queue envelope
|
383
379
|
@next_request_id += 1
|
384
|
-
logger.info "Server sent #{method}"
|
385
380
|
logger.debug params
|
386
381
|
end
|
387
382
|
end
|
@@ -693,6 +688,11 @@ module Solargraph
|
|
693
688
|
|
694
689
|
private
|
695
690
|
|
691
|
+
# @return [Array<Integer>]
|
692
|
+
def cancelled
|
693
|
+
@cancelled ||= []
|
694
|
+
end
|
695
|
+
|
696
696
|
# @return [MessageWorker]
|
697
697
|
def message_worker
|
698
698
|
@message_worker ||= MessageWorker.new(self)
|
@@ -61,18 +61,11 @@ module Solargraph
|
|
61
61
|
# @return [void]
|
62
62
|
def send_response
|
63
63
|
return if id.nil?
|
64
|
-
|
65
|
-
|
66
|
-
# cancel should send response RequestCancelled
|
67
|
-
Solargraph::Logging.logger.info "Cancelled response to #{method}"
|
68
|
-
set_result nil
|
69
|
-
set_error ErrorCodes::REQUEST_CANCELLED, "cancelled by client"
|
70
|
-
else
|
71
|
-
Solargraph::Logging.logger.info "Sending response to #{method}"
|
72
|
-
end
|
64
|
+
|
65
|
+
accept_or_cancel
|
73
66
|
response = {
|
74
|
-
jsonrpc:
|
75
|
-
id: id
|
67
|
+
jsonrpc: '2.0',
|
68
|
+
id: id
|
76
69
|
}
|
77
70
|
response[:result] = result unless result.nil?
|
78
71
|
response[:error] = error unless error.nil?
|
@@ -83,6 +76,20 @@ module Solargraph
|
|
83
76
|
host.queue envelope
|
84
77
|
host.clear id
|
85
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def accept_or_cancel
|
83
|
+
if host.cancel?(id)
|
84
|
+
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
|
85
|
+
# cancel should send response RequestCancelled
|
86
|
+
Solargraph::Logging.logger.info "Cancelled response to ##{id} #{method}"
|
87
|
+
set_result nil
|
88
|
+
set_error ErrorCodes::REQUEST_CANCELLED, 'Cancelled by client'
|
89
|
+
else
|
90
|
+
Solargraph::Logging.logger.info "Sending response to ##{id} #{method}"
|
91
|
+
end
|
92
|
+
end
|
86
93
|
end
|
87
94
|
end
|
88
95
|
end
|
@@ -12,9 +12,6 @@ module Solargraph
|
|
12
12
|
col = params['position']['character']
|
13
13
|
begin
|
14
14
|
completion = host.completions_at(params['textDocument']['uri'], line, col)
|
15
|
-
if host.cancel?(id)
|
16
|
-
return set_result(empty_result) if host.cancel?(id)
|
17
|
-
end
|
18
15
|
items = []
|
19
16
|
last_context = nil
|
20
17
|
idx = -1
|
@@ -13,10 +13,10 @@ module Solargraph::LanguageServer::Message::TextDocument
|
|
13
13
|
def code_location
|
14
14
|
suggestions = host.definitions_at(params['textDocument']['uri'], @line, @column)
|
15
15
|
return nil if suggestions.empty?
|
16
|
-
suggestions.reject { |pin| pin.
|
16
|
+
suggestions.reject { |pin| pin.best_location.nil? || pin.best_location.filename.nil? }.map do |pin|
|
17
17
|
{
|
18
|
-
uri: file_to_uri(pin.
|
19
|
-
range: pin.
|
18
|
+
uri: file_to_uri(pin.best_location.filename),
|
19
|
+
range: pin.best_location.range.to_hash
|
20
20
|
}
|
21
21
|
end
|
22
22
|
end
|
@@ -6,15 +6,15 @@ class Solargraph::LanguageServer::Message::TextDocument::DocumentSymbol < Solarg
|
|
6
6
|
def process
|
7
7
|
pins = host.document_symbols params['textDocument']['uri']
|
8
8
|
info = pins.map do |pin|
|
9
|
-
next nil unless pin.
|
9
|
+
next nil unless pin.best_location&.filename
|
10
10
|
|
11
11
|
result = {
|
12
12
|
name: pin.name,
|
13
13
|
containerName: pin.namespace,
|
14
14
|
kind: pin.symbol_kind,
|
15
15
|
location: {
|
16
|
-
uri: file_to_uri(pin.
|
17
|
-
range: pin.
|
16
|
+
uri: file_to_uri(pin.best_location.filename),
|
17
|
+
range: pin.best_location.range.to_hash
|
18
18
|
},
|
19
19
|
deprecated: pin.deprecated?
|
20
20
|
}
|
@@ -21,7 +21,7 @@ module Solargraph
|
|
21
21
|
parts.push pin.documentation unless pin.documentation.nil? || pin.documentation.empty?
|
22
22
|
unless parts.empty?
|
23
23
|
data = parts.join("\n\n")
|
24
|
-
next if contents.last
|
24
|
+
next if contents.last&.end_with?(data)
|
25
25
|
contents.push data
|
26
26
|
end
|
27
27
|
last_link = this_link unless this_link.nil?
|
@@ -13,10 +13,10 @@ module Solargraph::LanguageServer::Message::TextDocument
|
|
13
13
|
def code_location
|
14
14
|
suggestions = host.type_definitions_at(params['textDocument']['uri'], @line, @column)
|
15
15
|
return nil if suggestions.empty?
|
16
|
-
suggestions.reject { |pin| pin.
|
16
|
+
suggestions.reject { |pin| pin.best_location.nil? || pin.best_location.filename.nil? }.map do |pin|
|
17
17
|
{
|
18
|
-
uri: file_to_uri(pin.
|
19
|
-
range: pin.
|
18
|
+
uri: file_to_uri(pin.best_location.filename),
|
19
|
+
range: pin.best_location.range.to_hash
|
20
20
|
}
|
21
21
|
end
|
22
22
|
end
|
@@ -6,14 +6,14 @@ class Solargraph::LanguageServer::Message::Workspace::WorkspaceSymbol < Solargra
|
|
6
6
|
def process
|
7
7
|
pins = host.query_symbols(params['query'])
|
8
8
|
info = pins.map do |pin|
|
9
|
-
uri = file_to_uri(pin.
|
9
|
+
uri = file_to_uri(pin.best_location.filename)
|
10
10
|
{
|
11
11
|
name: pin.path,
|
12
12
|
containerName: pin.namespace,
|
13
13
|
kind: pin.symbol_kind,
|
14
14
|
location: {
|
15
15
|
uri: uri,
|
16
|
-
range: pin.
|
16
|
+
range: pin.best_location.range.to_hash
|
17
17
|
},
|
18
18
|
deprecated: pin.deprecated?
|
19
19
|
}
|
@@ -66,10 +66,10 @@ module Solargraph
|
|
66
66
|
return unless host.client_supports_progress? && !finished?
|
67
67
|
|
68
68
|
message = build
|
69
|
-
|
70
|
-
create(host) unless created?
|
69
|
+
create(host)
|
71
70
|
host.send_notification '$/progress', message
|
72
71
|
@status = FINISHED if kind == 'end'
|
72
|
+
keep_alive host
|
73
73
|
end
|
74
74
|
|
75
75
|
def created?
|
@@ -113,6 +113,23 @@ module Solargraph
|
|
113
113
|
raise "Invalid progress kind #{kind}"
|
114
114
|
end
|
115
115
|
end
|
116
|
+
|
117
|
+
# @param host [Host]
|
118
|
+
def keep_alive host
|
119
|
+
mutex.synchronize { @last = Time.now }
|
120
|
+
@keep_alive ||= Thread.new do
|
121
|
+
until finished?
|
122
|
+
sleep 10
|
123
|
+
break if finished?
|
124
|
+
next if mutex.synchronize { Time.now - @last < 10 }
|
125
|
+
send host
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def mutex
|
131
|
+
@mutex ||= Mutex.new
|
132
|
+
end
|
116
133
|
end
|
117
134
|
end
|
118
135
|
end
|
data/lib/solargraph/library.rb
CHANGED
@@ -27,11 +27,11 @@ module Solargraph
|
|
27
27
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
28
28
|
@workspace = workspace
|
29
29
|
@name = name
|
30
|
-
@threads = []
|
31
30
|
# @type [Integer, nil]
|
32
31
|
@total = nil
|
33
32
|
# @type [Source, nil]
|
34
33
|
@current = nil
|
34
|
+
@sync_count = 0
|
35
35
|
end
|
36
36
|
|
37
37
|
def inspect
|
@@ -44,7 +44,7 @@ module Solargraph
|
|
44
44
|
#
|
45
45
|
# @return [Boolean]
|
46
46
|
def synchronized?
|
47
|
-
|
47
|
+
@sync_count < 2
|
48
48
|
end
|
49
49
|
|
50
50
|
# Attach a source to the library.
|
@@ -174,9 +174,9 @@ module Solargraph
|
|
174
174
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
175
175
|
# @todo Take filename/position instead of filename/line/column
|
176
176
|
def definitions_at filename, line, column
|
177
|
+
sync_catalog
|
177
178
|
position = Position.new(line, column)
|
178
179
|
cursor = Source::Cursor.new(read(filename), position)
|
179
|
-
sync_catalog
|
180
180
|
if cursor.comment?
|
181
181
|
source = read(filename)
|
182
182
|
offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
|
@@ -190,7 +190,14 @@ module Solargraph
|
|
190
190
|
[]
|
191
191
|
end
|
192
192
|
else
|
193
|
-
mutex.synchronize
|
193
|
+
mutex.synchronize do
|
194
|
+
clip = api_map.clip(cursor)
|
195
|
+
if cursor.assign?
|
196
|
+
[Pin::ProxyType.new(name: cursor.word, return_type: clip.infer)]
|
197
|
+
else
|
198
|
+
clip.define.map { |pin| pin.realize(api_map) }
|
199
|
+
end
|
200
|
+
end
|
194
201
|
end
|
195
202
|
rescue FileNotFoundError => e
|
196
203
|
handle_file_not_found(filename, e)
|
@@ -205,9 +212,9 @@ module Solargraph
|
|
205
212
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
206
213
|
# @todo Take filename/position instead of filename/line/column
|
207
214
|
def type_definitions_at filename, line, column
|
215
|
+
sync_catalog
|
208
216
|
position = Position.new(line, column)
|
209
217
|
cursor = Source::Cursor.new(read(filename), position)
|
210
|
-
sync_catalog
|
211
218
|
mutex.synchronize { api_map.clip(cursor).types }
|
212
219
|
rescue FileNotFoundError => e
|
213
220
|
handle_file_not_found filename, e
|
@@ -222,9 +229,9 @@ module Solargraph
|
|
222
229
|
# @return [Array<Solargraph::Pin::Base>]
|
223
230
|
# @todo Take filename/position instead of filename/line/column
|
224
231
|
def signatures_at filename, line, column
|
232
|
+
sync_catalog
|
225
233
|
position = Position.new(line, column)
|
226
234
|
cursor = Source::Cursor.new(read(filename), position)
|
227
|
-
sync_catalog
|
228
235
|
mutex.synchronize { api_map.clip(cursor).signify }
|
229
236
|
end
|
230
237
|
|
@@ -416,20 +423,7 @@ module Solargraph
|
|
416
423
|
#
|
417
424
|
# @return [void]
|
418
425
|
def catalog
|
419
|
-
@
|
420
|
-
@threads.push(Thread.new do
|
421
|
-
sleep 0.05 if RUBY_PLATFORM =~ /mingw/
|
422
|
-
next unless @threads.last == Thread.current
|
423
|
-
|
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/
|
426
|
+
@sync_count += 1
|
433
427
|
end
|
434
428
|
|
435
429
|
# @return [Bench]
|
@@ -467,7 +461,6 @@ module Solargraph
|
|
467
461
|
# @param source [Source]
|
468
462
|
# @return [Boolean] True if the source was merged into the workspace.
|
469
463
|
def merge source
|
470
|
-
Logging.logger.debug "Merging source: #{source.filename}"
|
471
464
|
result = workspace.merge(source)
|
472
465
|
maybe_map source
|
473
466
|
result
|
@@ -489,7 +482,6 @@ module Solargraph
|
|
489
482
|
if src
|
490
483
|
Logging.logger.debug "Mapping #{src.filename}"
|
491
484
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
492
|
-
find_external_requires(source_map_hash[src.filename])
|
493
485
|
source_map_hash[src.filename]
|
494
486
|
else
|
495
487
|
false
|
@@ -500,7 +492,7 @@ module Solargraph
|
|
500
492
|
def map!
|
501
493
|
workspace.sources.each do |src|
|
502
494
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
503
|
-
find_external_requires
|
495
|
+
find_external_requires source_map_hash[src.filename]
|
504
496
|
end
|
505
497
|
self
|
506
498
|
end
|
@@ -580,22 +572,10 @@ module Solargraph
|
|
580
572
|
return unless source
|
581
573
|
return unless @current == source || workspace.has_file?(source.filename)
|
582
574
|
if source_map_hash.key?(source.filename)
|
583
|
-
|
584
|
-
|
585
|
-
source.synchronized?
|
586
|
-
if source.synchronized?
|
587
|
-
new_map = Solargraph::SourceMap.map(source)
|
588
|
-
unless source_map_hash[source.filename].try_merge!(new_map)
|
589
|
-
source_map_hash[source.filename] = new_map
|
590
|
-
find_external_requires(source_map_hash[source.filename])
|
591
|
-
end
|
592
|
-
else
|
593
|
-
# @todo Smelly instance variable access
|
594
|
-
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
595
|
-
end
|
575
|
+
new_map = Solargraph::SourceMap.map(source)
|
576
|
+
source_map_hash[source.filename] = new_map
|
596
577
|
else
|
597
578
|
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
598
|
-
find_external_requires(source_map_hash[source.filename])
|
599
579
|
end
|
600
580
|
end
|
601
581
|
|
@@ -625,6 +605,7 @@ module Solargraph
|
|
625
605
|
ensure
|
626
606
|
end_cache_progress
|
627
607
|
catalog
|
608
|
+
sync_catalog
|
628
609
|
end
|
629
610
|
end
|
630
611
|
|
@@ -666,8 +647,17 @@ module Solargraph
|
|
666
647
|
end
|
667
648
|
|
668
649
|
def sync_catalog
|
669
|
-
@
|
670
|
-
|
650
|
+
return if @sync_count == 0
|
651
|
+
|
652
|
+
mutex.synchronize do
|
653
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
654
|
+
api_map.catalog bench
|
655
|
+
source_map_hash.values.each { |map| find_external_requires(map) }
|
656
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
657
|
+
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
658
|
+
cache_next_gemspec
|
659
|
+
@sync_count = 0
|
660
|
+
end
|
671
661
|
end
|
672
662
|
end
|
673
663
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solargraph
|
4
|
-
# A section of text identified by its filename
|
4
|
+
# A pointer to a section of source text identified by its filename
|
5
|
+
# and Range.
|
5
6
|
#
|
6
7
|
class Location
|
7
8
|
# @return [String]
|
@@ -17,6 +18,11 @@ module Solargraph
|
|
17
18
|
@range = range
|
18
19
|
end
|
19
20
|
|
21
|
+
# @param location [self]
|
22
|
+
def contain? location
|
23
|
+
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|
24
|
+
end
|
25
|
+
|
20
26
|
# @return [Hash]
|
21
27
|
def to_hash
|
22
28
|
{
|
@@ -25,6 +31,13 @@ module Solargraph
|
|
25
31
|
}
|
26
32
|
end
|
27
33
|
|
34
|
+
# @param node [Parser::AST::Node, nil]
|
35
|
+
def self.from_node(node)
|
36
|
+
return nil if node.nil? || node.loc.nil?
|
37
|
+
range = Range.from_node(node)
|
38
|
+
self.new(node.loc.expression.source_buffer.name, range)
|
39
|
+
end
|
40
|
+
|
28
41
|
# @param other [BasicObject]
|
29
42
|
def == other
|
30
43
|
return false unless other.is_a?(Location)
|
@@ -89,15 +89,21 @@ module Solargraph
|
|
89
89
|
elsif n.type == :const
|
90
90
|
const = unpack_name(n)
|
91
91
|
result.push Chain::Constant.new(const)
|
92
|
-
elsif [:
|
92
|
+
elsif [:lvasgn, :ivasgn, :gvasgn, :cvasgn].include?(n.type)
|
93
|
+
result.concat generate_links(n.children[1])
|
94
|
+
elsif n.type == :lvar
|
93
95
|
result.push Chain::Call.new(n.children[0].to_s)
|
94
|
-
elsif
|
95
|
-
|
96
|
-
elsif
|
97
|
-
|
98
|
-
elsif
|
99
|
-
|
96
|
+
elsif n.type == :ivar
|
97
|
+
result.push Chain::InstanceVariable.new(n.children[0].to_s)
|
98
|
+
elsif n.type == :cvar
|
99
|
+
result.push Chain::ClassVariable.new(n.children[0].to_s)
|
100
|
+
elsif n.type == :gvar
|
101
|
+
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
100
102
|
elsif n.type == :or_asgn
|
103
|
+
# @todo: Need a new Link class here that evaluates the
|
104
|
+
# existing variable type with the RHS, and generates a
|
105
|
+
# union type of the LHS alone if never nil, or minus nil +
|
106
|
+
# RHS if it is nilable.
|
101
107
|
result.concat generate_links n.children[1]
|
102
108
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
103
109
|
# @todo Undefined or what?
|
@@ -311,7 +311,7 @@ module Solargraph
|
|
311
311
|
# statements in value positions.
|
312
312
|
module DeepInference
|
313
313
|
class << self
|
314
|
-
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless
|
314
|
+
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
|
315
315
|
CONDITIONAL_ALL = [:or]
|
316
316
|
ONLY_ONE_CHILD = [:return]
|
317
317
|
FIRST_TWO_CHILDREN = [:rescue]
|
@@ -6,22 +6,25 @@ module Solargraph
|
|
6
6
|
module NodeProcessors
|
7
7
|
class ArgsNode < Parser::NodeProcessor::Base
|
8
8
|
def process
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
callable = region.closure
|
10
|
+
if callable.is_a? Pin::Callable
|
11
|
+
if node.type == :forward_args
|
12
|
+
forward(callable)
|
13
|
+
else
|
14
|
+
node.children.each do |u|
|
15
|
+
loc = get_node_location(u)
|
16
|
+
locals.push Solargraph::Pin::Parameter.new(
|
17
|
+
location: loc,
|
18
|
+
closure: callable,
|
19
|
+
comments: comments_for(node),
|
20
|
+
name: u.children[0].to_s,
|
21
|
+
assignment: u.children[1],
|
22
|
+
asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
|
23
|
+
presence: callable.location.range,
|
24
|
+
decl: get_decl(u)
|
25
|
+
)
|
26
|
+
callable.parameters.push locals.last
|
27
|
+
end
|
25
28
|
end
|
26
29
|
end
|
27
30
|
process_children
|
@@ -29,16 +32,17 @@ module Solargraph
|
|
29
32
|
|
30
33
|
private
|
31
34
|
|
35
|
+
# @param callable [Pin::Callable]
|
32
36
|
# @return [void]
|
33
|
-
def forward
|
37
|
+
def forward(callable)
|
34
38
|
loc = get_node_location(node)
|
35
39
|
locals.push Solargraph::Pin::Parameter.new(
|
36
40
|
location: loc,
|
37
|
-
closure:
|
41
|
+
closure: callable,
|
38
42
|
presence: region.closure.location.range,
|
39
43
|
decl: get_decl(node)
|
40
44
|
)
|
41
|
-
|
45
|
+
callable.parameters.push locals.last
|
42
46
|
end
|
43
47
|
|
44
48
|
# @param node [AST::Node]
|
@@ -8,8 +8,8 @@ module Solargraph
|
|
8
8
|
include ParserGem::NodeMethods
|
9
9
|
|
10
10
|
def process
|
11
|
-
|
12
|
-
presence = Range.new(
|
11
|
+
# variable not visible until next statement
|
12
|
+
presence = Range.new(get_node_end_position(node), region.closure.location.range.ending)
|
13
13
|
loc = get_node_location(node)
|
14
14
|
locals.push Solargraph::Pin::LocalVariable.new(
|
15
15
|
location: loc,
|
@@ -30,11 +30,17 @@ module Solargraph
|
|
30
30
|
|
31
31
|
lhs_arr.each_with_index do |lhs, i|
|
32
32
|
location = get_node_location(lhs)
|
33
|
+
pin = if lhs.type == :lvasgn
|
34
|
+
# lvasgn is a local variable
|
35
|
+
locals.find { |l| l.location == location }
|
36
|
+
else
|
37
|
+
# e.g., ivasgn is an instance variable, etc
|
38
|
+
pins.find { |iv| iv.location == location && iv.is_a?(Pin::BaseVariable) }
|
39
|
+
end
|
33
40
|
# @todo in line below, nothing in typechecking alerts
|
34
41
|
# when a non-existant method is called on 'l'
|
35
|
-
pin = locals.find { |l| l.location == location }
|
36
42
|
if pin.nil?
|
37
|
-
Solargraph.logger.debug "Could not find
|
43
|
+
Solargraph.logger.debug { "Could not find local for masgn= value in location #{location.inspect} in #{lhs_arr} - masgn = #{masgn}, lhs.type = #{lhs.type}" }
|
38
44
|
next
|
39
45
|
end
|
40
46
|
pin.mass_assignment = [mass_rhs, i]
|
@@ -92,7 +92,7 @@ module Solargraph
|
|
92
92
|
pins.push method_pin
|
93
93
|
method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
94
94
|
if method_pin.return_type.defined?
|
95
|
-
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.
|
95
|
+
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.items.map(&:rooted_tags), 'value')
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
data/lib/solargraph/parser.rb
CHANGED
@@ -9,15 +9,12 @@ module Solargraph
|
|
9
9
|
class SyntaxError < StandardError
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.rubyvm?
|
13
|
-
false
|
14
|
-
end
|
15
|
-
|
16
12
|
# @deprecated
|
17
13
|
Legacy = ParserGem
|
18
14
|
|
19
15
|
ClassMethods = ParserGem::ClassMethods
|
20
|
-
|
16
|
+
# @todo should be able to just 'extend ClassMethods' here and
|
17
|
+
# typecheck things off it in strict mode
|
21
18
|
extend ParserGem::ClassMethods
|
22
19
|
|
23
20
|
NodeMethods = ParserGem::NodeMethods
|
data/lib/solargraph/pin/base.rb
CHANGED
@@ -15,6 +15,9 @@ module Solargraph
|
|
15
15
|
# @return [Solargraph::Location]
|
16
16
|
attr_reader :location
|
17
17
|
|
18
|
+
# @return [Solargraph::Location]
|
19
|
+
attr_reader :type_location
|
20
|
+
|
18
21
|
# @return [String]
|
19
22
|
attr_reader :name
|
20
23
|
|
@@ -25,11 +28,13 @@ module Solargraph
|
|
25
28
|
attr_accessor :source
|
26
29
|
|
27
30
|
# @param location [Solargraph::Location, nil]
|
31
|
+
# @param type_location [Solargraph::Location, nil]
|
28
32
|
# @param closure [Solargraph::Pin::Closure, nil]
|
29
33
|
# @param name [String]
|
30
34
|
# @param comments [String]
|
31
|
-
def initialize location: nil, closure: nil, name: '', comments: ''
|
35
|
+
def initialize location: nil, type_location: nil, closure: nil, name: '', comments: ''
|
32
36
|
@location = location
|
37
|
+
@type_location = type_location
|
33
38
|
@closure = closure
|
34
39
|
@name = name
|
35
40
|
@comments = comments
|
@@ -66,8 +71,11 @@ module Solargraph
|
|
66
71
|
# @param context_type [ComplexType] The receiver type
|
67
72
|
# @return [self]
|
68
73
|
def resolve_generics definitions, context_type
|
69
|
-
|
70
|
-
|
74
|
+
transform_types { |t| t.resolve_generics(definitions, context_type) if t }
|
75
|
+
end
|
76
|
+
|
77
|
+
def all_rooted?
|
78
|
+
!return_type || return_type.all_rooted?
|
71
79
|
end
|
72
80
|
|
73
81
|
# @param generics_to_erase [Enumerable<String>]
|
@@ -102,6 +110,11 @@ module Solargraph
|
|
102
110
|
false
|
103
111
|
end
|
104
112
|
|
113
|
+
# @return [Location, nil]
|
114
|
+
def best_location
|
115
|
+
location || type_location
|
116
|
+
end
|
117
|
+
|
105
118
|
# Pin equality is determined using the #nearly? method and also
|
106
119
|
# requiring both pins to have the same location.
|
107
120
|
#
|
@@ -57,7 +57,7 @@ module Solargraph
|
|
57
57
|
# Use the return node for inference. The clip might infer from the
|
58
58
|
# first node in a method call instead of the entire call.
|
59
59
|
chain = Parser.chain(node, nil, nil)
|
60
|
-
result = chain.infer(api_map, closure, clip.locals).
|
60
|
+
result = chain.infer(api_map, closure, clip.locals).self_to_type(closure.context)
|
61
61
|
types.push result unless result.undefined?
|
62
62
|
end
|
63
63
|
end
|