solargraph 0.58.3 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +6 -5
  4. data/.github/workflows/plugins.yml +46 -34
  5. data/.github/workflows/rspec.yml +15 -28
  6. data/.github/workflows/typecheck.yml +3 -2
  7. data/.rubocop.yml +38 -6
  8. data/.rubocop_todo.yml +53 -966
  9. data/CHANGELOG.md +12 -0
  10. data/Gemfile +3 -1
  11. data/README.md +3 -3
  12. data/Rakefile +26 -23
  13. data/bin/solargraph +2 -1
  14. data/lib/solargraph/api_map/cache.rb +3 -3
  15. data/lib/solargraph/api_map/constants.rb +12 -3
  16. data/lib/solargraph/api_map/index.rb +29 -18
  17. data/lib/solargraph/api_map/source_to_yard.rb +22 -9
  18. data/lib/solargraph/api_map/store.rb +39 -28
  19. data/lib/solargraph/api_map.rb +156 -72
  20. data/lib/solargraph/bench.rb +2 -3
  21. data/lib/solargraph/complex_type/conformance.rb +176 -0
  22. data/lib/solargraph/complex_type/type_methods.rb +30 -18
  23. data/lib/solargraph/complex_type/unique_type.rb +216 -57
  24. data/lib/solargraph/complex_type.rb +171 -58
  25. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +1 -1
  26. data/lib/solargraph/convention/data_definition/data_definition_node.rb +7 -5
  27. data/lib/solargraph/convention/data_definition.rb +5 -2
  28. data/lib/solargraph/convention/gemfile.rb +1 -1
  29. data/lib/solargraph/convention/gemspec.rb +1 -1
  30. data/lib/solargraph/convention/rakefile.rb +1 -1
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -3
  33. data/lib/solargraph/convention/struct_definition.rb +8 -4
  34. data/lib/solargraph/convention.rb +2 -2
  35. data/lib/solargraph/converters/dd.rb +2 -0
  36. data/lib/solargraph/converters/dl.rb +2 -0
  37. data/lib/solargraph/converters/dt.rb +2 -0
  38. data/lib/solargraph/converters/misc.rb +2 -0
  39. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  40. data/lib/solargraph/diagnostics/rubocop.rb +11 -10
  41. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  42. data/lib/solargraph/diagnostics/type_check.rb +11 -10
  43. data/lib/solargraph/diagnostics/update_errors.rb +4 -8
  44. data/lib/solargraph/doc_map.rb +38 -39
  45. data/lib/solargraph/equality.rb +4 -4
  46. data/lib/solargraph/gem_pins.rb +6 -6
  47. data/lib/solargraph/language_server/error_codes.rb +10 -10
  48. data/lib/solargraph/language_server/host/diagnoser.rb +1 -1
  49. data/lib/solargraph/language_server/host/dispatch.rb +3 -3
  50. data/lib/solargraph/language_server/host/message_worker.rb +4 -3
  51. data/lib/solargraph/language_server/host/sources.rb +2 -1
  52. data/lib/solargraph/language_server/host.rb +30 -22
  53. data/lib/solargraph/language_server/message/base.rb +1 -1
  54. data/lib/solargraph/language_server/message/client/register_capability.rb +1 -3
  55. data/lib/solargraph/language_server/message/completion_item/resolve.rb +6 -8
  56. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +12 -18
  57. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  58. data/lib/solargraph/language_server/message/extended/document_gems.rb +7 -7
  59. data/lib/solargraph/language_server/message/extended/download_core.rb +2 -1
  60. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  61. data/lib/solargraph/language_server/message/initialize.rb +20 -14
  62. data/lib/solargraph/language_server/message/text_document/completion.rb +10 -8
  63. data/lib/solargraph/language_server/message/text_document/definition.rb +41 -32
  64. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +17 -10
  65. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +29 -19
  66. data/lib/solargraph/language_server/message/text_document/formatting.rb +8 -6
  67. data/lib/solargraph/language_server/message/text_document/hover.rb +5 -5
  68. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +13 -6
  69. data/lib/solargraph/language_server/message/text_document/references.rb +17 -10
  70. data/lib/solargraph/language_server/message/text_document/rename.rb +20 -13
  71. data/lib/solargraph/language_server/message/text_document/signature_help.rb +3 -2
  72. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -17
  73. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +34 -28
  74. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +38 -30
  75. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +23 -17
  76. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +27 -17
  77. data/lib/solargraph/language_server/message.rb +1 -1
  78. data/lib/solargraph/language_server/request.rb +4 -2
  79. data/lib/solargraph/language_server/transport/data_reader.rb +11 -13
  80. data/lib/solargraph/language_server/uri_helpers.rb +2 -2
  81. data/lib/solargraph/library.rb +57 -38
  82. data/lib/solargraph/location.rb +17 -14
  83. data/lib/solargraph/logging.rb +22 -4
  84. data/lib/solargraph/page.rb +1 -1
  85. data/lib/solargraph/parser/comment_ripper.rb +19 -4
  86. data/lib/solargraph/parser/flow_sensitive_typing.rb +324 -108
  87. data/lib/solargraph/parser/node_processor/base.rb +34 -4
  88. data/lib/solargraph/parser/node_processor.rb +8 -7
  89. data/lib/solargraph/parser/parser_gem/class_methods.rb +30 -14
  90. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -1
  91. data/lib/solargraph/parser/parser_gem/node_chainer.rb +50 -25
  92. data/lib/solargraph/parser/parser_gem/node_methods.rb +91 -70
  93. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  94. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +13 -11
  95. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  96. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -12
  97. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +10 -3
  98. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +9 -8
  99. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  100. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +5 -3
  101. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  102. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  103. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +3 -3
  104. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  105. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  106. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  107. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -5
  108. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +124 -113
  109. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +1 -1
  110. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  111. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +6 -2
  112. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  113. data/lib/solargraph/parser/parser_gem.rb +2 -0
  114. data/lib/solargraph/parser/region.rb +9 -3
  115. data/lib/solargraph/parser/snippet.rb +3 -1
  116. data/lib/solargraph/parser.rb +2 -0
  117. data/lib/solargraph/pin/base.rb +124 -80
  118. data/lib/solargraph/pin/base_variable.rb +273 -24
  119. data/lib/solargraph/pin/block.rb +29 -6
  120. data/lib/solargraph/pin/breakable.rb +7 -1
  121. data/lib/solargraph/pin/callable.rb +65 -21
  122. data/lib/solargraph/pin/closure.rb +7 -10
  123. data/lib/solargraph/pin/common.rb +24 -6
  124. data/lib/solargraph/pin/compound_statement.rb +55 -0
  125. data/lib/solargraph/pin/constant.rb +3 -5
  126. data/lib/solargraph/pin/conversions.rb +10 -4
  127. data/lib/solargraph/pin/delegated_method.rb +19 -8
  128. data/lib/solargraph/pin/documenting.rb +4 -2
  129. data/lib/solargraph/pin/instance_variable.rb +5 -1
  130. data/lib/solargraph/pin/keyword.rb +0 -4
  131. data/lib/solargraph/pin/local_variable.rb +15 -59
  132. data/lib/solargraph/pin/method.rb +156 -104
  133. data/lib/solargraph/pin/method_alias.rb +8 -0
  134. data/lib/solargraph/pin/namespace.rb +19 -12
  135. data/lib/solargraph/pin/parameter.rb +100 -36
  136. data/lib/solargraph/pin/proxy_type.rb +4 -1
  137. data/lib/solargraph/pin/reference/override.rb +1 -1
  138. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  139. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  140. data/lib/solargraph/pin/reference.rb +20 -0
  141. data/lib/solargraph/pin/search.rb +3 -2
  142. data/lib/solargraph/pin/signature.rb +15 -12
  143. data/lib/solargraph/pin/symbol.rb +2 -1
  144. data/lib/solargraph/pin/until.rb +2 -4
  145. data/lib/solargraph/pin/while.rb +2 -4
  146. data/lib/solargraph/pin.rb +2 -0
  147. data/lib/solargraph/pin_cache.rb +22 -19
  148. data/lib/solargraph/position.rb +17 -10
  149. data/lib/solargraph/range.rb +16 -15
  150. data/lib/solargraph/rbs_map/conversions.rb +358 -229
  151. data/lib/solargraph/rbs_map/core_fills.rb +18 -11
  152. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  153. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -5
  154. data/lib/solargraph/rbs_map.rb +76 -32
  155. data/lib/solargraph/server_methods.rb +1 -1
  156. data/lib/solargraph/shell.rb +258 -66
  157. data/lib/solargraph/source/chain/array.rb +4 -2
  158. data/lib/solargraph/source/chain/call.rb +96 -56
  159. data/lib/solargraph/source/chain/class_variable.rb +1 -1
  160. data/lib/solargraph/source/chain/constant.rb +5 -1
  161. data/lib/solargraph/source/chain/global_variable.rb +1 -1
  162. data/lib/solargraph/source/chain/hash.rb +8 -5
  163. data/lib/solargraph/source/chain/if.rb +12 -10
  164. data/lib/solargraph/source/chain/instance_variable.rb +24 -1
  165. data/lib/solargraph/source/chain/link.rb +12 -22
  166. data/lib/solargraph/source/chain/literal.rb +9 -6
  167. data/lib/solargraph/source/chain/or.rb +10 -4
  168. data/lib/solargraph/source/chain/q_call.rb +2 -0
  169. data/lib/solargraph/source/chain/variable.rb +3 -1
  170. data/lib/solargraph/source/chain/z_super.rb +1 -3
  171. data/lib/solargraph/source/chain.rb +51 -38
  172. data/lib/solargraph/source/change.rb +12 -5
  173. data/lib/solargraph/source/cursor.rb +23 -17
  174. data/lib/solargraph/source/encoding_fixes.rb +6 -7
  175. data/lib/solargraph/source/source_chainer.rb +56 -32
  176. data/lib/solargraph/source/updater.rb +5 -1
  177. data/lib/solargraph/source.rb +59 -35
  178. data/lib/solargraph/source_map/clip.rb +48 -29
  179. data/lib/solargraph/source_map/data.rb +4 -1
  180. data/lib/solargraph/source_map/mapper.rb +69 -42
  181. data/lib/solargraph/source_map.rb +21 -9
  182. data/lib/solargraph/type_checker/problem.rb +3 -1
  183. data/lib/solargraph/type_checker/rules.rb +81 -8
  184. data/lib/solargraph/type_checker.rb +195 -121
  185. data/lib/solargraph/version.rb +1 -1
  186. data/lib/solargraph/workspace/config.rb +14 -11
  187. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  188. data/lib/solargraph/workspace/require_paths.rb +1 -0
  189. data/lib/solargraph/workspace.rb +50 -28
  190. data/lib/solargraph/yard_map/helpers.rb +8 -3
  191. data/lib/solargraph/yard_map/mapper/to_method.rb +13 -7
  192. data/lib/solargraph/yard_map/mapper/to_namespace.rb +2 -1
  193. data/lib/solargraph/yard_map/mapper.rb +13 -8
  194. data/lib/solargraph/yard_map.rb +17 -18
  195. data/lib/solargraph/yard_tags.rb +2 -2
  196. data/lib/solargraph/yardoc.rb +7 -4
  197. data/lib/solargraph.rb +31 -8
  198. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  199. data/rbs/fills/tuple/tuple.rbs +28 -0
  200. data/rbs/shims/ast/0/node.rbs +1 -1
  201. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  202. data/solargraph.gemspec +37 -35
  203. metadata +41 -41
  204. data/lib/solargraph/type_checker/checks.rb +0 -124
  205. data/lib/solargraph/type_checker/param_def.rb +0 -37
  206. data/lib/solargraph/yard_map/to_method.rb +0 -89
