solargraph 0.54.1 → 0.54.3

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/lib/solargraph/api_map/cache.rb +10 -1
  4. data/lib/solargraph/api_map/index.rb +167 -0
  5. data/lib/solargraph/api_map/store.rb +48 -120
  6. data/lib/solargraph/api_map.rb +76 -20
  7. data/lib/solargraph/complex_type/type_methods.rb +7 -0
  8. data/lib/solargraph/complex_type/unique_type.rb +21 -1
  9. data/lib/solargraph/complex_type.rb +13 -12
  10. data/lib/solargraph/convention.rb +1 -0
  11. data/lib/solargraph/doc_map.rb +1 -0
  12. data/lib/solargraph/equality.rb +33 -0
  13. data/lib/solargraph/language_server/host/message_worker.rb +23 -6
  14. data/lib/solargraph/language_server/host.rb +12 -11
  15. data/lib/solargraph/language_server/message/base.rb +19 -12
  16. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  17. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  18. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  19. data/lib/solargraph/library.rb +3 -2
  20. data/lib/solargraph/location.rb +7 -0
  21. data/lib/solargraph/parser/node_methods.rb +1 -1
  22. data/lib/solargraph/parser/node_processor.rb +1 -0
  23. data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -3
  24. data/lib/solargraph/parser/parser_gem/node_methods.rb +2 -2
  25. data/lib/solargraph/pin/base.rb +28 -18
  26. data/lib/solargraph/pin/base_variable.rb +3 -2
  27. data/lib/solargraph/pin/block.rb +1 -3
  28. data/lib/solargraph/pin/callable.rb +3 -3
  29. data/lib/solargraph/pin/method.rb +6 -0
  30. data/lib/solargraph/pin/namespace.rb +1 -1
  31. data/lib/solargraph/pin/parameter.rb +2 -1
  32. data/lib/solargraph/position.rb +7 -0
  33. data/lib/solargraph/range.rb +7 -0
  34. data/lib/solargraph/rbs_map/conversions.rb +8 -2
  35. data/lib/solargraph/rbs_map.rb +1 -0
  36. data/lib/solargraph/shell.rb +2 -0
  37. data/lib/solargraph/source/chain/array.rb +1 -1
  38. data/lib/solargraph/source/chain/call.rb +15 -8
  39. data/lib/solargraph/source/chain/hash.rb +5 -0
  40. data/lib/solargraph/source/chain/if.rb +5 -0
  41. data/lib/solargraph/source/chain/link.rb +17 -5
  42. data/lib/solargraph/source/chain/literal.rb +5 -0
  43. data/lib/solargraph/source/chain.rb +33 -19
  44. data/lib/solargraph/source/cursor.rb +2 -1
  45. data/lib/solargraph/source.rb +2 -1
  46. data/lib/solargraph/source_map/clip.rb +1 -1
  47. data/lib/solargraph/type_checker.rb +8 -8
  48. data/lib/solargraph/version.rb +1 -1
  49. data/lib/solargraph/workspace/config.rb +7 -3
  50. data/lib/solargraph/workspace.rb +1 -1
  51. data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
  52. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  53. data/lib/solargraph/yard_map/mapper.rb +1 -0
  54. data/lib/solargraph.rb +1 -0
  55. data/solargraph.gemspec +5 -5
  56. metadata +26 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6619265fc1ba2cab9154e70c5f4a6626999b685d58e26a805ec606d6804f17b
4
- data.tar.gz: cfac32a13734ba9b392d27fcb8da7c76b180f0bf64189d17698b2246ce6e3773
3
+ metadata.gz: bfa5a38942b03bbc954c62e283a07144fd169467e82d29aedd549e0a122ad73e
4
+ data.tar.gz: 9076b8982f53dffe42861873eab5f8fe654c4a2503af67c2fba1880625dee5e6
5
5
  SHA512:
