solargraph 0.13.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 031c6210f7be6462d12e8ce7dd5c25e30b6c097d
4
- data.tar.gz: 422def5aafa30d23831434dafc5a69eb26d97e55
3
+ metadata.gz: a515f53b1eebf187bf4108abdba6c591f438cdb6
4
+ data.tar.gz: 832c13c89dcdf1bae7cb69aa3433d73346b86bec
5
5
  SHA512:
6
- metadata.gz: e597e62a01501ee615fcac8a194940e9d85ea69346eeb245104340deb9d2db69de1553facb00d9b6e1dc9c9c3b932c8b5f4cda4a00e43bd41be240548633f8f0
7
- data.tar.gz: 6137318fc634b925cc99a86b77b0ca86ae8c7f1ca842f4a864f93b88531151e3a96adc596aeb99fa94cf10c09e690432284090981e3c70b56151e72772d7dd95
6
+ metadata.gz: 74f08e71b1c0834aa6b18f4dcb0e176f91d0a40ac6f8a3fe3c76ad95081096eec4cb2ed904aaa7586433d05f8520214b9d1185755a549a2045870ba661acfd6e
7
+ data.tar.gz: 7ddcdf66369a65533d14e3c13763dad0ecb3f306b4b0ce7ef707802a61ae5b6c6d13a979b48bdd64c76b823064d32d9d1dd57dbd917d60e50dca018db1ab6799
@@ -3,16 +3,23 @@ require 'parser/current'
3
3
  module Solargraph
4
4
  class ApiMap
5
5
  class Source
6
+ # @return [String]
6
7
  attr_reader :code
8
+
9
+ # @return [Parser::AST::Node]
7
10
  attr_reader :node
11
+
12
+ # @return [Array]
8
13
  attr_reader :comments
14
+
15
+ # @return [String]
9
16
  attr_reader :filename
10
17
 
11
18
  include NodeMethods
12
19
 
13
20
  def initialize code, node, comments, filename
14
21
  @code = code
15
- root = AST::Node.new(:begin, [filename])
22
+ root = AST::Node.new(:source, [filename])
16
23
  root = root.append node
17
24
  @node = root
18
25
  @comments = comments
@@ -20,6 +27,8 @@ module Solargraph
20
27
  @filename = filename
21
28
  @namespace_nodes = {}
22
29
  @all_nodes = []
30
+ @node_stack = []
31
+ @node_tree = {}
23
32
  inner_map_node @node
24
33
  end
25
34
 
@@ -55,6 +64,14 @@ module Solargraph
55
64
  @class_variable_pins ||= []
56
65
  end
57
66
 
67
+ def local_variable_pins
68
+ @local_variable_pins ||= []
69
+ end
70
+
71
+ def global_variable_pins
72
+ @global_variable_pins ||= []
73
+ end
74
+
58
75
  def constant_pins
59
76
  @constant_pins ||= []
60
77
  end
@@ -78,6 +95,10 @@ module Solargraph
78
95
  frag.strip.gsub(/,$/, '')
79
96
  end
80
97
 
98
+ def tree_for node
99
+ @node_tree[node] || []
100
+ end
101
+
81
102
  def include? node
82
103
  @all_nodes.include? node
83
104
  end
@@ -115,7 +136,11 @@ module Solargraph
115
136
  source = self
116
137
  if node.kind_of?(AST::Node)
117
138
  @all_nodes.push node
118
- return if node.type == :str or node.type == :dstr
139
+ if node.type == :str or node.type == :dstr
140
+ stack.pop
141
+ return
142
+ end
143
+ @node_stack.unshift node
119
144
  if node.type == :class or node.type == :module
120
145
  visibility = :public
121
146
  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
@@ -134,6 +159,7 @@ module Solargraph
134
159
  file = source.filename
135
160
  node.children.each do |c|
136
161
  if c.kind_of?(AST::Node)
162
+ @node_tree[c] = @node_stack.clone
137
163
  if c.type == :ivasgn
138
164
  par = find_parent(stack, :class, :module, :def, :defs)
139
165
  local_scope = ( (par.kind_of?(AST::Node) and par.type == :def) ? :instance : :class )