@@ -24,12 +24,26 @@ module Solargraph
24
24
  attr_reader :missing_docs
25
25
 
26
26
  # @param pins [Array<Solargraph::Pin::Base>]
27
- def initialize pins: []
27
+ # @param loose_unions [Boolean] if true, a potential type can be
28
+ # inferred if ANY of the UniqueTypes in the base chain's
29
+ # ComplexType match it. If false, every single UniqueTypes in
30
+ # the base must be ALL able to independently provide this
31
+ # type. The former is useful during completion, but the
32
+ # latter is best for typechecking at higher levels.
33
+ #
34
+ def initialize pins: [], loose_unions: true
28
35
  @source_map_hash = {}
29
36
  @cache = Cache.new
37
+ @loose_unions = loose_unions
30
38
  index pins
31
39
  end
32
40
 
41
+ # @param out [StringIO, IO, nil] output stream for logging
42
+ # @return [void]
43
+ def self.reset_core out: nil
44
+ @@core_map = RbsMap::CoreMap.new
45
+ end
46
+
33
47
  #
34
48
  # This is a mutable object, which is cached in the Chain class -
35
49
  # if you add any fields which change the results of calls (not
@@ -37,21 +51,24 @@ module Solargraph
37
51
  #
38
52
 
39
53
  # @param other [Object]
