solargraph 0.52.0 → 0.53.4

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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +1 -3
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/CHANGELOG.md +53 -0
  6. data/README.md +13 -16
  7. data/SPONSORS.md +1 -7
  8. data/lib/solargraph/api_map/cache.rb +59 -21
  9. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  10. data/lib/solargraph/api_map/store.rb +45 -9
  11. data/lib/solargraph/api_map.rb +178 -113
  12. data/lib/solargraph/bench.rb +3 -2
  13. data/lib/solargraph/cache.rb +29 -5
  14. data/lib/solargraph/complex_type/type_methods.rb +53 -8
  15. data/lib/solargraph/complex_type/unique_type.rb +171 -58
  16. data/lib/solargraph/complex_type.rb +62 -9
  17. data/lib/solargraph/convention.rb +0 -1
  18. data/lib/solargraph/converters/dd.rb +5 -0
  19. data/lib/solargraph/converters/dl.rb +3 -0
  20. data/lib/solargraph/converters/dt.rb +3 -0
  21. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  22. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  23. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  24. data/lib/solargraph/diagnostics.rb +2 -2
  25. data/lib/solargraph/doc_map.rb +171 -0
  26. data/lib/solargraph/gem_pins.rb +64 -0
  27. data/lib/solargraph/language_server/host/cataloger.rb +1 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +15 -5
  30. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  31. data/lib/solargraph/language_server/host/sources.rb +7 -4
  32. data/lib/solargraph/language_server/host.rb +35 -7
  33. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  34. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  35. data/lib/solargraph/language_server/message/initialize.rb +5 -2
  36. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  37. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  38. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  39. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  40. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  41. data/lib/solargraph/library.rb +71 -12
  42. data/lib/solargraph/location.rb +1 -0
  43. data/lib/solargraph/page.rb +6 -0
  44. data/lib/solargraph/parser/comment_ripper.rb +3 -0
  45. data/lib/solargraph/parser/node_methods.rb +47 -8
  46. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  47. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +29 -3
  48. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  49. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +42 -34
  50. data/lib/solargraph/parser/{legacy → parser_gem}/node_methods.rb +201 -29
  51. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  52. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/args_node.rb +4 -1
  53. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  54. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  55. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  56. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  57. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
  58. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  60. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  62. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  63. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  67. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  69. data/lib/solargraph/parser/parser_gem.rb +12 -0
  70. data/lib/solargraph/parser/snippet.rb +2 -0
  71. data/lib/solargraph/parser.rb +8 -11
  72. data/lib/solargraph/pin/base.rb +63 -8
  73. data/lib/solargraph/pin/base_variable.rb +7 -3
  74. data/lib/solargraph/pin/block.rb +26 -38
  75. data/lib/solargraph/pin/closure.rb +17 -2
  76. data/lib/solargraph/pin/common.rb +7 -3
  77. data/lib/solargraph/pin/conversions.rb +33 -3
  78. data/lib/solargraph/pin/documenting.rb +25 -34
  79. data/lib/solargraph/pin/instance_variable.rb +4 -0
  80. data/lib/solargraph/pin/local_variable.rb +13 -1
  81. data/lib/solargraph/pin/method.rb +110 -16
  82. data/lib/solargraph/pin/namespace.rb +16 -10
  83. data/lib/solargraph/pin/parameter.rb +41 -10
  84. data/lib/solargraph/pin/reference/override.rb +2 -2
  85. data/lib/solargraph/pin/reference.rb +8 -0
  86. data/lib/solargraph/pin/search.rb +3 -3
  87. data/lib/solargraph/pin/signature.rb +114 -2
  88. data/lib/solargraph/pin.rb +0 -1
  89. data/lib/solargraph/range.rb +2 -2
  90. data/lib/solargraph/rbs_map/conversions.rb +213 -61
  91. data/lib/solargraph/rbs_map/core_fills.rb +12 -28
  92. data/lib/solargraph/rbs_map/core_map.rb +2 -12
  93. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  94. data/lib/solargraph/rbs_map.rb +24 -12
  95. data/lib/solargraph/shell.rb +62 -59
  96. data/lib/solargraph/source/chain/array.rb +4 -1
  97. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  98. data/lib/solargraph/source/chain/call.rb +95 -26
  99. data/lib/solargraph/source/chain/constant.rb +15 -1
  100. data/lib/solargraph/source/chain/if.rb +23 -0
  101. data/lib/solargraph/source/chain/link.rb +7 -1
  102. data/lib/solargraph/source/chain/or.rb +1 -1
  103. data/lib/solargraph/source/chain/z_super.rb +2 -2
  104. data/lib/solargraph/source/chain.rb +20 -4
  105. data/lib/solargraph/source/change.rb +3 -0
  106. data/lib/solargraph/source/cursor.rb +2 -0
  107. data/lib/solargraph/source/source_chainer.rb +6 -5
  108. data/lib/solargraph/source.rb +15 -16
  109. data/lib/solargraph/source_map/clip.rb +14 -9
  110. data/lib/solargraph/source_map/mapper.rb +10 -0
  111. data/lib/solargraph/source_map.rb +12 -10
  112. data/lib/solargraph/type_checker/checks.rb +10 -2
  113. data/lib/solargraph/type_checker.rb +96 -21
  114. data/lib/solargraph/version.rb +1 -1
  115. data/lib/solargraph/workspace/config.rb +8 -6
  116. data/lib/solargraph/workspace.rb +15 -2
  117. data/lib/solargraph/yard_map/cache.rb +6 -0
  118. data/lib/solargraph/yard_map/helpers.rb +1 -1
  119. data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
  120. data/lib/solargraph/yard_map/to_method.rb +11 -4
  121. data/lib/solargraph/yard_map.rb +0 -292
  122. data/lib/solargraph/yardoc.rb +52 -0
  123. data/lib/solargraph.rb +4 -1
  124. data/solargraph.gemspec +2 -2
  125. metadata +35 -58
  126. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  127. data/lib/solargraph/documentor.rb +0 -76
  128. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  129. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  130. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  131. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  132. data/lib/solargraph/parser/legacy.rb +0 -12
  133. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -151
  134. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -163
  135. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  136. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  137. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  138. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  139. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  140. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  141. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  142. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  143. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  144. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  145. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  146. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  147. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  148. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  149. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  150. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  151. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  152. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  153. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  154. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  155. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  156. data/lib/solargraph/parser/rubyvm.rb +0 -40
  157. data/lib/solargraph/rbs_map/core_signs.rb +0 -33
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
4
- require 'set'
5
3
  require 'pathname'
