solargraph 0.51.2 → 0.54.2

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 (183) 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/.yardopts +2 -2
  6. data/CHANGELOG.md +127 -5
  7. data/README.md +13 -16
  8. data/SPONSORS.md +1 -7
  9. data/lib/solargraph/api_map/cache.rb +50 -20
  10. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  11. data/lib/solargraph/api_map/store.rb +60 -15
  12. data/lib/solargraph/api_map.rb +282 -123
  13. data/lib/solargraph/bench.rb +3 -2
  14. data/lib/solargraph/cache.rb +29 -5
  15. data/lib/solargraph/complex_type/type_methods.rb +122 -39
  16. data/lib/solargraph/complex_type/unique_type.rb +310 -76
  17. data/lib/solargraph/complex_type.rb +166 -44
  18. data/lib/solargraph/convention.rb +0 -1
  19. data/lib/solargraph/converters/dd.rb +5 -0
  20. data/lib/solargraph/converters/dl.rb +3 -0
  21. data/lib/solargraph/converters/dt.rb +3 -0
  22. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  23. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  24. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  25. data/lib/solargraph/diagnostics.rb +2 -2
  26. data/lib/solargraph/doc_map.rb +187 -0
  27. data/lib/solargraph/gem_pins.rb +72 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  30. data/lib/solargraph/language_server/host/message_worker.rb +49 -5
  31. data/lib/solargraph/language_server/host/sources.rb +8 -65
  32. data/lib/solargraph/language_server/host.rb +65 -84
  33. data/lib/solargraph/language_server/message/base.rb +19 -12
  34. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  35. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  36. data/lib/solargraph/language_server/message/initialize.rb +19 -2
  37. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  38. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  39. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  40. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/hover.rb +3 -1
  42. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  43. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  44. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  45. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  46. data/lib/solargraph/language_server/progress.rb +135 -0
  47. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  48. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  49. data/lib/solargraph/language_server.rb +1 -0
  50. data/lib/solargraph/library.rb +207 -111
  51. data/lib/solargraph/location.rb +15 -1
  52. data/lib/solargraph/page.rb +6 -0
  53. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  54. data/lib/solargraph/parser/node_methods.rb +47 -7
  55. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  56. data/lib/solargraph/parser/node_processor.rb +1 -0
  57. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  58. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +62 -43
  60. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  61. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  62. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +57 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +4 -4
  72. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  77. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +8 -6
  78. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  80. data/lib/solargraph/parser/parser_gem.rb +12 -0
  81. data/lib/solargraph/parser/region.rb +1 -1
  82. data/lib/solargraph/parser/snippet.rb +2 -0
  83. data/lib/solargraph/parser.rb +8 -12
  84. data/lib/solargraph/pin/base.rb +78 -10
  85. data/lib/solargraph/pin/base_variable.rb +40 -7
  86. data/lib/solargraph/pin/block.rb +69 -46
  87. data/lib/solargraph/pin/callable.rb +147 -0
  88. data/lib/solargraph/pin/closure.rb +23 -3
  89. data/lib/solargraph/pin/common.rb +6 -6
  90. data/lib/solargraph/pin/conversions.rb +36 -5
  91. data/lib/solargraph/pin/delegated_method.rb +6 -2
  92. data/lib/solargraph/pin/documenting.rb +25 -32
  93. data/lib/solargraph/pin/instance_variable.rb +6 -2
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +205 -32
  96. data/lib/solargraph/pin/namespace.rb +20 -7
  97. data/lib/solargraph/pin/parameter.rb +41 -36
  98. data/lib/solargraph/pin/proxy_type.rb +1 -1
  99. data/lib/solargraph/pin/reference/override.rb +2 -2
  100. data/lib/solargraph/pin/reference.rb +8 -0
  101. data/lib/solargraph/pin/search.rb +3 -3
  102. data/lib/solargraph/pin/signature.rb +8 -14
  103. data/lib/solargraph/pin.rb +4 -2
  104. data/lib/solargraph/range.rb +4 -6
  105. data/lib/solargraph/rbs_map/conversions.rb +326 -76
  106. data/lib/solargraph/rbs_map/core_fills.rb +16 -33
  107. data/lib/solargraph/rbs_map/core_map.rb +3 -13
  108. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  109. data/lib/solargraph/rbs_map.rb +32 -13
  110. data/lib/solargraph/shell.rb +95 -72
  111. data/lib/solargraph/source/chain/array.rb +33 -0
  112. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  113. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  114. data/lib/solargraph/source/chain/call.rb +152 -69
  115. data/lib/solargraph/source/chain/constant.rb +15 -1
  116. data/lib/solargraph/source/chain/if.rb +23 -0
  117. data/lib/solargraph/source/chain/link.rb +17 -2
  118. data/lib/solargraph/source/chain/or.rb +2 -2
  119. data/lib/solargraph/source/chain/z_super.rb +3 -3
  120. data/lib/solargraph/source/chain.rb +85 -26
  121. data/lib/solargraph/source/change.rb +3 -0
  122. data/lib/solargraph/source/cursor.rb +16 -2
  123. data/lib/solargraph/source/source_chainer.rb +8 -5
  124. data/lib/solargraph/source/updater.rb +1 -0
  125. data/lib/solargraph/source.rb +120 -148
  126. data/lib/solargraph/source_map/clip.rb +16 -27
  127. data/lib/solargraph/source_map/data.rb +30 -0
  128. data/lib/solargraph/source_map/mapper.rb +15 -3
  129. data/lib/solargraph/source_map.rb +48 -24
  130. data/lib/solargraph/type_checker/checks.rb +10 -2
  131. data/lib/solargraph/type_checker/rules.rb +6 -1
  132. data/lib/solargraph/type_checker.rb +150 -39
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +3 -5
  135. data/lib/solargraph/workspace/config.rb +9 -6
  136. data/lib/solargraph/workspace.rb +30 -3
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -292
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +6 -4
  146. data/solargraph.gemspec +7 -6
  147. metadata +71 -82
  148. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  149. data/lib/solargraph/documentor.rb +0 -76
  150. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  151. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  152. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  153. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -50
  154. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  155. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  156. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  157. data/lib/solargraph/parser/legacy.rb +0 -12
  158. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
  159. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  160. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  161. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  162. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  163. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  164. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  166. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  167. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  168. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  169. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  171. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  172. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  174. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  176. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  177. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  179. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  180. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  181. data/lib/solargraph/parser/rubyvm.rb +0 -40
  182. data/lib/solargraph/rbs_map/core_signs.rb +0 -33
  183. data/lib/yard-solargraph.rb +0 -33