40
- def eql?(other)
54
+ def eql? other
41
55
  self.class == other.class &&
42
- # @sg-ignore Flow sensitive typing needs to handle self.class == other.class
56
+ # @sg-ignore flow sensitive typing needs to handle self.class == other.class
43
57
  equality_fields == other.equality_fields
44
58
  end
45
59
 
46
60
  # @param other [Object]
47
- def ==(other)
48
- self.eql?(other)
61
+ def == other
62
+ eql?(other)
49
63
  end
50
64
 
65
+ # @return [Integer]
51
66
  def hash
52
67
  equality_fields.hash
53
68
  end
54
69
 
70
+ attr_reader :loose_unions
71
+
55
72
  def to_s
56
73
  self.class.to_s
57
74
  end
@@ -98,11 +115,12 @@ module Solargraph
98
115
  end
99
116
  unresolved_requires = (bench.external_requires + conventions_environ.requires + bench.workspace.config.required).to_a.compact.uniq
100
117
  recreate_docmap = @unresolved_requires != unresolved_requires ||
101
- @doc_map&.uncached_yard_gemspecs&.any? ||
102
- @doc_map&.uncached_rbs_collection_gemspecs&.any? ||
103
- @doc_map&.rbs_collection_path != bench.workspace.rbs_collection_path
118
+ # @sg-ignore Unresolved call to rbs_collection_path on Solargraph::Workspace, nil
119
+ workspace.rbs_collection_path != bench.workspace.rbs_collection_path ||
120
+ @doc_map.uncached_gemspecs.any?
121
+
104
122
  if recreate_docmap