6
- metadata.gz: 8d1d40bf5d19b37f6a2ee8cce73e36027140ae402d27326c15e39a961217153e8b269722503ca0a8a3b592bee50cb6227fffcd812f62a1ec8a1bf94219270eea
7
- data.tar.gz: 627df7fb0bd23b641f0b1a40434a6384def8f32bf318b4f92d243266ee0c3145059adc29ea487dcdc30c914045e5737bca92bff6bd67fd06527f97c2e4690fb8
6
+ metadata.gz: 66cad45bdab9c446a1bb25e29beabae7b6371f36270d23a36a48dd7c5b0347fb3239862b67bc30c4510b82d93ef97dee9656e3f80e242b1c281d17f86da782b6
7
+ data.tar.gz: b34f32af68d295b41ac2ec48d7ec9defb832933c4825b2666791b51bd9050e11d06036b52d6200f4f2897f197aecdb2123d6a5c4256f6c87502b08d8eeda7f5c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## 0.54.3 - May 13, 2025
2
+ - Improve inspect()/desc()/to_s() methods for better debugging output (#913)
3
+ - Fix generic resolution in Hash types (#906)
4
+ - Stop parsing RBS type parameter constraints as the type name (#918)
5
+ - Fix pin inference stack (#922)
6
+ - Refactor pin equality for performance (#925)
7
+ - Improve ApiMap catalog speed by preserving static pin indexes (#930)
8
+ - Update jaro_winkler dependency (#931)
9
+
10
+ ## 0.54.2 - April 28, 2025
11
+ - Resolve generics correctly on mixin inclusion (#898)
12
+ - Pick correct String#split overload (#905)
13
+ - Fix type sent into YARD method (#912)
14
+ - Early CancelRequest handling (#914)
15
+ - Destructure partial yield types (#915)
16
+ - Dependency versions (#916)
17
+
1
18
  ## 0.54.1 - April 26, 2025
2
19
  - Retire more RubyVM-specific code (#797)
3
20
  - Add additional docs for key classes, modules and methods (#802)
@@ -8,7 +8,7 @@ module Solargraph
8
8
  @methods = {}
9
9
  # @type [Hash{(String, Array<String>) => Array<Pin::Base>}]
10
10
  @constants = {}
11
- # @type [Hash{(String, String) => String}]
11
+ # @type [Hash{String => String}]
12
12
  @qualified_namespaces = {}
13
13
  # @type [Hash{String => Pin::Method}]
14
14
  @receiver_definitions = {}
@@ -16,6 +16,15 @@ module Solargraph
16
16
  @clips = {}
17
17
  end
18
18
 
19
+ def to_s
20
+ self.class.to_s
21
+ end
22
+
23
+ # avoid enormous dump
24
+ def inspect
25
+ to_s
26
+ end
27
+
19
28
  # @param fqns [String]
20
29
  # @param scope [Symbol]
21
30
  # @param visibility [Array<Symbol>]
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class ApiMap
5
+ class Index
6
+ # @param pins [Array<Pin::Base>]
7
+ def initialize pins
8
+ catalog pins
9
+ end
10
+
11
+ # @return [Array<Pin::Base>]
12
+ def pins
13
+ @pins ||= []
14
+ end
15
+
16
+ # @return [Hash{String => Array<Pin::Namespace>}]
17
+ def namespace_hash
18
+ @namespace_hash ||= Hash.new { |h, k| h[k] = [] }
19
+ end
20
+
21
+ # @return [Hash{String => Array<Pin::Base>}]
22
+ def pin_class_hash
23
+ @pin_class_hash ||= Hash.new { |h, k| h[k] = [] }
24
+ end
25
+
26
+ # @return [Hash{String => Array<Pin::Base>}]
27
+ def path_pin_hash
28
+ @path_pin_hash ||= Hash.new { |h, k| h[k] = [] }
29
+ end
30
+
31
+ # @generic T
32
+ # @param klass [Class<generic<T>>]
33
+ # @return [Set<generic<T>>]
34
+ def pins_by_class klass
35
+ # @type [Set<Solargraph::Pin::Base>]
36
+ s = Set.new
37
+ @pin_select_cache[klass] ||= pin_class_hash.each_with_object(s) { |(key, o), n| n.merge(o) if key <= klass }
38
+ end
39
+
40
+ # @return [Hash{String => Array<Pin::Reference::Include>}]
41
+ def include_references
42
+ @include_references ||= Hash.new { |h, k| h[k] = [] }
43
+ end
44
+
45
+ # @return [Hash{String => Array<Pin::Reference::Extend>}]
46
+ def extend_references
47
+ @extend_references ||= Hash.new { |h, k| h[k] = [] }
48
+ end
49
+
50
+ # @return [Hash{String => Array<Pin::Reference::Prepend>}]
51
+ def prepend_references
52
+ @prepend_references ||= Hash.new { |h, k| h[k] = [] }
53
+ end
54
+
55
+ # @return [Hash{String => Array<Pin::Reference::Superclass>}]
56
+ def superclass_references
57
+ @superclass_references ||= Hash.new { |h, k| h[k] = [] }
58
+ end
59
+
60
+ # @param pins [Array<Pin::Base>]
61
+ def merge pins
62
+ deep_clone.catalog pins
63
+ end
64
+
65
+ protected
66
+
67
+ attr_writer :pins, :pin_select_cache, :namespace_hash, :pin_class_hash, :path_pin_hash, :include_references,
68
+ :extend_references, :prepend_references, :superclass_references
69
+
70
+ def deep_clone
71
+ Index.allocate.tap do |copy|
72
+ copy.pin_select_cache = {}
73
+ copy.pins = pins.clone
74
+ %i[
75
+ namespace_hash pin_class_hash path_pin_hash include_references extend_references prepend_references
76
+ superclass_references
77
+ ].each do |sym|
78
+ copy.send("#{sym}=", send(sym).clone)
79
+ copy.send(sym)&.transform_values!(&:clone)
80
+ end
81
+ end
82
+ end
83
+
84
+ # @param new_pins [Array<Pin::Base>]
85
+ def catalog new_pins
86
+ @pin_select_cache = {}
87
+ pins.concat new_pins
88
+ set = new_pins.to_set
89
+ set.classify(&:class)
90
+ .map { |k, v| pin_class_hash[k].concat v.to_a }
91
+ set.classify(&:namespace)
92
+ .map { |k, v| namespace_hash[k].concat v.to_a }
93
+ set.classify(&:path)
94
+ .map { |k, v| path_pin_hash[k].concat v.to_a }
95
+ @namespaces = path_pin_hash.keys.compact.to_set
96
+ map_references Pin::Reference::Include, include_references
97
+ map_references Pin::Reference::Prepend, prepend_references
98
+ map_references Pin::Reference::Extend, extend_references
99
+ map_references Pin::Reference::Superclass, superclass_references
100
+ map_overrides
101
+ self
102
+ end
103
+
104
+ # @param klass [Class<Pin::Reference>]
105
+ # @param hash [Hash{String => Array<Pin::Reference>}]
106
+ # @return [void]
107
+ def map_references klass, hash
108
+ pins_by_class(klass).each do |pin|
109
+ store_parametric_reference(hash, pin)
110
+ end
111
+ end
112
+
113
+ # Add references to a map
114
+ #
115
+ # @param hash [Hash{String => Array<Pin::Reference>}]
116
+ # @param reference_pin [Pin::Reference]
117
+ #
118
+ # @return [void]
119
+ def store_parametric_reference(hash, reference_pin)
120
+ referenced_ns = reference_pin.name
121
+ referenced_tag_params = reference_pin.generic_values
122
+ referenced_tag = referenced_ns +
123
+ if referenced_tag_params && referenced_tag_params.length > 0
124
+ "<" + referenced_tag_params.join(', ') + ">"
125
+ else
126
+ ''
127
+ end
128
+ referencing_ns = reference_pin.namespace
129
+ hash[referencing_ns].push referenced_tag
130
+ end
131
+
132
+ # @return [void]
133
+ def map_overrides
134
+ pins_by_class(Pin::Reference::Override).each do |ovr|
135
+ pin = path_pin_hash[ovr.name].first
136
+ next if pin.nil?
137
+ new_pin = if pin.path.end_with?('#initialize')
138
+ path_pin_hash[pin.path.sub(/#initialize/, '.new')].first
139
+ end
140
+ (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
141
+ pin.docstring.delete_tags tag
142
+ new_pin.docstring.delete_tags tag if new_pin
143
+ end
144
+ ovr.tags.each do |tag|
145
+ pin.docstring.add_tag(tag)
146
+ redefine_return_type pin, tag
147
+ if new_pin
148
+ new_pin.docstring.add_tag(tag)
149
+ redefine_return_type new_pin, tag
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ # @param pin [Pin::Method]
156
+ # @param tag [YARD::Tags::Tag]
157
+ # @return [void]
158
+ def redefine_return_type pin, tag
159
+ return unless pin && tag.tag_name == 'return'
160
+ pin.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
161
+ pin.signatures.each do |sig|
162
+ sig.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -7,13 +7,40 @@ module Solargraph
7
7
  # core.
8
8
  #
9
9
  class Store
10
+ # @param static [Enumerable<Pin::Base>]
11
+ # @param dynamic [Enumerable<Pin::Base>]
12
+ def initialize static = [], dynamic = []
13
+ @static_index = Index.new(static)
14
+ @dynamic = dynamic
15
+ @index = @static_index.merge(dynamic)
16
+ end
17
+
10
18
  # @return [Array<Solargraph::Pin::Base>]
11
- attr_reader :pins
19
+ def pins
20
+ index.pins
21
+ end
12
22
 
13
- # @param pins [Enumerable<Solargraph::Pin::Base>]
14
- def initialize pins = []
15
- @pins = pins
16
- index
23
+ # @param static [Enumerable<Pin::Base>]
24
+ # @param dynamic [Enumerable<Pin::Base>]
25
+ def update! static = [], dynamic = []
26
+ # @todo Fix this map
27
+ @fqns_pins_map = nil
28
+ if @static_index.pins == static
29
+ return self if @dynamic == dynamic
30
+ else
31
+ @static_index = Index.new(static)
32
+ end
33
+ @dynamic = dynamic
34
+ @index = @static_index.merge(dynamic)
35
+ self
36
+ end
37
+
38
+ def to_s
39
+ self.class.to_s
40
+ end
41
+
42
+ def inspect
43
+ to_s
17
44
  end
18
45
 
19
46
  # @param fqns [String]
@@ -66,11 +93,7 @@ module Solargraph
66
93
  # @param path [String]
67
94
  # @return [Array<Solargraph::Pin::Base>]
68
95
  def get_path_pins path
69
- path_pin_hash[path] || []
70
- end
71
-
72
- def cacheable_pins
73
- @cacheable_pins ||= pins_by_class(Pin::Namespace) + pins_by_class(Pin::Constant) + pins_by_class(Pin::Method) + pins_by_class(Pin::Reference)
96
+ index.path_pin_hash[path]
74
97
  end
75
98
 
76
99
  # @param fqns [String]
@@ -101,10 +124,10 @@ module Solargraph
101
124
 
102
125
  # @return [Set<String>]
103
126
  def namespaces
104
- @namespaces ||= Set.new
127
+ index.namespaces
105
128
  end
106
129
 
107
- # @return [Enumerable<Solargraph::Pin::Base>]
130
+ # @return [Enumerable<Solargraph::Pin::Namespace>]
108
131
  def namespace_pins
109
132
  pins_by_class(Solargraph::Pin::Namespace)
110
133
  end
@@ -143,18 +166,11 @@ module Solargraph
143
166
  pins_by_class(Pin::Block)
144
167
  end
145
168
 
146
- def inspect
147
- # Avoid insane dumps in specs
148
- to_s
149
- end
150
-
151
169
  # @generic T
152
- # @param klass [Class<T>]
153
- # @return [Set<T>]
170
+ # @param klass [Class<generic<T>>]
171
+ # @return [Set<generic<T>>]
154
172
  def pins_by_class klass
155
- # @type [Set<Solargraph::Pin::Base>]
156
- s = Set.new
157
- @pin_select_cache[klass] ||= @pin_class_hash.each_with_object(s) { |(key, o), n| n.merge(o) if key <= klass }
173
+ index.pins_by_class klass
158
174
  end
159
175
 
160
176
  # @param fqns [String]
@@ -174,6 +190,8 @@ module Solargraph
174
190
 
175
191
  private
176
192
 
193
+ attr_reader :index
194
+
177
195
  # @return [Hash{::Array(String, String) => ::Array<Pin::Namespace>}]
178
196
  def fqns_pins_map
179
197
  @fqns_pins_map ||= Hash.new do |h, (base, name)|
@@ -184,129 +202,39 @@ module Solargraph
184
202
 
185
203
  # @return [Enumerable<Solargraph::Pin::Symbol>]
186
204
  def symbols
187
- pins_by_class(Pin::Symbol)
205
+ index.pins_by_class(Pin::Symbol)
188
206
  end
189
207
 
190
208
  # @return [Hash{String => Array<String>}]
191
209
  def superclass_references
192
- @superclass_references ||= {}
210
+ index.superclass_references
193
211
  end
194
212
 
195
213
  # @return [Hash{String => Array<String>}]
196
214
  def include_references
197
- @include_references ||= {}
215
+ index.include_references
198
216
  end
199
217
 
200
218
  # @return [Hash{String => Array<String>}]
201
219
  def prepend_references
202
- @prepend_references ||= {}
220
+ index.prepend_references
203
221
  end
204
222
 
205
223
  # @return [Hash{String => Array<String>}]
206
224
  def extend_references
207
- @extend_references ||= {}
225
+ index.extend_references
208
226
  end
209
227
 
210
228
  # @param name [String]
211
229
  # @return [Enumerable<Solargraph::Pin::Base>]
212
230
  def namespace_children name
213
- namespace_map[name] || []
214
- end
215
-
216
- # @return [Hash{String => Enumerable<Pin::Base>}
217
- def namespace_map
218
- @namespace_map ||= {}
231
+ return [] unless index.namespace_hash.key?(name)
232
+ index.namespace_hash[name]
219
233
  end
220
234
 
221
235
  # @return [Enumerable<Pin::InstanceVariable>]
222
236
  def all_instance_variables
223
- pins_by_class(Pin::InstanceVariable)
224
- end
225
-
226
- # @return [Hash{String => Array<Pin::Base>}]
227
- def path_pin_hash
228
- @path_pin_hash ||= {}
229
- end
230
-
231
- # Add references to a map
232
- #
233
- # @param h [Hash{String => Pin:Base}]
234
- # @param reference_pin [Pin::Reference]
235
- #
236
- # @return [void]
237
- def store_parametric_reference(h, reference_pin)
238
- referenced_ns = reference_pin.name
239
- referenced_tag_params = reference_pin.generic_values
240
- referenced_tag = referenced_ns +
241
- if referenced_tag_params && referenced_tag_params.length > 0
242
- "<" + referenced_tag_params.join(', ') + ">"
243
- else
244
- ''
245
- end
246
- referencing_ns = reference_pin.namespace
247
- h[referencing_ns] ||= []
248
- h[referencing_ns].push referenced_tag
249
- end
250
-
251
- # @return [void]
252
- def index
253
- set = pins.to_set
254
- @pin_class_hash = set.classify(&:class).transform_values(&:to_a)
255
- # @type [Hash{Class => ::Array<Solargraph::Pin::Base>}]
256
- @pin_select_cache = {}
257
- @namespace_map = set.classify(&:namespace)
258
- @path_pin_hash = set.classify(&:path)
259
- @namespaces = @path_pin_hash.keys.compact.to_set
260
- pins_by_class(Pin::Reference::Include).each do |pin|
261
- store_parametric_reference(include_references, pin)
262
- end
263
- # @todo move the rest of these reference pins over to use
264
- # generic types, adding rbs_map/conversions.rb code to
265
- # populate type parameters and adding related specs ensuring
266
- # the generics get resolved, along with any api_map.rb
267
- # changes needed in
268
- pins_by_class(Pin::Reference::Prepend).each do |pin|
269
- prepend_references[pin.namespace] ||= []
270
- prepend_references[pin.namespace].push pin.name
271
- end
272
- pins_by_class(Pin::Reference::Extend).each do |pin|
273
- extend_references[pin.namespace] ||= []
274
- extend_references[pin.namespace].push pin.name
275
- end
276
- pins_by_class(Pin::Reference::Superclass).each do |pin|
277
- superclass_references[pin.namespace] ||= []
278
- superclass_references[pin.namespace].push pin.name
279
- end
280
- pins_by_class(Pin::Reference::Override).each do |ovr|
281
- pin = get_path_pins(ovr.name).first
282
- next if pin.nil?
283
- new_pin = if pin.path.end_with?('#initialize')
284
- get_path_pins(pin.path.sub(/#initialize/, '.new')).first
285
- end
286
- (ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
287
- pin.docstring.delete_tags tag.to_sym
288
- new_pin.docstring.delete_tags tag.to_sym if new_pin
289
- end
290
- ovr.tags.each do |tag|
291
- pin.docstring.add_tag(tag)
292
- redefine_return_type pin, tag
293
- if new_pin
294
- new_pin.docstring.add_tag(tag)
295
- redefine_return_type new_pin, tag
296
- end
297
- end
298
- end
299
- end
300
-
301
- # @param pin [Pin::Base]
302
- # @param tag [String]
303
- # @return [void]
304
- def redefine_return_type pin, tag
305
- return unless pin && tag.tag_name == 'return'
306
- pin.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
307
- pin.signatures.each do |sig|
308
- sig.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
309
- end
237
+ index.pins_by_class(Pin::InstanceVariable)
310
238
  end
311
239
  end
312
240
  end
@@ -12,6 +12,7 @@ module Solargraph
12
12
  autoload :Cache, 'solargraph/api_map/cache'
13
13
  autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
14
14
  autoload :Store, 'solargraph/api_map/store'
15
+ autoload :Index, 'solargraph/api_map/index'
15
16
 
16
17
  # @return [Array<String>]
17
18
  attr_reader :unresolved_requires
@@ -48,6 +49,15 @@ module Solargraph
48
49
  equality_fields.hash
49
50
  end
50
51
 
52
+ def to_s
53
+ self.class.to_s
54
+ end
55
+
56
+ # avoid enormous dump
57
+ def inspect
58
+ to_s
59
+ end
60
+
51
61
  # @param pins [Array<Pin::Base>]
52
62
  # @return [self]
53
63
  def index pins
@@ -56,7 +66,7 @@ module Solargraph
56
66
  @source_map_hash = {}
57
67
  implicit.clear
58
68
  cache.clear
59
- @store = Store.new(@@core_map.pins + pins)
69
+ store.update! @@core_map.pins, pins
60
70
  self
61
71
  end
62
72
 
@@ -77,6 +87,7 @@ module Solargraph
77
87
  def catalog bench
78
88
  old_api_hash = @source_map_hash&.values&.map(&:api_hash)
79
89
  need_to_uncache = (old_api_hash != bench.source_maps.map(&:api_hash))
90
+ # @todo Work around #to_h problem in current Ruby head (3.5)
80
91
  @source_map_hash = bench.source_maps.map { |s| [s.filename, s] }.to_h
81
92
  pins = bench.source_maps.flat_map(&:pins).flatten
82
93
  implicit.clear
@@ -89,13 +100,16 @@ module Solargraph
89
100
  @unresolved_requires = unresolved_requires
90
101
  need_to_uncache = true
91
102
  end
92
- @store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
103
+ store.update! @@core_map.pins + @doc_map.pins, implicit.pins + pins
93
104
  @cache.clear if need_to_uncache
94
105
 
95
106
  @missing_docs = [] # @todo Implement missing docs
96
107
  self
97
108
  end
98
109
 
110
+ # @todo need to model type def statement in chains as a symbol so
111
+ # that this overload of 'protected' will typecheck @sg-ignore
112
+ # @sg-ignore
99
113
  protected def equality_fields
100
114
  [self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires, @missing_docs]
101
115
  end
@@ -183,7 +197,7 @@ module Solargraph
183
197
 
184
198
  # @return [Array<Solargraph::Pin::Base>]
185
199
  def pins
186
- store.pins
200
+ store.pins.clone.freeze
187
201
  end
188
202
 
189
203
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
@@ -341,8 +355,12 @@ module Solargraph
341
355
  # @param deep [Boolean] True to include superclasses, mixins, etc.
342
356
  # @return [Array<Solargraph::Pin::Method>]
343
357
  def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
358
+ rooted_type = ComplexType.try_parse(rooted_tag)
359
+ fqns = rooted_type.namespace
360
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
344
361
  cached = cache.get_methods(rooted_tag, scope, visibility, deep)
345
362
  return cached.clone unless cached.nil?
363
+ # @type [Array<Solargraph::Pin::Method>]
346
364
  result = []
347
365
  skip = Set.new
348
366
  if rooted_tag == ''
@@ -380,9 +398,12 @@ module Solargraph
380
398
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
381
399
  result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
382
400
  end
383
- resolved = resolve_method_aliases(result, visibility)
384
- cache.set_methods(rooted_tag, scope, visibility, deep, resolved)
385
- resolved
401
+ result = resolve_method_aliases(result, visibility)
402
+ if namespace_pin && rooted_tag != rooted_type.name
403
+ result = result.map { |method_pin| method_pin.resolve_generics(namespace_pin, rooted_type) }
404
+ end
405
+ cache.set_methods(rooted_tag, scope, visibility, deep, result)
406
+ result
386
407
  end
387
408
 
388
409
  # Get an array of method pins for a complex type.
@@ -438,8 +459,13 @@ module Solargraph
438
459
  # @param name [String] Method name to look up
439
460
  # @param scope [Symbol] :instance or :class
440
461
  # @return [Array<Solargraph::Pin::Method>]
441
- def get_method_stack rooted_tag, name, scope: :instance
442
- get_methods(rooted_tag, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
462
+ def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
463
+ rooted_type = ComplexType.parse(rooted_tag)
464
+ fqns = rooted_type.namespace
465
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
466
+ methods = get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
467
+ methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
468
+ methods
443
469
  end
444
470
 
445
471
  # Get an array of all suggestions that match the specified path.
@@ -601,6 +627,7 @@ module Solargraph
601
627
  rooted_type = ComplexType.parse(rooted_tag).force_rooted
602
628
  fqns = rooted_type.namespace
603
629
  fqns_generic_params = rooted_type.all_params
630
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
604
631
  return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
605
632
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
606
633
  return [] if skip.include?(reqstr)
@@ -615,15 +642,7 @@ module Solargraph
615
642
  # Store#get_methods doesn't know about full tags, just
616
643
  # namespaces; resolving the generics in the method pins is this
617
644
  # class' responsibility
618
- raw_methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
619
- namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
620
- methods = if namespace_pin && rooted_tag != fqns
621
- methods = raw_methods.map do |method_pin|
622
- method_pin.resolve_generics(namespace_pin, rooted_type)
623
- end
624
- else
625
- raw_methods
626
- end
645
+ methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
627
646
  result.concat methods
628
647
  if deep
629
648
  if scope == :instance
@@ -768,8 +787,8 @@ module Solargraph
768
787
 
769
788
  # Sort an array of pins to put nil or undefined variables last.
770
789
  #
771
- # @param pins [Enumerable<Solargraph::Pin::Base>]
772
- # @return [Enumerable<Solargraph::Pin::Base>]
790
+ # @param pins [Enumerable<Pin::BaseVariable>]
791
+ # @return [Enumerable<Pin::BaseVariable>]
773
792
  def prefer_non_nil_variables pins
774
793
  result = []
775
794
  nil_pins = []
@@ -809,11 +828,48 @@ module Solargraph
809
828
  name: pin.name,
810
829
  comments: origin.comments,
811
830
  scope: origin.scope,
831
+ # context: pin.context,
812
832
  visibility: origin.visibility,
813
833
  signatures: origin.signatures,
814
- attribute: origin.attribute?
834
+ attribute: origin.attribute?,
835
+ generics: origin.generics,
836
+ return_type: origin.return_type,
815
837
  }
816
838
  Pin::Method.new **args
817
839
  end
840
+
841
+ include Logging
842
+
843
+ private
844
+
845
+ # @param namespace_pin [Pin::Namespace]
846
+ # @param rooted_type [ComplexType]
847
+ # @param pins [Enumerable<Pin::Base>]
848
+ # @return [Array<Pin::Base>]
849
+ def erase_generics(namespace_pin, rooted_type, pins)
850
+ return pins unless should_erase_generics_when_done?(namespace_pin, rooted_type)
851
+
852
+ logger.debug("Erasing generics on namespace_pin=#{namespace_pin} / rooted_type=#{rooted_type}")
853
+ pins.map do |method_pin|
854
+ method_pin.erase_generics(namespace_pin.generics)
855
+ end
856
+ end
857
+
858
+ # @param namespace_pin [Pin::Namespace]
859
+ # @param rooted_type [ComplexType]
860
+ def should_erase_generics_when_done?(namespace_pin, rooted_type)
861
+ has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
862
+ end
863
+
864
+ # @param namespace_pin [Pin::Namespace]
865
+ def has_generics?(namespace_pin)
866
+ namespace_pin && !namespace_pin.generics.empty?
867
+ end
868
+
869
+ # @param namespace_pin [Pin::Namespace]
870
+ # @param rooted_type [ComplexType]
871
+ def can_resolve_generics?(namespace_pin, rooted_type)
872
+ has_generics?(namespace_pin) && !rooted_type.all_params.empty?
873
+ end
818
874
  end
819
875
  end
@@ -129,6 +129,13 @@ module Solargraph
129
129
  end.call
130
130
  end
131
131
 
132
+ def namespace_type
133
+ return ComplexType.parse('::Object') if duck_type?
134
+ return ComplexType.parse('::NilClass') if nil_type?
135
+ return subtypes.first if (name == 'Class' || name == 'Module') && !subtypes.empty?
136
+ self
137
+ end
138
+
132
139
  # @return [String]
133
140
  def rooted_namespace
134
141
  return namespace unless rooted? && can_root_name?(namespace)