solargraph 0.47.2 → 0.53.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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +137 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +60 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +60 -12
  14. data/lib/solargraph/api_map.rb +171 -99
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +61 -12
  18. data/lib/solargraph/complex_type/unique_type.rb +193 -16
  19. data/lib/solargraph/complex_type.rb +113 -10
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +171 -0
  30. data/lib/solargraph/gem_pins.rb +64 -0
  31. data/lib/solargraph/language_server/host/cataloger.rb +2 -1
  32. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  33. data/lib/solargraph/language_server/host/dispatch.rb +15 -5
  34. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  35. data/lib/solargraph/language_server/host/sources.rb +7 -4
  36. data/lib/solargraph/language_server/host.rb +50 -26
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +13 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  52. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  53. data/lib/solargraph/library.rb +124 -37
  54. data/lib/solargraph/location.rb +1 -0
  55. data/lib/solargraph/page.rb +6 -0
  56. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  57. data/lib/solargraph/parser/node_methods.rb +47 -7
  58. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  59. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  60. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  62. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  64. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  65. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  69. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  77. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  81. data/lib/solargraph/parser/parser_gem.rb +12 -0
  82. data/lib/solargraph/parser/region.rb +1 -1
  83. data/lib/solargraph/parser/snippet.rb +2 -0
  84. data/lib/solargraph/parser.rb +9 -10
  85. data/lib/solargraph/pin/base.rb +69 -11
  86. data/lib/solargraph/pin/base_variable.rb +8 -4
  87. data/lib/solargraph/pin/block.rb +21 -28
  88. data/lib/solargraph/pin/closure.rb +17 -2
  89. data/lib/solargraph/pin/common.rb +7 -3
  90. data/lib/solargraph/pin/conversions.rb +34 -8
  91. data/lib/solargraph/pin/delegated_method.rb +97 -0
  92. data/lib/solargraph/pin/documenting.rb +25 -34
  93. data/lib/solargraph/pin/instance_variable.rb +4 -0
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +270 -16
  96. data/lib/solargraph/pin/namespace.rb +17 -1
  97. data/lib/solargraph/pin/parameter.rb +52 -17
  98. data/lib/solargraph/pin/reference/override.rb +2 -2
  99. data/lib/solargraph/pin/reference.rb +8 -0
  100. data/lib/solargraph/pin/search.rb +4 -4
  101. data/lib/solargraph/pin/signature.rb +143 -0
  102. data/lib/solargraph/pin.rb +2 -1
  103. data/lib/solargraph/range.rb +4 -6
  104. data/lib/solargraph/rbs_map/conversions.rb +601 -0
  105. data/lib/solargraph/rbs_map/core_fills.rb +47 -0
  106. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  107. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  108. data/lib/solargraph/rbs_map.rb +84 -0
  109. data/lib/solargraph/shell.rb +69 -48
  110. data/lib/solargraph/source/chain/array.rb +32 -0
  111. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  112. data/lib/solargraph/source/chain/call.rb +125 -61
  113. data/lib/solargraph/source/chain/constant.rb +15 -1
  114. data/lib/solargraph/source/chain/if.rb +23 -0
  115. data/lib/solargraph/source/chain/link.rb +8 -2
  116. data/lib/solargraph/source/chain/or.rb +1 -1
  117. data/lib/solargraph/source/chain/z_super.rb +3 -3
  118. data/lib/solargraph/source/chain.rb +44 -14
  119. data/lib/solargraph/source/change.rb +3 -0
  120. data/lib/solargraph/source/cursor.rb +2 -0
  121. data/lib/solargraph/source/source_chainer.rb +8 -5
  122. data/lib/solargraph/source.rb +18 -19
  123. data/lib/solargraph/source_map/clip.rb +30 -23
  124. data/lib/solargraph/source_map/mapper.rb +20 -5
  125. data/lib/solargraph/source_map.rb +28 -13
  126. data/lib/solargraph/type_checker/checks.rb +10 -2
  127. data/lib/solargraph/type_checker.rb +201 -98
  128. data/lib/solargraph/version.rb +1 -1
  129. data/lib/solargraph/views/environment.erb +2 -2
  130. data/lib/solargraph/workspace/config.rb +14 -11
  131. data/lib/solargraph/workspace.rb +28 -17
  132. data/lib/solargraph/yard_map/cache.rb +6 -0
  133. data/lib/solargraph/yard_map/helpers.rb +1 -1
  134. data/lib/solargraph/yard_map/mapper/to_method.rb +18 -5
  135. data/lib/solargraph/yard_map/mapper.rb +1 -1
  136. data/lib/solargraph/yard_map/to_method.rb +11 -4
  137. data/lib/solargraph/yard_map.rb +1 -443
  138. data/lib/solargraph/yard_tags.rb +20 -0
  139. data/lib/solargraph/yardoc.rb +52 -0
  140. data/lib/solargraph.rb +8 -6
  141. data/solargraph.gemspec +19 -8
  142. metadata +162 -98
  143. data/.travis.yml +0 -19
  144. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  145. data/lib/solargraph/compat.rb +0 -37
  146. data/lib/solargraph/convention/rspec.rb +0 -30
  147. data/lib/solargraph/documentor.rb +0 -76
  148. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  149. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  150. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  151. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  152. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  153. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  154. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  155. data/lib/solargraph/parser/legacy.rb +0 -12
  156. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  157. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  158. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  159. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  160. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  161. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  162. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  163. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  164. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  166. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  167. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  168. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  169. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  171. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  172. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  173. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  174. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  176. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  177. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  178. data/lib/solargraph/parser/rubyvm.rb +0 -40
  179. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  180. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  181. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  182. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  183. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  184. data/lib/yard-solargraph.rb +0 -33
  185. data/yardoc/2.2.2.tar.gz +0 -0
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
4
- require 'set'
5
3
  require 'pathname'
