solargraph 0.16.0 → 0.17.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.
- checksums.yaml +4 -4
- data/.yardopts +2 -0
- data/lib/solargraph/api_map/source.rb +24 -7
- data/lib/solargraph/api_map/source_to_yard.rb +1 -0
- data/lib/solargraph/api_map.rb +204 -73
- data/lib/solargraph/code_map.rb +130 -125
- data/lib/solargraph/core_fills.rb +23 -0
- data/lib/solargraph/live_map.rb +0 -19
- data/lib/solargraph/pin/base.rb +1 -1
- data/lib/solargraph/pin/base_variable.rb +6 -2
- data/lib/solargraph/pin/method.rb +1 -1
- data/lib/solargraph/plugin/process.rb +1 -0
- data/lib/solargraph/server.rb +69 -30
- data/lib/solargraph/shell.rb +1 -1
- data/lib/solargraph/suggestion.rb +7 -3
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map/core_docs.rb +1 -1
- data/lib/solargraph/yard_map.rb +71 -20
- data/lib/solargraph.rb +1 -1
- data/lib/yard-solargraph.rb +3 -1
- metadata +4 -3
- data/lib/solargraph/snippets.rb +0 -186
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0eee03f14aa3abbcaad7015b94ad8c33df50acc
|
4
|
+
data.tar.gz: b4485de9e9cf36aa8df184687cd9e5476e6b627d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3845660c58589e9d5222d9800fb3a48aa3970aa548468f643363d653b28b6b086c2d3b5c7d38afb322e6f45271292096acec3af7be24088d726957de7cbcbd1b
|
7
|
+
data.tar.gz: 3040f8716959d1378a2478dd23d76c8232f0451669860267f5cbb07b7be6ed2bda987039912d6501665e3cf7d3af6ff1d9e71e01792cdca949bfdf45c09f42b6
|
data/.yardopts
ADDED
@@ -20,6 +20,10 @@ module Solargraph
|
|
20
20
|
# @return [Array<Integer>]
|
21
21
|
attr_reader :stubbed_lines
|
22
22
|
|
23
|
+
attr_reader :directives
|
24
|
+
|
25
|
+
attr_reader :path_macros
|
26
|
+
|
23
27
|
include NodeMethods
|
24
28
|
|
25
29
|
def initialize code, node, comments, filename, stubbed_lines = []
|
@@ -29,6 +33,7 @@ module Solargraph
|
|
29
33
|
@node = root
|
30
34
|
@comments = comments
|
31
35
|
@directives = {}
|
36
|
+
@path_macros = {}
|
32
37
|
@docstring_hash = associate_comments(node, comments)
|
33
38
|
@filename = filename
|
34
39
|
@mtime = (!filename.nil? and File.exist?(filename) ? File.mtime(filename) : nil)
|
@@ -54,6 +59,10 @@ module Solargraph
|
|
54
59
|
gen_src = Source.virtual("def #{d.tag.name};end", filename)
|
55
60
|
gen_pin = gen_src.method_pins.first
|
56
61
|
method_pins.push Solargraph::Pin::Directed::Method.new(gen_src, gen_pin.node, ns, :instance, :public, docstring, gen_pin.name)
|
62
|
+
elsif d.tag.tag_name == 'macro'
|
63
|
+
# @todo Handle various types of macros (attach, new, whatever)
|
64
|
+
path = path_for(k.node)
|
65
|
+
@path_macros[path] = v
|
57
66
|
else
|
58
67
|
STDERR.puts "Nothing to do for directive: #{d}"
|
59
68
|
end
|
@@ -61,6 +70,10 @@ module Solargraph
|
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
73
|
+
def macro path
|
74
|
+
@path_macros[path]
|
75
|
+
end
|
76
|
+
|
64
77
|
def namespaces
|
65
78
|
@namespace_nodes.keys
|
66
79
|
end
|
@@ -160,6 +173,15 @@ module Solargraph
|
|
160
173
|
parts.join('::')
|
161
174
|
end
|
162
175
|
|
176
|
+
def path_for node
|
177
|
+
path = namespace_for(node) || ''
|
178
|
+
mp = (method_pins + attribute_pins).select{|p| p.node == node}.first
|
179
|
+
unless mp.nil?
|
180
|
+
path += (mp.scope == :instance ? '#' : '.') + mp.name
|
181
|
+
end
|
182
|
+
path
|
183
|
+
end
|
184
|
+
|
163
185
|
def include? node
|
164
186
|
@all_nodes.include? node
|
165
187
|
end
|
@@ -394,11 +416,6 @@ module Solargraph
|
|
394
416
|
stubs = []
|
395
417
|
fixed_position = false
|
396
418
|
tmp = code
|
397
|
-
if !offset.nil? and offset > 0
|
398
|
-
if tmp[offset - 1] == '.'
|
399
|
-
tmp = tmp[0..offset-2] + '_' + tmp[offset..-1]
|
400
|
-
end
|
401
|
-
end
|
402
419
|
begin
|
403
420
|
node, comments = Parser::CurrentRuby.parse_with_comments(tmp)
|
404
421
|
Source.new(code, node, comments, filename, stubs)
|
@@ -407,11 +424,11 @@ module Solargraph
|
|
407
424
|
tries += 1
|
408
425
|
# Stub periods before the offset to retain the expected node tree
|
409
426
|
if !offset.nil? and tmp[offset-1] == '.'
|
410
|
-
tmp = tmp[0, offset-1] + '
|
427
|
+
tmp = tmp[0, offset-1] + ';' + tmp[offset..-1]
|
411
428
|
elsif !fixed_position and !offset.nil?
|
412
429
|
fixed_position = true
|
413
430
|
beg = beginning_of_line_from(tmp, offset)
|
414
|
-
tmp = tmp[0, beg]
|
431
|
+
tmp = "#{tmp[0, beg]}##{tmp[beg+1..-1]}"
|
415
432
|
stubs.push(pos[0])
|
416
433
|
elsif e.message.include?('token $end')
|
417
434
|
tmp += "\nend"
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -11,20 +11,9 @@ module Solargraph
|
|
11
11
|
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
12
12
|
@@source_cache = {}
|
13
13
|
|
14
|
-
KEYWORDS = [
|
15
|
-
'__ENCODING__', '__LINE__', '__FILE__', 'BEGIN', 'END', 'alias', 'and',
|
16
|
-
'begin', 'break', 'case', 'class', 'def', 'defined?', 'do', 'else',
|
17
|
-
'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in', 'module', 'next',
|
18
|
-
'nil', 'not', 'or', 'redo', 'rescue', 'retry', 'return', 'self', 'super',
|
19
|
-
'then', 'true', 'undef', 'unless', 'until', 'when', 'while', 'yield'
|
20
|
-
].freeze
|
21
|
-
|
22
|
-
METHODS_RETURNING_SELF = [
|
23
|
-
'clone', 'dup', 'freeze', 'taint', 'untaint'
|
24
|
-
].freeze
|
25
|
-
|
26
14
|
include NodeMethods
|
27
15
|
include Solargraph::ApiMap::SourceToYard
|
16
|
+
include CoreFills
|
28
17
|
|
29
18
|
# The root directory of the project. The ApiMap will search here for
|
30
19
|
# additional files to parse and analyze.
|
@@ -58,6 +47,10 @@ module Solargraph
|
|
58
47
|
yard_map
|
59
48
|
end
|
60
49
|
|
50
|
+
# Get the configuration for the ApiMap's workspace. This method will
|
51
|
+
# initialize the settings from the workspace's root .solargraph.yml file
|
52
|
+
# if it exists.
|
53
|
+
#
|
61
54
|
# @return [Solargraph::ApiMap::Config]
|
62
55
|
def config reload = false
|
63
56
|
@config = ApiMap::Config.new(@workspace) if @config.nil? or reload
|
@@ -78,6 +71,8 @@ module Solargraph
|
|
78
71
|
@required ||= []
|
79
72
|
end
|
80
73
|
|
74
|
+
# Get a YardMap associated with the current namespace.
|
75
|
+
#
|
81
76
|
# @return [Solargraph::YardMap]
|
82
77
|
def yard_map
|
83
78
|
refresh
|
@@ -87,6 +82,8 @@ module Solargraph
|
|
87
82
|
@yard_map
|
88
83
|
end
|
89
84
|
|
85
|
+
# Get a LiveMap associated with the current namespace.
|
86
|
+
#
|
90
87
|
# @return [Solargraph::LiveMap]
|
91
88
|
def live_map
|
92
89
|
@live_map ||= Solargraph::LiveMap.new(self)
|
@@ -130,19 +127,24 @@ module Solargraph
|
|
130
127
|
virtualize code, filename
|
131
128
|
end
|
132
129
|
|
130
|
+
# Refresh the ApiMap.
|
131
|
+
#
|
132
|
+
# @param force [Boolean] Perform a refresh even if the map is not "stale."
|
133
133
|
def refresh force = false
|
134
134
|
process_maps if @stale or force
|
135
135
|
end
|
136
136
|
|
137
|
+
# True if a workspace file has been created, modified, or deleted since
|
138
|
+
# the last time the map was processed.
|
139
|
+
#
|
140
|
+
# @return [Boolean]
|
137
141
|
def changed?
|
138
142
|
current = config.calculated
|
139
143
|
unless (Set.new(current) ^ workspace_files).empty?
|
140
|
-
STDERR.puts "Change based on difference in file list"
|
141
144
|
return true
|
142
145
|
end
|
143
146
|
current.each do |f|
|
144
147
|
if !File.exist?(f) or File.mtime(f) != source_file_mtime(f)
|
145
|
-
STDERR.puts "Change based on file #{f}"
|
146
148
|
return true
|
147
149
|
end
|
148
150
|
end
|
@@ -159,39 +161,48 @@ module Solargraph
|
|
159
161
|
@sources[filename].docstring_for(node)
|
160
162
|
end
|
161
163
|
|
162
|
-
#
|
163
|
-
|
164
|
-
get_docstring_for node
|
165
|
-
end
|
166
|
-
|
164
|
+
# An array of suggestions based on Ruby keywords (`if`, `end`, etc.).
|
165
|
+
#
|
167
166
|
# @return [Array<Solargraph::Suggestion>]
|
168
|
-
def self.
|
167
|
+
def self.keywords
|
169
168
|
@keyword_suggestions ||= KEYWORDS.map{ |s|
|
170
169
|
Suggestion.new(s.to_s, kind: Suggestion::KEYWORD, detail: 'Keyword')
|
171
170
|
}.freeze
|
172
171
|
end
|
173
172
|
|
173
|
+
# An array of namespace names defined in the ApiMap.
|
174
|
+
#
|
174
175
|
# @return [Array<String>]
|
175
176
|
def namespaces
|
176
177
|
refresh
|
177
178
|
namespace_map.keys
|
178
179
|
end
|
179
180
|
|
181
|
+
# True if the namespace exists.
|
182
|
+
#
|
183
|
+
# @param name [String] The namespace to match
|
184
|
+
# @param root [String] The context to search
|
185
|
+
# @return [Boolean]
|
180
186
|
def namespace_exists? name, root = ''
|
181
187
|
!find_fully_qualified_namespace(name, root).nil?
|
182
188
|
end
|
183
189
|
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
190
|
+
# Get an array of constant pins defined in the ApiMap. (This method does
|
191
|
+
# not include constants from external gems or the Ruby core.)
|
192
|
+
#
|
193
|
+
# @param namespace [String] The namespace to match
|
194
|
+
# @param root [String] The context to search
|
189
195
|
# @return [Array<Solargraph::Pin::Constant>]
|
190
196
|
def get_constant_pins namespace, root
|
191
197
|
fqns = find_fully_qualified_namespace(namespace, root)
|
192
198
|
@const_pins[fqns] || []
|
193
199
|
end
|
194
200
|
|
201
|
+
# Get suggestions for constants in the specified namespace. The result
|
202
|
+
# will include constant variables, classes, and modules.
|
203
|
+
#
|
204
|
+
# @param namespace [String] The namespace to match
|
205
|
+
# @param root [String] The context to search
|
195
206
|
# @return [Array<Solargraph::Suggestion>]
|
196
207
|
def get_constants namespace, root = ''
|
197
208
|
result = []
|
@@ -212,17 +223,11 @@ module Solargraph
|
|
212
223
|
result
|
213
224
|
end
|
214
225
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
set = @namespace_pins['']
|
221
|
-
end
|
222
|
-
return [] if set.nil?
|
223
|
-
set.select{|p| p.path == fqns}
|
224
|
-
end
|
225
|
-
|
226
|
+
# Get a fully qualified namespace name. This method will start the search
|
227
|
+
# in the specified root until it finds a match for the name.
|
228
|
+
#
|
229
|
+
# @param name [String] The namespace to match
|
230
|
+
# @param root [String] The context to search
|
226
231
|
# @return [String]
|
227
232
|
def find_fully_qualified_namespace name, root = '', skip = []
|
228
233
|
refresh
|
@@ -263,18 +268,22 @@ module Solargraph
|
|
263
268
|
result
|
264
269
|
end
|
265
270
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
271
|
+
# Get an array of instance variable pins defined in specified namespace
|
272
|
+
# and scope.
|
273
|
+
#
|
274
|
+
# @param namespace [String] A fully qualified namespace
|
275
|
+
# @param scope [Symbol] :instance or :class
|
272
276
|
# @return [Array<Solargraph::Pin::InstanceVariable>]
|
273
277
|
def get_instance_variable_pins(namespace, scope = :instance)
|
274
278
|
refresh
|
275
279
|
(@ivar_pins[namespace] || []).select{ |pin| pin.scope == scope }
|
276
280
|
end
|
277
281
|
|
282
|
+
# Get an array of instance variable suggestions defined in specified
|
283
|
+
# namespace and scope.
|
284
|
+
#
|
285
|
+
# @param namespace [String] A fully qualified namespace
|
286
|
+
# @param scope [Symbol] :instance or :class
|
278
287
|
# @return [Array<Solargraph::Suggestion>]
|
279
288
|
def get_instance_variables(namespace, scope = :instance)
|
280
289
|
refresh
|
@@ -332,7 +341,13 @@ module Solargraph
|
|
332
341
|
return nil if pins.nil?
|
333
342
|
pin = pins.select{|p| p.name == var and p.scope == scope}.first
|
334
343
|
return nil if pin.nil?
|
335
|
-
pin.return_type
|
344
|
+
type = pin.return_type
|
345
|
+
if type.nil?
|
346
|
+
zparts = resolve_node_signature(pin.assignment_node).split('.')
|
347
|
+
ztype = infer_signature_type(zparts[0..-2].join('.'), namespace, scope: :instance, call_node: pin.assignment_node)
|
348
|
+
type = get_return_type_from_macro(ztype, zparts[-1], pin.assignment_node, :instance, [:public, :private, :protected])
|
349
|
+
end
|
350
|
+
type
|
336
351
|
end
|
337
352
|
|
338
353
|
# @return [String]
|
@@ -366,6 +381,8 @@ module Solargraph
|
|
366
381
|
|
367
382
|
# @return [String]
|
368
383
|
def infer_assignment_node_type node, namespace
|
384
|
+
cached = cache.get_assignment_node_type(node, namespace)
|
385
|
+
return cached unless cached.nil?
|
369
386
|
name_i = (node.type == :casgn ? 1 : 0)
|
370
387
|
sig_i = (node.type == :casgn ? 2 : 1)
|
371
388
|
type = infer_literal_node_type(node.children[sig_i])
|
@@ -373,13 +390,32 @@ module Solargraph
|
|
373
390
|
sig = resolve_node_signature(node.children[sig_i])
|
374
391
|
# Avoid infinite loops from variable assignments that reference themselves
|
375
392
|
return nil if node.children[name_i].to_s == sig.split('.').first
|
376
|
-
type = infer_signature_type(sig, namespace)
|
393
|
+
type = infer_signature_type(sig, namespace, call_node: node.children[sig_i])
|
377
394
|
end
|
395
|
+
cache.set_assignment_node_type(node, namespace, type)
|
378
396
|
type
|
379
397
|
end
|
380
398
|
|
399
|
+
def get_call_arguments node
|
400
|
+
return [] unless node.type == :send
|
401
|
+
result = []
|
402
|
+
node.children[2..-1].each do |c|
|
403
|
+
result.push unpack_name(c)
|
404
|
+
end
|
405
|
+
result
|
406
|
+
end
|
407
|
+
|
408
|
+
# Get the return type for a signature within the specified namespace and
|
409
|
+
# scope.
|
410
|
+
#
|
411
|
+
# @example
|
412
|
+
# api_map.infer_signature_type('String.new', '') #=> 'String'
|
413
|
+
#
|
414
|
+
# @param signature [String]
|
415
|
+
# @param namespace [String] A fully qualified namespace
|
416
|
+
# @param scope [Symbol] :class or :instance
|
381
417
|
# @return [String]
|
382
|
-
def infer_signature_type signature, namespace, scope: :class
|
418
|
+
def infer_signature_type signature, namespace, scope: :class, call_node: nil
|
383
419
|
namespace ||= ''
|
384
420
|
if cache.has_signature_type?(signature, namespace, scope)
|
385
421
|
return cache.get_signature_type(signature, namespace, scope)
|
@@ -396,20 +432,20 @@ module Solargraph
|
|
396
432
|
end
|
397
433
|
result = nil
|
398
434
|
if namespace.end_with?('#class')
|
399
|
-
result = infer_signature_type signature, namespace[0..-7], scope: (scope == :class ? :instance : :class)
|
435
|
+
result = infer_signature_type signature, namespace[0..-7], scope: (scope == :class ? :instance : :class), call_node: call_node
|
400
436
|
else
|
401
437
|
parts = signature.split('.', 2)
|
402
438
|
if parts[0].start_with?('@@')
|
403
439
|
type = infer_class_variable(parts[0], namespace)
|
404
440
|
if type.nil? or parts.empty?
|
405
|
-
result = inner_infer_signature_type(parts[1], type, scope: :instance)
|
441
|
+
result = inner_infer_signature_type(parts[1], type, scope: :instance, call_node: call_node)
|
406
442
|
else
|
407
443
|
result = type
|
408
444
|
end
|
409
445
|
elsif parts[0].start_with?('@')
|
410
446
|
type = infer_instance_variable(parts[0], namespace, scope)
|
411
447
|
if type.nil? or parts.empty?
|
412
|
-
result = inner_infer_signature_type(parts[1], type, scope: :instance)
|
448
|
+
result = inner_infer_signature_type(parts[1], type, scope: :instance, call_node: call_node)
|
413
449
|
else
|
414
450
|
result = type
|
415
451
|
end
|
@@ -417,21 +453,29 @@ module Solargraph
|
|
417
453
|
type = find_fully_qualified_namespace(parts[0], namespace)
|
418
454
|
if type.nil?
|
419
455
|
# It's a method call
|
420
|
-
type = inner_infer_signature_type(parts[0], namespace, scope: scope)
|
421
|
-
if parts
|
456
|
+
type = inner_infer_signature_type(parts[0], namespace, scope: scope, call_node: call_node)
|
457
|
+
if parts.length < 2
|
458
|
+
if type.nil? and !parts.length.nil?
|
459
|
+
path = "#{clean_namespace_string(namespace)}#{scope == :class ? '.' : '#'}#{parts[0]}"
|
460
|
+
subtypes = get_subtypes(namespace)
|
461
|
+
type = subtypes[0] if METHODS_RETURNING_SUBTYPES.include?(path)
|
462
|
+
end
|
422
463
|
result = type
|
423
464
|
else
|
424
|
-
result = inner_infer_signature_type(parts[1], type, scope: :instance)
|
465
|
+
result = inner_infer_signature_type(parts[1], type, scope: :instance, call_node: call_node)
|
425
466
|
end
|
426
467
|
else
|
427
|
-
result = inner_infer_signature_type(parts[1], type, scope: :class)
|
468
|
+
result = inner_infer_signature_type(parts[1], type, scope: :class, call_node: call_node)
|
428
469
|
end
|
470
|
+
result = type if result == 'self'
|
429
471
|
end
|
430
472
|
end
|
431
473
|
cache.set_signature_type signature, namespace, scope, result
|
432
474
|
result
|
433
475
|
end
|
434
476
|
|
477
|
+
# Get the namespace's type (Class or Module).
|
478
|
+
#
|
435
479
|
# @param [String] A fully qualified namespace
|
436
480
|
# @return [Symbol] :class, :module, or nil
|
437
481
|
def get_namespace_type fqns
|
@@ -499,9 +543,7 @@ module Solargraph
|
|
499
543
|
def get_instance_methods(namespace, root = '', visibility: [:public])
|
500
544
|
refresh
|
501
545
|
namespace = clean_namespace_string(namespace)
|
502
|
-
if namespace.end_with?('#class')
|
503
|
-
return get_methods(namespace.split('#').first, root, visibility: visibility)
|
504
|
-
elsif namespace.end_with?('#module')
|
546
|
+
if namespace.end_with?('#class') or namespace.end_with?('#module')
|
505
547
|
return get_methods(namespace.split('#').first, root, visibility: visibility)
|
506
548
|
end
|
507
549
|
meths = []
|
@@ -531,21 +573,9 @@ module Solargraph
|
|
531
573
|
meths
|
532
574
|
end
|
533
575
|
|
534
|
-
# @return [Array<String>]
|
535
|
-
def get_include_strings_from *nodes
|
536
|
-
arr = []
|
537
|
-
nodes.each { |node|
|
538
|
-
next unless node.kind_of?(AST::Node)
|
539
|
-
arr.push unpack_name(node.children[2]) if (node.type == :send and node.children[1] == :include)
|
540
|
-
node.children.each { |n|
|
541
|
-
arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module and n.type != :sclass
|
542
|
-
}
|
543
|
-
}
|
544
|
-
arr
|
545
|
-
end
|
546
|
-
|
547
576
|
# Update the ApiMap with the most recent version of the specified file.
|
548
577
|
#
|
578
|
+
# @param filename [String]
|
549
579
|
def update filename
|
550
580
|
filename.gsub!(/\\/, '/')
|
551
581
|
if filename.end_with?('.rb')
|
@@ -570,11 +600,16 @@ module Solargraph
|
|
570
600
|
end
|
571
601
|
end
|
572
602
|
|
603
|
+
# All sources generated from workspace files.
|
604
|
+
#
|
573
605
|
# @return [Array<Solargraph::ApiMap::Source>]
|
574
606
|
def sources
|
575
607
|
@sources.values
|
576
608
|
end
|
577
609
|
|
610
|
+
# Get an array of all suggestions that match the specified path.
|
611
|
+
#
|
612
|
+
# @param path [String] The path to find
|
578
613
|
# @return [Array<Solargraph::Suggestion>]
|
579
614
|
def get_path_suggestions path
|
580
615
|
refresh
|
@@ -599,6 +634,12 @@ module Solargraph
|
|
599
634
|
result
|
600
635
|
end
|
601
636
|
|
637
|
+
# Get a list of documented paths that match the query.
|
638
|
+
#
|
639
|
+
# @example
|
640
|
+
# api_map.query('str') # Results will include `String` and `Struct`
|
641
|
+
#
|
642
|
+
# @param query [String] The text to match
|
602
643
|
# @return [Array<String>]
|
603
644
|
def search query
|
604
645
|
refresh
|
@@ -613,6 +654,12 @@ module Solargraph
|
|
613
654
|
found.concat(yard_map.search(query)).uniq.sort
|
614
655
|
end
|
615
656
|
|
657
|
+
# Get YARD documentation for the specified path.
|
658
|
+
#
|
659
|
+
# @example
|
660
|
+
# api_map.document('String#split')
|
661
|
+
#
|
662
|
+
# @param path [String] The path to find
|
616
663
|
# @return [Array<YARD::CodeObject::Base>]
|
617
664
|
def document path
|
618
665
|
refresh
|
@@ -634,6 +681,7 @@ module Solargraph
|
|
634
681
|
def clear
|
635
682
|
@stale = false
|
636
683
|
namespace_map.clear
|
684
|
+
path_macros.clear
|
637
685
|
@required = config.required.clone
|
638
686
|
end
|
639
687
|
|
@@ -756,6 +804,7 @@ module Solargraph
|
|
756
804
|
@namespace_pins[pin.namespace] ||= []
|
757
805
|
@namespace_pins[pin.namespace].push pin
|
758
806
|
end
|
807
|
+
path_macros.merge! source.path_macros
|
759
808
|
source.required.each do |r|
|
760
809
|
required.push r
|
761
810
|
end
|
@@ -835,7 +884,7 @@ module Solargraph
|
|
835
884
|
#
|
836
885
|
# @return [String] The fully qualified namespace for the signature's type
|
837
886
|
# or nil if a type could not be determined
|
838
|
-
def inner_infer_signature_type signature, namespace, scope: :instance, top: true
|
887
|
+
def inner_infer_signature_type signature, namespace, scope: :instance, top: true, call_node: nil
|
839
888
|
return nil if signature.nil?
|
840
889
|
signature.gsub!(/\.$/, '')
|
841
890
|
if signature.empty?
|
@@ -863,7 +912,8 @@ module Solargraph
|
|
863
912
|
end
|
864
913
|
if scope == :class and part == 'new'
|
865
914
|
scope = :instance
|
866
|
-
|
915
|
+
else
|
916
|
+
curtype = type
|
867
917
|
type = nil
|
868
918
|
visibility = [:public]
|
869
919
|
visibility.concat [:private, :protected] if top
|
@@ -873,9 +923,22 @@ module Solargraph
|
|
873
923
|
tmp = get_methods(namespace, visibility: visibility)
|
874
924
|
end
|
875
925
|
tmp.concat get_instance_methods('Kernel', visibility: [:public]) if top
|
876
|
-
|
877
|
-
return nil if
|
878
|
-
|
926
|
+
matches = tmp.select{|s| s.label == part}
|
927
|
+
return nil if matches.empty?
|
928
|
+
matches.each do |m|
|
929
|
+
type = get_return_type_from_macro(namespace, signature, call_node, scope, visibility)
|
930
|
+
if type.nil?
|
931
|
+
if METHODS_RETURNING_SELF.include?(m.path)
|
932
|
+
type = curtype
|
933
|
+
elsif METHODS_RETURNING_SUBTYPES.include?(m.path)
|
934
|
+
subtypes = get_subtypes(namespace)
|
935
|
+
type = subtypes[0]
|
936
|
+
else
|
937
|
+
type = m.return_type
|
938
|
+
end
|
939
|
+
end
|
940
|
+
break unless type.nil?
|
941
|
+
end
|
879
942
|
scope = :instance
|
880
943
|
end
|
881
944
|
top = false
|
@@ -985,5 +1048,73 @@ module Solargraph
|
|
985
1048
|
end
|
986
1049
|
nil
|
987
1050
|
end
|
1051
|
+
|
1052
|
+
# @return [Array<Solargraph::Pin::Namespace>]
|
1053
|
+
def find_namespace_pins fqns
|
1054
|
+
set = nil
|
1055
|
+
if fqns.include?('::')
|
1056
|
+
set = @namespace_pins[fqns.split('::')[0..-2].join('::')]
|
1057
|
+
else
|
1058
|
+
set = @namespace_pins['']
|
1059
|
+
end
|
1060
|
+
return [] if set.nil?
|
1061
|
+
set.select{|p| p.path == fqns}
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
def get_namespace_nodes(fqns)
|
1065
|
+
return file_nodes if fqns == '' or fqns.nil?
|
1066
|
+
refresh
|
1067
|
+
namespace_map[fqns] || []
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# @return [Array<String>]
|
1071
|
+
def get_include_strings_from *nodes
|
1072
|
+
arr = []
|
1073
|
+
nodes.each { |node|
|
1074
|
+
next unless node.kind_of?(AST::Node)
|
1075
|
+
arr.push unpack_name(node.children[2]) if (node.type == :send and node.children[1] == :include)
|
1076
|
+
node.children.each { |n|
|
1077
|
+
arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module and n.type != :sclass
|
1078
|
+
}
|
1079
|
+
}
|
1080
|
+
arr
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
# @todo DRY this method. It's duplicated in CodeMap
|
1084
|
+
def get_subtypes type
|
1085
|
+
return nil if type.nil?
|
1086
|
+
match = type.match(/<([a-z0-9_:, ]*)>/i)
|
1087
|
+
return [] if match.nil?
|
1088
|
+
match[1].split(',').map(&:strip)
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# @return [Hash]
|
1092
|
+
def path_macros
|
1093
|
+
@path_macros ||= {}
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
def get_return_type_from_macro namespace, signature, call_node, scope, visibility
|
1097
|
+
return nil if signature.empty? or signature.include?('.') or call_node.nil?
|
1098
|
+
path = "#{namespace}#{scope == :class ? '.' : '#'}#{signature}"
|
1099
|
+
macmeth = get_path_suggestions(path).first
|
1100
|
+
type = nil
|
1101
|
+
unless macmeth.nil?
|
1102
|
+
macro = path_macros[macmeth.path]
|
1103
|
+
macro = macro.first unless macro.nil?
|
1104
|
+
if macro.nil? and !macmeth.code_object.nil? and !macmeth.code_object.base_docstring.nil? and macmeth.code_object.base_docstring.all.include?('@!macro')
|
1105
|
+
all = YARD::Docstring.parser.parse(macmeth.code_object.base_docstring.all).directives
|
1106
|
+
macro = all.select{|m| m.tag.tag_name == 'macro'}.first
|
1107
|
+
end
|
1108
|
+
unless macro.nil?
|
1109
|
+
docstring = YARD::Docstring.parser.parse(macro.tag.text).to_docstring
|
1110
|
+
rt = docstring.tag(:return)
|
1111
|
+
unless rt.nil? or rt.types.nil? or call_node.nil?
|
1112
|
+
args = get_call_arguments(call_node)
|
1113
|
+
type = "#{args[rt.types[0][1..-1].to_i-1]}"
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
end
|
1117
|
+
type
|
1118
|
+
end
|
988
1119
|
end
|
989
1120
|
end
|