105
- @doc_map = DocMap.new(unresolved_requires, [], bench.workspace) # @todo Implement gem preferences
123
+ @doc_map = DocMap.new(unresolved_requires, bench.workspace, out: nil) # @todo Implement gem preferences
106
124
  @unresolved_requires = @doc_map.unresolved_requires
107
125
  end
108
126
  @cache.clear if store.update(@@core_map.pins, @doc_map.pins, conventions_environ.pins, iced_pins, live_pins)
@@ -110,21 +128,14 @@ module Solargraph
110
128
  self
111
129
  end
112
130
 
113
- # @todo need to model type def statement in chains as a symbol so
114
- # that this overload of 'protected' will typecheck @sg-ignore
115
- # @sg-ignore
116
- protected def equality_fields
117
- [self.class, @source_map_hash, conventions_environ, @doc_map, @unresolved_requires]
118
- end
119
-
120
131
  # @return [DocMap]
121
132
  def doc_map
122
- @doc_map ||= DocMap.new([], [])
133
+ @doc_map ||= DocMap.new([], Workspace.new('.'))
123
134
  end
124
135
 
125
136
  # @return [::Array<Gem::Specification>]
126
137
  def uncached_gemspecs
127
- @doc_map&.uncached_gemspecs || []
138
+ doc_map.uncached_gemspecs || []
128
139
  end
129
140
 
130
141
  # @return [::Array<Gem::Specification>]
@@ -142,9 +153,10 @@ module Solargraph
142
153
  @@core_map.pins
143
154
  end
144
155
 
145
- # @param name [String]
156
+ # @param name [String, nil]
146
157
  # @return [YARD::Tags::MacroDirective, nil]
147
158
  def named_macro name
159
+ # @sg-ignore Need to add nil check here
148
160
  store.named_macros[name]
149
161
  end
150
162
 
@@ -180,10 +192,11 @@ module Solargraph
180
192
  # Create an ApiMap with a workspace in the specified directory.
181
193
  #
182
194
  # @param directory [String]
195
+ # @param loose_unions [Boolean] See #initialize
183
196
  #
184
197
  # @return [ApiMap]
185
- def self.load directory
186
- api_map = new
198
+ def self.load directory, loose_unions: true
199
+ api_map = new(loose_unions: loose_unions)
187
200
  workspace = Solargraph::Workspace.new(directory)
188
201
  # api_map.catalog Bench.new(workspace: workspace)
189
202
  library = Library.new(workspace)
@@ -192,18 +205,19 @@ module Solargraph
192
205
  api_map
193
206
  end
194
207
 
195
- # @param out [IO, nil]
208
+ # @param out [StringIO, IO, nil]
209
+ # @param rebuild [Boolean] whether to rebuild the pins even if they are cached
196
210
  # @return [void]
197
- def cache_all!(out)
198
- @doc_map.cache_all!(out)
211
+ def cache_all_for_doc_map! out: $stderr, rebuild: false
212
+ doc_map.cache_all!(out, rebuild: rebuild)
199
213
  end
200
214
 
201
215
  # @param gemspec [Gem::Specification]
202
216
  # @param rebuild [Boolean]
203
- # @param out [IO, nil]
217
+ # @param out [StringIO, IO, nil]
204
218
  # @return [void]
205
- def cache_gem(gemspec, rebuild: false, out: nil)
206
- @doc_map.cache(gemspec, rebuild: rebuild, out: out)
219
+ def cache_gem gemspec, rebuild: false, out: nil
220
+ doc_map.cache(gemspec, rebuild: rebuild, out: out)
207
221
  end
208
222
 
209
223
  class << self
@@ -215,18 +229,19 @@ module Solargraph
215
229
  #
216
230
  #
217
231
  # @param directory [String]
218
- # @param out [IO] The output stream for messages
232
+ # @param out [IO, StringIO, nil] The output stream for messages
233
+ # @param loose_unions [Boolean] See #initialize
219
234
  #
220
235
  # @return [ApiMap]
221
- def self.load_with_cache directory, out
222
- api_map = load(directory)
236
+ def self.load_with_cache directory, out = $stderr, loose_unions: true
237
+ api_map = load(directory, loose_unions: loose_unions)
223
238
  if api_map.uncached_gemspecs.empty?
224
239
  logger.info { "All gems cached for #{directory}" }
225
240
  return api_map
226
241
  end
227
242
 
228
- api_map.cache_all!(out)
229
- load(directory)
243
+ api_map.cache_all_for_doc_map!(out: out)
244
+ load(directory, loose_unions: loose_unions)
230
245
  end
231
246
 