6
4
  require 'yard'
7
- require 'yard-solargraph'
5
+ require 'solargraph/yard_tags'
8
6
 
9
7
  module Solargraph
10
8
  # An aggregate provider for information about workspaces, sources, gems, and
@@ -14,13 +12,12 @@ 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
23
18
 
19
+ @@core_map = RbsMap::CoreMap.new
20
+
24
21
  # @return [Array<String>]
25
22
  attr_reader :missing_docs
26
23
 
@@ -40,7 +37,7 @@ module Solargraph
40
37
  @source_map_hash = {}
41
38
  implicit.clear
42
39
  cache.clear
43
- @store = Store.new(yard_map.pins + pins)
40
+ @store = Store.new(@@core_map.pins + pins)
44
41
  self
45
42
  end
46
43
 
@@ -57,32 +54,41 @@ module Solargraph
57
54
  # Catalog a bench.
58
55
  #
59
56
  # @param bench [Bench]
57
+ # @return [self]
60
58
  def catalog bench
61
59
  implicit.clear
62
60
  @cache.clear
63
61
  @source_map_hash = bench.source_maps.map { |s| [s.filename, s] }.to_h
64
62
  pins = bench.source_maps.map(&:pins).flatten
65
- external_requires = bench.external_requires
66
63
  source_map_hash.each_value do |map|
67
64
  implicit.merge map.environ
68
65
  end
69
- external_requires.merge implicit.requires
70
- external_requires.merge bench.workspace.config.required
71
- yard_map.change(external_requires, bench.workspace.directory, bench.workspace.source_gems)
72
- @store = Store.new(yard_map.pins + implicit.pins + pins)
73
- @unresolved_requires = yard_map.unresolved_requires
74
- @missing_docs = yard_map.missing_docs
75
- @rebindable_method_names = nil
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
76
71
  store.block_pins.each { |blk| blk.rebind(self) }
77
72
  self
78
73
  end
79
74
 
75
+ # @return [::Array<Gem::Specification>]
76
+ def uncached_gemspecs
77
+ @doc_map&.uncached_gemspecs || []
78
+ end
79
+
80
+ # @return [Array<Pin::Base>]
81
+ def core_pins
82
+ @@core_map.pins
83
+ end
84
+
80
85
  # @param name [String]
81
86
  # @return [YARD::Tags::MacroDirective, nil]
82
87
  def named_macro name
83
88
  store.named_macros[name]
84
89
  end
85
90
 
91
+ # @return [Set<String>]
86
92
  def required
