solargraph 0.12.2 → 0.13.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/lib/solargraph.rb +1 -0
- data/lib/solargraph/api_map.rb +179 -431
- data/lib/solargraph/api_map/cache.rb +4 -0
- data/lib/solargraph/api_map/config.rb +1 -1
- data/lib/solargraph/api_map/source.rb +297 -0
- data/lib/solargraph/code_map.rb +81 -134
- data/lib/solargraph/pin.rb +12 -0
- data/lib/solargraph/pin/attribute.rb +16 -0
- data/lib/solargraph/pin/base.rb +47 -0
- data/lib/solargraph/pin/base_variable.rb +33 -0
- data/lib/solargraph/pin/class_variable.rb +6 -0
- data/lib/solargraph/pin/constant.rb +18 -0
- data/lib/solargraph/pin/instance_variable.rb +12 -0
- data/lib/solargraph/pin/method.rb +65 -0
- data/lib/solargraph/pin/symbol.rb +9 -0
- data/lib/solargraph/server.rb +15 -7
- data/lib/solargraph/shell.rb +7 -0
- data/lib/solargraph/suggestion.rb +7 -2
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map.rb +1 -1
- data/lib/solargraph/yard_methods.rb +28 -1
- metadata +12 -6
- data/lib/solargraph/api_map/attr_pin.rb +0 -37
- data/lib/solargraph/api_map/cvar_pin.rb +0 -27
- data/lib/solargraph/api_map/ivar_pin.rb +0 -29
- data/lib/solargraph/api_map/method_pin.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 031c6210f7be6462d12e8ce7dd5c25e30b6c097d
|
4
|
+
data.tar.gz: 422def5aafa30d23831434dafc5a69eb26d97e55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e597e62a01501ee615fcac8a194940e9d85ea69346eeb245104340deb9d2db69de1553facb00d9b6e1dc9c9c3b932c8b5f4cda4a00e43bd41be240548633f8f0
|
7
|
+
data.tar.gz: 6137318fc634b925cc99a86b77b0ca86ae8c7f1ca842f4a864f93b88531151e3a96adc596aeb99fa94cf10c09e690432284090981e3c70b56151e72772d7dd95
|
data/lib/solargraph.rb
CHANGED
@@ -14,6 +14,7 @@ module Solargraph
|
|
14
14
|
autoload :Server, 'solargraph/server'
|
15
15
|
autoload :YardMap, 'solargraph/yard_map'
|
16
16
|
autoload :YardMethods, 'solargraph/yard_methods'
|
17
|
+
autoload :Pin, 'solargraph/pin'
|
17
18
|
|
18
19
|
YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
|
19
20
|
YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -4,13 +4,11 @@ require 'thread'
|
|
4
4
|
|
5
5
|
module Solargraph
|
6
6
|
class ApiMap
|
7
|
-
autoload :Config,
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :AttrPin, 'solargraph/api_map/attr_pin'
|
11
|
-
autoload :IvarPin, 'solargraph/api_map/ivar_pin'
|
12
|
-
autoload :CvarPin, 'solargraph/api_map/cvar_pin'
|
7
|
+
autoload :Config, 'solargraph/api_map/config'
|
8
|
+
autoload :Source, 'solargraph/api_map/source'
|
9
|
+
autoload :Cache, 'solargraph/api_map/cache'
|
13
10
|
|
11
|
+
@@source_cache = {}
|
14
12
|
@@yard_map_cache = {}
|
15
13
|
@@semaphore = Mutex.new
|
16
14
|
|
@@ -22,17 +20,6 @@ module Solargraph
|
|
22
20
|
'then', 'true', 'undef', 'unless', 'until', 'when', 'while', 'yield'
|
23
21
|
].freeze
|
24
22
|
|
25
|
-
MAPPABLE_NODES = [
|
26
|
-
:array, :hash, :str, :dstr, :int, :float, :sym, :block, :class, :sclass,
|
27
|
-
:module, :def, :defs, :ivasgn, :gvasgn, :lvasgn, :cvasgn, :casgn,
|
28
|
-
:or_asgn, :const, :lvar, :args, :kwargs
|
29
|
-
].freeze
|
30
|
-
|
31
|
-
MAPPABLE_METHODS = [
|
32
|
-
:include, :extend, :require, :autoload, :attr_reader, :attr_writer,
|
33
|
-
:attr_accessor, :private, :public, :protected
|
34
|
-
].freeze
|
35
|
-
|
36
23
|
METHODS_RETURNING_SELF = [
|
37
24
|
'clone', 'dup', 'freeze', 'taint', 'untaint'
|
38
25
|
].freeze
|
@@ -40,6 +27,10 @@ module Solargraph
|
|
40
27
|
include NodeMethods
|
41
28
|
include YardMethods
|
42
29
|
|
30
|
+
# @todo Temp for testing
|
31
|
+
attr_reader :new_method_pins
|
32
|
+
attr_reader :new_ivar_pins
|
33
|
+
|
43
34
|
# The root directory of the project. The ApiMap will search here for
|
44
35
|
# additional files to parse and analyze.
|
45
36
|
#
|
@@ -53,61 +44,37 @@ module Solargraph
|
|
53
44
|
def initialize workspace = nil
|
54
45
|
@workspace = workspace.gsub(/\\/, '/') unless workspace.nil?
|
55
46
|
clear
|
47
|
+
@workspace_files = []
|
56
48
|
unless @workspace.nil?
|
57
49
|
config = ApiMap::Config.new(@workspace)
|
58
|
-
config.included
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
}
|
50
|
+
@workspace_files.concat (config.included - config.excluded)
|
51
|
+
@workspace_files.each do |wf|
|
52
|
+
@@source_cache[wf] ||= Source.load(wf)
|
53
|
+
end
|
63
54
|
end
|
55
|
+
@sources = {}
|
56
|
+
@virtual_source = nil
|
57
|
+
@virtual_filename = nil
|
58
|
+
@stale = false
|
59
|
+
@new_method_pins = []
|
60
|
+
@new_ivar_pins = []
|
64
61
|
end
|
65
62
|
|
66
63
|
# @return [Solargraph::YardMap]
|
67
64
|
def yard_map
|
68
65
|
@@semaphore.synchronize {
|
69
|
-
|
70
|
-
@@yard_map_cache[[required, workspace]] ||= @yard_map
|
66
|
+
@@yard_map_cache[[required, workspace]] ||= Solargraph::YardMap.new(required: required, workspace: workspace)
|
71
67
|
}
|
72
68
|
end
|
73
69
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def append_file filename
|
79
|
-
append_source File.read(filename), filename
|
80
|
-
end
|
81
|
-
|
82
|
-
# Add a string of source code to the map.
|
83
|
-
#
|
84
|
-
# @param text [String]
|
85
|
-
# @param filename [String]
|
86
|
-
# @return [AST::Node]
|
87
|
-
def append_source text, filename = nil
|
88
|
-
@file_source[filename] = text
|
89
|
-
begin
|
90
|
-
node, comments = Parser::CurrentRuby.parse_with_comments(text)
|
91
|
-
append_node(node, comments, filename)
|
92
|
-
rescue Parser::SyntaxError => e
|
93
|
-
STDERR.puts "Error parsing '#{filename}': #{e.message}"
|
94
|
-
nil
|
95
|
-
end
|
70
|
+
def virtualize filename, code, cursor = nil
|
71
|
+
@stale = true
|
72
|
+
@virtual_filename = filename
|
73
|
+
@virtual_source = Source.fix(filename, code, cursor)
|
96
74
|
end
|
97
75
|
|
98
|
-
|
99
|
-
|
100
|
-
# @return [AST::Node]
|
101
|
-
def append_node node, comments, filename = nil
|
102
|
-
@stale = true
|
103
|
-
@file_comments[filename] = associate_comments(node, comments)
|
104
|
-
mapified = reduce(node, @file_comments[filename])
|
105
|
-
root = AST::Node.new(:begin, [filename])
|
106
|
-
root = root.append mapified
|
107
|
-
@file_nodes[filename] = root
|
108
|
-
@required.uniq!
|
109
|
-
#process_maps
|
110
|
-
root
|
76
|
+
def append_source code, filename
|
77
|
+
virtualize filename, code
|
111
78
|
end
|
112
79
|
|
113
80
|
def refresh force = false
|
@@ -120,13 +87,13 @@ module Solargraph
|
|
120
87
|
# @return [YARD::Docstring]
|
121
88
|
def get_comment_for node
|
122
89
|
filename = get_filename_for(node)
|
123
|
-
return nil if @
|
124
|
-
@
|
90
|
+
return nil if @sources[filename].nil?
|
91
|
+
@sources[filename].docstring_for(node)
|
125
92
|
end
|
126
93
|
|
127
94
|
# @return [Array<Solargraph::Suggestion>]
|
128
95
|
def self.get_keywords
|
129
|
-
@keyword_suggestions ||=
|
96
|
+
@keyword_suggestions ||= KEYWORDS.map{ |s|
|
130
97
|
Suggestion.new(s.to_s, kind: Suggestion::KEYWORD, detail: 'Keyword')
|
131
98
|
}.freeze
|
132
99
|
end
|
@@ -145,16 +112,21 @@ module Solargraph
|
|
145
112
|
result = []
|
146
113
|
result += inner_namespaces_in(name, root, [])
|
147
114
|
result += yard_map.get_constants name, root
|
148
|
-
fqns = find_fully_qualified_namespace(name, root)
|
149
|
-
unless fqns.nil?
|
150
|
-
nodes = get_namespace_nodes(fqns)
|
151
|
-
get_include_strings_from(*nodes).each { |i|
|
152
|
-
result += yard_map.get_constants(i, root)
|
153
|
-
}
|
154
|
-
end
|
155
115
|
result
|
156
116
|
end
|
157
117
|
|
118
|
+
def get_constants namespace, root
|
119
|
+
result = []
|
120
|
+
fqns = find_fully_qualified_namespace(namespace, root)
|
121
|
+
cp = @const_pins[fqns]
|
122
|
+
unless cp.nil?
|
123
|
+
cp.each do |pin|
|
124
|
+
result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
result.concat yard_map.get_constants(namespace, root)
|
128
|
+
end
|
129
|
+
|
158
130
|
def find_fully_qualified_namespace name, root = '', skip = []
|
159
131
|
refresh
|
160
132
|
return nil if skip.include?(root)
|
@@ -168,7 +140,7 @@ module Solargraph
|
|
168
140
|
else
|
169
141
|
if (root == '')
|
170
142
|
return name unless @namespace_map[name].nil?
|
171
|
-
get_include_strings_from(
|
143
|
+
get_include_strings_from(*file_nodes).each { |i|
|
172
144
|
reroot = "#{root == '' ? '' : root + '::'}#{i}"
|
173
145
|
recname = find_fully_qualified_namespace name.to_s, reroot, skip
|
174
146
|
return recname unless recname.nil?
|
@@ -181,7 +153,7 @@ module Solargraph
|
|
181
153
|
roots.pop
|
182
154
|
end
|
183
155
|
return name unless @namespace_map[name].nil?
|
184
|
-
get_include_strings_from(
|
156
|
+
get_include_strings_from(*file_nodes).each { |i|
|
185
157
|
recname = find_fully_qualified_namespace name, i, skip
|
186
158
|
return recname unless recname.nil?
|
187
159
|
}
|
@@ -191,7 +163,7 @@ module Solargraph
|
|
191
163
|
end
|
192
164
|
|
193
165
|
def get_namespace_nodes(fqns)
|
194
|
-
return
|
166
|
+
return file_nodes if fqns == '' or fqns.nil?
|
195
167
|
refresh
|
196
168
|
@namespace_map[fqns] || []
|
197
169
|
end
|
@@ -202,7 +174,8 @@ module Solargraph
|
|
202
174
|
ip = @ivar_pins[namespace]
|
203
175
|
unless ip.nil?
|
204
176
|
ip.select{ |pin| pin.scope == scope }.each do |pin|
|
205
|
-
result.push pin.suggestion
|
177
|
+
#result.push pin.suggestion
|
178
|
+
result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
|
206
179
|
end
|
207
180
|
end
|
208
181
|
result
|
@@ -214,114 +187,45 @@ module Solargraph
|
|
214
187
|
ip = @cvar_pins[namespace]
|
215
188
|
unless ip.nil?
|
216
189
|
ip.each do |pin|
|
217
|
-
result.push pin
|
190
|
+
result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
|
218
191
|
end
|
219
192
|
end
|
220
193
|
result
|
221
194
|
end
|
222
195
|
|
223
|
-
def
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
def get_root_for(node)
|
232
|
-
s = @parent_stack[node]
|
233
|
-
return nil if s.nil?
|
234
|
-
return node if s.empty?
|
235
|
-
s.last
|
196
|
+
def get_symbols
|
197
|
+
refresh
|
198
|
+
result = []
|
199
|
+
@symbol_pins.each do |s|
|
200
|
+
result.push s
|
201
|
+
end
|
202
|
+
result
|
236
203
|
end
|
237
204
|
|
238
205
|
def get_filename_for(node)
|
239
|
-
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
def yardoc_has_file?(file)
|
244
|
-
return false if workspace.nil?
|
245
|
-
if @yardoc_files.nil?
|
246
|
-
@yardoc_files = []
|
247
|
-
yard_options[:include].each { |glob|
|
248
|
-
Dir[File.join workspace, glob].each { |f|
|
249
|
-
@yardoc_files.push File.absolute_path(f)
|
250
|
-
}
|
251
|
-
}
|
206
|
+
@sources.each do |filename, source|
|
207
|
+
return source.filename if source.include?(node)
|
252
208
|
end
|
253
|
-
|
209
|
+
nil
|
254
210
|
end
|
255
211
|
|
256
212
|
def infer_instance_variable(var, namespace, scope)
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
break unless vn.nil?
|
264
|
-
}
|
265
|
-
end
|
266
|
-
result = infer_assignment_node_type(vn, namespace) unless vn.nil?
|
267
|
-
result
|
213
|
+
refresh
|
214
|
+
pins = @ivar_pins[namespace]
|
215
|
+
return nil if pins.nil?
|
216
|
+
pin = pins.select{|p| p.name == var and p.scope == scope}.first
|
217
|
+
return nil if pin.nil?
|
218
|
+
pin.return_type
|
268
219
|
end
|
269
220
|
|
270
221
|
def infer_class_variable(var, namespace)
|
271
|
-
|
272
|
-
vn = nil
|
222
|
+
refresh
|
273
223
|
fqns = find_fully_qualified_namespace(namespace)
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
end
|
280
|
-
unless vn.nil?
|
281
|
-
cmnt = get_comment_for(vn)
|
282
|
-
unless cmnt.nil?
|
283
|
-
tag = cmnt.tag(:type)
|
284
|
-
result = tag.types[0] unless tag.nil? or tag.types.empty?
|
285
|
-
end
|
286
|
-
result = infer_literal_node_type(vn.children[1]) if result.nil?
|
287
|
-
if result.nil?
|
288
|
-
signature = resolve_node_signature(vn.children[1])
|
289
|
-
result = infer_signature_type(signature, namespace)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
result
|
293
|
-
end
|
294
|
-
|
295
|
-
def find_instance_variable_assignment(var, node, scope)
|
296
|
-
node.children.each { |c|
|
297
|
-
if c.kind_of?(AST::Node)
|
298
|
-
is_inst = !find_parent(c, :def).nil?
|
299
|
-
if c.type == :ivasgn and ( (scope == :instance and is_inst) or (scope != :instance and !is_inst) )
|
300
|
-
if c.children[0].to_s == var
|
301
|
-
return c
|
302
|
-
end
|
303
|
-
else
|
304
|
-
inner = find_instance_variable_assignment(var, c, scope)
|
305
|
-
return inner unless inner.nil?
|
306
|
-
end
|
307
|
-
end
|
308
|
-
}
|
309
|
-
nil
|
310
|
-
end
|
311
|
-
|
312
|
-
def find_class_variable_assignment(var, node)
|
313
|
-
node.children.each { |c|
|
314
|
-
next unless c.kind_of?(AST::Node)
|
315
|
-
if c.type == :cvasgn
|
316
|
-
if c.children[0].to_s == var
|
317
|
-
return c
|
318
|
-
end
|
319
|
-
else
|
320
|
-
inner = find_class_variable_assignment(var, c)
|
321
|
-
return inner unless inner.nil?
|
322
|
-
end
|
323
|
-
}
|
324
|
-
nil
|
224
|
+
pins = @cvar_pins[fqns]
|
225
|
+
return nil if pins.nil?
|
226
|
+
pin = pins.select{|p| p.name == var}.first
|
227
|
+
return nil if pin.nil?
|
228
|
+
pin.return_type
|
325
229
|
end
|
326
230
|
|
327
231
|
def get_global_variables
|
@@ -358,8 +262,9 @@ module Solargraph
|
|
358
262
|
end
|
359
263
|
|
360
264
|
def infer_signature_type signature, namespace, scope: :class
|
361
|
-
|
362
|
-
|
265
|
+
if cache.has_signature_type?(signature, namespace, scope)
|
266
|
+
return cache.get_signature_type(signature, namespace, scope)
|
267
|
+
end
|
363
268
|
return nil if signature.nil? or signature.empty?
|
364
269
|
result = nil
|
365
270
|
if namespace.end_with?('#class')
|
@@ -428,8 +333,19 @@ module Solargraph
|
|
428
333
|
elsif type == :module
|
429
334
|
meths += yard_map.get_methods('Module')
|
430
335
|
end
|
431
|
-
meths
|
432
336
|
end
|
337
|
+
news = meths.select{|s| s.label == 'new'}
|
338
|
+
unless news.empty?
|
339
|
+
fqns = find_fully_qualified_namespace(namespace, root)
|
340
|
+
if @method_pins[fqns]
|
341
|
+
inits = @method_pins[fqns].select{|p| p.name == 'initialize'}
|
342
|
+
meths -= news unless inits.empty?
|
343
|
+
inits.each do |pin|
|
344
|
+
meths.push Suggestion.new('new', kind: pin.kind, documentation: pin.docstring, detail: pin.namespace, arguments: pin.parameters, path: pin.path)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
meths
|
433
349
|
end
|
434
350
|
|
435
351
|
# Get an array of instance methods that are available in the specified
|
@@ -459,27 +375,6 @@ module Solargraph
|
|
459
375
|
meths
|
460
376
|
end
|
461
377
|
|
462
|
-
def get_superclass(namespace, root = '')
|
463
|
-
fqns = find_fully_qualified_namespace(namespace, root)
|
464
|
-
nodes = get_namespace_nodes(fqns)
|
465
|
-
nodes.each { |n|
|
466
|
-
if n.kind_of?(AST::Node)
|
467
|
-
if n.type == :class and !n.children[1].nil?
|
468
|
-
return unpack_name(n.children[1])
|
469
|
-
end
|
470
|
-
end
|
471
|
-
}
|
472
|
-
return nil
|
473
|
-
end
|
474
|
-
|
475
|
-
def self.current
|
476
|
-
if @current.nil?
|
477
|
-
@current = ApiMap.new
|
478
|
-
@current.merge(Parser::CurrentRuby.parse(File.read("#{Solargraph::STUB_PATH}/ruby/2.3.0/core.rb")))
|
479
|
-
end
|
480
|
-
@current
|
481
|
-
end
|
482
|
-
|
483
378
|
def get_include_strings_from *nodes
|
484
379
|
arr = []
|
485
380
|
nodes.each { |node|
|
@@ -492,42 +387,19 @@ module Solargraph
|
|
492
387
|
arr
|
493
388
|
end
|
494
389
|
|
495
|
-
def
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
e = node.location.expression.end.end_pos
|
500
|
-
src[b..e].strip.gsub(/,$/, '')
|
501
|
-
end
|
390
|
+
def update filename
|
391
|
+
@@source_cache[filename] ||= Source.load(filename)
|
392
|
+
cache.clear
|
393
|
+
end
|
502
394
|
|
503
|
-
|
504
|
-
|
505
|
-
def update_yardoc
|
506
|
-
if workspace.nil?
|
507
|
-
STDERR.puts "No workspace specified for yardoc update."
|
508
|
-
else
|
509
|
-
Dir.chdir(workspace) do
|
510
|
-
STDERR.puts "Updating the yardoc for #{workspace}..."
|
511
|
-
cmd = "yardoc -e #{Solargraph::YARD_EXTENSION_FILE}"
|
512
|
-
STDERR.puts "Update yardoc with #{cmd}"
|
513
|
-
STDERR.puts `#{cmd}`
|
514
|
-
unless $?.success?
|
515
|
-
STDERR.puts "There was an error processing the workspace yardoc."
|
516
|
-
end
|
517
|
-
end
|
518
|
-
@@semaphore.synchronize {
|
519
|
-
@@yard_map_cache.clear
|
520
|
-
}
|
521
|
-
end
|
395
|
+
def sources
|
396
|
+
@sources.values
|
522
397
|
end
|
523
398
|
|
524
399
|
private
|
525
400
|
|
526
401
|
def clear
|
527
402
|
@stale = false
|
528
|
-
@file_source = {}
|
529
|
-
@file_nodes = {}
|
530
|
-
@file_comments = {}
|
531
403
|
@parent_stack = {}
|
532
404
|
@namespace_map = {}
|
533
405
|
@namespace_tree = {}
|
@@ -535,54 +407,83 @@ module Solargraph
|
|
535
407
|
end
|
536
408
|
|
537
409
|
def process_maps
|
410
|
+
@sources.clear
|
411
|
+
@workspace_files.each do |f|
|
412
|
+
@@source_cache[f] ||= Source.load(f)
|
413
|
+
@sources[f] = @@source_cache[f]
|
414
|
+
end
|
538
415
|
cache.clear
|
539
416
|
@ivar_pins = {}
|
540
417
|
@cvar_pins = {}
|
418
|
+
@const_pins = {}
|
541
419
|
@method_pins = {}
|
542
|
-
@
|
420
|
+
@symbol_pins = []
|
421
|
+
@attr_pins = {}
|
543
422
|
@namespace_includes = {}
|
544
423
|
@superclasses = {}
|
545
424
|
@parent_stack = {}
|
546
425
|
@namespace_map = {}
|
547
426
|
@namespace_tree = {}
|
548
|
-
@
|
549
|
-
|
550
|
-
|
427
|
+
@required = []
|
428
|
+
unless @virtual_source.nil?
|
429
|
+
@sources[@virtual_filename] = @virtual_source
|
430
|
+
end
|
431
|
+
@sources.values.each do |s|
|
432
|
+
s.namespace_nodes.each_pair do |k, v|
|
433
|
+
@namespace_map[k] ||= []
|
434
|
+
@namespace_map[k].concat v
|
435
|
+
add_to_namespace_tree k.split('::')
|
436
|
+
end
|
437
|
+
end
|
438
|
+
@sources.values.each { |s|
|
439
|
+
map_source s
|
551
440
|
}
|
441
|
+
@required.uniq!
|
552
442
|
@stale = false
|
553
443
|
end
|
554
444
|
|
445
|
+
# @param [Solargraph::ApiMap::Source]
|
446
|
+
def map_source source
|
447
|
+
source.method_pins.each do |pin|
|
448
|
+
@method_pins[pin.namespace] ||= []
|
449
|
+
@method_pins[pin.namespace].push pin
|
450
|
+
end
|
451
|
+
source.attribute_pins.each do |pin|
|
452
|
+
@attr_pins[pin.namespace] ||= []
|
453
|
+
@attr_pins[pin.namespace].push pin
|
454
|
+
end
|
455
|
+
source.instance_variable_pins.each do |pin|
|
456
|
+
@ivar_pins[pin.namespace] ||= []
|
457
|
+
@ivar_pins[pin.namespace].push pin
|
458
|
+
end
|
459
|
+
source.class_variable_pins.each do |pin|
|
460
|
+
@cvar_pins[pin.namespace] ||= []
|
461
|
+
@cvar_pins[pin.namespace].push pin
|
462
|
+
end
|
463
|
+
source.constant_pins.each do |pin|
|
464
|
+
@const_pins[pin.namespace] ||= []
|
465
|
+
@const_pins[pin.namespace].push pin
|
466
|
+
end
|
467
|
+
source.symbol_pins.each do |pin|
|
468
|
+
@symbol_pins.push Suggestion.new(pin.name, kind: Suggestion::CONSTANT, return_type: 'Symbol')
|
469
|
+
end
|
470
|
+
source.namespace_includes.each_pair do |ns, i|
|
471
|
+
@namespace_includes[ns] ||= []
|
472
|
+
@namespace_includes[ns].concat(i).uniq!
|
473
|
+
end
|
474
|
+
source.superclasses.each_pair do |cls, sup|
|
475
|
+
@superclasses[cls] = sup
|
476
|
+
end
|
477
|
+
source.required.each do |r|
|
478
|
+
required.push r
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
555
482
|
# @return [Solargraph::ApiMap::Cache]
|
556
483
|
def cache
|
557
484
|
@cache ||= Cache.new
|
558
485
|
end
|
559
486
|
|
560
|
-
def associate_comments node, comments
|
561
|
-
comment_hash = Parser::Source::Comment.associate_locations(node, comments)
|
562
|
-
yard_hash = {}
|
563
|
-
comment_hash.each_pair { |k, v|
|
564
|
-
ctxt = ''
|
565
|
-
num = nil
|
566
|
-
started = false
|
567
|
-
v.each { |l|
|
568
|
-
# Trim the comment and minimum leading whitespace
|
569
|
-
p = l.text.gsub(/^#/, '')
|
570
|
-
if num.nil? and !p.strip.empty?
|
571
|
-
num = p.index(/[^ ]/)
|
572
|
-
started = true
|
573
|
-
elsif started and !p.strip.empty?
|
574
|
-
cur = p.index(/[^ ]/)
|
575
|
-
num = cur if cur < num
|
576
|
-
end
|
577
|
-
if started
|
578
|
-
ctxt += "#{p[num..-1]}\n"
|
579
|
-
end
|
580
|
-
}
|
581
|
-
yard_hash[k] = YARD::Docstring.parser.parse(ctxt).to_docstring
|
582
|
-
}
|
583
|
-
yard_hash
|
584
|
-
end
|
585
|
-
|
586
487
|
def inner_get_methods(namespace, root = '', skip = [])
|
587
488
|
meths = []
|
588
489
|
return meths if skip.include?(namespace)
|
@@ -592,7 +493,7 @@ module Solargraph
|
|
592
493
|
mn = @method_pins[fqns]
|
593
494
|
unless mn.nil?
|
594
495
|
mn.select{ |pin| pin.scope == :class }.each do |pin|
|
595
|
-
meths.push
|
496
|
+
meths.push Suggestion.pull(pin)
|
596
497
|
end
|
597
498
|
end
|
598
499
|
meths.uniq
|
@@ -603,21 +504,24 @@ module Solargraph
|
|
603
504
|
meths = []
|
604
505
|
return meths if skip.include?(fqns)
|
605
506
|
skip.push fqns
|
606
|
-
an = @
|
507
|
+
an = @attr_pins[fqns]
|
607
508
|
unless an.nil?
|
608
509
|
an.each do |pin|
|
609
|
-
meths.
|
510
|
+
meths.push Suggestion.pull(pin)
|
610
511
|
end
|
611
512
|
end
|
612
513
|
mn = @method_pins[fqns]
|
613
514
|
unless mn.nil?
|
614
515
|
mn.select{|pin| visibility.include?(pin.visibility) and pin.scope == :instance }.each do |pin|
|
615
|
-
meths.push
|
516
|
+
meths.push Suggestion.pull(pin)
|
616
517
|
end
|
617
518
|
end
|
618
519
|
if visibility.include?(:public) or visibility.include?(:protected)
|
619
520
|
sc = @superclasses[fqns]
|
620
|
-
|
521
|
+
unless sc.nil?
|
522
|
+
meths.concat inner_get_instance_methods(sc, fqns, skip, visibility - [:private])
|
523
|
+
meths.concat yard_map.get_instance_methods(sc, fqns, visibility: visibility - [:private])
|
524
|
+
end
|
621
525
|
end
|
622
526
|
im = @namespace_includes[fqns]
|
623
527
|
unless im.nil?
|
@@ -634,7 +538,6 @@ module Solargraph
|
|
634
538
|
unless fqns.nil? or skip.include?(fqns)
|
635
539
|
skip.push fqns
|
636
540
|
nodes = get_namespace_nodes(fqns)
|
637
|
-
nodes.delete_if { |n| yardoc_has_file?(get_filename_for(n))}
|
638
541
|
unless nodes.empty?
|
639
542
|
cursor = @namespace_tree
|
640
543
|
parts = fqns.split('::')
|
@@ -655,29 +558,18 @@ module Solargraph
|
|
655
558
|
end
|
656
559
|
result.push Suggestion.new(k, kind: kind, detail: detail)
|
657
560
|
}
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
561
|
+
cp = @const_pins[fqns]
|
562
|
+
unless cp.nil?
|
563
|
+
cp.each do |pin|
|
564
|
+
result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
|
565
|
+
end
|
566
|
+
end
|
567
|
+
inc = @namespace_includes[fqns]
|
568
|
+
unless inc.nil?
|
569
|
+
inc.each do |i|
|
570
|
+
result.concat inner_namespaces_in(i, fqns, skip)
|
571
|
+
end
|
664
572
|
end
|
665
|
-
end
|
666
|
-
end
|
667
|
-
end
|
668
|
-
result
|
669
|
-
end
|
670
|
-
|
671
|
-
def get_constant_nodes(node, fqns)
|
672
|
-
result = []
|
673
|
-
node.children.each do |n|
|
674
|
-
if n.kind_of?(AST::Node)
|
675
|
-
if n.type == :casgn
|
676
|
-
cmnt = get_comment_for(n)
|
677
|
-
type = infer_assignment_node_type(n, fqns)
|
678
|
-
result.push Suggestion.new(n.children[1].to_s, kind: Suggestion::CONSTANT, documentation: cmnt, return_type: type)
|
679
|
-
else
|
680
|
-
result.concat get_constant_nodes(n, fqns) unless n.type == :class or n.type == :module
|
681
573
|
end
|
682
574
|
end
|
683
575
|
end
|
@@ -772,98 +664,6 @@ module Solargraph
|
|
772
664
|
type
|
773
665
|
end
|
774
666
|
|
775
|
-
def mappable?(node)
|
776
|
-
if node.kind_of?(AST::Node) and MAPPABLE_NODES.include?(node.type)
|
777
|
-
true
|
778
|
-
elsif node.kind_of?(AST::Node) and node.type == :send and node.children[0] == nil and MAPPABLE_METHODS.include?(node.children[1])
|
779
|
-
true
|
780
|
-
else
|
781
|
-
false
|
782
|
-
end
|
783
|
-
end
|
784
|
-
|
785
|
-
def reduce node, comment_hash
|
786
|
-
return node unless node.kind_of?(AST::Node)
|
787
|
-
mappable = get_mappable_nodes(node.children, comment_hash)
|
788
|
-
result = node.updated nil, mappable
|
789
|
-
result
|
790
|
-
end
|
791
|
-
|
792
|
-
def get_mappable_nodes arr, comment_hash
|
793
|
-
result = []
|
794
|
-
arr.each { |n|
|
795
|
-
if mappable?(n)
|
796
|
-
min = minify(n, comment_hash)
|
797
|
-
result.push min
|
798
|
-
else
|
799
|
-
next unless n.kind_of?(AST::Node)
|
800
|
-
result += get_mappable_nodes(n.children, comment_hash)
|
801
|
-
end
|
802
|
-
}
|
803
|
-
result
|
804
|
-
end
|
805
|
-
|
806
|
-
def minify node, comment_hash
|
807
|
-
return node if node.type == :args
|
808
|
-
type = node.type
|
809
|
-
children = []
|
810
|
-
if node.type == :class or node.type == :block or node.type == :sclass
|
811
|
-
children += node.children[0, 2]
|
812
|
-
children += get_mappable_nodes(node.children[2..-1], comment_hash)
|
813
|
-
elsif node.type == :const or node.type == :args or node.type == :kwargs
|
814
|
-
children += node.children
|
815
|
-
elsif node.type == :def
|
816
|
-
children += node.children[0, 2]
|
817
|
-
children += get_mappable_nodes(node.children[2..-1], comment_hash)
|
818
|
-
elsif node.type == :defs
|
819
|
-
children += node.children[0, 3]
|
820
|
-
children += get_mappable_nodes(node.children[3..-1], comment_hash)
|
821
|
-
elsif node.type == :module
|
822
|
-
children += node.children[0, 1]
|
823
|
-
children += get_mappable_nodes(node.children[1..-1], comment_hash)
|
824
|
-
elsif node.type == :ivasgn or node.type == :gvasgn or node.type == :lvasgn or node.type == :cvasgn or node.type == :casgn
|
825
|
-
children += node.children
|
826
|
-
elsif node.type == :send and node.children[1] == :include
|
827
|
-
children += node.children[0,3]
|
828
|
-
elsif node.type == :send and node.children[1] == :require
|
829
|
-
if node.children[2].children[0].kind_of?(String)
|
830
|
-
path = node.children[2].children[0].to_s
|
831
|
-
@required.push(path) unless local_path?(path)
|
832
|
-
end
|
833
|
-
children += node.children[0, 3]
|
834
|
-
elsif node.type == :send and node.children[1] == :autoload
|
835
|
-
@required.push(node.children[3].children[0]) if node.children[3].children[0].kind_of?(String)
|
836
|
-
type = :require
|
837
|
-
children += node.children[1, 3]
|
838
|
-
elsif node.type == :send or node.type == :lvar
|
839
|
-
children += node.children
|
840
|
-
elsif node.type == :or_asgn
|
841
|
-
# TODO: The api_map should ignore local variables.
|
842
|
-
type = node.children[0].type
|
843
|
-
children.push node.children[0].children[0], node.children[1]
|
844
|
-
elsif [:array, :hash, :str, :dstr, :int, :float, :sym].include?(node.type)
|
845
|
-
# @todo Do we really care about the details?
|
846
|
-
end
|
847
|
-
result = node.updated(type, children)
|
848
|
-
result
|
849
|
-
end
|
850
|
-
|
851
|
-
def local_path? path
|
852
|
-
return false if workspace.nil?
|
853
|
-
return true if File.exist?(File.join workspace, 'lib', path)
|
854
|
-
return true if File.exist?(File.join workspace, 'lib', "#{path}.rb")
|
855
|
-
false
|
856
|
-
end
|
857
|
-
|
858
|
-
def map_parents node, tree = []
|
859
|
-
if node.kind_of?(AST::Node)
|
860
|
-
@parent_stack[node] = tree
|
861
|
-
node.children.each { |c|
|
862
|
-
map_parents c, [node] + tree
|
863
|
-
}
|
864
|
-
end
|
865
|
-
end
|
866
|
-
|
867
667
|
def add_to_namespace_tree tree
|
868
668
|
cursor = @namespace_tree
|
869
669
|
tree.each { |t|
|
@@ -872,69 +672,8 @@ module Solargraph
|
|
872
672
|
}
|
873
673
|
end
|
874
674
|
|
875
|
-
def
|
876
|
-
|
877
|
-
return if node.type == :str or node.type == :dstr
|
878
|
-
if node.type == :class or node.type == :module
|
879
|
-
visibility = :public
|
880
|
-
if node.children[0].kind_of?(AST::Node) and node.children[0].children[0].kind_of?(AST::Node) and node.children[0].children[0].type == :cbase
|
881
|
-
tree = pack_name(node.children[0])
|
882
|
-
else
|
883
|
-
tree = tree + pack_name(node.children[0])
|
884
|
-
end
|
885
|
-
add_to_namespace_tree tree
|
886
|
-
fqn = tree.join('::')
|
887
|
-
@namespace_map[fqn] ||= []
|
888
|
-
@namespace_map[fqn].push node
|
889
|
-
if node.type == :class and !node.children[1].nil?
|
890
|
-
sc = unpack_name(node.children[1])
|
891
|
-
@superclasses[fqn] = sc
|
892
|
-
end
|
893
|
-
end
|
894
|
-
file = get_filename_for(node)
|
895
|
-
in_yardoc = yardoc_has_file?(file)
|
896
|
-
node.children.each do |c|
|
897
|
-
if c.kind_of?(AST::Node)
|
898
|
-
if c.type == :ivasgn
|
899
|
-
@ivar_pins[fqn || ''] ||= []
|
900
|
-
par = find_parent(c, :class, :module, :def, :defs)
|
901
|
-
local_scope = ( (par.kind_of?(AST::Node) and par.type == :def) ? :instance : :class )
|
902
|
-
@ivar_pins[fqn || ''].push IvarPin.new(self, c, fqn || '', local_scope, get_comment_for(c))
|
903
|
-
elsif c.type == :cvasgn
|
904
|
-
@cvar_pins[fqn] ||= []
|
905
|
-
@cvar_pins[fqn].push CvarPin.new(self, c, fqn, get_comment_for(c))
|
906
|
-
else
|
907
|
-
unless fqn.nil? or in_yardoc
|
908
|
-
if c.kind_of?(AST::Node)
|
909
|
-
if c.type == :def and c.children[0].to_s[0].match(/[a-z]/i)
|
910
|
-
@method_pins[fqn] ||= []
|
911
|
-
@method_pins[fqn].push MethodPin.new(c, fqn, scope, visibility, get_comment_for(c))
|
912
|
-
map_namespaces c, tree, visibility, scope, fqn
|
913
|
-
next
|
914
|
-
elsif c.type == :defs
|
915
|
-
@method_pins[fqn] ||= []
|
916
|
-
@method_pins[fqn].push MethodPin.new(c, fqn, :class, :public, get_comment_for(c))
|
917
|
-
map_namespaces c, tree, :public, :class, fqn
|
918
|
-
next
|
919
|
-
elsif c.type == :send and [:public, :protected, :private].include?(c.children[1])
|
920
|
-
visibility = c.children[1]
|
921
|
-
elsif c.type == :send and c.children[1] == :include and node.type == :class
|
922
|
-
@namespace_includes[fqn] ||= []
|
923
|
-
@namespace_includes[fqn].push unpack_name(c.children[2])
|
924
|
-
elsif c.type == :send and [:attr_reader, :attr_writer, :attr_accessor].include?(c.children[1])
|
925
|
-
@attr_nodes[fqn] ||= []
|
926
|
-
@attr_nodes[fqn].push AttrPin.new(c)
|
927
|
-
elsif c.type == :sclass and c.children[0].type == :self
|
928
|
-
map_namespaces c, tree, :public, :class, fqn
|
929
|
-
next
|
930
|
-
end
|
931
|
-
end
|
932
|
-
end
|
933
|
-
map_namespaces c, tree, visibility, scope, fqn
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end
|
937
|
-
end
|
675
|
+
def file_nodes
|
676
|
+
@sources.values.map(&:node)
|
938
677
|
end
|
939
678
|
|
940
679
|
def clean_namespace_string namespace
|
@@ -945,5 +684,14 @@ module Solargraph
|
|
945
684
|
end
|
946
685
|
result
|
947
686
|
end
|
687
|
+
|
688
|
+
def resolve_pin_return_type pin
|
689
|
+
return pin.return_type unless pin.return_type.nil?
|
690
|
+
return nil if pin.signature.nil?
|
691
|
+
# Avoid infinite loops from variable assignments that reference themselves
|
692
|
+
return nil if pin.name == pin.signature.split('.').first
|
693
|
+
infer_signature_type(pin.signature, pin.namespace)
|
694
|
+
end
|
695
|
+
|
948
696
|
end
|
949
697
|
end
|