solargraph 0.55.4 → 0.56.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +2 -0
  3. data/.github/workflows/typecheck.yml +2 -0
  4. data/.gitignore +2 -0
  5. data/CHANGELOG.md +17 -0
  6. data/README.md +13 -3
  7. data/lib/solargraph/api_map/index.rb +23 -15
  8. data/lib/solargraph/api_map/store.rb +2 -1
  9. data/lib/solargraph/api_map.rb +53 -27
  10. data/lib/solargraph/complex_type/type_methods.rb +5 -1
  11. data/lib/solargraph/complex_type/unique_type.rb +7 -0
  12. data/lib/solargraph/convention/base.rb +3 -3
  13. data/lib/solargraph/convention.rb +3 -3
  14. data/lib/solargraph/doc_map.rb +200 -43
  15. data/lib/solargraph/gem_pins.rb +53 -38
  16. data/lib/solargraph/language_server/host.rb +9 -1
  17. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -0
  18. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  19. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  20. data/lib/solargraph/library.rb +6 -3
  21. data/lib/solargraph/location.rb +13 -0
  22. data/lib/solargraph/parser/parser_gem/class_methods.rb +5 -8
  23. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -2
  24. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +2 -2
  25. data/lib/solargraph/pin/base.rb +268 -24
  26. data/lib/solargraph/pin/base_variable.rb +9 -8
  27. data/lib/solargraph/pin/callable.rb +69 -0
  28. data/lib/solargraph/pin/closure.rb +12 -0
  29. data/lib/solargraph/pin/local_variable.rb +8 -5
  30. data/lib/solargraph/pin/method.rb +134 -17
  31. data/lib/solargraph/pin/parameter.rb +43 -6
  32. data/lib/solargraph/pin/signature.rb +38 -0
  33. data/lib/solargraph/pin_cache.rb +185 -0
  34. data/lib/solargraph/position.rb +9 -0
  35. data/lib/solargraph/range.rb +9 -0
  36. data/lib/solargraph/rbs_map/conversions.rb +19 -8
  37. data/lib/solargraph/rbs_map/core_map.rb +31 -9
  38. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  39. data/lib/solargraph/rbs_map.rb +74 -17
  40. data/lib/solargraph/shell.rb +16 -18
  41. data/lib/solargraph/source_map.rb +0 -17
  42. data/lib/solargraph/version.rb +1 -1
  43. data/lib/solargraph/views/_method.erb +10 -10
  44. data/lib/solargraph/views/_namespace.erb +3 -3
  45. data/lib/solargraph/views/document.erb +10 -10
  46. data/lib/solargraph/workspace.rb +15 -5
  47. data/lib/solargraph/yardoc.rb +6 -9
  48. data/lib/solargraph.rb +10 -12
  49. data/rbs_collection.yaml +19 -0
  50. data/solargraph.gemspec +1 -0
  51. metadata +19 -7
  52. data/lib/solargraph/cache.rb +0 -77
@@ -33,6 +33,70 @@ module Solargraph
33
33
  @anon_splat = anon_splat
34
34
  end
35
35
 