87
93
  @required ||= Set.new
88
94
  end
@@ -108,7 +114,7 @@ module Solargraph
108
114
  # @return [SourceMap::Clip]
109
115
  def clip_at filename, position
110
116
  position = Position.normalize(position)
111
- SourceMap::Clip.new(self, cursor_at(filename, position))
117
+ clip(cursor_at(filename, position))
112
118
  end
113
119
 
114
120
  # Create an ApiMap with a workspace in the specified directory.
@@ -125,21 +131,28 @@ module Solargraph
125
131
  api_map
126
132
  end
127
133
 
134
+ # Create an ApiMap with a workspace in the specified directory and cache
135
+ # any missing gems.
136
+ #
137
+ # @param directory [String]
138
+ # @return [ApiMap]
139
+ def self.load_with_cache directory
140
+ api_map = load(directory)
141
+ return api_map if api_map.uncached_gemspecs.empty?
142
+
143
+ api_map.uncached_gemspecs.each do |gemspec|
144
+ Solargraph.logger.info "Caching #{gemspec.name} #{gemspec.version}..."
145
+ pins = GemPins.build(gemspec)
146
+ Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
147
+ end
148
+ load(directory)
149
+ end
150
+
128
151
  # @return [Array<Solargraph::Pin::Base>]
129
152
  def pins
130
153
  store.pins
131
154
  end
132
155
 
133
- def rebindable_method_names
134
- @rebindable_method_names ||= begin
135
- result = yard_map.rebindable_method_names
136
- source_maps.each do |map|
137
- result.merge map.rebindable_method_names
138
- end
139
- result
140
- end
141
- end
142
-
143
156
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
144
157
  #
145
158
  # @return [Enumerable<Solargraph::Pin::Keyword>]
@@ -186,22 +199,55 @@ module Solargraph
186
199
  result
187
200
  end
188
201
 
189
- # Get a fully qualified namespace name. This method will start the search
190
- # in the specified context until it finds a match for the name.
202
+ # @param namespace [String]
203
+ # @param context [String]
204
+ # @return [Array<Pin::Namespace>]
205
+ def get_namespace_pins namespace, context
206
+ store.fqns_pins(qualify(namespace, context))
207
+ end
208
+
209
+ # Determine fully qualified tag for a given tag used inside the
210
+ # definition of another tag ("context"). This method will start
211
+ # the search in the specified context until it finds a match for
212
+ # the tag.
213
+ #
214
+ # Does not recurse into qualifying the type parameters, but
215
+ # returns any which were passed in unchanged.
216
+ #
217
+ # @param tag [String, nil] The namespace to
218
+ # match, complete with generic parameters set to appropriate
219
+ # values if available
220
+ # @param context_tag [String] The context in which the tag was
221
+ # referenced; start from here to resolve the name
222
+ # @return [String, nil] fully qualified tag
223
+ def qualify tag, context_tag = ''
224
+ return tag if ['self', nil].include?(tag)
225
+ context_type = ComplexType.parse(context_tag)
226
+ type = ComplexType.parse(tag)
227
+ fqns = qualify_namespace(type.rooted_namespace, context_type.rooted_namespace)
228
+ return nil if fqns.nil?
229
+ fqns + type.substring
230
+ end
231
+
232
+ # Determine fully qualified namespace for a given namespace used
233
+ # inside the definition of another tag ("context"). This method
234
+ # will start the search in the specified context until it finds a
235
+ # match for the namespace.
191
236
  #
192
- # @param namespace [String, nil] The namespace to match
193
- # @param context [String] The context to search
194
- # @return [String]
195
- def qualify namespace, context = ''
196
- return namespace if ['self', nil].include?(namespace)
197
- cached = cache.get_qualified_namespace(namespace, context)
237
+ # @param namespace [String, nil] The namespace to
238
+ # match
239
+ # @param context_namespace [String] The context namespace in which the
240
+ # tag was referenced; start from here to resolve the name
241
+ # @return [String, nil] fully qualified namespace
242
+ def qualify_namespace(namespace, context_namespace = '')
243
+ cached = cache.get_qualified_namespace(namespace, context_namespace)
198
244
  return cached.clone unless cached.nil?
199
245
  result = if namespace.start_with?('::')
