solargraph 0.59.0.dev.2 → 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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +3 -1
  3. data/.github/workflows/plugins.yml +8 -2
  4. data/.github/workflows/rspec.yml +6 -40
  5. data/.github/workflows/typecheck.yml +2 -1
  6. data/.rubocop.yml +6 -1
  7. data/.rubocop_todo.yml +3 -0
  8. data/CHANGELOG.md +15 -0
  9. data/lib/solargraph/api_map/constants.rb +0 -1
  10. data/lib/solargraph/api_map/index.rb +6 -0
  11. data/lib/solargraph/api_map/store.rb +6 -0
  12. data/lib/solargraph/api_map.rb +20 -4
  13. data/lib/solargraph/complex_type/type_methods.rb +2 -1
  14. data/lib/solargraph/complex_type/unique_type.rb +2 -4
  15. data/lib/solargraph/complex_type.rb +1 -1
  16. data/lib/solargraph/doc_map.rb +370 -131
  17. data/lib/solargraph/gem_pins.rb +16 -17
  18. data/lib/solargraph/library.rb +44 -66
  19. data/lib/solargraph/logging.rb +0 -2
  20. data/lib/solargraph/parser/flow_sensitive_typing.rb +0 -2
  21. data/lib/solargraph/parser/parser_gem/class_methods.rb +0 -2
  22. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +0 -1
  23. data/lib/solargraph/pin/base.rb +0 -2
  24. data/lib/solargraph/pin/method.rb +3 -0
  25. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  26. data/lib/solargraph/pin/reference.rb +1 -0
  27. data/lib/solargraph/pin_cache.rb +66 -480
  28. data/lib/solargraph/position.rb +7 -4
  29. data/lib/solargraph/rbs_map/conversions.rb +18 -18
  30. data/lib/solargraph/rbs_map.rb +2 -3
  31. data/lib/solargraph/shell.rb +163 -15
  32. data/lib/solargraph/source/chain.rb +3 -1
  33. data/lib/solargraph/source_map/mapper.rb +0 -2
  34. data/lib/solargraph/type_checker.rb +1 -2
  35. data/lib/solargraph/version.rb +1 -1
  36. data/lib/solargraph/workspace/config.rb +1 -1
  37. data/lib/solargraph/workspace/gemspecs.rb +2 -2
  38. data/lib/solargraph/workspace.rb +32 -129
  39. data/lib/solargraph/yard_map.rb +17 -18
  40. data/lib/solargraph/yardoc.rb +26 -33
  41. data/lib/solargraph.rb +2 -0
  42. data/solargraph.gemspec +2 -2
  43. metadata +6 -11
@@ -1,437 +1,13 @@
1
- # frozen_string_literal: true
2
-
1
+ require 'yard-activesupport-concern'
3
2
  require 'fileutils'
3
+ require 'pathname' # @todo Required by RBS but not loaded in some use cases
4
4
  require 'rbs'
5
- require 'rubygems'
6
5
 
7
6
  module Solargraph