@@ -141,6 +167,7 @@ module Solargraph
141
167
  ora = find_parent(stack, :or_asgn)
142
168
  unless ora.nil?
143
169
  u = c.updated(:ivasgn, c.children + ora.children[1..-1], nil)
170
+ @node_tree[u] = @node_stack.clone
144
171
  instance_variable_pins.push Solargraph::Pin::InstanceVariable.new(self, u, fqn || '', local_scope)
145
172
  end
146
173
  else
@@ -151,11 +178,27 @@ module Solargraph
151
178
  ora = find_parent(stack, :or_asgn)
152
179
  unless ora.nil?
153
180
  u = c.updated(:cvasgn, c.children + ora.children[1..-1], nil)
181
+ @node_tree[u] = @node_stack.clone
154
182
  class_variable_pins.push Solargraph::Pin::ClassVariable.new(self, u, fqn || '')
155
183
  end
156
184
  else
157
185
  class_variable_pins.push Solargraph::Pin::ClassVariable.new(self, c, fqn || '')
158
186
  end
187
+ elsif c.type == :lvasgn
188
+ if c.children[1].nil?
189
+ ora = find_parent(stack, :or_asgn)
190
+ unless ora.nil?
191
+ u = c.updated(:lvasgn, c.children + ora.children[1..-1], nil)
192
+ @node_tree[u] = @node_stack.clone
193
+ @docstring_hash[u.loc] = docstring_for(ora)
194
+ local_variable_pins.push Solargraph::Pin::LocalVariable.new(self, u, fqn || '', @node_stack.clone)
195
+ end
196
+ else
197
+ @node_tree[c] = @node_stack.clone
198
+ local_variable_pins.push Solargraph::Pin::LocalVariable.new(self, c, fqn || '', @node_stack.clone)
199
+ end
200
+ elsif c.type == :gvasgn
201
+ global_variable_pins.push Solargraph::Pin::GlobalVariable.new(self, c, fqn || '')
159
202
  elsif c.type == :sym
160
203
  symbol_pins.push Solargraph::Pin::Symbol.new(self, c, fqn)
161
204
  elsif c.type == :casgn
@@ -165,8 +208,8 @@ module Solargraph
165
208
  if c.kind_of?(AST::Node)
166
209
  if c.type == :def and c.children[0].to_s[0].match(/[a-z]/i)
167
210
  method_pins.push Solargraph::Pin::Method.new(source, c, fqn, scope, visibility)
168
- inner_map_node c, tree, visibility, scope, fqn, stack
169
- next
211
+ #inner_map_node c, tree, visibility, scope, fqn, stack
212
+ #next
170
213
  elsif c.type == :defs
171
214
  method_pins.push Solargraph::Pin::Method.new(source, c, fqn, :class, :public)
172
215
  inner_map_node c, tree, :public, :class, fqn, stack
@@ -181,10 +224,10 @@ module Solargraph
181
224
  elsif c.type == :send and [:attr_reader, :attr_writer, :attr_accessor].include?(c.children[1])
182
225
  c.children[2..-1].each do |a|
183
226
  if c.children[1] == :attr_reader or c.children[1] == :attr_accessor
184
- attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn, :reader) #AttrPin.new(c)
227
+ attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn, :reader, docstring_for(c)) #AttrPin.new(c)
185
228
  end
186
229
  if c.children[1] == :attr_writer or c.children[1] == :attr_accessor
187
- attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn, :writer) #AttrPin.new(c)
230
+ attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn, :writer, docstring_for(c)) #AttrPin.new(c)
188
231
  end
189
232
  end
190
233
  elsif c.type == :sclass and c.children[0].type == :self
@@ -198,10 +241,11 @@ module Solargraph
198
241
  required.push c.children[2].children[0].to_s
199
242
  end
200
243
  end
201
- inner_map_node c, tree, visibility, scope, fqn, stack
202
244
  end
245
+ inner_map_node c, tree, visibility, scope, fqn, stack
203
246
  end
204
247
  end
248
+ @node_stack.shift
205
249
  end
206
250
  stack.pop
207
251
  end
@@ -220,11 +264,13 @@ module Solargraph
220
264
  Source.virtual(filename, code)
221
265
  end