200
246
  inner_qualify(namespace[2..-1], '', Set.new)
201
247
  else
202
- inner_qualify(namespace, context, Set.new)
248
+ inner_qualify(namespace, context_namespace, Set.new)
203
249
  end
204
- cache.set_qualified_namespace(namespace, context, result)
250
+ cache.set_qualified_namespace(namespace, context_namespace, result)
205
251
  result
206
252
  end
207
253
 
@@ -227,49 +273,50 @@ module Solargraph
227
273
  # Get an array of class variable pins for a namespace.
228
274
  #
229
275
  # @param namespace [String] A fully qualified namespace
230
- # @return [Array<Solargraph::Pin::ClassVariable>]
276
+ # @return [Enumerable<Solargraph::Pin::ClassVariable>]
231
277
  def get_class_variable_pins(namespace)
232
278
  prefer_non_nil_variables(store.get_class_variables(namespace))
233
279
  end
234
280
 
235
- # @return [Array<Solargraph::Pin::Base>]
281
+ # @return [Enumerable<Solargraph::Pin::Base>]
236
282
  def get_symbols
237
283
  store.get_symbols
238
284
  end
239
285
 
240
- # @return [Array<Solargraph::Pin::GlobalVariable>]
286
+ # @return [Enumerable<Solargraph::Pin::GlobalVariable>]
241
287
  def get_global_variable_pins
242
288
  store.pins_by_class(Pin::GlobalVariable)
243
289
  end
244
290
 
245
291
  # Get an array of methods available in a particular context.
246
292
  #
247
- # @param fqns [String] The fully qualified namespace to search for methods
293
+ # @param rooted_tag [String] The fully qualified namespace to search for methods
248
294
  # @param scope [Symbol] :class or :instance
249
295
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
250
296
  # @param deep [Boolean] True to include superclasses, mixins, etc.
251
297
  # @return [Array<Solargraph::Pin::Method>]
252
- def get_methods fqns, scope: :instance, visibility: [:public], deep: true
253
- cached = cache.get_methods(fqns, scope, visibility, deep)
298
+ def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
299
+ cached = cache.get_methods(rooted_tag, scope, visibility, deep)
254
300
  return cached.clone unless cached.nil?
255
301
  result = []
256
302
  skip = Set.new
257
- if fqns == ''
303
+ if rooted_tag == ''
258
304
  # @todo Implement domains
259
305
  implicit.domains.each do |domain|
260
306
  type = ComplexType.try_parse(domain)
261
307
  next if type.undefined?
262
308
  result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
263
309
  end
264
- result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
265
- result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
310
+ result.concat inner_get_methods(rooted_tag, :class, visibility, deep, skip)
311
+ result.concat inner_get_methods(rooted_tag, :instance, visibility, deep, skip)
266
312
  result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
267
313
  else
268
- result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
314
+ result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
269
315
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
316
+ result.concat inner_get_methods('Module', scope, visibility, deep, skip)
270
317
  end
271
318
  resolved = resolve_method_aliases(result, visibility)
272
- cache.set_methods(fqns, scope, visibility, deep, resolved)
319
+ cache.set_methods(rooted_tag, scope, visibility, deep, resolved)
273
320
  resolved
274
321
  end
275
322
 
@@ -307,27 +354,27 @@ module Solargraph
307
354
  visibility.push :protected
308
355
  visibility.push :private if internal
309
356
  end
310
- result.merge get_methods(type.namespace, scope: type.scope, visibility: visibility)
357
+ result.merge get_methods(type.tag, scope: type.scope, visibility: visibility)
311
358
  end
312
359
  end
313
360
  end
314
361
  result.to_a
315
362
  end
316
363
 
317
- # Get a stack of method pins for a method name in a namespace. The order
318
- # of the pins corresponds to the ancestry chain, with highest precedence
319
- # first.
364
+ # Get a stack of method pins for a method name in a potentially
365
+ # parameterized namespace. The order of the pins corresponds to
366
+ # the ancestry chain, with highest precedence first.
320
367
  #
321
368
  # @example
322
369
  # api_map.get_method_stack('Subclass', 'method_name')
323
370
  # #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]
324
371
  #