6
4
  require 'yard'
7
5
  require 'solargraph/yard_tags'
@@ -14,9 +12,6 @@ module Solargraph
14
12
  autoload :Cache, 'solargraph/api_map/cache'
15
13
  autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
16
14
  autoload :Store, 'solargraph/api_map/store'
17
- autoload :BundlerMethods, 'solargraph/api_map/bundler_methods'
18
-
19
- include SourceToYard
20
15
 
21
16
  # @return [Array<String>]
22
17
  attr_reader :unresolved_requires
@@ -59,34 +54,31 @@ module Solargraph
59
54
  # Catalog a bench.
60
55
  #
61
56
  # @param bench [Bench]
57
+ # @return [self]
62
58
  def catalog bench
63
59
  implicit.clear
64
60
  @cache.clear
65
61
  @source_map_hash = bench.source_maps.map { |s| [s.filename, s] }.to_h
66
62
  pins = bench.source_maps.map(&:pins).flatten
67
- external_requires = bench.external_requires
68
63
  source_map_hash.each_value do |map|
69
64
  implicit.merge map.environ
70
65
  end
71
- external_requires.merge implicit.requires
72
- external_requires.merge bench.workspace.config.required
73
- @rbs_maps = external_requires.map { |r| load_rbs_map(r) }
74
- unresolved_requires = @rbs_maps.reject(&:resolved?).map(&:library)
75
- yard_map.change(unresolved_requires, bench.workspace.directory, bench.workspace.source_gems)
76
- @store = Store.new(@@core_map.pins + @rbs_maps.flat_map(&:pins) + yard_map.pins + implicit.pins + pins)
77
- @unresolved_requires = yard_map.unresolved_requires
78
- @missing_docs = yard_map.missing_docs
79
- @rebindable_method_names = nil
80
- store.block_pins.each { |blk| blk.rebind(self) }
66
+ unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).uniq
67
+ @doc_map = DocMap.new(unresolved_requires, []) # @todo Implement gem preferences
68
+ @store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
69
+ @unresolved_requires = @doc_map.unresolved_requires
70
+ @missing_docs = [] # @todo Implement missing docs
81
71
  self