@@ -1,22 +1,17 @@
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
- # An aggregate provider for information about workspaces, sources, gems, and
8
+ # An aggregate provider for information about Workspaces, Sources, gems, and
11
9
  # the Ruby core.
12
10
  #
13
11
  class ApiMap
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
@@ -34,6 +29,25 @@ module Solargraph
34
29
  index pins
35
30
  end
36
31
 
32
+ #
33
+ # This is a mutable object, which is cached in the Chain class -
34
+ # if you add any fields which change the results of calls (not
35
+ # just caches), please also change `equality_fields` below.
36
+ #
37
+
38
+ def eql?(other)
39
+ self.class == other.class &&
40
+ equality_fields == other.equality_fields
41
+ end
42
+
43
+ def ==(other)
44
+ self.eql?(other)
45
+ end
46
+
47
+ def hash
48
+ equality_fields.hash
49
+ end
50
+
37
51
  # @param pins [Array<Pin::Base>]
38
52
  # @return [self]
39
53
  def index pins
@@ -59,34 +73,44 @@ module Solargraph
59
73
  # Catalog a bench.
60
74
  #
61
75
  # @param bench [Bench]
76
+ # @return [self]
62
77
  def catalog bench
63
- implicit.clear
64
- @cache.clear
78
+ old_api_hash = @source_map_hash&.values&.map(&:api_hash)
79
+ need_to_uncache = (old_api_hash != bench.source_maps.map(&:api_hash))
65
80
  @source_map_hash = bench.source_maps.map { |s| [s.filename, s] }.to_h