8
- class PinCache
9
- include Logging
10
-
11
- attr_reader :directory, :rbs_collection_path, :rbs_collection_config_path, :yard_plugins
12
-
13
- # @param rbs_collection_path [String, nil]
14
- # @param rbs_collection_config_path [String, nil]
15
- # @param directory [String, nil]
16
- # @param yard_plugins [Array<String>]
17
- def initialize rbs_collection_path:, rbs_collection_config_path:,
18
- directory:,
19
- yard_plugins:
20
- @rbs_collection_path = rbs_collection_path
21
- @rbs_collection_config_path = rbs_collection_config_path
22
- @directory = directory
23
- @yard_plugins = yard_plugins
24
- end
25
-
26
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
27
- def cached? gemspec
28
- rbs_version_cache_key = lookup_rbs_version_cache_key(gemspec)
29
- combined_gem?(gemspec, rbs_version_cache_key)
30
- end
31
-
32
- # @param gemspec [Gem::Specification]
33
- # @param rebuild [Boolean] whether to rebuild the cache regardless of whether it already exists
34
- # @param out [StringIO, IO, nil] output stream for logging
35
- # @return [void]
36
- def cache_gem gemspec:, rebuild: false, out: nil
37
- rbs_version_cache_key = lookup_rbs_version_cache_key(gemspec)
38
-
39
- build_yard, build_rbs_collection, build_combined =
40
- calculate_build_needs(gemspec,
41
- rebuild: rebuild,
42
- rbs_version_cache_key: rbs_version_cache_key)
43
-
44
- return unless build_yard || build_rbs_collection || build_combined
45
-
46
- build_combine_and_cache(gemspec,
47
- rbs_version_cache_key,
48
- build_yard: build_yard,
49
- build_rbs_collection: build_rbs_collection,
50
- build_combined: build_combined,
51
- out: out)
52
- end
53
-
54
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
55
- # @param rbs_version_cache_key [String, nil]
56
- def suppress_yard_cache? gemspec, rbs_version_cache_key
57
- if gemspec.name == 'parser' && rbs_version_cache_key != RbsMap::CACHE_KEY_UNRESOLVED
58
- # parser takes forever to build YARD pins, but has excellent RBS collection pins
59
- return true
60
- end
61
- false
62
- end
63
-
64
- # @param out [StringIO, IO, nil] output stream for logging
65
- # @param rebuild [Boolean] build pins regardless of whether we
66
- # have cached them already
67
- #
68
- # @return [void]
69
- def cache_all_stdlibs rebuild: false, out: $stderr
70
- possible_stdlibs.each do |stdlib|
71
- RbsMap::StdlibMap.new(stdlib, rebuild: rebuild, out: out)
72
- end
73
- end
74
-
75
- # @param path [String] require path that might be in the RBS stdlib collection
76
- # @return [void]
77
- def cache_stdlib_rbs_map path
78
- # these are held in memory in RbsMap::StdlibMap
79
- map = RbsMap::StdlibMap.load(path)
80
- if map.resolved?
81
- logger.debug { "Loading stdlib pins for #{path}" }
82
- pins = map.pins
83
- logger.debug { "Loaded #{pins.length} stdlib pins for #{path}" }
84
- pins
85
- else
86
- # @todo Temporarily ignoring unresolved `require 'set'`
87
- logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
88
- nil
89
- end
90
- end
91
-
92
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
93
- #
94
- # @return [String]
95
- def lookup_rbs_version_cache_key gemspec
96
- rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
97
- rbs_map.cache_key
98
- end
99
-
100
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
101
- # @param rbs_version_cache_key [String, nil]
102
- # @param yard_pins [Array<Pin::Base>]
103
- # @param rbs_collection_pins [Array<Pin::Base>]
104
- # @return [void]
105
- def cache_combined_pins gemspec, rbs_version_cache_key, yard_pins, rbs_collection_pins
106
- combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
107
- serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
108
- end
109
-
110
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
111
- # @return [Array<Pin::Base>, nil]
112
- def deserialize_combined_pin_cache gemspec
113
- rbs_version_cache_key = lookup_rbs_version_cache_key(gemspec)
114
-
115
- load_combined_gem(gemspec, rbs_version_cache_key)
116
- end
117
-
118
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
119
- # @param out [StringIO, IO, nil]
120
- # @return [void]
121
- def uncache_gem gemspec, out: nil
122
- PinCache.uncache(yardoc_path(gemspec), out: out)
123
- PinCache.uncache(yard_gem_path(gemspec), out: out)
124
- uncache_by_prefix(rbs_collection_pins_path_prefix(gemspec), out: out)
125
- uncache_by_prefix(combined_path_prefix(gemspec), out: out)
126
- rbs_version_cache_key = lookup_rbs_version_cache_key(gemspec)
127
- combined_pins_in_memory.delete([gemspec.name, gemspec.version, rbs_version_cache_key])
128
- end
129
-
130
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
131
- def yardoc_processing? gemspec
132
- Yardoc.processing?(yardoc_path(gemspec))
133
- end
134
-
135
- # @return [Array<String>] a list of possible standard library names
136
- def possible_stdlibs
137
- # all dirs and .rb files in Gem::RUBYGEMS_DIR
138
- Dir.glob(File.join(Gem::RUBYGEMS_DIR, '*')).map do |file_or_dir|
139
- basename = File.basename(file_or_dir)
140
- # remove .rb
141
- # @sg-ignore flow sensitive typing should be able to handle redefinition
142
- basename = basename[0..-4] if basename.end_with?('.rb')
143
- basename
144
- end.sort.uniq
145
- rescue StandardError => e
146
- logger.info { "Failed to get possible stdlibs: #{e.message}" }
147
- # @sg-ignore Need to add nil check here
148
- logger.debug { e.backtrace.join("\n") }
149
- []
150
- end
151
-
152
- private
153
-
154
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
155
- # @param rebuild [Boolean] whether to rebuild the cache regardless of whether it already exists
156
- # @param rbs_version_cache_key [String, nil] the cache key for the gem in the RBS collection
157
- #
158
- # @return [Array(Boolean, Boolean, Boolean)] whether to build YARD
159
- # pins, RBS collection pins, and combined pins
160
- def calculate_build_needs gemspec, rebuild:, rbs_version_cache_key:
161
- if rebuild
162
- build_yard = true
163
- build_rbs_collection = true
164
- build_combined = true
165
- else
166
- build_yard = !yard_gem?(gemspec)
167
- build_rbs_collection = !rbs_collection_pins?(gemspec, rbs_version_cache_key)
168
- # @sg-ignore Need to add nil check here
169
- build_combined = !combined_gem?(gemspec, rbs_version_cache_key) || build_yard || build_rbs_collection
170
- end
171
-
172
- build_yard = false if suppress_yard_cache?(gemspec, rbs_version_cache_key)
173
-
174
- [build_yard, build_rbs_collection, build_combined]
175
- end
176
-
177
- # @param gemspec [Gem::Specification]
178
- # @param rbs_version_cache_key [String, nil]
179
- # @param build_yard [Boolean]
180
- # @param build_rbs_collection [Boolean]
181
- # @param build_combined [Boolean]
182
- # @param out [StringIO, IO, nil]
183
- #
184
- # @return [void]
185
- def build_combine_and_cache gemspec,
186
- rbs_version_cache_key,
187
- build_yard:,
188
- build_rbs_collection:,
189
- build_combined:,
190
- out:
191
- log_cache_info(gemspec, rbs_version_cache_key,
192
- build_yard: build_yard,
193
- build_rbs_collection: build_rbs_collection,
194
- build_combined: build_combined,
195
- out: out)
196
- cache_yard_pins(gemspec, out) if build_yard
197
- # this can be nil even if we aren't told to build it - see suppress_yard_cache?
198
- yard_pins = deserialize_yard_pin_cache(gemspec) || []
199
- cache_rbs_collection_pins(gemspec, out) if build_rbs_collection
200
- rbs_collection_pins = deserialize_rbs_collection_cache(gemspec, rbs_version_cache_key) || []
201
- cache_combined_pins(gemspec, rbs_version_cache_key, yard_pins, rbs_collection_pins) if build_combined
202
- end
203
-
204
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
205
- # @param rbs_version_cache_key [String, nil]
206
- # @param build_yard [Boolean]
207
- # @param build_rbs_collection [Boolean]
208
- # @param build_combined [Boolean]
209
- # @param out [StringIO, IO, nil]
210
- #
211
- # @return [void]
212
- def log_cache_info gemspec,
213
- rbs_version_cache_key,
214
- build_yard:,
215
- build_rbs_collection:,
216
- build_combined:,
217
- out:
218
- type = []
219
- type << 'YARD' if build_yard
220
- rbs_source_desc = RbsMap.rbs_source_desc(rbs_version_cache_key)
221
- type << rbs_source_desc if build_rbs_collection && !rbs_source_desc.nil?
222
- # we'll build it anyway, but it won't take long to build with
223
- # only a single source
224
-
225
- # 'combining' is awkward terminology in this case
226
- just_yard = build_yard && rbs_source_desc.nil?
227
-
228
- type << 'combined' if build_combined && !just_yard
229
- out&.puts("Caching #{type.join(' and ')} pins for gem #{gemspec.name}:#{gemspec.version}")
230
- end
231
-
232
- # @param gemspec [Gem::Specification]
233
- # @param out [StringIO, IO, nil]
234
- # @return [Array<Pin::Base>]
235
- def cache_yard_pins gemspec, out
236
- gem_yardoc_path = yardoc_path(gemspec)
237
- Yardoc.build_docs(gem_yardoc_path, yard_plugins, gemspec) unless Yardoc.docs_built?(gem_yardoc_path)
238
- pins = Yardoc.build_pins(gem_yardoc_path, gemspec, out: out)
239
- serialize_yard_gem(gemspec, pins)
240
- logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
241
- pins
242
- end
243
-
244
- # @return [Hash{Array(String, String, String) => Array<Pin::Base>}]
245
- def combined_pins_in_memory
246
- PinCache.all_combined_pins_in_memory[yard_plugins] ||= {}
247
- end
248
-
249
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
250
- # @param _out [StringIO, IO, nil]
251
- # @return [Array<Pin::Base>]
252
- def cache_rbs_collection_pins gemspec, _out
253
- rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
254
- pins = rbs_map.pins
255
- rbs_version_cache_key = rbs_map.cache_key
256
- # cache pins even if result is zero, so we don't retry building pins
257
- pins ||= []
258
- serialize_rbs_collection_pins(gemspec, rbs_version_cache_key, pins)
259
- logger.info do
260
- unless pins.empty?
261
- "Cached #{pins.length} RBS collection pins for gem #{gemspec.name} #{gemspec.version} with " \
262
- "cache_key #{rbs_version_cache_key.inspect}"
263
- end
264
- end
265
- pins
266
- end
267
-
268
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
269
- # @return [Array<Pin::Base>, nil]
270
- def deserialize_yard_pin_cache gemspec
271
- cached = load_yard_gem(gemspec)
272
- if cached
273
- cached
274
- else
275
- logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
276
- nil
277
- end
278
- end
279
-
280
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
281
- # @param rbs_version_cache_key [String, nil]
282
- # @return [Array<Pin::Base>, nil]
283
- def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
284
- cached = load_rbs_collection_pins(gemspec, rbs_version_cache_key)
285
- Solargraph.assert_or_log(:pin_cache_rbs_collection, 'Asked for non-existent rbs collection') if cached.nil?
286
- logger.info do
287
- "Loaded #{cached&.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}"
288
- end
289
- cached
290
- end
291
-
292
- # @return [Array<String>]
293
- def yard_path_components
294
- ["yard-#{YARD::VERSION}",
295
- yard_plugins.sort.uniq.join('-')]
296
- end
297
-
298
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
299
- # @return [String]
300
- def yardoc_path gemspec
301
- File.join(PinCache.base_dir,
302
- *yard_path_components,
303
- "#{gemspec.name}-#{gemspec.version}.yardoc")
304
- end
305
-
306
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
307
- # @return [String]
308
- def yard_gem_path gemspec
309
- File.join(PinCache.work_dir, *yard_path_components, "#{gemspec.name}-#{gemspec.version}.ser")
310
- end
311
-
312
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
313
- # @return [Array<Pin::Base>, nil]
314
- def load_yard_gem gemspec
315
- PinCache.load(yard_gem_path(gemspec))
316
- end
317
-
318
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
319
- # @param pins [Array<Pin::Base>]
320
- # @return [void]
321
- def serialize_yard_gem gemspec, pins
322
- PinCache.save(yard_gem_path(gemspec), pins)
323
- end
324
-
325
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
326
- # @return [Boolean]
327
- def yard_gem? gemspec
328
- exist?(yard_gem_path(gemspec))
329
- end
330
-
331
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
332
- # @param hash [String, nil]
333
- # @return [String]
334
- def rbs_collection_pins_path gemspec, hash
335
- rbs_collection_pins_path_prefix(gemspec) + "#{hash || 0}.ser"
336
- end
337
-
338
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
339
- # @return [String]
340
- def rbs_collection_pins_path_prefix gemspec
341
- File.join(PinCache.work_dir, 'rbs', "#{gemspec.name}-#{gemspec.version}-")
342
- end
343
-
344
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
345
- # @param hash [String, nil]
346
- #
347
- # @return [Array<Pin::Base>, nil]
348
- def load_rbs_collection_pins gemspec, hash
349
- PinCache.load(rbs_collection_pins_path(gemspec, hash))
350
- end
351
-
352
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
353
- # @param hash [String, nil]
354
- # @param pins [Array<Pin::Base>]
355
- # @return [void]
356
- def serialize_rbs_collection_pins gemspec, hash, pins
357
- PinCache.save(rbs_collection_pins_path(gemspec, hash), pins)
358
- end
359
-
360
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
361
- # @param hash [String, nil]
362
- # @return [String]
363
- def combined_path gemspec, hash
364
- File.join(combined_path_prefix(gemspec) + "-#{hash || 0}.ser")
365
- end
366
-
367
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
368
- # @return [String]
369
- def combined_path_prefix gemspec
370
- File.join(PinCache.work_dir, 'combined', yard_plugins.sort.join('-'), "#{gemspec.name}-#{gemspec.version}")
371
- end
372
-
373
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
374
- # @param hash [String, nil]
375
- # @param pins [Array<Pin::Base>]
376
- # @return [void]
377
- def serialize_combined_gem gemspec, hash, pins
378
- PinCache.save(combined_path(gemspec, hash), pins)
379
- end
380
-
381
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
382
- # @param hash [String]
383
- def combined_gem? gemspec, hash
384
- exist?(combined_path(gemspec, hash))
385
- end
386
-
387
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
388
- # @param hash [String, nil]
389
- # @return [Array<Pin::Base>, nil]
390
- def load_combined_gem gemspec, hash
391
- cached = combined_pins_in_memory[[gemspec.name, gemspec.version, hash]]
392
- return cached if cached
393
- loaded = PinCache.load(combined_path(gemspec, hash))
394
- combined_pins_in_memory[[gemspec.name, gemspec.version, hash]] = loaded if loaded
395
- loaded
396
- end
397
-
398
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
399
- # @param hash [String, nil]
400
- def rbs_collection_pins? gemspec, hash
401
- exist?(rbs_collection_pins_path(gemspec, hash))
402
- end
403
-
404
- include Logging
405
-
406
- # @param path [String]
407
- def exist? *path
408
- File.file? File.join(*path)
409
- end
410
-
411
- # @return [void]
412
- # @param path_segments [Array<String>]
413
- # @param out [StringIO, IO, nil]
414
- def uncache_by_prefix *path_segments, out: nil
415
- path = File.join(*path_segments)
416
- glob = "#{path}*"
417
- out&.puts "Clearing pin cache in #{glob}"
418
- Dir.glob(glob).each do |file|
419
- next unless File.file?(file)
420
- FileUtils.rm_rf file, secure: true
421
- out&.puts "Clearing pin cache in #{file}"
422
- end
423
- end
424
-
7
+ module PinCache
425
8
  class << self
