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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ff8b6c3f8f03cacb73e9a6b398d3f984dc2e240
4
- data.tar.gz: 58449ce1fd531e8426bcbad2733487a66a23ff3a
3
+ metadata.gz: 031c6210f7be6462d12e8ce7dd5c25e30b6c097d
4
+ data.tar.gz: 422def5aafa30d23831434dafc5a69eb26d97e55
5
5
  SHA512:
6
- metadata.gz: dc8c5611342e2be6c3fbcd354663e611523b2aaf756f738a08f20bcd1a4ca8a9e6a278a64cb31541d09e8243be8170e2c7588de827ae6d36cf95253594eed3cc
7
- data.tar.gz: a1d6666d9098e565b2d663a5d1ece4a617fb3ea1d0a97ca4703f4d114656afb831552b60345b9970abb6081028bc623ad65e117dfb98f20029f120e2a665f437
6
+ metadata.gz: e597e62a01501ee615fcac8a194940e9d85ea69346eeb245104340deb9d2db69de1553facb00d9b6e1dc9c9c3b932c8b5f4cda4a00e43bd41be240548633f8f0
7
+ data.tar.gz: 6137318fc634b925cc99a86b77b0ca86ae8c7f1ca842f4a864f93b88531151e3a96adc596aeb99fa94cf10c09e690432284090981e3c70b56151e72772d7dd95
@@ -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')
@@ -4,13 +4,11 @@ require 'thread'
4
4
 
5
5
  module Solargraph
6
6
  class ApiMap
7
- autoload :Config, 'solargraph/api_map/config'
8
- autoload :Cache, 'solargraph/api_map/cache'
9
- autoload :MethodPin, 'solargraph/api_map/method_pin'
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.each { |f|
59
- unless config.excluded.include?(f)
60
- append_file f
61
- end
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
- @yard_map ||= @@yard_map_cache[[required, workspace]] || Solargraph::YardMap.new(required: required, workspace: workspace)
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
- # Add a file to the map.
75
- #
76
- # @param filename [String]
77
- # @return [AST::Node]
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
- # Add an AST node to the map.
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 @file_comments[filename].nil?
124
- @file_comments[filename][node.loc]
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 ||= (KEYWORDS + MAPPABLE_METHODS).map{ |s|
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(*@file_nodes.values).each { |i|
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(*@file_nodes.values).each { |i|
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 @file_nodes.values if fqns == '' or fqns.nil?
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.suggestion
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 find_parent(node, *types)
224
- parents = @parent_stack[node]
225
- parents.each { |p|
226
- return p if types.include?(p.type)
227
- }
228
- nil
229
- end
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
- root = get_root_for(node)
240
- root.nil? ? nil : root.children[0]
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
- @yardoc_files.include?(file)
209
+ nil
254
210
  end
255
211
 
256
212
  def infer_instance_variable(var, namespace, scope)
257
- result = nil
258
- vn = nil
259
- fqns = find_fully_qualified_namespace(namespace)
260
- unless fqns.nil?
261
- get_namespace_nodes(fqns).each { |node|
262
- vn = find_instance_variable_assignment(var, node, scope)
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
- result = nil
272
- vn = nil
222
+ refresh
273
223
  fqns = find_fully_qualified_namespace(namespace)
274
- unless fqns.nil?
275
- get_namespace_nodes(fqns).each { |node|
276
- vn = find_class_variable_assignment(var, node)
277
- break unless vn.nil?
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
- cached = cache.get_signature_type(signature, namespace, scope)
362
- return cached unless cached.nil?
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 code_for node
496
- src = @file_source[get_filename_for(node)]
497
- return nil if src.nil?
498
- b = node.location.expression.begin.begin_pos
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
- # Update the YARD documentation for the current workspace.
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
- @attr_nodes = {}
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
- @file_nodes.values.each { |f|
549
- map_parents f
550
- map_namespaces f
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 pin.suggestion(self)
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 = @attr_nodes[fqns]
507
+ an = @attr_pins[fqns]
607
508
  unless an.nil?
608
509
  an.each do |pin|
609
- meths.concat pin.suggestions
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 pin.suggestion(self)
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
- meths.concat inner_get_instance_methods(sc, fqns, skip, visibility - [:private]) unless sc.nil?
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
- nodes = get_namespace_nodes(fqns)
659
- nodes.each do |n|
660
- result.concat get_constant_nodes(n, fqns)
661
- get_include_strings_from(n).each { |i|
662
- result += inner_namespaces_in(i, fqns, skip)
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 map_namespaces node, tree = [], visibility = :public, scope = :instance, fqn = nil
876
- if node.kind_of?(AST::Node)
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