66
- pins = bench.source_maps.map(&:pins).flatten
67
- external_requires = bench.external_requires
81
+ pins = bench.source_maps.flat_map(&:pins).flatten
82
+ implicit.clear
68
83
  source_map_hash.each_value do |map|
69
84
  implicit.merge map.environ
70
85
  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) }
86
+ unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).to_a.compact.uniq
87
+ if @unresolved_requires != unresolved_requires || @doc_map&.uncached_gemspecs&.any?
88
+ @doc_map = DocMap.new(unresolved_requires, [], bench.workspace.rbs_collection_path) # @todo Implement gem preferences
89
+ @unresolved_requires = unresolved_requires
90
+ need_to_uncache = true
91
+ end
92
+ @store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
93
+ @cache.clear if need_to_uncache
94
+
95
+ @missing_docs = [] # @todo Implement missing docs
81
96
  self
82
97
  end
83
98
 
84
- def core_pins
85
- @@core_map.pins
99
+ # @todo need to model type def statement in chains as a symbol so
100
+ # that this overload of 'protected' will typecheck @sg-ignore
101
+ # @sg-ignore
102
+ protected def equality_fields
103
+ [self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires, @missing_docs]
104
+ end
105
+
106
+ # @return [::Array<Gem::Specification>]
107
+ def uncached_gemspecs
108
+ @doc_map&.uncached_gemspecs || []
86
109
  end
87
110
 
88
- def yard_map
89
- @yard_map ||= YardMap.new
111
+ # @return [Array<Pin::Base>]
112
+ def core_pins
113
+ @@core_map.pins
90
114
  end
91
115
 
92
116
  # @param name [String]
@@ -95,6 +119,7 @@ module Solargraph
95
119
  store.named_macros[name]
96
120
  end
97
121
 
122
+ # @return [Set<String>]
98
123
  def required
99
124
  @required ||= Set.new
100
125
  end
@@ -120,7 +145,7 @@ module Solargraph
120
145
  # @return [SourceMap::Clip]
121
146
  def clip_at filename, position
122
147
  position = Position.normalize(position)
123
- SourceMap::Clip.new(self, cursor_at(filename, position))
148
+ clip(cursor_at(filename, position))
124
149
  end
125
150
 
126
151
  # Create an ApiMap with a workspace in the specified directory.
@@ -137,22 +162,33 @@ module Solargraph
137
162
  api_map
138
163
  end
139
164
 
165
+ # Create an ApiMap with a workspace in the specified directory and cache
166
+ # any missing gems.
167
+ #
168
+ #
169
+ # @todo IO::NULL is incorrectly inferred to be a String.
170
+ # @sg-ignore
171
+ #
172
+ # @param directory [String]
173
+ # @param out [IO] The output stream for messages
174
+ # @return [ApiMap]
175
+ def self.load_with_cache directory, out = IO::NULL
176
+ api_map = load(directory)
177
+ return api_map if api_map.uncached_gemspecs.empty?
178
+
179
+ api_map.uncached_gemspecs.each do |gemspec|
180
+ out.puts "Caching gem #{gemspec.name} #{gemspec.version}"
181
+ pins = GemPins.build(gemspec)
182
+ Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
183
+ end
184
+ load(directory)
185
+ end
186
+
140
187
  # @return [Array<Solargraph::Pin::Base>]
141
188
  def pins
142
189
  store.pins
143
190
  end
144
191
 
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
154
- end
155
-
156
192
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
157
193
  #
158
194
  # @return [Enumerable<Solargraph::Pin::Keyword>]
@@ -199,22 +235,62 @@ module Solargraph
199
235
  result
200
236
  end
201
237
 
202
- # Get a fully qualified namespace name. This method will start the search
203
- # in the specified context until it finds a match for the name.
238
+ # @param namespace [String]
239
+ # @param context [String]
240
+ # @return [Array<Pin::Namespace>]
241
+ def get_namespace_pins namespace, context
242
+ store.fqns_pins(qualify(namespace, context))
243
+ end
244
+
245
+ # Determine fully qualified tag for a given tag used inside the
246
+ # definition of another tag ("context"). This method will start
247
+ # the search in the specified context until it finds a match for
248
+ # the tag.
204
249
  #
