solargraph 0.47.2 → 0.53.3

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/plugins.yml +40 -0
  4. data/.github/workflows/rspec.yml +4 -8
  5. data/.github/workflows/typecheck.yml +34 -0
  6. data/.yardopts +2 -2
  7. data/CHANGELOG.md +137 -3
  8. data/LICENSE +1 -1
  9. data/README.md +19 -16
  10. data/SPONSORS.md +2 -9
  11. data/lib/solargraph/api_map/cache.rb +60 -20
  12. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  13. data/lib/solargraph/api_map/store.rb +60 -12
  14. data/lib/solargraph/api_map.rb +171 -99
  15. data/lib/solargraph/bench.rb +3 -2
  16. data/lib/solargraph/cache.rb +77 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +61 -12
  18. data/lib/solargraph/complex_type/unique_type.rb +193 -16
  19. data/lib/solargraph/complex_type.rb +113 -10
  20. data/lib/solargraph/convention/rakefile.rb +17 -0
  21. data/lib/solargraph/convention.rb +2 -3
  22. data/lib/solargraph/converters/dd.rb +5 -0
  23. data/lib/solargraph/converters/dl.rb +3 -0
  24. data/lib/solargraph/converters/dt.rb +3 -0
  25. data/lib/solargraph/diagnostics/rubocop.rb +23 -8
  26. data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
  27. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  28. data/lib/solargraph/diagnostics.rb +2 -2
  29. data/lib/solargraph/doc_map.rb +171 -0
  30. data/lib/solargraph/gem_pins.rb +64 -0
  31. data/lib/solargraph/language_server/host/cataloger.rb +2 -1
  32. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  33. data/lib/solargraph/language_server/host/dispatch.rb +15 -5
  34. data/lib/solargraph/language_server/host/message_worker.rb +4 -0
  35. data/lib/solargraph/language_server/host/sources.rb +7 -4
  36. data/lib/solargraph/language_server/host.rb +50 -26
  37. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  38. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  39. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  40. data/lib/solargraph/language_server/message/initialize.rb +13 -0
  41. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  42. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
  43. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -4
  44. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  46. data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
  47. data/lib/solargraph/language_server/message/text_document.rb +1 -1
  48. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  49. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  50. data/lib/solargraph/language_server/message.rb +1 -0
  51. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  52. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  53. data/lib/solargraph/library.rb +124 -37
  54. data/lib/solargraph/location.rb +1 -0
  55. data/lib/solargraph/page.rb +6 -0
  56. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  57. data/lib/solargraph/parser/node_methods.rb +47 -7
  58. data/lib/solargraph/parser/node_processor/base.rb +9 -0
  59. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -5
  60. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  61. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
  62. data/lib/solargraph/parser/parser_gem/node_methods.rb +499 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  64. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
  65. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  69. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  72. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  77. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
  78. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +2 -2
  79. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors.rb +54 -0
  81. data/lib/solargraph/parser/parser_gem.rb +12 -0
  82. data/lib/solargraph/parser/region.rb +1 -1
  83. data/lib/solargraph/parser/snippet.rb +2 -0
  84. data/lib/solargraph/parser.rb +9 -10
  85. data/lib/solargraph/pin/base.rb +69 -11
  86. data/lib/solargraph/pin/base_variable.rb +8 -4
  87. data/lib/solargraph/pin/block.rb +21 -28
  88. data/lib/solargraph/pin/closure.rb +17 -2
  89. data/lib/solargraph/pin/common.rb +7 -3
  90. data/lib/solargraph/pin/conversions.rb +34 -8
  91. data/lib/solargraph/pin/delegated_method.rb +97 -0
  92. data/lib/solargraph/pin/documenting.rb +25 -34
  93. data/lib/solargraph/pin/instance_variable.rb +4 -0
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +270 -16
  96. data/lib/solargraph/pin/namespace.rb +17 -1
  97. data/lib/solargraph/pin/parameter.rb +52 -17
  98. data/lib/solargraph/pin/reference/override.rb +2 -2
  99. data/lib/solargraph/pin/reference.rb +8 -0
  100. data/lib/solargraph/pin/search.rb +4 -4
  101. data/lib/solargraph/pin/signature.rb +143 -0
  102. data/lib/solargraph/pin.rb +2 -1
  103. data/lib/solargraph/range.rb +4 -6
  104. data/lib/solargraph/rbs_map/conversions.rb +601 -0
  105. data/lib/solargraph/rbs_map/core_fills.rb +47 -0
  106. data/lib/solargraph/rbs_map/core_map.rb +28 -0
  107. data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
  108. data/lib/solargraph/rbs_map.rb +84 -0
  109. data/lib/solargraph/shell.rb +69 -48
  110. data/lib/solargraph/source/chain/array.rb +32 -0
  111. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  112. data/lib/solargraph/source/chain/call.rb +125 -61
  113. data/lib/solargraph/source/chain/constant.rb +15 -1
  114. data/lib/solargraph/source/chain/if.rb +23 -0
  115. data/lib/solargraph/source/chain/link.rb +8 -2
  116. data/lib/solargraph/source/chain/or.rb +1 -1
  117. data/lib/solargraph/source/chain/z_super.rb +3 -3
  118. data/lib/solargraph/source/chain.rb +44 -14
  119. data/lib/solargraph/source/change.rb +3 -0
  120. data/lib/solargraph/source/cursor.rb +2 -0
  121. data/lib/solargraph/source/source_chainer.rb +8 -5
  122. data/lib/solargraph/source.rb +18 -19
  123. data/lib/solargraph/source_map/clip.rb +30 -23
  124. data/lib/solargraph/source_map/mapper.rb +20 -5
  125. data/lib/solargraph/source_map.rb +28 -13
  126. data/lib/solargraph/type_checker/checks.rb +10 -2
  127. data/lib/solargraph/type_checker.rb +201 -98
  128. data/lib/solargraph/version.rb +1 -1
  129. data/lib/solargraph/views/environment.erb +2 -2
  130. data/lib/solargraph/workspace/config.rb +14 -11
  131. data/lib/solargraph/workspace.rb +28 -17
  132. data/lib/solargraph/yard_map/cache.rb +6 -0
  133. data/lib/solargraph/yard_map/helpers.rb +1 -1
  134. data/lib/solargraph/yard_map/mapper/to_method.rb +18 -5
  135. data/lib/solargraph/yard_map/mapper.rb +1 -1
  136. data/lib/solargraph/yard_map/to_method.rb +11 -4
  137. data/lib/solargraph/yard_map.rb +1 -443
  138. data/lib/solargraph/yard_tags.rb +20 -0
  139. data/lib/solargraph/yardoc.rb +52 -0
  140. data/lib/solargraph.rb +8 -6
  141. data/solargraph.gemspec +19 -8
  142. metadata +162 -98
  143. data/.travis.yml +0 -19
  144. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  145. data/lib/solargraph/compat.rb +0 -37
  146. data/lib/solargraph/convention/rspec.rb +0 -30
  147. data/lib/solargraph/documentor.rb +0 -76
  148. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  149. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  150. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
  151. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  152. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
  153. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
  154. data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
  155. data/lib/solargraph/parser/legacy.rb +0 -12
  156. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
  157. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  158. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
  159. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  160. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  161. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
  162. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  163. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
  164. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  166. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  167. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  168. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  169. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  171. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  172. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
  173. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
  174. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
  176. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
  177. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
  178. data/lib/solargraph/parser/rubyvm.rb +0 -40
  179. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  180. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  181. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  182. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  183. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  184. data/lib/yard-solargraph.rb +0 -33
  185. data/yardoc/2.2.2.tar.gz +0 -0