222
266
 
267
+ # @return [Solargraph::ApiMap::Source]
223
268
  def virtual filename, code
224
269
  node, comments = Parser::CurrentRuby.parse_with_comments(code)
225
270
  Source.new(code, node, comments, filename)
226
271
  end
227
272
 
273
+ # @return [Solargraph::ApiMap::Source]
228
274
  def fix filename, code, cursor = nil
229
275
  tries = 0
230
276
  code.gsub!(/\r/, '')
@@ -236,10 +282,6 @@ module Solargraph
236
282
  # incomplete trees resulting from short scripts (e.g., a lone variable
237
283
  # assignment).
238
284
  node, comments = Parser::CurrentRuby.parse_with_comments(tmp + "\n_")
239
- #@node = self.api_map.append_node(node, @comments, filename)
240
- #@parsed = tmp
241
- #@code.freeze
242
- #@parsed.freeze
243
285
  Source.new(code, node, comments, filename)
244
286
  rescue Parser::SyntaxError => e
245
287
  if tries < 10
@@ -247,10 +289,10 @@ module Solargraph
247
289
  if tries == 10 and e.message.include?('token $end')
248
290
  tmp += "\nend"
249
291
  else
250
- if !fixed_cursor and !cursor.nil? and e.message.include?('token $end') and cursor >= 2
292
+ if !fixed_cursor and !cursor.nil? and cursor >= 2 and (e.message.include?('token $end') or tmp[cursor - 1] == '$')
251
293
  fixed_cursor = true
252
294
  spot = cursor - 2
253
- if tmp[cursor - 1] == '.'
295
+ if tmp[cursor - 1] == '.' or tmp[cursor - 1] == '$'
254
296
  repl = ';'
255
297
  else
256
298
  repl = '#'
@@ -9,8 +9,6 @@ module Solargraph
9
9
  autoload :Cache, 'solargraph/api_map/cache'
10
10
 
11
11
  @@source_cache = {}
12
- @@yard_map_cache = {}
13
- @@semaphore = Mutex.new
14
12
 