36
+ # @return [Array<Pin::Signature>]
37
+ def combine_all_signature_pins(*signature_pins)
38
+ by_arity = {}
39
+ signature_pins.each do |signature_pin|
40
+ by_arity[signature_pin.arity] ||= []
41
+ by_arity[signature_pin.arity] << signature_pin
42
+ end
43
+ by_arity.transform_values! do |same_arity_pins|
44
+ same_arity_pins.reduce(nil) do |memo, signature|
45
+ next signature if memo.nil?
46
+ memo.combine_with(signature)
47
+ end
48
+ end
49
+ by_arity.values.flatten
50
+ end
51
+
52
+ # @param other [Pin::Method]
53
+ # @return [Symbol]
54
+ def combine_visibility(other)
55
+ if dodgy_visibility_source? && !other.dodgy_visibility_source?
56
+ other.visibility
57
+ elsif other.dodgy_visibility_source? && !dodgy_visibility_source?
58
+ visibility
59
+ else
60
+ assert_same(other, :visibility)
61
+ end
62
+ end
63
+
64
+ # @param other [Pin::Method]
65
+ # @return [Array<Pin::Signature>]
66
+ def combine_signatures(other)
67
+ all_undefined = signatures.all? { |sig| sig.return_type.undefined? }
68
+ other_all_undefined = other.signatures.all? { |sig| sig.return_type.undefined? }
69
+ if all_undefined && !other_all_undefined
70
+ other.signatures
71
+ elsif other_all_undefined && !all_undefined
72
+ signatures
73
+ else
74
+ combine_all_signature_pins(*signatures, *other.signatures)
75
+ end
76
+ end
77
+
78
+ def combine_with(other, attrs = {})
79
+ sigs = combine_signatures(other)
80
+ parameters = if sigs.length > 0
81
+ [].freeze
82
+ else
83
+ choose(other, :parameters).clone.freeze
84
+ end
85
+ new_attrs = {
86
+ visibility: combine_visibility(other),
87
+ explicit: explicit? || other.explicit?,
88
+ block: combine_blocks(other),
89
+ node: choose_node(other, :node),
90
+ attribute: prefer_rbs_location(other, :attribute?),
91
+ parameters: parameters,
92
+ signatures: sigs,
93
+ anon_splat: assert_same(other, :anon_splat?),
94
+ return_type: nil # pulled from signatures on first call
95
+ }.merge(attrs)
96
+ super(other, new_attrs)
97
+ end
98
+
99
+ # @param other [Pin::Method]
36
100
  def == other
37
101
  super && other.node == node
38
102
  end
@@ -44,11 +108,24 @@ module Solargraph
44
108
  sig.transform_types(&transform)
45
109
  end
46
110
  m.block = block&.transform_types(&transform)
47
- m.signature_help = nil
48
- m.documentation = nil
111
+ m.reset_generated!
49
112
  m
50
113
  end
51
114
 
115
+ # @return [void]
116
+ def reset_generated!
117
+ super
118
+ unless signatures.empty?
119
+ return_type = nil
120
+ @block = :undefined
121
+ parameters = []
122
+ end
123
+ block&.reset_generated!
124
+ @signatures&.each(&:reset_generated!)
125
+ signature_help = nil
126
+ documentation = nil
127
+ end
128
+
52
129
  def all_rooted?
53
130
  super && parameters.all?(&:all_rooted?) && (!block || block&.all_rooted?) && signatures.all?(&:all_rooted?)
54
131
  end
@@ -57,8 +134,7 @@ module Solargraph
57
134
  # @return [Pin::Method]
58
135
  def with_single_signature(signature)
59
136
  m = proxy signature.return_type
60
- m.signature_help = nil
61
- m.documentation = nil
137
+ m.reset_generated!
62
138
  # @todo populating the single parameters/return_type/block
63
139
  # arguments here seems to be needed for some specs to pass,
64
140
  # even though we have a signature with the same information.
@@ -123,7 +199,7 @@ module Solargraph
123
199
  )
124
200
  end
125
201
  yield_return_type = ComplexType.try_parse(*yieldreturn_tags.flat_map(&:types))
126
- block = Signature.new(generics: generics, parameters: yield_parameters, return_type: yield_return_type, source: source)
202
+ block = Signature.new(generics: generics, parameters: yield_parameters, return_type: yield_return_type, source: source, closure: self)
127
203
  end
128
204
  signature = Signature.new(generics: generics, parameters: parameters, return_type: return_type, block: block, closure: self, source: source)
129
205
  block.closure = signature if block
@@ -142,6 +218,14 @@ module Solargraph
142
218
  end
143
219
  end
144
220
 
221
+ # @param return_type [ComplexType]
222
+ # @return [self]
223
+ def proxy_with_signatures return_type
224
+ out = proxy return_type
225
+ out.signatures = out.signatures.map { |sig| sig.proxy return_type }
226
+ out
227
+ end
228
+
145
229
  # @return [String, nil]
146
230
  def detail
147
231
  # This property is not cached in an instance variable because it can
@@ -193,12 +277,26 @@ module Solargraph
193
277
  @path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}"
194
278
  end
195
279
 