@@ -97,7 +97,7 @@ module Solargraph
97
97
  def create filename, text
98
98
  result = false
99
99
  mutex.synchronize do
100
- next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
100
+ next unless contain?(filename) || open?(filename)
101
101
  @synchronized = false
102
102
  source = Solargraph::Source.load_string(text, filename)
103
103
  workspace.merge(source)
@@ -106,36 +106,37 @@ module Solargraph
106
106
  result
107
107
  end
108
108
 
109
- # Create a file source from a file on disk. The file is ignored if it is
109
+ # Create file sources from files on disk. A file is ignored if it is
110
110
  # neither open in the library nor included in the workspace.
111
111
  #
112
- # @param filename [String]
113
- # @return [Boolean] True if the file was added to the workspace.
114
- def create_from_disk filename
112
+ # @param filenames [Array<String>]
113
+ # @return [Boolean] True if at least one file was added to the workspace.
114
+ def create_from_disk *filenames
115
115
  result = false
116
116
  mutex.synchronize do
117
- next if File.directory?(filename) || !File.exist?(filename)
118
- next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
119
- source = Solargraph::Source.load_string(File.read(filename), filename)
120
- workspace.merge(source)
121
- maybe_map source
122
- result = true
117
+ sources = filenames
118
+ .reject { |filename| File.directory?(filename) || !File.exist?(filename) }
119
+ .map { |filename| Solargraph::Source.load_string(File.read(filename), filename) }
120
+ result = workspace.merge(*sources)
121
+ sources.each { |source| maybe_map source }
123
122
  end
