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