82
72
  end
83
73
 
84
- def core_pins
85
- @@core_map.pins
74
+ # @return [::Array<Gem::Specification>]
75
+ def uncached_gemspecs
76
+ @doc_map&.uncached_gemspecs || []
86
77
  end
87
78
 
88
- def yard_map
89
- @yard_map ||= YardMap.new
79
+ # @return [Array<Pin::Base>]
80
+ def core_pins
81
+ @@core_map.pins
90
82
  end
91
83
 
92
84
  # @param name [String]
@@ -95,6 +87,7 @@ module Solargraph
95
87
  store.named_macros[name]
96
88
  end
97
89
 
90
+ # @return [Set<String>]
98
91
  def required
99
92
  @required ||= Set.new
100
93
  end
@@ -120,7 +113,7 @@ module Solargraph
120
113
  # @return [SourceMap::Clip]
121
114
  def clip_at filename, position
122
115
  position = Position.normalize(position)
123
- SourceMap::Clip.new(self, cursor_at(filename, position))
116
+ clip(cursor_at(filename, position))
124
117
  end
125
118
 
126
119
  # Create an ApiMap with a workspace in the specified directory.
@@ -137,20 +130,26 @@ module Solargraph
137
130
  api_map
138
131
  end
139
132
 
140
- # @return [Enumerable<Solargraph::Pin::Base>]
141
- def pins
142
- store.pins
133
+ # Create an ApiMap with a workspace in the specified directory and cache
134
+ # any missing gems.
135
+ #
136
+ # @param directory [String]
137
+ # @return [ApiMap]
138
+ def self.load_with_cache directory
139
+ api_map = load(directory)
140
+ return api_map if api_map.uncached_gemspecs.empty?
141
+
142
+ api_map.uncached_gemspecs.each do |gemspec|
143
+ Solargraph.logger.info "Caching #{gemspec.name} #{gemspec.version}..."
144
+ pins = GemPins.build(gemspec)
145
+ Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
146
+ end
147
+ load(directory)
143
148
  end
144
149
 
145
- def rebindable_method_names
146
- @rebindable_method_names ||= begin
147
- # result = yard_map.rebindable_method_names
148
- result = ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec', 'define_method'].to_set
149
- source_maps.each do |map|
150
- result.merge map.rebindable_method_names
151
- end
152
- result
153
- end
150
+ # @return [Array<Solargraph::Pin::Base>]
151
+ def pins
152
+ store.pins
154
153
  end
155
154
 
156
155
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
@@ -206,22 +205,48 @@ module Solargraph
206
205
  store.fqns_pins(qualify(namespace, context))
207
206
  end
208
207
 