124
123
  result
125
124
  end
126
125
 
127
- # Delete a file from the library. Deleting a file will make it unavailable
126
+ # Delete files from the library. Deleting a file will make it unavailable
128
127
  # for checkout and optionally remove it from the workspace unless the
129
128
  # workspace configuration determines that it should still exist.
130
129
  #
131
- # @param filename [String]
132
- # @return [Boolean] True if the file was deleted
133
- def delete filename
134
- detach filename
130
+ # @param filenames [Array<String>]
131
+ # @return [Boolean] True if any file was deleted
132
+ def delete *filenames
135
133
  result = false
136
- mutex.synchronize do
137
- result = workspace.remove(filename)
138
- @synchronized = !result if synchronized?
134
+ filenames.each do |filename|
135
+ detach filename
136
+ mutex.synchronize do
137
+ result ||= workspace.remove(filename)
138
+ @synchronized = !result if synchronized?
139
+ end
139
140
  end
140
141
  result
141
142
  end
@@ -158,7 +159,7 @@ module Solargraph
158
159
  # @param filename [String] The file to analyze
159
160
  # @param line [Integer] The zero-based line number
160
161
  # @param column [Integer] The zero-based column number
161
- # @return [SourceMap::Completion]
162
+ # @return [SourceMap::Completion, nil]
162
163
  # @todo Take a Location instead of filename/line/column
163
164
  def completions_at filename, line, column
164
165
  position = Position.new(line, column)
@@ -174,7 +175,7 @@ module Solargraph
174
175
  # @param filename [String] The file to analyze
175
176
  # @param line [Integer] The zero-based line number
176
177
  # @param column [Integer] The zero-based column number
177
- # @return [Array<Solargraph::Pin::Base>]
178
+ # @return [Array<Solargraph::Pin::Base>, nil]
178
179
  # @todo Take filename/position instead of filename/line/column
179
180
  def definitions_at filename, line, column
180
181
  position = Position.new(line, column)
@@ -198,6 +199,22 @@ module Solargraph
198
199
  handle_file_not_found(filename, e)
199
200
  end
200
201
 
202
+ # Get type definition suggestions for the expression at the specified file and
203
+ # location.
204
+ #
205
+ # @param filename [String] The file to analyze
206
+ # @param line [Integer] The zero-based line number
207
+ # @param column [Integer] The zero-based column number
208
+ # @return [Array<Solargraph::Pin::Base>, nil]
209
+ # @todo Take filename/position instead of filename/line/column
210
+ def type_definitions_at filename, line, column
211
+ position = Position.new(line, column)
212
+ cursor = Source::Cursor.new(read(filename), position)
213
+ api_map.clip(cursor).types
214
+ rescue FileNotFoundError => e
215
+ handle_file_not_found filename, e
216
+ end
217
+
201
218
  # Get signature suggestions for the method at the specified file and
202
219
  # location.
203
220
  #
@@ -234,7 +251,19 @@ module Solargraph
234
251
  found = source.references(pin.name)
235
252
  found.select! do |loc|
236
253
  referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
237
- referenced && referenced.path == pin.path
254
+ referenced&.path == pin.path
255
+ end
256
+ if pin.path == 'Class#new'
257
+ caller = cursor.chain.base.infer(api_map, clip.send(:block), clip.locals).first
258
+ if caller.defined?
259
+ found.select! do |loc|
260
+ clip = api_map.clip_at(loc.filename, loc.range.start)
261
+ other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:block), clip.locals).first
262
+ caller == other
263
+ end
264
+ else
265
+ found.clear
266
+ end
238
267
  end
239
268
  # HACK: for language clients that exclude special characters from the start of variable names
240
269
  if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
@@ -257,17 +286,27 @@ module Solargraph
257
286
  api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
258
287
  end
259
288
 
289
+ # Match a require reference to a file.
290
+ #
291
+ # @param location [Location]
292
+ # @return [Location, nil]
260
293
  def locate_ref location
