solargraph 0.58.2 → 0.59.0.dev.1

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