205
- # @param namespace [String, nil] The namespace to match
206
- # @param context [String] The context to search
207
- # @return [String, nil]
208
- def qualify namespace, context = ''
209
- return namespace if ['self', nil].include?(namespace)
210
- cached = cache.get_qualified_namespace(namespace, context)
250
+ # Does not recurse into qualifying the type parameters, but
251
+ # returns any which were passed in unchanged.
252
+ #
253
+ # @param tag [String, nil] The namespace to
254
+ # match, complete with generic parameters set to appropriate
255
+ # values if available
256
+ # @param context_tag [String] The fully qualified context in which
257
+ # the tag was referenced; start from here to resolve the name.
258
+ # Should not be prefixed with '::'.
259
+ # @return [String, nil] fully qualified tag
260
+ def qualify tag, context_tag = ''
261
+ return tag if ['self', nil].include?(tag)
262
+
263
+ context_type = ComplexType.parse(context_tag).force_rooted
264
+ return unless context_type
265
+
266
+ type = ComplexType.try_parse(tag)
267
+ return unless type
268
+
269
+ fqns = qualify_namespace(type.rooted_namespace, context_type.namespace)
270
+ return unless fqns
271
+
272
+ fqns + type.substring
273
+ end
274
+
275
+ # Determine fully qualified namespace for a given namespace used
276
+ # inside the definition of another tag ("context"). This method
277
+ # will start the search in the specified context until it finds a
278
+ # match for the namespace.
279
+ #
280
+ # @param namespace [String, nil] The namespace to
281
+ # match
282
+ # @param context_namespace [String] The context namespace in which the
283
+ # tag was referenced; start from here to resolve the name
284
+ # @return [String, nil] fully qualified namespace
285
+ def qualify_namespace(namespace, context_namespace = '')
286
+ cached = cache.get_qualified_namespace(namespace, context_namespace)
211
287
  return cached.clone unless cached.nil?
212
288
  result = if namespace.start_with?('::')
213
289
  inner_qualify(namespace[2..-1], '', Set.new)
214
290
  else
215
- inner_qualify(namespace, context, Set.new)
291
+ inner_qualify(namespace, context_namespace, Set.new)
216
292
  end
217
- cache.set_qualified_namespace(namespace, context, result)
293
+ cache.set_qualified_namespace(namespace, context_namespace, result)
218
294
  result
219
295
  end
220
296
 
@@ -240,50 +316,82 @@ module Solargraph
240
316
  # Get an array of class variable pins for a namespace.
241
317
  #
242
318
  # @param namespace [String] A fully qualified namespace
243
- # @return [Array<Solargraph::Pin::ClassVariable>]
319
+ # @return [Enumerable<Solargraph::Pin::ClassVariable>]
244
320
  def get_class_variable_pins(namespace)
245
321
  prefer_non_nil_variables(store.get_class_variables(namespace))
246
322
  end
247
323
 
248
- # @return [Array<Solargraph::Pin::Base>]
324
+ # @return [Enumerable<Solargraph::Pin::Base>]
249
325
  def get_symbols
250
326
  store.get_symbols
251
327
  end
252
328
 
253
- # @return [Array<Solargraph::Pin::GlobalVariable>]
329
+ # @return [Enumerable<Solargraph::Pin::GlobalVariable>]
254
330
  def get_global_variable_pins
255
331
  store.pins_by_class(Pin::GlobalVariable)
256
332
  end
257
333
 
334
+ # @return [Enumerable<Solargraph::Pin::Block>]
335
+ def get_block_pins
336
+ store.pins_by_class(Pin::Block)
337
+ end
338
+
258
339
  # Get an array of methods available in a particular context.
259
340
  #
260
- # @param fqns [String] The fully qualified namespace to search for methods
341
+ # @param rooted_tag [String] The fully qualified namespace to search for methods
261
342
  # @param scope [Symbol] :class or :instance
262
343
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
263
344
  # @param deep [Boolean] True to include superclasses, mixins, etc.