426
9
  include Logging
427
10
 
428
- # @return [Hash{Array<String> => Hash{Array(String, String) =>
429
- # Array<Pin::Base>}}] yard plugins, then gemspec name and
430
- # version
431
- def all_combined_pins_in_memory
432
- @all_combined_pins_in_memory ||= {}
433
- end
434
-
435
11
  # The base directory where cached YARD documentation and serialized pins are serialized
436
12
  #
437
13
  # @return [String]
@@ -443,47 +19,6 @@ module Solargraph
443
19
  File.join(Dir.home, '.cache', 'solargraph')
444
20
  end
445
21
 
446
- # @param path_segments [Array<String>]
447
- # @param out [IO, nil]
448
- # @return [void]
449
- def uncache *path_segments, out: nil
450
- path = File.join(*path_segments)
451
- if File.exist?(path)
452
- FileUtils.rm_rf path, secure: true
453
- out&.puts "Clearing pin cache in #{path}"
454
- else
455
- out&.puts "Pin cache file #{path} does not exist"
456
- end
457
- end
458
-
459
- # @return [void]
460
- # @param out [IO, nil]
461
- # @param path_segments [Array<String>]
462
- def uncache_by_prefix *path_segments, out: nil
463
- path = File.join(*path_segments)
464
- glob = "#{path}*"
465
- out&.puts "Clearing pin cache in #{glob}"
466
- Dir.glob(glob).each do |file|
467
- next unless File.file?(file)
468
- FileUtils.rm_rf file, secure: true
469
- out&.puts "Clearing pin cache in #{file}"
470
- end
471
- end
472
-
473
- # @param out [StringIO, IO, nil]
474
- # @return [void]
475
- def uncache_core out: nil
476
- uncache(core_path, out: out)
477
- # ApiMap keep this in memory
478
- ApiMap.reset_core(out: out)
479
- end
480
-
481
- # @param out [StringIO, IO, nil]
482
- # @return [void]
483
- def uncache_stdlib out: nil
484
- uncache(stdlib_path, out: out)
485
- end
486
-
487
22
  # The working directory for the current Ruby, RBS, and Solargraph versions.