209
- # Get a fully qualified namespace name. This method will start the search
210
- # in the specified context until it finds a match for the name.
208
+ # Determine fully qualified tag for a given tag used inside the
209
+ # definition of another tag ("context"). This method will start
210
+ # the search in the specified context until it finds a match for
211
+ # the tag.
212
+ #
213
+ # Does not recurse into qualifying the type parameters, but
214
+ # returns any which were passed in unchanged.
215
+ #
216
+ # @param tag [String, nil] The namespace to
217
+ # match, complete with generic parameters set to appropriate
218
+ # values if available
219
+ # @param context_tag [String] The context in which the tag was
220
+ # referenced; start from here to resolve the name
221
+ # @return [String, nil] fully qualified tag
222
+ def qualify tag, context_tag = ''
223
+ return tag if ['self', nil].include?(tag)
224
+ context_type = ComplexType.parse(context_tag)
225
+ type = ComplexType.parse(tag)
226
+ fqns = qualify_namespace(type.rooted_namespace, context_type.rooted_namespace)
227
+ return nil if fqns.nil?
228
+ fqns + type.substring
229
+ end
230
+
231
+ # Determine fully qualified namespace for a given namespace used
232
+ # inside the definition of another tag ("context"). This method
233
+ # will start the search in the specified context until it finds a
234
+ # match for the namespace.
211
235
  #
212
- # @param namespace [String, nil] The namespace to match
213
- # @param context [String] The context to search
214
- # @return [String, nil]
215
- def qualify namespace, context = ''
216
- return namespace if ['self', nil].include?(namespace)
217
- cached = cache.get_qualified_namespace(namespace, context)
236
+ # @param namespace [String, nil] The namespace to
237
+ # match
238
+ # @param context_namespace [String] The context namespace in which the
239
+ # tag was referenced; start from here to resolve the name
240
+ # @return [String, nil] fully qualified namespace
241
+ def qualify_namespace(namespace, context_namespace = '')
242
+ cached = cache.get_qualified_namespace(namespace, context_namespace)
218
243
  return cached.clone unless cached.nil?
219
244
  result = if namespace.start_with?('::')
220
245
  inner_qualify(namespace[2..-1], '', Set.new)
221
246
  else
222
- inner_qualify(namespace, context, Set.new)
247
+ inner_qualify(namespace, context_namespace, Set.new)
223
248
  end
224
- cache.set_qualified_namespace(namespace, context, result)
249
+ cache.set_qualified_namespace(namespace, context_namespace, result)
225
250
  result
226
251
  end
227
252
 
@@ -247,7 +272,7 @@ module Solargraph
247
272
  # Get an array of class variable pins for a namespace.
248
273
  #
249
274
  # @param namespace [String] A fully qualified namespace
250
- # @return [Array<Solargraph::Pin::ClassVariable>]
275
+ # @return [Enumerable<Solargraph::Pin::ClassVariable>]
251
276
  def get_class_variable_pins(namespace)
252
277
  prefer_non_nil_variables(store.get_class_variables(namespace))
253
278
  end
@@ -264,32 +289,53 @@ module Solargraph
264
289
 
265
290
  # Get an array of methods available in a particular context.
266
291
  #
267
- # @param fqns [String] The fully qualified namespace to search for methods
292
+ # @param rooted_tag [String] The fully qualified namespace to search for methods
268
293
  # @param scope [Symbol] :class or :instance
269
294
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
270
295
  # @param deep [Boolean] True to include superclasses, mixins, etc.
271
296
  # @return [Array<Solargraph::Pin::Method>]
272
- def get_methods fqns, scope: :instance, visibility: [:public], deep: true
273
- cached = cache.get_methods(fqns, scope, visibility, deep)
297
+ def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
298
+ cached = cache.get_methods(rooted_tag, scope, visibility, deep)
274
299
  return cached.clone unless cached.nil?
275
300
  result = []
276
301
  skip = Set.new
277
- if fqns == ''
302
+ if rooted_tag == ''
278
303
  # @todo Implement domains
279
304
  implicit.domains.each do |domain|
280
305
  type = ComplexType.try_parse(domain)
281
306
  next if type.undefined?
282
307
  result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
283
308
  end
284
- result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
285
- result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
309
+ result.concat inner_get_methods(rooted_tag, :class, visibility, deep, skip)
310
+ result.concat inner_get_methods(rooted_tag, :instance, visibility, deep, skip)
286
311
  result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
287
312
  else