325
- # @param fqns [String]
326
- # @param name [String]
372
+ # @param rooted_tag [String] Parameterized namespace, fully qualified
373
+ # @param name [String] Method name to look up
327
374
  # @param scope [Symbol] :instance or :class
328
375
  # @return [Array<Solargraph::Pin::Method>]
329
- def get_method_stack fqns, name, scope: :instance
330
- get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
376
+ def get_method_stack rooted_tag, name, scope: :instance
377
+ get_methods(rooted_tag, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
331
378
  end
332
379
 
333
380
  # Get an array of all suggestions that match the specified path.
@@ -335,7 +382,7 @@ module Solargraph
335
382
  # @deprecated Use #get_path_pins instead.
336
383
  #
337
384
  # @param path [String] The path to find
338
- # @return [Array<Solargraph::Pin::Base>]
385
+ # @return [Enumerable<Solargraph::Pin::Base>]
339
386
  def get_path_suggestions path
340
387
  return [] if path.nil?
341
388
  resolve_method_aliases store.get_path_pins(path)
@@ -344,7 +391,7 @@ module Solargraph
344
391
  # Get an array of pins that match the specified path.
345
392
  #
346
393
  # @param path [String]
347
- # @return [Array<Pin::Base>]
394
+ # @return [Enumerable<Pin::Base>]
348
395
  def get_path_pins path
349
396
  get_path_suggestions(path)
350
397
  end
@@ -357,15 +404,9 @@ module Solargraph
357
404
  # @param query [String] The text to match
358
405
  # @return [Array<String>]
359
406
  def search query
360
- rake_yard(store)
361
- found = []
362
- code_object_paths.each do |k|
363
- if (found.empty? || (query.include?('.') || query.include?('#')) || !(k.include?('.') || k.include?('#'))) &&
364
- k.downcase.include?(query.downcase)
365
- found.push k
366
- end
367
- end
368
- found
407
+ pins.map(&:path)
408
+ .compact
409
+ .select { |path| path.downcase.include?(query.downcase) }
369
410
  end
370
411
 
371
412
  # Get YARD documentation for the specified path.
@@ -373,13 +414,13 @@ module Solargraph
373
414
  # @example
374
415
  # api_map.document('String#split')
375
416
  #
417
+ # @todo This method is likely superfluous. Calling get_path_pins directly
418
+ # should be sufficient.
419
+ #
376
420
  # @param path [String] The path to find
377
- # @return [Array<YARD::CodeObjects::Base>]
421
+ # @return [Enumerable<Pin::Base>]
378
422
  def document path
379
- rake_yard(store)
380
- docs = []
381
- docs.push code_object_at(path) unless code_object_at(path).nil?
382
- docs
423
+ get_path_pins(path)
383
424
  end
384
425
 
385
426
  # Get an array of all symbols in the workspace that match the query.
@@ -405,6 +446,10 @@ module Solargraph
405
446
  # @return [SourceMap::Clip]
406
447
  def clip cursor
407
448
  raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)
449
+
450
+ # @todo Clip caches are disabled pending resolution of a stale cache bug
451
+ # cache.get_clip(cursor) ||
452
+ # SourceMap::Clip.new(self, cursor).tap { |clip| cache.set_clip(cursor, clip) }
408
453
  SourceMap::Clip.new(self, cursor)
409
454
  end
410
455
 
@@ -447,25 +492,24 @@ module Solargraph
447
492
  def super_and_sub?(sup, sub)
448
493
  fqsup = qualify(sup)
449
494
  cls = qualify(sub)
450
- until fqsup.nil? || cls.nil?
495
+ tested = []
496
+ until fqsup.nil? || cls.nil? || tested.include?(cls)
451
497
  return true if cls == fqsup
498
+ tested.push cls
452
499
  cls = qualify_superclass(cls)
453
500
  end
454
501
  false
455
502
  end
456
503
 
457
- # @return [YardMap]
458
- def yard_map
459
- @yard_map ||= YardMap.new
460
- end
461
-
462
- # Check if the host class includes the specified module.
504
+ # Check if the host class includes the specified module, ignoring
505
+ # type parameters used.
506
+ #
507
+ # @param host_ns [String] The class namesapce (no type parameters)
508
+ # @param module_ns [String] The module namespace (no type parameters)
463
509
  #