488
23
  #
489
24
  # @return [String]
@@ -493,6 +28,15 @@ module Solargraph
493
28
  File.join(base_dir, "ruby-#{RUBY_VERSION}", "rbs-#{RBS::VERSION}", "solargraph-#{Solargraph::VERSION}")
494
29
  end
495
30
 
31
+ # @param gemspec [Gem::Specification]
32
+ # @return [String]
33
+ def yardoc_path gemspec
34
+ File.join(base_dir,
35
+ "yard-#{YARD::VERSION}",
36
+ "yard-activesupport-concern-#{YARD::ActiveSupport::Concern::VERSION}",
37
+ "#{gemspec.name}-#{gemspec.version}.yardoc")
38
+ end
39
+
496
40
  # @return [String]
497
41
  def stdlib_path
498
42
  File.join(work_dir, 'stdlib')
@@ -552,6 +96,12 @@ module Solargraph
552
96
  save(yard_gem_path(gemspec), pins)
553
97
  end
554
98
 
99
+ # @param gemspec [Gem::Specification]
100
+ # @return [Boolean]
101
+ def has_yard? gemspec
102
+ exist?(yard_gem_path(gemspec))
103
+ end
104
+
555
105
  # @param gemspec [Gem::Specification]
556
106
  # @param hash [String, nil]