288
- result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
313
+ result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
314
+ unless %w[Class Class<Class>].include?(rooted_tag)
315
+ result.map! do |pin|
316
+ next pin unless pin.path == 'Class#new'
317
+ init_pin = get_method_stack(rooted_tag, 'initialize').first
318
+ next pin unless init_pin
319
+
320
+ type = ComplexType.try_parse(ComplexType.try_parse(rooted_tag).namespace)
321
+ Pin::Method.new(
322
+ name: 'new',
323
+ scope: :class,
324
+ location: init_pin.location,
325
+ parameters: init_pin.parameters,
326
+ signatures: init_pin.signatures.map { |sig| sig.proxy(type) },
327
+ return_type: type,
328
+ comments: init_pin.comments,
329
+ closure: init_pin.closure
330
+ # @todo Hack to force TypeChecker#internal_or_core?
331
+ ).tap { |pin| pin.source = :rbs }
332
+ end
333
+ end
289
334
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
335
+ result.concat inner_get_methods('Module', scope, visibility, deep, skip)
290
336
  end
291
337
  resolved = resolve_method_aliases(result, visibility)
292
- cache.set_methods(fqns, scope, visibility, deep, resolved)
338
+ cache.set_methods(rooted_tag, scope, visibility, deep, resolved)
293
339
  resolved
294
340
  end
295
341
 
@@ -327,27 +373,27 @@ module Solargraph
327
373
  visibility.push :protected
328
374
  visibility.push :private if internal
329
375
  end
330
- result.merge get_methods(type.namespace, scope: type.scope, visibility: visibility)
376
+ result.merge get_methods(type.tag, scope: type.scope, visibility: visibility)
331
377
  end
332
378
  end
333
379
  end
334
380
  result.to_a
335
381
  end
336
382
 
337
- # Get a stack of method pins for a method name in a namespace. The order
338
- # of the pins corresponds to the ancestry chain, with highest precedence
339
- # first.
383
+ # Get a stack of method pins for a method name in a potentially
384
+ # parameterized namespace. The order of the pins corresponds to
385
+ # the ancestry chain, with highest precedence first.
340
386
  #
341
387
  # @example
342
388
  # api_map.get_method_stack('Subclass', 'method_name')
343
389
  # #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]
344
390
  #
345
- # @param fqns [String]
346
- # @param name [String]
391
+ # @param rooted_tag [String] Parameterized namespace, fully qualified
392
+ # @param name [String] Method name to look up
347
393
  # @param scope [Symbol] :instance or :class
348
394
  # @return [Array<Solargraph::Pin::Method>]
349
- def get_method_stack fqns, name, scope: :instance
350
- get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
395
+ def get_method_stack rooted_tag, name, scope: :instance
396
+ get_methods(rooted_tag, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
351
397
  end
352
398
 
353
399
  # Get an array of all suggestions that match the specified path.
@@ -355,7 +401,7 @@ module Solargraph
355
401
  # @deprecated Use #get_path_pins instead.
356
402
  #
357
403
  # @param path [String] The path to find
358
- # @return [Array<Solargraph::Pin::Base>]
404
+ # @return [Enumerable<Solargraph::Pin::Base>]
359
405
  def get_path_suggestions path
360
406
  return [] if path.nil?
361
407
  resolve_method_aliases store.get_path_pins(path)
@@ -364,7 +410,7 @@ module Solargraph
364
410
  # Get an array of pins that match the specified path.
365
411
  #
366
412
  # @param path [String]
367
- # @return [Array<Pin::Base>]
413
+ # @return [Enumerable<Pin::Base>]
368
414
  def get_path_pins path
369
415
  get_path_suggestions(path)
370
416
  end
@@ -377,15 +423,9 @@ module Solargraph
377
423
  # @param query [String] The text to match
378
424
  # @return [Array<String>]
379
425
  def search query
380
- rake_yard(store)
381
- found = []
382
- code_object_paths.each do |k|
383
- if (found.empty? || (query.include?('.') || query.include?('#')) || !(k.include?('.') || k.include?('#'))) &&
384
- k.downcase.include?(query.downcase)
385
- found.push k
386
- end
387
- end
388
- found
426
+ pins.map(&:path)
427
+ .compact
428
+ .select { |path| path.downcase.include?(query.downcase) }
389
429
  end
390
430
 
391
431
  # Get YARD documentation for the specified path.
@@ -393,13 +433,13 @@ module Solargraph
393
433
  # @example
394
434
  # api_map.document('String#split')
395
435
  #
436
+ # @todo This method is likely superfluous. Calling get_path_pins directly
437
+ # should be sufficient.
438
+ #
396
439
  # @param path [String] The path to find
397
- # @return [Array<YARD::CodeObjects::Base>]
440
+ # @return [Enumerable<Pin::Base>]
398
441
  def document path
399
- rake_yard(store)
400
- docs = []
401
- docs.push code_object_at(path) unless code_object_at(path).nil?
402
- docs
442
+ get_path_pins(path)
403
443
  end
404
444
 
405
445
  # Get an array of all symbols in the workspace that match the query.
@@ -425,6 +465,10 @@ module Solargraph
425
465
  # @return [SourceMap::Clip]
426
466
  def clip cursor
427
467
  raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)