261
294
  map = source_map_hash[location.filename]
262
295
  return if map.nil?
263
296
  pin = map.requires.select { |p| p.location.range.contain?(location.range.start) }.first
264
297
  return nil if pin.nil?
298
+ # @param full [String]
299
+ return_if_match = proc do |full|
300
+ if source_map_hash.key?(full)
301
+ return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
302
+ end
303
+ end
265
304
  workspace.require_paths.each do |path|
266
- full = Pathname.new(path).join("#{pin.name}.rb").to_s
267
- next unless source_map_hash.key?(full)
268
- return Location.new(full, Solargraph::Range.from_to(0, 0, 0, 0))
305
+ full = File.join path, pin.name
306
+ return_if_match.(full)
307
+ return_if_match.(full << ".rb")
269
308
  end
270
- api_map.yard_map.require_reference(pin.name)
309
+ nil
271
310
  rescue FileNotFoundError
272
311
  nil
273
312
  end
@@ -275,13 +314,13 @@ module Solargraph
275
314
  # Get an array of pins that match a path.
276
315
  #
277
316
  # @param path [String]
278
- # @return [Array<Solargraph::Pin::Base>]
317
+ # @return [Enumerable<Solargraph::Pin::Base>]
279
318
  def get_path_pins path
280
319
  api_map.get_path_suggestions(path)
281
320
  end
282
321
 
283
322
  # @param query [String]
284
- # @return [Array<YARD::CodeObjects::Base>]
323
+ # @return [Enumerable<YARD::CodeObjects::Base>]
285
324
  def document query
286
325
  api_map.document query
287
326
  end
@@ -313,11 +352,12 @@ module Solargraph
313
352
  end
314
353
 
315
354
  # @param path [String]
316
- # @return [Array<Solargraph::Pin::Base>]
355
+ # @return [Enumerable<Solargraph::Pin::Base>]
317
356
  def path_pins path
318
357
  api_map.get_path_suggestions(path)
319
358
  end
320
359
 
360
+ # @return [Array<SourceMap>]
321
361
  def source_maps
322
362
  source_map_hash.values
323
363
  end
@@ -374,14 +414,19 @@ module Solargraph
374
414
  end
375
415
  end
376
416
 
417
+ # @return [void]
377
418
  private def catalog_inlock
378
- return if synchronized?
379
- logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
380
- api_map.catalog bench
381
- @synchronized = true
382
- logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
419
+ return if synchronized?
420
+
421
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
422
+ api_map.catalog bench
423
+ @synchronized = true
424
+ logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
425
+ logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
426
+ cache_next_gemspec
383
427
  end
384
428
 
429
+ # @return [Bench]
385
430
  def bench