557
107
  # @return [String]
@@ -615,13 +165,35 @@ module Solargraph
615
165
  exist?(rbs_collection_path(gemspec, hash))
616
166
  end
617
167
 
168
+ # @return [void]
169
+ def uncache_core
170
+ uncache(core_path)
171
+ end
172
+
173
+ # @return [void]
174
+ def uncache_stdlib
175
+ uncache(stdlib_path)
176
+ end
177
+
178
+ # @param gemspec [Gem::Specification]
179
+ # @param out [IO, StringIO, nil]
180
+ # @return [void]
181
+ def uncache_gem gemspec, out: nil
182
+ uncache(yardoc_path(gemspec), out: out)
183
+ uncache_by_prefix(rbs_collection_path_prefix(gemspec), out: out)
184
+ uncache(yard_gem_path(gemspec), out: out)
185
+ uncache_by_prefix(combined_path_prefix(gemspec), out: out)
186
+ end
187
+
618
188
  # @return [void]
619
189
  def clear
620
190
  FileUtils.rm_rf base_dir, secure: true
621
191
  end
622
192
 
193
+ private
194
+
623
195
  # @param file [String]
624
- # @sg-ignore Marshal.load evaluates to boolean here which is wrong
196
+ # @sg-ignore Marshal.load returns Object; we know it's Array<Pin::Base>
625
197
  # @return [Array<Solargraph::Pin::Base>, nil]