464
- # @param host [String] The class
465
- # @param mod [String] The module
466
510
  # @return [Boolean]
467
- def type_include?(host, mod)
468
- store.get_includes(host).include?(mod)
511
+ def type_include?(host_ns, module_ns)
512
+ store.get_includes(host_ns).map { |inc_tag| ComplexType.parse(inc_tag).name }.include?(module_ns)
469
513
  end
470
514
 
471
515
  private
@@ -483,15 +527,19 @@ module Solargraph
483
527
  # @return [Solargraph::ApiMap::Cache]
484
528
  attr_reader :cache
485
529
 
486
- # @param fqns [String] A fully qualified namespace
530
+ # @param rooted_tag [String] A fully qualified namespace, with
531
+ # generic parameter values if applicable
487
532
  # @param scope [Symbol] :class or :instance
488
533
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
489
534
  # @param deep [Boolean]
490
535
  # @param skip [Set<String>]
491
536
  # @param no_core [Boolean] Skip core classes if true
492
537
  # @return [Array<Pin::Base>]
493
- def inner_get_methods fqns, scope, visibility, deep, skip, no_core = false
494
- return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module|Kernel)$/
538
+ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
539
+ rooted_type = ComplexType.parse(rooted_tag)
540
+ fqns = rooted_type.namespace
541
+ fqns_generic_params = rooted_type.all_params
542
+ return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
495
543
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
496
544
  return [] if skip.include?(reqstr)
497
545
  skip.add reqstr
@@ -502,12 +550,33 @@ module Solargraph
502
550
  result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
503
551
  end
504
552
  end
505
- result.concat store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
553
+ # Store#get_methods doesn't know about full tags, just
554
+ # namespaces; resolving the generics in the method pins is this
555
+ # class' responsibility
556
+ raw_methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
557
+ namespace_pin = store.get_path_pins(fqns).select{|p| p.is_a?(Pin::Namespace)}.first
558
+ methods = if rooted_tag != fqns
559
+ methods = raw_methods.map do |method_pin|
560
+ method_pin.resolve_generics(namespace_pin, rooted_type)
561
+ end
562
+ else
563
+ raw_methods
564
+ end
565
+ result.concat methods
506
566
  if deep
507
567
  if scope == :instance
508
- store.get_includes(fqns).reverse.each do |im|
509
- fqim = qualify(im, fqns)
510
- result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
568
+ store.get_includes(fqns).reverse.each do |include_tag|
569
+ rooted_include_tag = qualify(include_tag, rooted_tag)
570
+ # Ensure the types returned by the included methods are
571
+ # relative to the generics passed to the include. e.g.,
572
+ # Foo<String> might include Enumerable<String>
573
+ #
574
+ # @todo perform the same translation in the other areas
575
+ # here after adding a spec and handling things correctly
576
+ # in ApiMap::Store and RbsMap::Conversions
577
+ resolved_include_type = ComplexType.parse(rooted_include_tag).resolve_generics(namespace_pin, rooted_type)
578
+ methods = inner_get_methods(resolved_include_type.tag, scope, visibility, deep, skip, true)
579
+ result.concat methods
511
580
  end
512
581
  fqsc = qualify_superclass(fqns)
513
582
  unless fqsc.nil?
@@ -571,6 +640,8 @@ module Solargraph
571
640
  qualify namespace, context.split('::')[0..-2].join('::')
572
641
  end
573
642
 
643
+ # @param fqsub [String]
644
+ # @return [String, nil]
574
645
  def qualify_superclass fqsub
575
646
  sup = store.get_superclass(fqsub)
576
647
  return nil if sup.nil?
@@ -580,11 +651,12 @@ module Solargraph
580
651
  qualify(sup, parts.join('::'))
581
652
  end
582
653
 
583
- # @param name [String]
584
- # @param root [String]
585
- # @param skip [Set<String>]
586
- # @return [String, nil]
654
+ # @param name [String] Namespace to fully qualify
655
+ # @param root [String] The context to search
656
+ # @param skip [Set<String>] Contexts already searched
657
+ # @return [String, nil] Fully qualified ("rooted") namespace
587
658
  def inner_qualify name, root, skip