468
+
469
+ # @todo Clip caches are disabled pending resolution of a stale cache bug
470
+ # cache.get_clip(cursor) ||
471
+ # SourceMap::Clip.new(self, cursor).tap { |clip| cache.set_clip(cursor, clip) }
428
472
  SourceMap::Clip.new(self, cursor)
429
473
  end
430
474
 
@@ -476,13 +520,15 @@ module Solargraph
476
520
  false
477
521
  end
478
522
 
479
- # Check if the host class includes the specified module.
523
+ # Check if the host class includes the specified module, ignoring
524
+ # type parameters used.
525
+ #
526
+ # @param host_ns [String] The class namesapce (no type parameters)
527
+ # @param module_ns [String] The module namespace (no type parameters)
480
528
  #
481
- # @param host [String] The class
482
- # @param mod [String] The module
483
529
  # @return [Boolean]
484
- def type_include?(host, mod)
485
- store.get_includes(host).include?(mod)
530
+ def type_include?(host_ns, module_ns)
531
+ store.get_includes(host_ns).map { |inc_tag| ComplexType.parse(inc_tag).name }.include?(module_ns)
486
532
  end
487
533
 
488
534
  private
@@ -492,14 +538,6 @@ module Solargraph
492
538
  # @return [Hash{String => SourceMap}]
493
539
  attr_reader :source_map_hash
494
540
 
495
- # @param library [String]
496
- # @return [RbsMap]
497
- def load_rbs_map library
498
- # map = RbsMap.load(library)
499
- # return map if map.resolved?
500
- RbsMap::StdlibMap.load(library)
501
- end
502
-
503
541
  # @return [ApiMap::Store]
504
542
  def store
505
543
  @store ||= Store.new
@@ -508,15 +546,19 @@ module Solargraph
508
546
  # @return [Solargraph::ApiMap::Cache]
509
547
  attr_reader :cache
510
548
 
511
- # @param fqns [String] A fully qualified namespace
549
+ # @param rooted_tag [String] A fully qualified namespace, with
550
+ # generic parameter values if applicable
512
551
  # @param scope [Symbol] :class or :instance
513
552
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
514
553
  # @param deep [Boolean]
515
554
  # @param skip [Set<String>]
516
555
  # @param no_core [Boolean] Skip core classes if true
517
556
  # @return [Array<Pin::Base>]
518
- def inner_get_methods fqns, scope, visibility, deep, skip, no_core = false
519
- return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module|Kernel)$/
557
+ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
558
+ rooted_type = ComplexType.parse(rooted_tag)
559
+ fqns = rooted_type.namespace
560
+ fqns_generic_params = rooted_type.all_params
561
+ return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
520
562
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
521
563
  return [] if skip.include?(reqstr)
522
564
  skip.add reqstr
@@ -527,12 +569,33 @@ module Solargraph
527
569
  result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
528
570
  end
529
571
  end