626
198
  def load file
627
199
  return nil unless File.file?(file)
@@ -632,6 +204,11 @@ module Solargraph
632
204
  nil
633
205
  end
634
206
 
207
+ # @param path [String]
208
+ def exist? *path
209
+ File.file? File.join(*path)
210
+ end
211
+
635
212
  # @param file [String]
636
213
  # @param pins [Array<Pin::Base>]
637
214
  # @return [void]
@@ -643,19 +220,28 @@ module Solargraph
643
220
  logger.debug { "Cache#save: Saved #{pins.length} pins to #{file}" }
644
221
  end
645
222
 
646
- def core?
647
- File.file?(core_path)
648
- end
649
-
650
- # @param out [StringIO, IO, nil]
651
- # @return [Array<Pin::Base>]
652
- def cache_core out: $stderr
653
- RbsMap::CoreMap.new.cache_core(out: out)
223
+ # @param path_segments [Array<String>]
224
+ # @return [void]
225
+ # @param [Object, nil] out
226
+ def uncache *path_segments, out: nil
227
+ path = File.join(*path_segments)
228
+ return unless File.exist?(path)
229
+ FileUtils.rm_rf path, secure: true
230
+ out&.puts "Clearing pin cache in #{path}"
654
231
  end
655
232
 
656
- # @param path [String]
657
- def exist? *path
658
- File.file? File.join(*path)
233
+ # @return [void]
234
+ # @param path_segments [Array<String>]
235
+ # @param [Object, nil] out
236
+ def uncache_by_prefix *path_segments, out: nil
237
+ path = File.join(*path_segments)
238
+ glob = "#{path}*"
239
+ out&.puts "Clearing pin cache in #{glob}"
240
+ Dir.glob(glob).each do |file|
241
+ next unless File.file?(file)
242
+ FileUtils.rm_rf file, secure: true
243
+ out&.puts "Clearing pin cache in #{file}"
244
+ end
659
245
  end