15
13
  KEYWORDS = [
16
14
  '__ENCODING__', '__LINE__', '__FILE__', 'BEGIN', 'END', 'alias', 'and',
@@ -27,10 +25,6 @@ module Solargraph
27
25
  include NodeMethods
28
26
  include YardMethods
29
27
 
30
- # @todo Temp for testing
31
- attr_reader :new_method_pins
32
- attr_reader :new_ivar_pins
33
-
34
28
  # The root directory of the project. The ApiMap will search here for
35
29
  # additional files to parse and analyze.
36
30
  #
@@ -49,30 +43,42 @@ module Solargraph
49
43
  config = ApiMap::Config.new(@workspace)
50
44
  @workspace_files.concat (config.included - config.excluded)
51
45
  @workspace_files.each do |wf|
52
- @@source_cache[wf] ||= Source.load(wf)
46
+ begin
47
+ @@source_cache[wf] ||= Source.load(wf)
48
+ rescue
49
+ STDERR.puts "Failed to load #{wf}"
50
+ end
53
51
  end
54
52
  end
55
53
  @sources = {}
56
54
  @virtual_source = nil
57
55
  @virtual_filename = nil
58
- @stale = false
59
- @new_method_pins = []
60
- @new_ivar_pins = []
56
+ @stale = true
57
+ refresh
61
58
  end
62
59
 
63
60
  # @return [Solargraph::YardMap]
64
61
  def yard_map
65
- @@semaphore.synchronize {
66
- @@yard_map_cache[[required, workspace]] ||= Solargraph::YardMap.new(required: required, workspace: workspace)
67
- }
62
+ refresh
63
+ if @yard_map.nil? || @yard_map.required != required
64
+ @yard_map = Solargraph::YardMap.new(required: required, workspace: workspace)
65
+ end
66
+ @yard_map
68
67
  end
69
68
 
69
+ # @return [Solargraph::ApiMap::Source]
70
70
  def virtualize filename, code, cursor = nil
71
- @stale = true
71
+ unless @virtual_source.nil? or @virtual_filename == filename or @workspace_files.include?(@virtual_filename)
72
+ eliminate @virtual_filename
73
+ end
74
+ refresh
72
75
  @virtual_filename = filename
73
76
  @virtual_source = Source.fix(filename, code, cursor)
77
+ process_virtual
78
+ @virtual_source
74
79
  end
75
80
 
81
+ # @return [Solargraph::ApiMap::Source]
76
82
  def append_source code, filename
77
83
  virtualize filename, code
78
84
  end
@@ -115,18 +121,26 @@ module Solargraph
115
121
  result
116
122
  end
117
123
 
124
+ # @return [Array<Solargraph::Pin::Constant>]
125
+ def get_constant_pins namespace, root
126
+ fqns = find_fully_qualified_namespace(namespace, root)
127
+ @const_pins[fqns] || []
128
+ end
129
+
130
+ # @return [Array<Solargraph::Suggestion>]
118
131
  def get_constants namespace, root
119
132
  result = []
120
133
  fqns = find_fully_qualified_namespace(namespace, root)
121
134
  cp = @const_pins[fqns]
122
135
  unless cp.nil?
123
136
  cp.each do |pin|
124
- result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
137
+ result.push pin_to_suggestion(pin)
125
138
  end
126
139
  end
127
140
  result.concat yard_map.get_constants(namespace, root)
128
141
  end
129
142
 
143
+ # @return [String]
130
144
  def find_fully_qualified_namespace name, root = '', skip = []
131
145
  refresh
132
146
  return nil if skip.include?(root)
@@ -168,40 +182,51 @@ module Solargraph
168
182
  @namespace_map[fqns] || []
169
183
  end
170
184
 
185
+ # @return [Array<Solargraph::Pin::InstanceVariable>]
186
+ def get_instance_variable_pins(namespace, scope = :instance)
187
+ refresh
188
+ (@ivar_pins[namespace] || []).select{ |pin| pin.scope == scope }
189
+ end
190
+
191
+ # @return [Array<Solargraph::Suggestion>]
171
192
  def get_instance_variables(namespace, scope = :instance)
172
193
  refresh
173
194
  result = []
174
195
  ip = @ivar_pins[namespace]
175
196
  unless ip.nil?
176
197
  ip.select{ |pin| pin.scope == scope }.each do |pin|
177
- #result.push pin.suggestion
178
- result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
198
+ result.push pin_to_suggestion(pin)
179
199
  end
180
200
  end
181
201
  result
182
202
  end
183
203
 
204
+ # @return [Array<Solargraph::Pin::ClassVariable>]
205
+ def get_class_variable_pins(namespace)
206
+ refresh
207
+ @cvar_pins[namespace] || []
208
+ end
209
+
210
+ # @return [Array<Solargraph::Suggestion>]
184
211
  def get_class_variables(namespace)
185
212
  refresh
186
213
  result = []
187
214
  ip = @cvar_pins[namespace]
188
215
  unless ip.nil?
189
216
  ip.each do |pin|
190
- result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
217
+ result.push pin_to_suggestion(pin)
191
218
  end
192
219
  end
193
220
  result
194
221
  end
195
222
 
223
+ # @return [Array<Solargraph::Pin::Symbol>]
196
224
  def get_symbols
197
225
  refresh
198
- result = []
199
- @symbol_pins.each do |s|
200
- result.push s
201
- end
202
- result
226
+ @symbol_pins.uniq(&:label)
203
227
  end
204
228
 
229
+ # @return [String]
205
230
  def get_filename_for(node)
206
231
  @sources.each do |filename, source|
207
232
  return source.filename if source.include?(node)
@@ -209,6 +234,7 @@ module Solargraph
209
234
  nil
210
235
  end
211
236
 
237
+ # @return [String]
212
238
  def infer_instance_variable(var, namespace, scope)
213
239
  refresh
214
240
  pins = @ivar_pins[namespace]
@@ -218,6 +244,7 @@ module Solargraph
218
244
  pin.return_type
219
245
  end
220
246
 
247
+ # @return [String]
221
248
  def infer_class_variable(var, namespace)
222
249
  refresh
223
250
  fqns = find_fully_qualified_namespace(namespace)
@@ -228,11 +255,18 @@ module Solargraph
228
255
  pin.return_type
229
256
  end
230
257
 
258
+ # @return [Array<Solargraph::Suggestion>]
231
259
  def get_global_variables
232
- # TODO: Get them
233
- []
260
+ result = []
261
+ @sources.values.each do |s|
262
+ s.global_variable_pins.each do |p|
263
+ result.push pin_to_suggestion(p)
264
+ end
265
+ end
266
+ result
234
267
  end
235
268
 
269
+ # @return [String]
236
270
  def infer_assignment_node_type node, namespace
237
271
  type = cache.get_assignment_node_type(node, namespace)
238
272
  if type.nil?
@@ -261,6 +295,7 @@ module Solargraph
261
295
  type
262
296
  end
263
297
 
298
+ # @return [String]
264
299
  def infer_signature_type signature, namespace, scope: :class
265
300
  if cache.has_signature_type?(signature, namespace, scope)
266
301
  return cache.get_signature_type(signature, namespace, scope)
@@ -322,16 +357,16 @@ module Solargraph
322
357
  refresh
323
358
  namespace = clean_namespace_string(namespace)
324
359
  meths = []
325
- meths += inner_get_methods(namespace, root, []) #unless has_yardoc?
360
+ meths.concat inner_get_methods(namespace, root, []) #unless has_yardoc?
326
361
  yard_meths = yard_map.get_methods(namespace, root, visibility: visibility)
327
362
  if yard_meths.any?
328
363
  meths.concat yard_meths
329
364
  else
330
365
  type = get_namespace_type(namespace, root)
331
366
  if type == :class
332
- meths += yard_map.get_instance_methods('Class')
367
+ meths.concat yard_map.get_instance_methods('Class')
333
368
  elsif type == :module
334
- meths += yard_map.get_methods('Module')
369
+ meths.concat yard_map.get_methods('Module')
335
370
  end
336
371
  end
337
372
  news = meths.select{|s| s.label == 'new'}
@@ -341,7 +376,7 @@ module Solargraph
341
376
  inits = @method_pins[fqns].select{|p| p.name == 'initialize'}
342
377
  meths -= news unless inits.empty?
343
378
  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)