232
247
  # @return [Array<Solargraph::Pin::Base>]
@@ -241,6 +256,12 @@ module Solargraph
241
256
  store.pins_by_class(Pin::Keyword)
242
257
  end
243
258
 
259
+ # @param name [String]
260
+ # @return [ComplexType, nil]
261
+ def unalias name
262
+ store.unalias(name)
263
+ end
264
+
244
265
  # True if the namespace exists.
245
266
  #
246
267
  # @param name [String] The namespace to match
@@ -306,19 +327,19 @@ module Solargraph
306
327
  #
307
328
  # @param pin [Pin::Reference]
308
329
  # @return [String, nil]
309
- def dereference(pin)
330
+ def dereference pin
310
331
  store.constants.dereference(pin)
311
332
  end
312
333
 
313
334
  # @param fqns [String]
314
335
  # @return [Array<Pin::Reference::Extend>]
315
- def get_extends(fqns)
336
+ def get_extends fqns
316
337
  store.get_extends(fqns)
317
338
  end
318
339
 
319
340
  # @param fqns [String]
320
341
  # @return [Array<Pin::Reference::Include>]
321
- def get_includes(fqns)
342
+ def get_includes fqns
322
343
  store.get_includes(fqns)
323
344
  end
324
345
 
@@ -328,29 +349,47 @@ module Solargraph
328
349
  # @param namespace [String] A fully qualified namespace
329
350
  # @param scope [Symbol] :instance or :class
330
351
  # @return [Array<Solargraph::Pin::InstanceVariable>]
331
- def get_instance_variable_pins(namespace, scope = :instance)
352
+ def get_instance_variable_pins namespace, scope = :instance
332
353
  result = []
333
- used = [namespace]
354
+ [namespace]
334
355
  result.concat store.get_instance_variables(namespace, scope)
335
356
  sc_fqns = namespace
336
357
  while (sc = store.get_superclass(sc_fqns))
358
+ # @sg-ignore flow sensitive typing needs to handle "if foo = bar"
337
359
  sc_fqns = store.constants.dereference(sc)
338
360
  result.concat store.get_instance_variables(sc_fqns, scope)
339
361
  end
340
362
  result
341
363
  end
342
364
 
343
- # @sg-ignore Missing @return tag for Solargraph::ApiMap#visible_pins
344
- # @see Solargraph::Parser::FlowSensitiveTyping#visible_pins
345
- def visible_pins(*args, **kwargs, &blk)
346
- Solargraph::Parser::FlowSensitiveTyping.visible_pins(*args, **kwargs, &blk)
365
+ # Find a variable pin by name and where it is used.
366
+ #
367
+ # Resolves our most specific view of this variable's type by
368
+ # preferring pins created by flow-sensitive typing when we have
369
+ # them based on the Closure and Location.
370
+ #
371
+ # @param candidates [Array<Pin::BaseVariable>]
372
+ # @param name [String]
373
+ # @param closure [Pin::Closure]
374
+ # @param location [Location]
375
+ #
376
+ # @return [Pin::BaseVariable, nil]
377
+ def var_at_location candidates, name, closure, location
378
+ with_correct_name = candidates.select { |pin| pin.name == name }
379
+ vars_at_location = with_correct_name.reject do |pin|
380
+ # visible_at? excludes the starting position, but we want to
381
+ # include it for this purpose
382
+ !pin.visible_at?(closure, location) && !pin.starts_at?(location)
383
+ end
384
+
385
+ vars_at_location.inject(&:combine_with)
347
386
  end
348
387
 
349
388
  # Get an array of class variable pins for a namespace.
350
389
  #
351
390
  # @param namespace [String] A fully qualified namespace
352
391
  # @return [Enumerable<Solargraph::Pin::ClassVariable>]
353
- def get_class_variable_pins(namespace)
392
+ def get_class_variable_pins namespace
354
393
  prefer_non_nil_variables(store.get_class_variables(namespace))
355
394
  end
356
395
 
@@ -417,7 +456,7 @@ module Solargraph
417
456
  comments: init_pin.comments,
418
457
  closure: init_pin.closure,
419
458
  source: init_pin.source,
420
- type_location: init_pin.type_location,
459
+ type_location: init_pin.type_location
421
460
  )
422
461
  new_pin.parameters = init_pin.parameters.map do |init_param|
423
462
  param = init_param.clone
@@ -476,7 +515,7 @@ module Solargraph
476
515
  result = Set.new
477
516
  complex_type.each do |type|
478
517
  if type.duck_type?
479
- result.add Pin::DuckMethod.new(name: type.to_s[1..-1], source: :api_map)
518
+ result.add Pin::DuckMethod.new(name: type.to_s[1..], source: :api_map)
480
519
  result.merge get_methods('Object')
481
520
  else
482
521
  unless type.nil? || type.name == 'void'