264
345
  # @return [Array<Solargraph::Pin::Method>]
265
- def get_methods fqns, scope: :instance, visibility: [:public], deep: true
266
- cached = cache.get_methods(fqns, scope, visibility, deep)
346
+ def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
347
+ rooted_type = ComplexType.try_parse(rooted_tag)
348
+ fqns = rooted_type.namespace
349
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
350
+ cached = cache.get_methods(rooted_tag, scope, visibility, deep)
267
351
  return cached.clone unless cached.nil?
268
352
  result = []
269
353
  skip = Set.new
270
- if fqns == ''
354
+ if rooted_tag == ''
271
355
  # @todo Implement domains
272
356
  implicit.domains.each do |domain|
273
357
  type = ComplexType.try_parse(domain)
274
358
  next if type.undefined?
275
359
  result.concat inner_get_methods(type.name, type.scope, visibility, deep, skip)
276
360
  end
277
- result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
278
- result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
361
+ result.concat inner_get_methods(rooted_tag, :class, visibility, deep, skip)
362
+ result.concat inner_get_methods(rooted_tag, :instance, visibility, deep, skip)
279
363
  result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
280
364
  else
281
- result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
365
+ result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
366
+ unless %w[Class Class<Class>].include?(rooted_tag)
367
+ result.map! do |pin|
368
+ next pin unless pin.path == 'Class#new'
369
+ init_pin = get_method_stack(rooted_tag, 'initialize').first
370
+ next pin unless init_pin
371
+
372
+ type = ComplexType.try_parse(ComplexType.try_parse(rooted_tag).namespace)
373
+ Pin::Method.new(
374
+ name: 'new',
375
+ scope: :class,
376
+ location: init_pin.location,
377
+ parameters: init_pin.parameters,
378
+ signatures: init_pin.signatures.map { |sig| sig.proxy(type) },
379
+ return_type: type,
380
+ comments: init_pin.comments,
381
+ closure: init_pin.closure
382
+ # @todo Hack to force TypeChecker#internal_or_core?
383
+ ).tap { |pin| pin.source = :rbs }
384
+ end
385
+ end
282
386
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
387
+ result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
283
388
  end
284
- resolved = resolve_method_aliases(result, visibility)
285
- cache.set_methods(fqns, scope, visibility, deep, resolved)
286
- resolved
389
+ result = resolve_method_aliases(result, visibility)
390
+ if namespace_pin && rooted_tag != rooted_type.name
391
+ result = result.map { |method_pin| method_pin.resolve_generics(namespace_pin, rooted_type) }
392
+ end
393
+ cache.set_methods(rooted_tag, scope, visibility, deep, result)
394
+ result
287
395
  end
288
396
 
289
397
  # Get an array of method pins for a complex type.
@@ -320,27 +428,32 @@ module Solargraph
320
428
  visibility.push :protected
321
429
  visibility.push :private if internal
322
430
  end
323
- result.merge get_methods(type.namespace, scope: type.scope, visibility: visibility)
431
+ result.merge get_methods(type.tag, scope: type.scope, visibility: visibility)
324
432
  end
325
433
  end
326
434
  end
327
435
  result.to_a
328
436
  end
329
437
 
330
- # Get a stack of method pins for a method name in a namespace. The order
331
- # of the pins corresponds to the ancestry chain, with highest precedence
332
- # first.
438
+ # Get a stack of method pins for a method name in a potentially
439
+ # parameterized namespace. The order of the pins corresponds to
440
+ # the ancestry chain, with highest precedence first.
333
441
  #
334
442
  # @example
335
443
  # api_map.get_method_stack('Subclass', 'method_name')
336
444
  # #=> [ <Subclass#method_name pin>, <Superclass#method_name pin> ]
337
445
  #
338
- # @param fqns [String]
339
- # @param name [String]
446
+ # @param rooted_tag [String] Parameterized namespace, fully qualified
447
+ # @param name [String] Method name to look up
340
448
  # @param scope [Symbol] :instance or :class
341
449
  # @return [Array<Solargraph::Pin::Method>]