379
+ meths.push Suggestion.new('new', kind: pin.kind, docstring: pin.docstring, detail: pin.namespace, arguments: pin.parameters, path: pin.path)
345
380
  end
346
381
  end
347
382
  end
@@ -396,6 +431,27 @@ module Solargraph
396
431
  @sources.values
397
432
  end
398
433
 
434
+ def get_path_suggestions path
435
+ result = []
436
+ if path.include?('#')
437
+ # It's an instance method
438
+ parts = path.split('#')
439
+ result = get_instance_methods(parts[0], '', visibility: [:public, :private, :protected]).select{|s| s.label == parts[1]}
440
+ elsif path.include?('.')
441
+ # It's a class method
442
+ parts = path.split('.')
443
+ result = get_instance_methods(parts[0], '', visibility: [:public, :private, :protected]).select{|s| s.label == parts[1]}
444
+ else
445
+ # It's a class or module
446
+ get_namespace_nodes(path).each do |node|
447
+ # TODO This is way underimplemented
448
+ result.push Suggestion.new(path, kind: Suggestion::CLASS)
449
+ end
450
+ result.concat yard_map.objects(path)
451
+ end
452
+ result
453
+ end
454
+
399
455
  private
400
456
 
401
457
  def clear
@@ -409,8 +465,12 @@ module Solargraph
409
465
  def process_maps
410
466
  @sources.clear
411
467
  @workspace_files.each do |f|
412
- @@source_cache[f] ||= Source.load(f)
413
- @sources[f] = @@source_cache[f]
468
+ begin
469
+ @@source_cache[f] ||= Source.load(f)
470
+ @sources[f] = @@source_cache[f]
471
+ rescue
472
+ STDERR.puts "Failed to load #{f}"
473
+ end
414
474
  end
415
475
  cache.clear
416
476
  @ivar_pins = {}
@@ -425,6 +485,7 @@ module Solargraph
425
485
  @namespace_map = {}
426
486
  @namespace_tree = {}
427
487
  @required = []
488
+ @pin_suggestions = {}
428
489
  unless @virtual_source.nil?