@@ -507,12 +546,14 @@ module Solargraph
507
546
  # @param preserve_generics [Boolean] True to preserve any
508
547
  # unresolved generic parameters, false to erase them
509
548
  # @return [Array<Solargraph::Pin::Method>]
510
- def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
549
+ def get_method_stack rooted_tag, name, scope: :instance, visibility: %i[private protected public],
550
+ preserve_generics: false
511
551
  rooted_type = ComplexType.parse(rooted_tag)
512
552
  fqns = rooted_type.namespace
513
553
  namespace_pin = store.get_path_pins(fqns).first
514
554
  methods = if namespace_pin.is_a?(Pin::Constant)
515
- type = namespace_pin.infer(self)
555
+ type = namespace_pin.typify(self)
556
+ type = namespace_pin.probe(self) unless type.defined?
516
557
  if type.defined?
517
558
  namespace_pin = store.get_path_pins(type.namespace).first
518
559
  get_methods(type.namespace, scope: scope, visibility: visibility).select { |p| p.name == name }
@@ -630,18 +671,22 @@ module Solargraph
630
671
  # @param sup [String] The superclass
631
672
  # @param sub [String] The subclass
632
673
  # @return [Boolean]
633
- def super_and_sub?(sup, sub)
674
+ def super_and_sub? sup, sub
634
675
  sup = ComplexType.try_parse(sup)
635
676
  sub = ComplexType.try_parse(sub)
636
677
  # @todo If two literals are different values of the same type, it would
637
678
  # make more sense for super_and_sub? to return true, but there are a
638
679
  # few callers that currently expect this to be false.
680
+ # @sg-ignore flow-sensitive typing should be able to handle redefinition
639
681
  return false if sup.literal? && sub.literal? && sup.to_s != sub.to_s
682
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
640
683
  sup = sup.simplify_literals.to_s
684
+ # @sg-ignore flow sensitive typing should be able to handle redefinition
641
685
  sub = sub.simplify_literals.to_s
642
686
  return true if sup == sub
643
687
  sc_fqns = sub
644
688
  while (sc = store.get_superclass(sc_fqns))
689
+ # @sg-ignore flow sensitive typing needs to handle "if foo = bar"
645
690
  sc_new = store.constants.dereference(sc)
646
691
  # Cyclical inheritance is invalid
647
692
  return false if sc_new == sc_fqns
@@ -658,24 +703,32 @@ module Solargraph
658
703
  # @param module_ns [String] The module namespace (no type parameters)
659
704
  #
660
705
  # @return [Boolean]
661
- def type_include?(host_ns, module_ns)
706
+ def type_include? host_ns, module_ns
662
707
  store.get_includes(host_ns).map { |inc_tag| inc_tag.type.name }.include?(module_ns)
663
708
  end
664
709
 
665
710
  # @param pins [Enumerable<Pin::Base>]
666
711
  # @param visibility [Enumerable<Symbol>]
667
712
  # @return [Array<Pin::Base>]
668
- def resolve_method_aliases pins, visibility = [:public, :private, :protected]
713
+ def resolve_method_aliases pins, visibility = %i[public private protected]
669
714
  with_resolved_aliases = pins.map do |pin|
670
715
  next pin unless pin.is_a?(Pin::MethodAlias)
671
716
  resolved = resolve_method_alias(pin)
717
+ # @sg-ignore Need to add nil check here
672
718
  next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
673
719
  resolved
674
720
  end.compact
675
- logger.debug { "ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}" }
721
+ logger.debug do
722
+ "ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}"
723
+ end
676
724
  GemPins.combine_method_pins_by_path(with_resolved_aliases)
677
725
  end
678
726
 
727
+ # @return [Workspace, nil]
728
+ def workspace
729
+ doc_map.workspace
730
+ end
731
+
679
732
  # @param fq_reference_tag [String] A fully qualified whose method should be pulled in
680
733
  # @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
681
734
  # parameter - used to pull generics information
@@ -687,7 +740,7 @@ module Solargraph
687
740
  # @param skip [Set<String>]
688
741
  # @param no_core [Boolean] Skip core classes if true
689
742
  # @return [Array<Pin::Base>]
690
- def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
743
+ def inner_get_methods_from_reference fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core
691
744
  logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
692
745
 
693
746
  # Ensure the types returned by the methods in the referenced
@@ -743,7 +796,7 @@ module Solargraph
743
796
  def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
744
797
  rooted_type = ComplexType.parse(rooted_tag).force_rooted
745
798
  fqns = rooted_type.namespace
746
- fqns_generic_params = rooted_type.all_params
799
+ rooted_type.all_params
747
800
  namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
748
801
  return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
749
802
  reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
@@ -754,7 +807,9 @@ module Solargraph
754
807
  # ensure we start out with any immediate methods in this
755
808
  # namespace so we roughly match the same ordering of get_methods
756
809
  # and obey the 'deep' instruction