659
+ return name if name == ComplexType::GENERIC_TAG_NAME
588
660
  return nil if name.nil?
589
661
  return nil if skip.include?(root)
590
662
  skip.add root
@@ -634,8 +706,8 @@ module Solargraph
634
706
 
635
707
  # Sort an array of pins to put nil or undefined variables last.
636
708
  #
637
- # @param pins [Array<Solargraph::Pin::Base>]
638
- # @return [Array<Solargraph::Pin::Base>]
709
+ # @param pins [Enumerable<Solargraph::Pin::Base>]
710
+ # @return [Enumerable<Solargraph::Pin::Base>]
639
711
  def prefer_non_nil_variables pins
640
712
  result = []
641
713
  nil_pins = []
@@ -649,8 +721,8 @@ module Solargraph
649
721
  result + nil_pins
650
722
  end
651
723
 
652
- # @param pins [Array<Pin::Base>]
653
- # @param visibility [Array<Symbol>]
724
+ # @param pins [Enumerable<Pin::Base>]
725
+ # @param visibility [Enumerable<Symbol>]
654
726
  # @return [Array<Pin::Base>]
655
727
  def resolve_method_aliases pins, visibility = [:public, :private, :protected]
656
728
  result = []
@@ -667,7 +739,7 @@ module Solargraph
667
739
  def resolve_method_alias pin
668
740
  return pin if !pin.is_a?(Pin::MethodAlias) || @method_alias_stack.include?(pin.path)
669
741
  @method_alias_stack.push pin.path
670
- origin = get_method_stack(pin.full_context.namespace, pin.original, scope: pin.scope).first
742
+ origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope).first
671
743
  @method_alias_stack.pop
672
744
  return pin if origin.nil?
673
745
  args = {
@@ -677,7 +749,7 @@ module Solargraph
677
749
  comments: origin.comments,
678
750
  scope: origin.scope,
679
751
  visibility: origin.visibility,
680
- parameters: origin.parameters,
752
+ signatures: origin.signatures,
681
753
  attribute: origin.attribute?
682
754
  }
683
755
  Pin::Method.new **args
@@ -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
@@ -0,0 +1,77 @@
1
+ require 'fileutils'
2
+ require 'rbs'
3
+
4
+ module Solargraph
5
+ module Cache
6
+ class << self
7
+ # The base directory where cached documentation is installed.
8
+ #
9
+ # @return [String]
10
+ def base_dir
11
+ # The directory is not stored in a variable so it can be overridden
12
+ # in specs.
13
+ ENV['SOLARGRAPH_CACHE'] ||
14
+ (ENV['XDG_CACHE_HOME'] ? File.join(ENV['XDG_CACHE_HOME'], 'solargraph') : nil) ||
15
+ File.join(Dir.home, '.cache', 'solargraph')
16
+ end
17
+
18
+ # The working directory for the current Ruby, RBS, and Solargraph versions.
19
+ #
20
+ # @return [String]
21
+ def work_dir
22
+ # The directory is not stored in a variable so it can be overridden
23
+ # in specs.
24
+ File.join(base_dir, "ruby-#{RUBY_VERSION}", "rbs-#{RBS::VERSION}", "solargraph-#{Solargraph::VERSION}")
25
+ end
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>]
39
+ # @return [Array<Solargraph::Pin::Base>, nil]
40
+ def load *path
41
+ file = join(*path)
42
+ return nil unless File.file?(file)
43
+ Marshal.load(File.read(file, mode: 'rb'))
44
+ rescue StandardError => e
45
+ Solargraph.logger.warn "Failed to load cached file #{file}: [#{e.class}] #{e.message}"
46
+ FileUtils.rm_f file
47
+ nil
48
+ end
49
+
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]
57
+ def save *path, pins
58
+ file = File.join(work_dir, *path)
59
+ base = File.dirname(file)
60
+ FileUtils.mkdir_p base unless File.directory?(base)
61
+ ser = Marshal.dump(pins)
62
+ File.write file, ser, mode: 'wb'
63
+ end
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]
72
+ def clear
73
+ FileUtils.rm_rf base_dir, secure: true
74
+ end
75
+ end
76
+ end
77
+ end