280
+ # @return [String]
281
+ def method_name
282
+ name
283
+ end
284
+
196
285
  def typify api_map
286
+ logger.debug { "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context.rooted_tags}, return_type=#{return_type.rooted_tags}) - starting" }
197
287
  decl = super
198
- return decl unless decl.undefined?
288
+ unless decl.undefined?
289
+ logger.debug { "Method#typify(self=#{self}, binder=#{binder}, closure=#{closure}, context=#{context}) => #{decl.rooted_tags.inspect} - decl found" }
290
+ return decl
291
+ end
199
292
  type = see_reference(api_map) || typify_from_super(api_map)
200
- return type.qualify(api_map, namespace) unless type.nil?
201
- name.end_with?('?') ? ComplexType::BOOLEAN : ComplexType::UNDEFINED
293
+ logger.debug { "Method#typify(self=#{self}) - type=#{type&.rooted_tags.inspect}" }
294
+ unless type.nil?
295
+ qualified = type.qualify(api_map, namespace)
296
+ logger.debug { "Method#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
297
+ return qualified
298
+ end
299
+ super
202
300
  end
203
301
 
204
302
  # @sg-ignore
@@ -285,14 +383,6 @@ module Solargraph
285
383
  attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map)
286
384
  end
287
385
 
288
- # @param pin [Pin::Method]
289
- def try_merge! pin
290
- return false unless super
291
- @node = pin.node
292
- @resolved_ref_tag = false
293
- true
294
- end
295
-
296
386
  # @return [::Array<Pin::Method>]
297
387
  def overloads
298
388
  # Ignore overload tags with nil parameters. If it's not an array, the
@@ -313,6 +403,7 @@ module Solargraph
313
403
  source: :overloads
314
404
  )
315
405
  end,
406
+ closure: self,
316
407
  return_type: ComplexType.try_parse(*tag.docstring.tags(:return).flat_map(&:types)),
317
408
  source: :overloads,
318
409
  )
@@ -347,6 +438,12 @@ module Solargraph
347
438
  self
348
439
  end
349
440
 
441
+ # @param api_map [ApiMap]
442
+ # @return [Array<Pin::Method>]
443
+ def rest_of_stack api_map
444
+ api_map.get_method_stack(method_namespace, method_name, scope: scope).reject { |pin| pin.path == path }
445
+ end
446
+
350
447
  protected
351
448
 
352
449
  attr_writer :block
@@ -355,6 +452,21 @@ module Solargraph
355
452
 
356
453
  attr_writer :documentation
357
454
 
455
+ def dodgy_visibility_source?
456
+ # as of 2025-03-12, the RBS generator used for
457
+ # e.g. activesupport did not understand 'private' markings
458
+ # inside 'class << self' blocks, but YARD did OK at it
459
+ source == :rbs && scope == :class && type_location&.filename&.include?('generated') && return_type.undefined? ||
460
+ # YARD's RBS generator seems to miss a lot of should-be protected instance methods
461
+ source == :rbs && scope == :instance && namespace.start_with?('YARD::') ||
462
+ # private on attr_readers seems to be broken in Prism's auto-generator script
463
+ source == :rbs && scope == :instance && namespace.start_with?('Prism::') ||
464
+ # The RBS for the RBS gem itself seems to use private as a
465
+ # 'is this a public API' concept, more aggressively than the
466
+ # actual code. Let's respect that and ignore the actual .rb file.
467
+ source == :yardoc && scope == :instance && namespace.start_with?('RBS::')
468
+ end
469
+
358
470
  private
359
471
 
360
472
  # @param name [String]
@@ -415,10 +527,15 @@ module Solargraph
415
527
  resolve_reference match[1], api_map
416
528
  end
417
529
 
530
+ # @return [String]
531
+ def method_namespace
532
+ namespace
533
+ end
534
+
418
535
  # @param api_map [ApiMap]
419
536
  # @return [ComplexType, nil]
420
537
  def typify_from_super api_map
421
- stack = api_map.get_method_stack(namespace, name, scope: scope).reject { |pin| pin.path == path }
538
+ stack = rest_of_stack api_map
422
539
  return nil if stack.empty?