757
- direct_convention_methods, convention_methods_by_reference = environ.pins.partition { |p| p.namespace == rooted_tag }
810
+ direct_convention_methods, convention_methods_by_reference = environ.pins.partition do |p|
811
+ p.namespace == rooted_tag
812
+ end
758
813
  result.concat direct_convention_methods
759
814
 
760
815
  if deep && scope == :instance
@@ -766,8 +821,10 @@ module Solargraph
766
821
  # Store#get_methods doesn't know about full tags, just
767
822
  # namespaces; resolving the generics in the method pins is this
768
823
  # class' responsibility
769
- methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
770
- logger.info { "ApiMap#inner_get_methods(rooted_tag=#{rooted_tag.inspect}, scope=#{scope.inspect}, visibility=#{visibility.inspect}, deep=#{deep.inspect}, skip=#{skip.inspect}, fqns=#{fqns}) - added from store: #{methods}" }
824
+ methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort { |a, b| a.name <=> b.name }
825
+ logger.info do
826
+ "ApiMap#inner_get_methods(rooted_tag=#{rooted_tag.inspect}, scope=#{scope.inspect}, visibility=#{visibility.inspect}, deep=#{deep.inspect}, skip=#{skip.inspect}, fqns=#{fqns}) - added from store: #{methods}"
827
+ end
771
828
  result.concat methods
772
829
  if deep
773
830
  result.concat convention_methods_by_reference
@@ -775,21 +832,27 @@ module Solargraph
775
832
  if scope == :instance
776
833
  store.get_includes(fqns).reverse.each do |ref|
777
834
  in_tag = dereference(ref)
778
- result.concat inner_get_methods_from_reference(in_tag, namespace_pin, rooted_type, scope, visibility, deep, skip, true)
835
+ # @sg-ignore Need to add nil check here
836
+ result.concat inner_get_methods_from_reference(in_tag, namespace_pin, rooted_type, scope, visibility, deep,
837
+ skip, true)
779
838
  end
780
839
  rooted_sc_tag = qualify_superclass(rooted_tag)
781
840
  unless rooted_sc_tag.nil?
782
- result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, no_core)
841
+ result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope,
842
+ visibility, true, skip, no_core)
783
843
  end
784
844
  else
785
- logger.info { "ApiMap#inner_get_methods(#{fqns}, #{scope}, #{visibility}, #{deep}, #{skip}) - looking for get_extends() from #{fqns}" }
845
+ logger.info do
846
+ "ApiMap#inner_get_methods(#{fqns}, #{scope}, #{visibility}, #{deep}, #{skip}) - looking for get_extends() from #{fqns}"
847
+ end
786
848
  store.get_extends(fqns).reverse.each do |em|
787
849
  fqem = dereference(em)
788
850
  result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
789
851
  end
790
852
  rooted_sc_tag = qualify_superclass(rooted_tag)
791
853
  unless rooted_sc_tag.nil?
792
- result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, true)
854
+ result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope,
855
+ visibility, true, skip, true)
793
856
  end
794
857
  unless no_core || fqns.empty?
795
858
  type = get_namespace_type(fqns)
@@ -817,7 +880,7 @@ module Solargraph
817
880
  def get_namespace_type fqns
818
881
  return nil if fqns.nil?
819
882
  # @type [Pin::Namespace, nil]
820
- pin = store.get_path_pins(fqns).select{|p| p.is_a?(Pin::Namespace)}.first
883
+ pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
821
884
  return nil if pin.nil?
822
885
  pin.type
823
886
  end
@@ -841,18 +904,21 @@ module Solargraph
841
904
 
842
905
  include Logging
843
906
 
844
- private
845
-
846
907
  # @param alias_pin [Pin::MethodAlias]
847
908
  # @return [Pin::Method, nil]
848
- def resolve_method_alias(alias_pin)
909
+ def resolve_method_alias alias_pin
849
910
  ancestors = store.get_ancestors(alias_pin.full_context.reduce_class_type.tag)
911
+ # @type [Pin::Method, nil]
850
912
  original = nil
851
913
 
852
914
  # Search each ancestor for the original method
853
915
  ancestors.each do |ancestor_fqns|
854
916
  next if ancestor_fqns.nil?
855
- ancestor_method_path = "#{ancestor_fqns}#{alias_pin.scope == :instance ? '#' : '.'}#{alias_pin.original}"
917
+ ancestor_method_path = if alias_pin.original == 'new' && alias_pin.scope == :class
918
+ "#{ancestor_fqns}#initialize"
919
+ else
920
+ "#{ancestor_fqns}#{alias_pin.scope == :instance ? '#' : '.'}#{alias_pin.original}"
921
+ end
856
922
 
857
923
  # Search for the original method in the ancestor
858
924
  original = store.get_path_pins(ancestor_method_path).find do |candidate_pin|