386
431
  Bench.new(
387
432
  source_maps: source_map_hash.values,
@@ -426,6 +471,7 @@ module Solargraph
426
471
  result
427
472
  end
428
473
 
474
+ # @return [Hash{String => SourceMap}]
429
475
  def source_map_hash
430
476
  @source_map_hash ||= {}
431
477
  end
@@ -434,6 +480,7 @@ module Solargraph
434
480
  (workspace.filenames - source_map_hash.keys).empty?
435
481
  end
436
482
 
483
+ # @return [SourceMap, Boolean]
437
484
  def next_map
438
485
  return false if mapped?
439
486
  mutex.synchronize do
@@ -450,6 +497,7 @@ module Solargraph
450
497
  end
451
498
  end
452
499
 
500
+ # @return [self]
453
501
  def map!
454
502
  workspace.sources.each do |src|
455
503
  source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
@@ -458,28 +506,34 @@ module Solargraph
458
506
  self
459
507
  end
460
508
 
509
+ # @return [Array<Solargraph::Pin::Base>]
461
510
  def pins
462
511
  @pins ||= []
463
512
  end
464
513
 
514
+ # @return [Set<String>]
465
515
  def external_requires
466
516
  @external_requires ||= source_map_external_require_hash.values.flatten.to_set
467
517
  end
468
518
 
469
519
  private
470
520
 
521
+ # @return [Hash{String => Set<String>}]
471
522
  def source_map_external_require_hash
472
523
  @source_map_external_require_hash ||= {}
473
524
  end
474
525
 
475
526
  # @param source_map [SourceMap]
527
+ # @return [void]
476
528
  def find_external_requires source_map
477
529
  new_set = source_map.requires.map(&:name).to_set
478
530
  # return if new_set == source_map_external_require_hash[source_map.filename]
531
+ _filenames = nil
532
+ filenames = ->{ _filenames ||= workspace.filenames.to_set }
479
533
  source_map_external_require_hash[source_map.filename] = new_set.reject do |path|
480
534
  workspace.require_paths.any? do |base|
481
- full = Pathname.new(base).join("#{path}.rb").to_s
482
- workspace.filenames.include?(full)
535
+ full = File.join(base, path)
536
+ filenames[].include?(full) or filenames[].include?(full << ".rb")
483
537
  end
484
538
  end
485
539
  @external_requires = nil
@@ -509,6 +563,9 @@ module Solargraph
509
563
  workspace.source(filename)
510
564
  end
511
565
 
566
+ # @param filename [String]
567
+ # @param error [FileNotFoundError]
568
+ # @return [nil]
512
569
  def handle_file_not_found filename, error
513
570
  if workspace.source(filename)
514
571
  Solargraph.logger.debug "#{filename} is not cataloged in the ApiMap"
@@ -518,11 +575,13 @@ module Solargraph
518
575
  end
519
576
  end
520
577
 
578
+ # @param source [Source]
579
+ # @return [void]
521
580
  def maybe_map source
522
581
  return unless source
523
582
  return unless @current == source || workspace.has_file?(source.filename)
524
583
  if source_map_hash.key?(source.filename)
525
- return if source_map_hash[source.filename].code == source.code &&
584
+ return if source_map_hash[source.filename].code == source.code &&
526
585
  source_map_hash[source.filename].source.synchronized? &&
527
586
  source.synchronized?
528
587
  if source.synchronized?
@@ -542,5 +601,33 @@ module Solargraph
542
601
  @synchronized = false
543
602
  end
544
603
  end
604
+
605
+ # @return [Set<Gem::Specification>]
606
+ def cache_errors
607
+ @cache_errors ||= Set.new
608
+ end
609
+
610
+ # @return [void]
611
+ def cache_next_gemspec
612
+ return if @cache_pid
613
+ spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec)}
614
+ return unless spec
615
+
616
+ logger.info "Caching #{spec.name} #{spec.version}"
617
+ Thread.new do
618
+ @cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
619
+ Process.wait(@cache_pid)
620
+ logger.info "Cached #{spec.name} #{spec.version}"
621
+ @synchronized = false
622
+ rescue Errno::EINVAL => e
623
+ logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
624
+ @synchronized = false
625
+ rescue StandardError => e
626
+ cache_errors.add spec
627
+ Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
628
+ ensure
629
+ @cache_pid = nil
630
+ end
631
+ end
545
632
  end
546
633
  end
@@ -25,6 +25,7 @@ module Solargraph
25
25
  }
26
26
  end
27
27
 
28
+ # @param other [BasicObject]
28
29
  def == other
29
30
  return false unless other.is_a?(Location)
30
31
  filename == other.filename and range == other.range
@@ -7,6 +7,12 @@ require 'cgi'
7
7
 
8
8
  module Solargraph
9
9
  class Page
10
+ # @todo This method directive is necessary because OpenStruct.new confuses
11
+ # the typechecker.
12
+ # @!method self.new(locals, render_method)
13
+ # @param locals[Hash]
14
+ # @param render_method [Proc]
15
+ # @return [Binder]
10
16
  class Binder < OpenStruct
11
17
  # @param locals [Hash]
12
18
  # @param render_method [Proc]
@@ -3,6 +3,9 @@ require 'ripper'
3
3
  module Solargraph
4
4
  module Parser
5
5
  class CommentRipper < Ripper::SexpBuilderPP
6
+ # @param src [String]
7
+ # @param filename [String]
8
+ # @param lineno [Integer]
6
9
  def initialize src, filename = '(ripper)', lineno = 0
7
10
  super
8
11
  @buffer = src
@@ -42,6 +45,7 @@ module Solargraph
42
45
  result
43
46
  end
44
47
 
48
+ # @return [Hash{Integer => String}]
45
49
  def parse
46
50
  @comments = {}
47
51
  super
@@ -3,38 +3,78 @@ module Solargraph
3
3
  class NodeMethods
4
4
  module_function
5
5
 
6
+ # @abstract
7
+ # @param node [Parser::AST::Node]
8
+ # @return [String]
6
9
  def unpack_name node
7
10
  raise NotImplementedError
8
11
  end
9
12
 