429
490
  @sources[@virtual_filename] = @virtual_source
430
491
  end
@@ -442,6 +503,31 @@ module Solargraph
442
503
  @stale = false
443
504
  end
444
505
 
506
+ def process_virtual
507
+ unless @virtual_source.nil?
508
+ cache.clear
509
+ @sources[@virtual_filename] = @virtual_source
510
+ @sources.values.each do |s|
511
+ s.namespace_nodes.each_pair do |k, v|
512
+ @namespace_map[k] ||= []
513
+ @namespace_map[k].concat v
514
+ add_to_namespace_tree k.split('::')
515
+ end
516
+ end
517
+ eliminate @virtual_filename
518
+ map_source @virtual_source
519
+ end
520
+ end
521
+
522
+ def eliminate filename
523
+ [@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values].each do |pinsets|
524
+ pinsets.each do |pins|
525
+ pins.delete_if{|pin| pin.filename == filename}
526
+ end
527
+ end
528
+ #@symbol_pins.delete_if{|pin| pin.filename == filename}
529
+ end
530
+
445
531
  # @param [Solargraph::ApiMap::Source]
446
532
  def map_source source
447
533
  source.method_pins.each do |pin|
@@ -484,7 +570,7 @@ module Solargraph
484
570
  @cache ||= Cache.new
485
571
  end
486
572
 
487
- def inner_get_methods(namespace, root = '', skip = [])
573
+ def inner_get_methods(namespace, root = '', skip = [], visibility = [:public])
488
574
  meths = []
489
575
  return meths if skip.include?(namespace)
490
576
  skip.push namespace
@@ -493,7 +579,14 @@ module Solargraph
493
579
  mn = @method_pins[fqns]
494
580
  unless mn.nil?
495
581
  mn.select{ |pin| pin.scope == :class }.each do |pin|
496
- meths.push Suggestion.pull(pin)
582
+ meths.push pin_to_suggestion(pin)
583
+ end
584
+ end
585
+ if visibility.include?(:public) or visibility.include?(:protected)
586
+ sc = @superclasses[fqns]
587
+ unless sc.nil?
588
+ meths.concat inner_get_methods(sc, fqns, skip, visibility - [:private])
589
+ meths.concat yard_map.get_methods(sc, fqns, visibility: visibility - [:private])
497
590
  end
498
591
  end
499
592
  meths.uniq
@@ -507,13 +600,13 @@ module Solargraph
507
600
  an = @attr_pins[fqns]
508
601
  unless an.nil?
509
602
  an.each do |pin|
510
- meths.push Suggestion.pull(pin)
603
+ meths.push pin_to_suggestion(pin)
511
604
  end
512
605
  end
513
606
  mn = @method_pins[fqns]
514
607
  unless mn.nil?
515
608
  mn.select{|pin| visibility.include?(pin.visibility) and pin.scope == :instance }.each do |pin|
516
- meths.push Suggestion.pull(pin)
609
+ meths.push pin_to_suggestion(pin)
517
610
  end
518
611
  end
519
612
  if visibility.include?(:public) or visibility.include?(:protected)
@@ -561,7 +654,7 @@ module Solargraph
561
654
  cp = @const_pins[fqns]
562
655
  unless cp.nil?
563
656
  cp.each do |pin|
564
- result.push Suggestion.pull(pin, resolve_pin_return_type(pin))
657
+ result.push pin_to_suggestion(pin)
565
658
  end
566
659
  end
567
660
  inc = @namespace_includes[fqns]
@@ -582,85 +675,48 @@ module Solargraph
582
675
  #
583
676
  # @return [String] The fully qualified namespace for the signature's type
584
677
  # or nil if a type could not be determined
585
- def inner_infer_signature_type signature, namespace, scope: :instance
586
- orig = namespace
587
- namespace = clean_namespace_string(namespace)
678
+ def inner_infer_signature_type signature, namespace, scope: :instance, top: true
588
679
  return nil if signature.nil?
589
680
  signature.gsub!(/\.$/, '')
590
- if signature.nil? or signature.empty?
681
+ if signature.empty?
591
682
  if scope == :class
592
- return "#{namespace}#class"
683
+ return "Class<#{namespace}>"
593
684
  else