@@ -864,21 +930,29 @@ module Solargraph
864
930
  break resolved if resolved
865
931
  end
866
932
 
867
- candidate_pin.is_a?(Pin::Method) && candidate_pin.scope == alias_pin.scope
933
+ candidate_pin.is_a?(Pin::Method)
868
934
  end
869
935
 
870
936
  break if original
871
937
  end
938
+ if original.nil?
939
+ # :nocov:
940
+ Solargraph.assert_or_log(:alias_target_missing) do
941
+ "Rejecting alias - target is missing while looking for #{alias_pin.full_context.tag} #{alias_pin.original} in #{alias_pin.scope} scope = #{alias_pin.inspect}"
942
+ end
943
+ return nil
944
+ # :nocov:
945
+ end
872
946
 
873
947
  # @sg-ignore ignore `received nil` for original
874
- create_resolved_alias_pin(alias_pin, original) if original
948
+ create_resolved_alias_pin(alias_pin, original)
875
949
  end
876
950
 
877
951
  # Fast path for creating resolved alias pins without individual method stack lookups
878
952
  # @param alias_pin [Pin::MethodAlias] The alias pin to resolve
879
953
  # @param original [Pin::Method] The original method pin that was already found
880
954
  # @return [Pin::Method] The resolved method pin
881
- def create_resolved_alias_pin(alias_pin, original)
955
+ def create_resolved_alias_pin alias_pin, original
882
956
  # Build the resolved method pin directly (same logic as resolve_method_alias but without lookup)
883
957
  args = {
884
958
  location: alias_pin.location,
@@ -894,7 +968,7 @@ module Solargraph
894
968
  return_type: original.return_type,
895
969
  source: :resolve_method_alias
896
970
  }
897
- resolved_pin = Pin::Method.new **args
971
+ resolved_pin = Pin::Method.new(**args)
898
972
 
899
973
  # Clone signatures and parameters
900
974
  resolved_pin.signatures.each do |sig|
@@ -916,7 +990,7 @@ module Solargraph
916
990
  # @param rooted_type [ComplexType]
917
991
  # @param pins [Enumerable<Pin::Base>]
918
992
  # @return [Array<Pin::Base>]
919
- def erase_generics(namespace_pin, rooted_type, pins)
993
+ def erase_generics namespace_pin, rooted_type, pins
920
994
  return pins unless should_erase_generics_when_done?(namespace_pin, rooted_type)
921
995
 
922
996
  logger.debug("Erasing generics on namespace_pin=#{namespace_pin} / rooted_type=#{rooted_type}")
@@ -927,19 +1001,29 @@ module Solargraph
927
1001
 
928
1002
  # @param namespace_pin [Pin::Namespace]
929
1003
  # @param rooted_type [ComplexType]
930
- def should_erase_generics_when_done?(namespace_pin, rooted_type)
1004
+ def should_erase_generics_when_done? namespace_pin, rooted_type
931
1005
  has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
932
1006
  end
933
1007
 
934
1008
  # @param namespace_pin [Pin::Namespace, Pin::Constant]
935
- def has_generics?(namespace_pin)
1009
+ def has_generics? namespace_pin
936
1010
  namespace_pin.is_a?(Pin::Namespace) && !namespace_pin.generics.empty?
937
1011
  end
938
1012
 
939
1013
  # @param namespace_pin [Pin::Namespace]
940
1014
  # @param rooted_type [ComplexType]
941
- def can_resolve_generics?(namespace_pin, rooted_type)
1015
+ def can_resolve_generics? namespace_pin, rooted_type
942
1016
  has_generics?(namespace_pin) && !rooted_type.all_params.empty?
943
1017
  end
1018
+
1019
+ protected
1020
+
1021
+ # @todo need to model type def statement in chains as a symbol so
1022
+ # that this overload of 'protected' will typecheck @sg-ignore
1023
+ # @sg-ignore
1024
+ def equality_fields
1025
+ [self.class, @source_map_hash, conventions_environ, @doc_map, @unresolved_requires, @missing_docs,
1026
+ @loose_unions]
1027
+ end
944
1028
  end
945
1029
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Solargraph
5
4
  # A container of source maps and workspace data to be cataloged in an ApiMap.
6
5
  #
@@ -30,11 +29,11 @@ module Solargraph
30
29
  .to_set
31
30
  end
32
31
 
32
+ # @sg-ignore flow sensitive typing needs better handling of ||= on lvars
33
33
  # @return [Hash{String => SourceMap}]
34
34
  def source_map_hash
35
35
  # @todo Work around #to_h bug in current Ruby head (3.5) with #map#to_h
36
- @source_map_hash ||= source_maps.map { |s| [s.filename, s] }
37
- .to_h
36
+ @source_map_hash ||= source_maps.to_h { |s| [s.filename, s] }
38
37
  end
39
38
 
40
39
  # @return [Set<SourceMap>]