10
- def infer_literal_type node
13
+ # @abstract
14
+ # @todo Temporarily here for testing. Move to Solargraph::Parser.
15
+ # @param node [Parser::AST::Node]
16
+ # @return [Array<Parser::AST::Node>]
17
+ def call_nodes_from node
11
18
  raise NotImplementedError
12
19
  end
13
20
 
14
- def calls_from node
21
+ # Find all the nodes within the provided node that potentially return a
22
+ # value.
23
+ #
24
+ # The node parameter typically represents a method's logic, e.g., the
25
+ # second child (after the :args node) of a :def node. A simple one-line
26
+ # method would typically return itself, while a node with conditions
27
+ # would return the resulting node from each conditional branch. Nodes
28
+ # that follow a :return node are assumed to be unreachable. Nil values
29
+ # are converted to nil node types.
30
+ #
31
+ # @abstract
32
+ # @param node [Parser::AST::Node]
33
+ # @return [Array<Parser::AST::Node>]
34
+ def returns_from_method_body node
15
35
  raise NotImplementedError
16
36
  end
17
37
 
18
- def returns_from node
38
+ # @abstract
39
+ # @param node [Parser::AST::Node]
40
+ #
41
+ # @return [Array<Parser::AST::Node>]
42
+ def const_nodes_from node
19
43
  raise NotImplementedError
20
44
  end
21
45
 
22
- def process node
46
+ # @abstract
47
+ # @param cursor [Solargraph::Source::Cursor]
48
+ # @return [Parser::AST::Node, nil]
49
+ def find_recipient_node cursor
23
50
  raise NotImplementedError
24
51
  end
25
52
 
26
- def references node
53
+ # @abstract
54
+ # @param node [Parser::AST::Node]
55
+ # @return [Array<AST::Node>] low-level value nodes in
56
+ # value position. Does not include explicit return
57
+ # statements
58
+ def value_position_nodes_only(node)
27
59
  raise NotImplementedError
28
60
  end
29
61
 
30
- def chain node, filename = nil, in_block = false
62
+ # @abstract
63
+ # @param nodes [Enumerable<Parser::AST::Node>]
64
+ def any_splatted_call?(nodes)
31
65
  raise NotImplementedError
32
66
  end
33
67
 
34
- def node? node
68
+ # @abstract
69
+ # @param node [Parser::AST::Node]
70
+ # @return [void]
71
+ def process node
35
72
  raise NotImplementedError
36
73
  end
37
74
 
75
+ # @abstract
76
+ # @param node [Parser::AST::Node]
77
+ # @return [Hash{Parser::AST::Node => Chain}]
38
78
  def convert_hash node
39
79
  raise NotImplementedError
40
80
  end
@@ -19,6 +19,7 @@ module Solargraph
19
19
  # @param node [Parser::AST::Node]
20
20
  # @param region [Region]
21
21
  # @param pins [Array<Pin::Base>]
22
+ # @param locals [Array<Pin::LocalVariable>]
22
23
  def initialize node, region, pins, locals
23
24
  @node = node
24
25
  @region = region
@@ -54,20 +55,28 @@ module Solargraph
54
55
  Location.new(region.filename, range)
55
56
  end
56
57
 
58
+ # @param node [Parser::AST::Node]
59
+ # @return [String, nil]
57
60
  def comments_for(node)
58
61
  region.source.comments_for(node)
59
62
  end
60
63
 
64
+ # @param position [Solargraph::Position]
65
+ # @return [Pin::Base, nil]
61
66
  def named_path_pin position
62
67
  pins.select{|pin| pin.is_a?(Pin::Closure) && pin.path && !pin.path.empty? && pin.location.range.contain?(position)}.last
63
68
  end
64
69
 
65
70
  # @todo Candidate for deprecation
71
+ # @param position [Solargraph::Position]
72
+ # @return [Pin::Closure, nil]
66
73
  def block_pin position
67
74
  pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
68
75
  end
69
76
 
70
77
  # @todo Candidate for deprecation
78
+ # @param position [Solargraph::Position]
79
+ # @return [Pin::Closure, nil]
71
80
  def closure_pin position
72
81
  pins.select{|pin| pin.is_a?(Pin::Closure) && pin.location.range.contain?(position)}.last
73
82
  end
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'parser/current'
4
+ require 'parser/source/buffer'
2
5
 
3
6
  module Solargraph
4
7
  module Parser