530
- result.concat store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
572
+ # Store#get_methods doesn't know about full tags, just
573
+ # namespaces; resolving the generics in the method pins is this
574
+ # class' responsibility
575
+ raw_methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
576
+ namespace_pin = store.get_path_pins(fqns).select{|p| p.is_a?(Pin::Namespace)}.first
577
+ methods = if rooted_tag != fqns
578
+ methods = raw_methods.map do |method_pin|
579
+ method_pin.resolve_generics(namespace_pin, rooted_type)
580
+ end
581
+ else
582
+ raw_methods
583
+ end
584
+ result.concat methods
531
585
  if deep
532
586
  if scope == :instance
533
- store.get_includes(fqns).reverse.each do |im|
534
- fqim = qualify(im, fqns)
535
- result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
587
+ store.get_includes(fqns).reverse.each do |include_tag|
588
+ rooted_include_tag = qualify(include_tag, rooted_tag)
589
+ # Ensure the types returned by the included methods are
590
+ # relative to the generics passed to the include. e.g.,
591
+ # Foo<String> might include Enumerable<String>
592
+ #
593
+ # @todo perform the same translation in the other areas
594
+ # here after adding a spec and handling things correctly
595
+ # in ApiMap::Store and RbsMap::Conversions
596
+ resolved_include_type = ComplexType.parse(rooted_include_tag).resolve_generics(namespace_pin, rooted_type)
597
+ methods = inner_get_methods(resolved_include_type.tag, scope, visibility, deep, skip, true)
598
+ result.concat methods
536
599
  end
537
600
  fqsc = qualify_superclass(fqns)
538
601
  unless fqsc.nil?
@@ -596,6 +659,8 @@ module Solargraph
596
659
  qualify namespace, context.split('::')[0..-2].join('::')
597
660
  end
598
661
 
662
+ # @param fqsub [String]
663
+ # @return [String, nil]
599
664
  def qualify_superclass fqsub
600
665
  sup = store.get_superclass(fqsub)
601
666
  return nil if sup.nil?
@@ -605,11 +670,12 @@ module Solargraph
605
670
  qualify(sup, parts.join('::'))
606
671
  end
607
672
 
608
- # @param name [String]
609
- # @param root [String]
610
- # @param skip [Set<String>]
611
- # @return [String, nil]
673
+ # @param name [String] Namespace to fully qualify
674
+ # @param root [String] The context to search
675
+ # @param skip [Set<String>] Contexts already searched
676
+ # @return [String, nil] Fully qualified ("rooted") namespace
612
677
  def inner_qualify name, root, skip
678
+ return name if name == ComplexType::GENERIC_TAG_NAME
613
679
  return nil if name.nil?
614
680
  return nil if skip.include?(root)
615
681
  skip.add root
@@ -659,8 +725,8 @@ module Solargraph
659
725
 
660
726
  # Sort an array of pins to put nil or undefined variables last.
661
727
  #
662
- # @param pins [Array<Solargraph::Pin::Base>]
663
- # @return [Array<Solargraph::Pin::Base>]
728
+ # @param pins [Enumerable<Solargraph::Pin::Base>]
729
+ # @return [Enumerable<Solargraph::Pin::Base>]
664
730
  def prefer_non_nil_variables pins
665
731
  result = []
666
732
  nil_pins = []
@@ -674,27 +740,26 @@ module Solargraph
674
740
  result + nil_pins
675
741
  end
676
742
 
677
- # @param pins [Array<Pin::Base>]
678
- # @param visibility [Array<Symbol>]
743
+ # @param pins [Enumerable<Pin::Base>]
744
+ # @param visibility [Enumerable<Symbol>]
679
745
  # @return [Array<Pin::Base>]
680
746
  def resolve_method_aliases pins, visibility = [:public, :private, :protected]
681
- result = []
682
- pins.each do |pin|
747
+ pins.map do |pin|
683
748
  resolved = resolve_method_alias(pin)