342
- def get_method_stack fqns, name, scope: :instance
343
- get_methods(fqns, scope: scope, visibility: [:private, :protected, :public]).select { |p| p.name == name }
450
+ def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
451
+ rooted_type = ComplexType.parse(rooted_tag)
452
+ fqns = rooted_type.namespace
453
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
454
+ methods = get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
455
+ methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
456
+ methods
344
457
  end
345
458
 
346
459
  # Get an array of all suggestions that match the specified path.
@@ -348,7 +461,7 @@ module Solargraph
348
461
  # @deprecated Use #get_path_pins instead.
349
462
  #
350
463
  # @param path [String] The path to find
351
- # @return [Array<Solargraph::Pin::Base>]
464
+ # @return [Enumerable<Solargraph::Pin::Base>]
352
465
  def get_path_suggestions path
353
466
  return [] if path.nil?
354
467
  resolve_method_aliases store.get_path_pins(path)
@@ -357,7 +470,7 @@ module Solargraph
357
470
  # Get an array of pins that match the specified path.
358
471
  #
359
472
  # @param path [String]
360
- # @return [Array<Pin::Base>]
473
+ # @return [Enumerable<Pin::Base>]
361
474
  def get_path_pins path
362
475
  get_path_suggestions(path)
363
476
  end
@@ -370,15 +483,9 @@ module Solargraph
370
483
  # @param query [String] The text to match
371
484
  # @return [Array<String>]
372
485
  def search query
373
- rake_yard(store)
374
- found = []
375
- code_object_paths.each do |k|
376
- if (found.empty? || (query.include?('.') || query.include?('#')) || !(k.include?('.') || k.include?('#'))) &&
377
- k.downcase.include?(query.downcase)
378
- found.push k
379
- end
380
- end
381
- found
486
+ pins.map(&:path)
487
+ .compact
488
+ .select { |path| path.downcase.include?(query.downcase) }
382
489
  end
383
490
 
384
491
  # Get YARD documentation for the specified path.
@@ -386,13 +493,13 @@ module Solargraph
386
493
  # @example
387
494
  # api_map.document('String#split')
388
495
  #
496
+ # @todo This method is likely superfluous. Calling get_path_pins directly
497
+ # should be sufficient.
498
+ #
389
499
  # @param path [String] The path to find
390
- # @return [Array<YARD::CodeObjects::Base>]
500
+ # @return [Enumerable<Pin::Base>]
391
501
  def document path
392
- rake_yard(store)
393
- docs = []
394
- docs.push code_object_at(path) unless code_object_at(path).nil?
395
- docs
502
+ get_path_pins(path)
396
503
  end
397
504
 
398
505
  # Get an array of all symbols in the workspace that match the query.
@@ -418,6 +525,7 @@ module Solargraph
418
525
  # @return [SourceMap::Clip]
419
526
  def clip cursor
420
527
  raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)
528
+
421
529
  SourceMap::Clip.new(self, cursor)
422
530
  end
423
531
 
@@ -469,13 +577,15 @@ module Solargraph
469
577
  false
470
578
  end
471
579
 
472
- # Check if the host class includes the specified module.
580
+ # Check if the host class includes the specified module, ignoring
581
+ # type parameters used.
582
+ #
583
+ # @param host_ns [String] The class namesapce (no type parameters)
584
+ # @param module_ns [String] The module namespace (no type parameters)
473
585
  #
474
- # @param host [String] The class
475
- # @param mod [String] The module
476
586
  # @return [Boolean]
477
- def type_include?(host, mod)
478
- store.get_includes(host).include?(mod)
587
+ def type_include?(host_ns, module_ns)
588
+ store.get_includes(host_ns).map { |inc_tag| ComplexType.parse(inc_tag).name }.include?(module_ns)
479
589
  end
480
590
 
481
591
  private
@@ -485,14 +595,6 @@ module Solargraph
485
595
  # @return [Hash{String => SourceMap}]
486
596
  attr_reader :source_map_hash
487
597
 
488
- # @param library [String]
489
- # @return [RbsMap]
490
- def load_rbs_map library
491
- # map = RbsMap.load(library)
492
- # return map if map.resolved?
493
- RbsMap::StdlibMap.load(library)
494
- end
495
-
496
598
  # @return [ApiMap::Store]