5
- module Legacy
8
+ module ParserGem
6
9
  module ClassMethods
7
10
  # @param code [String]
8
- # @param filename [String]
9
- # @return [Array(Parser::AST::Node, Array<Parser::Source::Comment>)]
11
+ # @param filename [String, nil]
12
+ # @return [Array(Parser::AST::Node, Hash{Integer => String})]
10
13
  def parse_with_comments code, filename = nil
11
14
  buffer = ::Parser::Source::Buffer.new(filename, 0)
12
15
  buffer.source = code
@@ -29,7 +32,7 @@ module Solargraph
29
32
  raise Parser::SyntaxError, e.message
30
33
  end
31
34
 
32
- # @return [Parser::Base]
35
+ # @return [::Parser::Base]
33
36
  def parser
34
37
  # @todo Consider setting an instance variable. We might not need to
35
38
  # recreate the parser every time we use it.
@@ -39,19 +42,30 @@ module Solargraph
39
42
  parser
40
43
  end
41
44
 
45
+ # @param source [Source]
46
+ # @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
42
47
  def map source
43
48
  NodeProcessor.process(source.node, Region.new(source: source))
44
49
  end
45
50
 
51
+ # @param node [Parser::AST::Node]
52
+ # @return [Array<Parser::AST::Node>]
46
53
  def returns_from node
47
54
  NodeMethods.returns_from(node)
48
55
  end
49
56
 
57
+ # @param source [Source]
58
+ # @param name [String]
59
+ # @return [Array<Location>]
50
60
  def references source, name
51
61
  if name.end_with?("=")
52
62
  reg = /#{Regexp.escape name[0..-2]}\s*=/
63
+ # @param code [String]
64
+ # @param offset [Integer]
53
65
  extract_offset = ->(code, offset) { reg.match(code, offset).offset(0) }
54
66
  else
67
+ # @param code [String]
68
+ # @param offset [Integer]
55
69
  extract_offset = ->(code, offset) { [soff = code.index(name, offset), soff + name.length] }
56
70
  end
57
71
  inner_node_references(name, source.node).map do |n|
@@ -80,36 +94,48 @@ module Solargraph
80
94
  result
81
95
  end
82
96
 
97
+ # @return [Source::Chain]
83
98
  def chain *args
84
99
  NodeChainer.chain *args
85
100
  end
86
101
 
102
+ # @return [Source::Chain]
87
103
  def chain_string *args
88
104
  NodeChainer.load_string *args
89
105
  end
90
106
 
107
+ # @return [Array(Array<Pin::Base>, Array<Pin::Base>)]
91
108
  def process_node *args
92
109
  Solargraph::Parser::NodeProcessor.process *args
93
110
  end
94
111
 
112
+ # @param node [Parser::AST::Node]
113
+ # @return [String, nil]
95
114
  def infer_literal_node_type node
96
115
  NodeMethods.infer_literal_node_type node
97
116
  end
98
117
 
118
+ # @return [void]
99
119
  def version
100
120
  parser.version
101
121
  end
102
122
 
123
+ # @param node [BasicObject]
124
+ # @return [Boolean]
103
125
  def is_ast_node? node
104
126
  node.is_a?(::Parser::AST::Node)
105
127
  end
106
128
 
129
+ # @param node [Parser::AST::Node]
130
+ # @return [Range]
107
131
  def node_range node
108
132
  st = Position.new(node.loc.line, node.loc.column)
109
133
  en = Position.new(node.loc.last_line, node.loc.last_column)
110
134
  Range.new(st, en)
111
135
  end
112
136
 
137
+ # @param node [Parser::AST::Node]
138
+ # @return [Array<Range>]
113
139
  def string_ranges node
114
140
  return [] unless is_ast_node?(node)
115
141
  result = []
@@ -128,7 +154,7 @@ module Solargraph
128
154
  end
129
155
  end
130
156
  result
131
- end
157
+ end
132
158
  end
133
159
  end
134
160
  end
@@ -2,11 +2,13 @@
2
2
 
3
3
  module Solargraph
4
4
  module Parser
5
- module Legacy
5
+ module ParserGem
6
6
  # A custom builder for source parsers that ignores character encoding
7
7
  # issues in literal strings.
8
8
  #
9
9
  class FlawedBuilder < ::Parser::Builders::Default
10
+ # @param token [::Parser::AST::Node]
11
+ # @return [String]
10
12
  def string_value(token)
11
13
  value(token)
12
14
  end