684
- next if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
685
- result.push resolved
686
- end
687
- result
749
+ next pin if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
750
+ resolved
751
+ end.compact
688
752
  end
689
753
 
690
754
  # @param pin [Pin::MethodAlias, Pin::Base]
691
755
  # @return [Pin::Method]
692
756
  def resolve_method_alias pin
693
- return pin if !pin.is_a?(Pin::MethodAlias) || @method_alias_stack.include?(pin.path)
757
+ return pin unless pin.is_a?(Pin::MethodAlias)
758
+ return nil if @method_alias_stack.include?(pin.path)
694
759
  @method_alias_stack.push pin.path
695
- origin = get_method_stack(pin.full_context.namespace, pin.original, scope: pin.scope).first
760
+ origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope).first
696
761
  @method_alias_stack.pop
697
- return pin if origin.nil?
762
+ return nil if origin.nil?
698
763
  args = {
699
764
  location: pin.location,
700
765
  closure: pin.closure,
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
3
 
5
4
  module Solargraph
6
5
  # A container of source maps and workspace data to be cataloged in an ApiMap.
@@ -21,7 +20,9 @@ module Solargraph
21
20
  def initialize source_maps: [], workspace: Workspace.new, external_requires: []
22
21
  @source_maps = source_maps.to_set
23
22
  @workspace = workspace
24
- @external_requires = external_requires.to_set
23
+ @external_requires = external_requires.reject { |path| workspace.would_require?(path) }
24
+ .compact
25
+ .to_set
25
26
  end
26
27
  end
27
28
  end
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'rbs'
2
3
 
3
4
  module Solargraph
4
5
  module Cache
@@ -14,7 +15,7 @@ module Solargraph
14
15
  File.join(Dir.home, '.cache', 'solargraph')
15
16
  end
16
17
 
17
- # The working directory for the current Ruby and Solargraph versions.
18
+ # The working directory for the current Ruby, RBS, and Solargraph versions.
18
19
  #
19
20
  # @return [String]
20
21
  def work_dir
@@ -23,9 +24,21 @@ module Solargraph
23
24
  File.join(base_dir, "ruby-#{RUBY_VERSION}", "rbs-#{RBS::VERSION}", "solargraph-#{Solargraph::VERSION}")
24
25
  end
25
26
 
27
+ # Append the given path to the current cache directory (`work_dir`).
28
+ #
29
+ # @example
30
+ # Cache.join('date-3.4.1.ser')
31
+ #
32
+ # @param path [Array<String>]
33
+ # @return [String]
34
+ def join *path
35
+ File.join(work_dir, *path)
36
+ end
37
+
38
+ # @param path [Array<String>]
26
39
  # @return [Array<Solargraph::Pin::Base>, nil]
27
40
  def load *path
28
- file = File.join(work_dir, *path)
41
+ file = join(*path)
29
42
  return nil unless File.file?(file)
30
43
  Marshal.load(File.read(file, mode: 'rb'))
31
44
  rescue StandardError => e
@@ -34,17 +47,28 @@ module Solargraph
34
47
  nil
35
48
  end
36
49
 
37
- # @return [Boolean]
50
+ def exist? *path
51
+ File.file? join(*path)
52
+ end
53
+
54
+ # @param path [Array<String>]
55
+ # @param pins [Array<Pin::Base>]
56
+ # @return [void]
38
57
  def save *path, pins
39
- return false if pins.empty?
40
58
  file = File.join(work_dir, *path)
41
59
  base = File.dirname(file)
42
60
  FileUtils.mkdir_p base unless File.directory?(base)
43
61
  ser = Marshal.dump(pins)
44
62
  File.write file, ser, mode: 'wb'
45
- true
46
63
  end
47
64
 
65
+ # @return [void]
66
+ # @param path [Array<String>]
67
+ def uncache *path
68
+ FileUtils.rm_rf File.join(work_dir, *path), secure: true
69
+ end
70
+
71
+ # @return [void]
48
72
  def clear
49
73
  FileUtils.rm_rf base_dir, secure: true
50
74
  end