497
599
  def store
498
600
  @store ||= Store.new
@@ -501,15 +603,20 @@ module Solargraph
501
603
  # @return [Solargraph::ApiMap::Cache]
502
604
  attr_reader :cache
503
605
 
504
- # @param fqns [String] A fully qualified namespace
606
+ # @param rooted_tag [String] A fully qualified namespace, with
607
+ # generic parameter values if applicable
505
608
  # @param scope [Symbol] :class or :instance
506
609
  # @param visibility [Array<Symbol>] :public, :protected, and/or :private
507
610
  # @param deep [Boolean]
508
611
  # @param skip [Set<String>]
509
612
  # @param no_core [Boolean] Skip core classes if true
510
613
  # @return [Array<Pin::Base>]
511
- def inner_get_methods fqns, scope, visibility, deep, skip, no_core = false
512
- return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module|Kernel)$/
614
+ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
615
+ rooted_type = ComplexType.parse(rooted_tag).force_rooted
616
+ fqns = rooted_type.namespace
617
+ fqns_generic_params = rooted_type.all_params
618
+ namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
619
+ return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
513
620
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
514
621
  return [] if skip.include?(reqstr)
515
622
  skip.add reqstr
@@ -520,12 +627,25 @@ module Solargraph
520
627
  result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
521
628
  end
522
629
  end
523
- result.concat store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
630
+ # Store#get_methods doesn't know about full tags, just
631
+ # namespaces; resolving the generics in the method pins is this
632
+ # class' responsibility
633
+ methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
634
+ result.concat methods
524
635
  if deep
525
636
  if scope == :instance
526
- store.get_includes(fqns).reverse.each do |im|
527
- fqim = qualify(im, fqns)
528
- result.concat inner_get_methods(fqim, scope, visibility, deep, skip, true) unless fqim.nil?
637
+ store.get_includes(fqns).reverse.each do |include_tag|
638
+ rooted_include_tag = qualify(include_tag, rooted_tag)
639
+ # Ensure the types returned by the included methods are
640
+ # relative to the generics passed to the include. e.g.,
641
+ # Foo<String> might include Enumerable<String>
642
+ #
643
+ # @todo perform the same translation in the other areas
644
+ # here after adding a spec and handling things correctly
645
+ # in ApiMap::Store and RbsMap::Conversions
646
+ resolved_include_type = ComplexType.parse(rooted_include_tag).force_rooted.resolve_generics(namespace_pin, rooted_type)
647
+ methods = inner_get_methods(resolved_include_type.tag, scope, visibility, deep, skip, true)
648
+ result.concat methods
529
649
  end
530
650
  fqsc = qualify_superclass(fqns)
531
651
  unless fqsc.nil?
@@ -584,11 +704,13 @@ module Solargraph
584
704
 
585
705
  # @param namespace [String]
586
706
  # @param context [String]
587
- # @return [String]
707
+ # @return [String, nil]
588
708
  def qualify_lower namespace, context
589
709
  qualify namespace, context.split('::')[0..-2].join('::')
590
710
  end
591
711
 
712
+ # @param fqsub [String]
713
+ # @return [String, nil]
592
714
  def qualify_superclass fqsub
593
715
  sup = store.get_superclass(fqsub)
594
716
  return nil if sup.nil?
@@ -598,11 +720,12 @@ module Solargraph
598
720
  qualify(sup, parts.join('::'))
599
721
  end
600
722
 
601
- # @param name [String]
602
- # @param root [String]
603
- # @param skip [Set<String>]
604
- # @return [String, nil]
723
+ # @param name [String] Namespace to fully qualify
724
+ # @param root [String] The context to search
725
+ # @param skip [Set<String>] Contexts already searched
726
+ # @return [String, nil] Fully qualified ("rooted") namespace
605
727
  def inner_qualify name, root, skip
728
+ return name if name == ComplexType::GENERIC_TAG_NAME
606
729
  return nil if name.nil?
607
730
  return nil if skip.include?(root)
608
731
  skip.add root