594
685
  return "#{namespace}"
595
686
  end
596
687
  end
597
- if !namespace.nil? and namespace.end_with?('#class')
598
- return inner_infer_signature_type signature, namespace[0..-7], scope: (scope == :class ? :instance : :class)
599
- end
600
688
  parts = signature.split('.')
601
- type = find_fully_qualified_namespace(namespace)
602
- type ||= ''
603
- top = true
604
- while parts.length > 0 and !type.nil?
605
- p = parts.shift
606
- next if p.empty?
607
- next if !type.nil? and !type.empty? and METHODS_RETURNING_SELF.include?(p)
608
- if top and scope == :class
609
- if p == 'self'
610
- top = false
611
- return "Class<#{type}>" if parts.empty?
612
- sub = inner_infer_signature_type(parts.join('.'), type, scope: :class)
613
- return sub unless sub.to_s == ''
614
- next
615
- end
616
- if p == 'new'
617
- scope = :instance
618
- type = namespace
619
- top = false
620
- next
621
- end
622
- first_class = find_fully_qualified_namespace(p, namespace)
623
- sub = nil
624
- sub = inner_infer_signature_type(parts.join('.'), first_class, scope: :class) unless first_class.nil?
625
- return sub unless sub.to_s == ''
689
+ type = namespace || ''
690
+ while (parts.length > 0)
691
+ part = parts.shift
692
+ if top == true and part == 'self'
693
+ top = false
694
+ next
626
695
  end
627
- if top and scope == :instance and p == 'self'
628
- return type if parts.empty?
629
- sub = infer_signature_type(parts.join('.'), type, scope: :instance)
630
- return sub unless sub.to_s == ''
696
+ cls_match = type.match(/^Class<([A-Za-z0-9_:]*?)>$/)
697
+ if cls_match
698
+ type = cls_match[1]
699
+ scope = :class
631
700
  end
632
- if top and scope == :instance and p == '[]' and !orig.nil?
633
- if orig.start_with?('Array<')
634
- match = orig.match(/Array<([a-z0-9:_]*)/i)[1]
635
- type = match
636
- next
637
- end
638
- end
639
- unless p == 'new' and scope != :instance
701
+ if scope == :class and part == 'new'
702
+ scope = :instance
703
+ elsif !METHODS_RETURNING_SELF.include?(part)
704
+ visibility = [:public]
705
+ visibility.concat [:private, :protected] if top
640
706
  if scope == :instance
641
- visibility = [:public]
642
- visibility.push :private, :protected if top
643
- meths = get_instance_methods(type, visibility: visibility)
644
- meths += get_methods('') if top or type.to_s == ''
707
+ meth = get_instance_methods(namespace, visibility: visibility).select{|s| s.label == part}.first
645
708
  else
646
- meths = get_methods(type)
647
- end
648
- meths.delete_if{ |m| m.insert != p }
649
- return nil if meths.empty?
650
- type = nil
651
- match = meths[0].return_type
652
- unless match.nil?
653
- cleaned = clean_namespace_string(match)
654
- if cleaned.end_with?('#class')
655
- return inner_infer_signature_type(parts.join('.'), cleaned.split('#').first, scope: :class)
656
- else
657
- type = find_fully_qualified_namespace(cleaned)
658
- end
709
+ meth = get_methods(namespace, visibility: visibility).select{|s| s.label == part}.first
659
710
  end
711
+ return nil if meth.nil? or meth.return_type.nil?
712
+ type = meth.return_type
713
+ scope = :instance
660
714
  end
661
- scope = :instance
662
715
  top = false
663
716
  end
717
+ if scope == :class
718
+ type = "Class<#{type}>"
719
+ end
664
720
  type
665
721
  end
666
722
 
@@ -685,13 +741,10 @@ module Solargraph
685
741
  result
686
742
  end
687
743
 
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)
744
+ # @param pin [Solargraph::Pin::Base]
745
+ # @return [Solargraph::Suggestion]
746
+ def pin_to_suggestion pin
747
+ @pin_suggestions[pin] ||= Suggestion.pull(pin)
694
748
  end
695
-
696
749
  end
697
750
  end