423
540
  stack.each do |pin|
424
541
  return pin.return_type unless pin.return_type.undefined?
@@ -21,6 +21,23 @@ module Solargraph
21
21
  @decl = decl
22
22
  end
23
23
 
24
+ def type_location
25
+ super || closure&.type_location
26
+ end
27
+
28
+ def location
29
+ super || closure&.type_location
30
+ end
31
+
32
+ def combine_with(other, attrs={})
33
+ new_attrs = {
34
+ decl: assert_same(other, :decl),
35
+ presence: choose(other, :presence),
36
+ asgn_code: choose(other, :asgn_code),
37
+ }.merge(attrs)
38
+ super(other, new_attrs)
39
+ end
40
+
24
41
  def keyword?
25
42
  [:kwarg, :kwoptarg].include?(decl)
26
43
  end
@@ -29,6 +46,32 @@ module Solargraph
29
46
  decl == :kwrestarg || (assignment && [:HASH, :hash].include?(assignment.type))
30
47
  end
31
48
 
49
+ def needs_consistent_name?
50
+ keyword?
51
+ end
52
+
53
+ # @return [String]
54
+ def arity_decl
55
+ name = (self.name || '(anon)')
56
+ type = (return_type&.to_rbs || 'untyped')
57
+ case decl
58
+ when :arg
59
+ ""
60
+ when :optarg
61
+ "?"
62
+ when :kwarg
63
+ "#{name}:"
64
+ when :kwoptarg
65
+ "?#{name}:"
66
+ when :restarg
67
+ "*"
68
+ when :kwrestarg
69
+ "**"
70
+ else
71
+ "(unknown decl: #{decl})"
72
+ end
73
+ end
74
+
32
75
  def arg?
33
76
  decl == :arg
34
77
  end
@@ -132,12 +175,6 @@ module Solargraph
132
175
  tag.text
133
176
  end
134
177
 
135
- # @param pin [Pin::Parameter]
136
- def try_merge! pin
137
- return false unless super && closure == pin.closure
138
- true
139
- end
140
-
141
178
  private
142
179
 
143
180
  # @return [YARD::Tags::Tag, nil]
@@ -16,6 +16,44 @@ module Solargraph
16
16
  def identity
17
17
  @identity ||= "signature#{object_id}"
18
18
  end