@@ -652,8 +775,8 @@ module Solargraph
652
775
 
653
776
  # Sort an array of pins to put nil or undefined variables last.
654
777
  #
655
- # @param pins [Array<Solargraph::Pin::Base>]
656
- # @return [Array<Solargraph::Pin::Base>]
778
+ # @param pins [Enumerable<Solargraph::Pin::Base>]
779
+ # @return [Enumerable<Solargraph::Pin::Base>]
657
780
  def prefer_non_nil_variables pins
658
781
  result = []
659
782
  nil_pins = []
@@ -667,38 +790,74 @@ module Solargraph
667
790
  result + nil_pins
668
791
  end
669
792
 
670
- # @param pins [Array<Pin::Base>]
671
- # @param visibility [Array<Symbol>]
793
+ # @param pins [Enumerable<Pin::Base>]
794
+ # @param visibility [Enumerable<Symbol>]
672
795
  # @return [Array<Pin::Base>]
673
796
  def resolve_method_aliases pins, visibility = [:public, :private, :protected]
674
- result = []
675
- pins.each do |pin|
797
+ pins.map do |pin|
676
798
  resolved = resolve_method_alias(pin)
677
- next if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
678
- result.push resolved
679
- end
680
- result
799
+ next pin if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
800
+ resolved
801
+ end.compact
681
802
  end
682
803
 
683
804
  # @param pin [Pin::MethodAlias, Pin::Base]
684
805
  # @return [Pin::Method]
685
806
  def resolve_method_alias pin
686
- return pin if !pin.is_a?(Pin::MethodAlias) || @method_alias_stack.include?(pin.path)
807
+ return pin unless pin.is_a?(Pin::MethodAlias)
808
+ return nil if @method_alias_stack.include?(pin.path)
687
809
  @method_alias_stack.push pin.path
688
- origin = get_method_stack(pin.full_context.namespace, pin.original, scope: pin.scope).first
810
+ origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope).first
689
811
  @method_alias_stack.pop
690
- return pin if origin.nil?
812
+ return nil if origin.nil?
691
813
  args = {
692
814
  location: pin.location,
693
815
  closure: pin.closure,
694
816
  name: pin.name,
695
817
  comments: origin.comments,
696
818
  scope: origin.scope,
819
+ # context: pin.context,
697
820
  visibility: origin.visibility,
698
821
  signatures: origin.signatures,
699
- attribute: origin.attribute?
822
+ attribute: origin.attribute?,
823
+ generics: origin.generics,
824
+ return_type: origin.return_type,
700
825
  }
701
826
  Pin::Method.new **args
702
827
  end
828
+
829
+ include Logging
830
+
831
+ private
832
+
833
+ # @param namespace_pin [Pin::Namespace]
834
+ # @param rooted_type [ComplexType]
835
+ # @param pins [Enumerable<Pin::Base>]
836
+ # @return [Array<Pin::Base>]
837
+ def erase_generics(namespace_pin, rooted_type, pins)
838
+ return pins unless should_erase_generics_when_done?(namespace_pin, rooted_type)
839
+
840
+ logger.debug("Erasing generics on namespace_pin=#{namespace_pin} / rooted_type=#{rooted_type}")
841
+ pins.map do |method_pin|
842
+ method_pin.erase_generics(namespace_pin.generics)
843
+ end
844
+ end
845
+
846
+ # @param namespace_pin [Pin::Namespace]
847
+ # @param rooted_type [ComplexType]
848
+ def should_erase_generics_when_done?(namespace_pin, rooted_type)
849
+ has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
850
+ end
851
+
852
+ # @param namespace_pin [Pin::Namespace]
853
+ def has_generics?(namespace_pin)
854
+ namespace_pin && !namespace_pin.generics.empty?
855
+ end
856
+
857
+ # @param namespace_pin [Pin::Namespace]
858
+ # @param rooted_type [ComplexType]
859
+ def can_resolve_generics?(namespace_pin, rooted_type)
860
+ has_generics?(namespace_pin) && !rooted_type.all_params.empty?
861
+ end
703
862
  end
704
863
  end
@@ -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