660
246
  end
661
247
  end
@@ -58,7 +58,8 @@ module Solargraph
58
58
  line = -1
59
59
  last_line_index = 0
60
60
 
61
- # @sg-ignore flow sensitive typing should be able to handle redefinition
61
+ # @sg-ignore Typechecker thinks `newline_index` inside of the assignment
62
+ # can be nil
62
63
  while (newline_index = text.index("\n", newline_index + 1)) && line <= position.line
63
64
  line += 1
64
65
  break if line == position.line
@@ -67,7 +68,8 @@ module Solargraph
67
68
  end
68
69
 
69
70
  last_line_index += 1 if position.line.positive?
70
- # @sg-ignore flow sensitive typing should be able to handle redefinition
71
+ # @sg-ignore `last_line_index` is always an Integer because `newline_index`
72
+ # is never nil inside the while block
71
73
  last_line_index + position.character
72
74
  end
73
75
 
@@ -97,10 +99,11 @@ module Solargraph
97
99
  character = offset
98
100
  newline_index = -1
99
101
 
100
- # @sg-ignore flow sensitive typing should be able to handle redefinition
102
+ # @sg-ignore Typechecker thinks `newline_index` inside of the assignment
103
+ # can be nil
101
104
  while (newline_index = text.index("\n", newline_index + 1)) && newline_index < offset
102
105
  line += 1
103
- # @sg-ignore flow sensitive typing should be able to handle redefinition
106
+ # @sg-ignore `newline_index` is always an Integer inside the while block
104
107
  character = offset - newline_index - 1
105
108
  end
106
109
  character = 0 if character.nil? && (cursor - offset).between?(0, 1)