19
+
20
+ attr_writer :closure
21
+
22
+ def dodgy_return_type_source?
23
+ super || closure&.dodgy_return_type_source?
24
+ end
25
+
26
+ def type_location
27
+ super || closure&.type_location
28
+ end
29
+
30
+ def location
31
+ super || closure&.location
32
+ end
33
+
34
+ def typify api_map
35
+ if return_type.defined?
36
+ qualified = return_type.qualify(api_map, closure.namespace)
37
+ logger.debug { "Signature#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
38
+ return qualified
39
+ end
40
+ return ComplexType::UNDEFINED if closure.nil?
41
+ return ComplexType::UNDEFINED unless closure.is_a?(Pin::Method)
42
+ method_stack = closure.rest_of_stack api_map
43
+ logger.debug { "Signature#typify(self=#{self}) - method_stack: #{method_stack}" }
44
+ method_stack.each do |pin|
45
+ sig = pin.signatures.find { |s| s.arity == self.arity }
46
+ next unless sig
47
+ unless sig.return_type.undefined?
48
+ qualified = sig.return_type.qualify(api_map, closure.namespace)
49
+ logger.debug { "Signature#typify(self=#{self}) => #{qualified.rooted_tags.inspect}" }
50
+ return qualified
51
+ end
52
+ end
53
+ out = super
54
+ logger.debug { "Signature#typify(self=#{self}) => #{out}" }
55
+ out
56
+ end
19
57
  end
20
58
  end
21
59
  end
@@ -0,0 +1,185 @@
1
+ require 'fileutils'
2
+ require 'rbs'
3
+
4
+ module Solargraph
5
+ module PinCache
6
+ class << self
7
+ include Logging
8
+
9
+ # The base directory where cached YARD documentation and serialized pins are serialized
10
+ #
11
+ # @return [String]
12
+ def base_dir
13
+ # The directory is not stored in a variable so it can be overridden
14
+ # in specs.
15
+ ENV['SOLARGRAPH_CACHE'] ||
16
+ (ENV['XDG_CACHE_HOME'] ? File.join(ENV['XDG_CACHE_HOME'], 'solargraph') : nil) ||
17
+ File.join(Dir.home, '.cache', 'solargraph')
18
+ end
19
+
20
+ # The working directory for the current Ruby, RBS, and Solargraph versions.
21
+ #
22
+ # @return [String]
23
+ def work_dir
24
+ # The directory is not stored in a variable so it can be overridden
25
+ # in specs.
26
+ File.join(base_dir, "ruby-#{RUBY_VERSION}", "rbs-#{RBS::VERSION}", "solargraph-#{Solargraph::VERSION}")
27
+ end
28
+
29
+ def yardoc_path gemspec
30
+ File.join(base_dir, "yard-#{YARD::VERSION}", "#{gemspec.name}-#{gemspec.version}.yardoc")
31
+ end
32
+
33
+ def stdlib_path
34
+ File.join(work_dir, 'stdlib')
35
+ end
36
+
37
+ def stdlib_require_path require
38
+ File.join(stdlib_path, "#{require}.ser")
39
+ end
40
+
41
+ def deserialize_stdlib_require require
42
+ load(stdlib_require_path(require))
43
+ end
44
+
45
+ def serialize_stdlib_require require, pins
46
+ save(stdlib_require_path(require), pins)
47
+ end
48
+
49
+ def core_path
50
+ File.join(work_dir, 'core.ser')
51
+ end
52
+
53
+ def deserialize_core
54
+ load(core_path)
55
+ end
56
+
57
+ def serialize_core pins
58
+ save(core_path, pins)
59
+ end
60
+
61
+ def yard_gem_path gemspec
62
+ File.join(work_dir, 'yard', "#{gemspec.name}-#{gemspec.version}.ser")
63
+ end
64
+
65
+ def deserialize_yard_gem(gemspec)
66
+ load(yard_gem_path(gemspec))
67
+ end
68
+
69
+ def serialize_yard_gem(gemspec, pins)
70
+ save(yard_gem_path(gemspec), pins)
71
+ end
72
+
73
+ def has_yard?(gemspec)
74
+ exist?(yard_gem_path(gemspec))
75
+ end
76
+
77
+ def rbs_collection_path(gemspec, hash)
78
+ File.join(work_dir, 'rbs', "#{gemspec.name}-#{gemspec.version}-#{hash || 0}.ser")
79
+ end
80
+
81
+ def rbs_collection_path_prefix(gemspec)
82
+ File.join(work_dir, 'rbs', "#{gemspec.name}-#{gemspec.version}-")
83
+ end
84
+
85
+ def deserialize_rbs_collection_gem(gemspec, hash)
86
+ load(rbs_collection_path(gemspec, hash))
87
+ end
88
+
89
+ def serialize_rbs_collection_gem(gemspec, hash, pins)
90
+ save(rbs_collection_path(gemspec, hash), pins)
91
+ end
92
+
93
+ def combined_path(gemspec, hash)
94
+ File.join(work_dir, 'combined', "#{gemspec.name}-#{gemspec.version}-#{hash || 0}.ser")
95
+ end
96
+
97
+ def combined_path_prefix(gemspec)
98
+ File.join(work_dir, 'combined', "#{gemspec.name}-#{gemspec.version}-")
99
+ end
100
+
101
+ def serialize_combined_gem(gemspec, hash, pins)
102
+ save(combined_path(gemspec, hash), pins)
103
+ end
104
+
105
+ def deserialize_combined_gem gemspec, hash
106
+ load(combined_path(gemspec, hash))
107
+ end
108
+
109
+ def has_rbs_collection?(gemspec, hash)
110
+ exist?(rbs_collection_path(gemspec, hash))
111
+ end
112
+
113
+ def uncache_core
114
+ uncache(core_path)
115
+ end
116
+
117
+ def uncache_stdlib
118
+ uncache(stdlib_path)
119
+ end
120
+
121
+ def uncache_gem(gemspec, out: nil)
122
+ uncache(yardoc_path(gemspec), out: out)
123
+ uncache_by_prefix(rbs_collection_path_prefix(gemspec), out: out)
124
+ uncache(yard_gem_path(gemspec), out: out)
125
+ uncache_by_prefix(combined_path_prefix(gemspec), out: out)
126
+ end
127
+
128
+ # @return [void]
129
+ def clear
130
+ FileUtils.rm_rf base_dir, secure: true
131
+ end
132
+
133
+ private
134
+
135
+ # @param file [String]
136
+ # @return [Array<Solargraph::Pin::Base>, nil]
137
+ def load file
138
+ return nil unless File.file?(file)
139
+ Marshal.load(File.read(file, mode: 'rb'))
140
+ rescue StandardError => e
141
+ Solargraph.logger.warn "Failed to load cached file #{file}: [#{e.class}] #{e.message}"
142
+ FileUtils.rm_f file
143
+ nil
144
+ end
145
+
146
+ def exist? *path
147
+ File.file? join(*path)
148
+ end
149
+
150
+ # @param path [Array<String>]
151
+ # @param pins [Array<Pin::Base>]
152
+ # @return [void]
153
+ def save file, pins
154
+ base = File.dirname(file)
155
+ FileUtils.mkdir_p base unless File.directory?(base)
156
+ ser = Marshal.dump(pins)
157
+ File.write file, ser, mode: 'wb'
158
+ logger.debug { "Cache#save: Saved #{pins.length} pins to #{file}" }
159
+ end
160
+
161
+ # @return [void]
162
+ # @param path_segments [Array<String>]
163
+ def uncache *path_segments, out: nil
164
+ path = File.join(*path_segments)
165
+ if File.exist?(path)
166
+ FileUtils.rm_rf path, secure: true
167
+ out.puts "Clearing pin cache in #{path}" unless out.nil?
168
+ end
169
+ end
170
+
171
+ # @return [void]
172
+ # @param path_segments [Array<String>]
173
+ def uncache_by_prefix *path_segments, out: nil
174
+ path = File.join(*path_segments)
175
+ glob = "#{path}*"
176
+ out.puts "Clearing pin cache in #{glob}" unless out.nil?
177
+ Dir.glob(glob).each do |file|
178
+ next unless File.file?(file)
179
+ FileUtils.rm_rf file, secure: true
180
+ out.puts "Clearing pin cache in #{file}" unless out.nil?
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -26,6 +26,15 @@ module Solargraph
26
26
  [line, character]
27
27
  end
28
28
 
29
+ def <=>(other)
30
+ return nil unless other.is_a?(Position)
31
+ if line == other.line
32
+ character <=> other.character
33
+ else
34
+ line <=> other.line
35
+ end
36
+ end
37
+
29
38
  # Get a hash of the position. This representation is suitable for use in
30
39
  # the language server protocol.
31
40
  #
@@ -24,6 +24,15 @@ module Solargraph
24
24
  [start, ending]
25
25
  end
26
26
 
27
+ def <=>(other)
28
+ return nil unless other.is_a?(Range)
29
+ if start == other.start
30
+ ending <=> other.ending
31
+ else
32
+ start <=> other.start
33
+ end
34
+ end
35
+
27
36
  # Get a hash of the range. This representation is suitable for use in
28
37
  # the language server protocol.
29
38
  #
@@ -6,7 +6,7 @@ module Solargraph
6
6
  class RbsMap
7
7
  # Functions for converting RBS declarations to Solargraph pins
8
8
  #
9
- module Conversions
9
+ class Conversions
10
10
  include Logging
11
11
 
12
12
  # A container for tracking the current context of the RBS conversion
@@ -22,11 +22,17 @@ module Solargraph
22
22
  end
23
23
  end
24
24
 
25
- # @return [Array<Pin::Base>]
26
- def pins
27
- @pins ||= []
25
+ def initialize(loader:)
26
+ @loader = loader
27
+ @pins = []
28
+ load_environment_to_pins(loader)
28
29
  end
29
30
 
31
+ attr_reader :loader
32
+
33
+ # @return [Array<Pin::Base>]
34
+ attr_reader :pins
35
+
30
36
  private
31
37
 
32
38
  # @return [Hash{String => RBS::AST::Declarations::TypeAlias}]
@@ -39,6 +45,10 @@ module Solargraph
39
45
  def load_environment_to_pins(loader)
40
46
  environment = RBS::Environment.from_loader(loader).resolve_type_names
41
47
  cursor = pins.length
48
+ if environment.declarations.empty?
49
+ Solargraph.logger.info "No RBS declarations found in environment for core_root #{loader.core_root.inspect}, libraries #{loader.libs} and directories #{loader.dirs}"
50
+ return
51
+ end
42
52
  environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
43
53
  end
44
54
 
@@ -488,7 +498,7 @@ module Solargraph
488
498
  type_location: location_decl_to_pin_location(decl.location),
489
499
  closure: closure,
490
500
  comments: decl.comment&.string,
491
- scope: :instance,
501
+ scope: final_scope,
492
502
  attribute: true,
493
503
  visibility: visibility,
494
504
  source: :rbs
@@ -512,7 +522,7 @@ module Solargraph
512
522
  closure: closure,
513
523
  parameters: [],
514
524
  comments: decl.comment&.string,
515
- scope: :instance,
525
+ scope: final_scope,
516
526
  attribute: true,
517
527
  visibility: visibility,
518
528
  source: :rbs
@@ -628,11 +638,13 @@ module Solargraph
628
638
  # @param closure [Pin::Namespace]
629
639
  # @return [void]
630
640
  def alias_to_pin decl, closure
641
+ final_scope = decl.singleton? ? :class : :instance
631
642
  pins.push Solargraph::Pin::MethodAlias.new(
632
643
  name: decl.new_name.to_s,
633
644
  type_location: location_decl_to_pin_location(decl.location),
634
645
  original: decl.old_name.to_s,
635
646
  closure: closure,
647
+ scope: final_scope,
636
648
  source: :rbs,
637
649
  )
638
650
  end
@@ -683,8 +695,7 @@ module Solargraph
683
695
  if type.is_a?(RBS::Types::Optional)
684
696
  "#{other_type_to_tag(type.type)}, nil"
685
697
  elsif type.is_a?(RBS::Types::Bases::Any)
686
- # @todo Not sure what to do with Any yet
687
- 'BasicObject'
698
+ 'undefined'
688
699
  elsif type.is_a?(RBS::Types::Bases::Bool)
689
700
  'Boolean'
690
701
  elsif type.is_a?(RBS::Types::Tuple)
@@ -5,24 +5,46 @@ module Solargraph
5
5
  # Ruby core pins
6
6
  #
7
7
  class CoreMap
8
- include Conversions
8
+
9
+ def resolved?
10
+ true
11
+ end
9
12
 
10
13
  FILLS_DIRECTORY = File.join(File.dirname(__FILE__), '..', '..', '..', 'rbs', 'fills')
11
14
 
12
- def initialize
13
- cache = Cache.load('core.ser')
15
+ def initialize; end
16
+
17
+ def pins
18
+ return @pins if @pins
19
+
20
+ @pins = []
21
+ cache = PinCache.deserialize_core
14
22
  if cache
15
- pins.replace cache
23
+ @pins.replace cache
16
24
  else
17
- loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
18
25
  loader.add(path: Pathname(FILLS_DIRECTORY))
19
- load_environment_to_pins(loader)
20
- pins.concat RbsMap::CoreFills::ALL
26
+ @pins = conversions.pins
27
+ @pins.concat RbsMap::CoreFills::ALL
21
28
  processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
22
- pins.replace processed
29
+ @pins.replace processed
23
30
 
24
- Cache.save('core.ser', pins)
31
+ PinCache.serialize_core @pins
25
32
  end
33
+ @pins
34
+ end
35
+
36
+ def loader
37
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
38
+ end
39
+
40
+ private
41
+
42
+ def loader
43
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
44
+ end
45
+
46
+ def conversions
47
+ @conversions ||= Conversions.new(loader: loader)
26
48
  end
27
49
  end
28
50
  end