solargraph 0.47.2 → 0.50.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/CHANGELOG.md +40 -0
  5. data/LICENSE +1 -1
  6. data/README.md +9 -3
  7. data/SPONSORS.md +4 -4
  8. data/lib/solargraph/api_map/store.rb +13 -1
  9. data/lib/solargraph/api_map.rb +30 -12
  10. data/lib/solargraph/cache.rb +53 -0
  11. data/lib/solargraph/complex_type/type_methods.rb +10 -6
  12. data/lib/solargraph/complex_type/unique_type.rb +57 -0
  13. data/lib/solargraph/complex_type.rb +32 -3
  14. data/lib/solargraph/convention/rakefile.rb +17 -0
  15. data/lib/solargraph/convention.rb +2 -0
  16. data/lib/solargraph/diagnostics/rubocop.rb +17 -3
  17. data/lib/solargraph/diagnostics/rubocop_helpers.rb +3 -1
  18. data/lib/solargraph/language_server/host/cataloger.rb +1 -1
  19. data/lib/solargraph/language_server/host.rb +22 -18
  20. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  21. data/lib/solargraph/language_server/message/initialize.rb +2 -0
  22. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  24. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  25. data/lib/solargraph/library.rb +25 -20
  26. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +12 -2
  27. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +24 -3
  28. data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -1
  29. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +13 -2
  30. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +20 -8
  31. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +14 -3
  32. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +14 -3
  33. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +4 -2
  34. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  35. data/lib/solargraph/pin/base.rb +5 -2
  36. data/lib/solargraph/pin/base_variable.rb +1 -1
  37. data/lib/solargraph/pin/conversions.rb +2 -6
  38. data/lib/solargraph/pin/method.rb +100 -10
  39. data/lib/solargraph/pin/namespace.rb +4 -1
  40. data/lib/solargraph/pin/parameter.rb +8 -3
  41. data/lib/solargraph/pin/signature.rb +23 -0
  42. data/lib/solargraph/pin.rb +1 -0
  43. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  44. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  45. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  46. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  47. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  48. data/lib/solargraph/rbs_map.rb +73 -0
  49. data/lib/solargraph/shell.rb +50 -32
  50. data/lib/solargraph/source/chain/call.rb +35 -24
  51. data/lib/solargraph/source/chain.rb +22 -7
  52. data/lib/solargraph/source_map/clip.rb +5 -0
  53. data/lib/solargraph/source_map/mapper.rb +8 -4
  54. data/lib/solargraph/type_checker.rb +71 -65
  55. data/lib/solargraph/version.rb +1 -1
  56. data/lib/solargraph/views/environment.erb +2 -2
  57. data/lib/solargraph/workspace.rb +11 -14
  58. data/lib/solargraph/yard_map/mapper/to_method.rb +7 -4
  59. data/lib/solargraph/yard_map.rb +35 -194
  60. data/lib/solargraph.rb +2 -2
  61. data/solargraph.gemspec +11 -6
  62. metadata +46 -37
  63. data/.travis.yml +0 -19
  64. data/lib/solargraph/compat.rb +0 -37
  65. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  66. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  67. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  68. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  69. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  70. data/yardoc/2.2.2.tar.gz +0 -0
@@ -120,12 +120,10 @@ module Solargraph
120
120
  # @param pin [Pin::Base]
121
121
  # @return [Boolean]
122
122
  def resolved_constant? pin
123
- api_map.get_constants('', pin.binder.tag)
123
+ return true if pin.typify(api_map).defined?
124
+ api_map.get_constants('', *pin.closure.gates)
124
125
  .select { |p| p.name == pin.return_type.namespace }
125
- .any? do |p|
126
- inferred = p.infer(api_map)
127
- ['Class', 'Module'].include?(inferred.name)
128
- end
126
+ .any? { |p| p.infer(api_map).defined? }
129
127
  end
130
128
 
131
129
  def virtual_pin? pin
@@ -139,10 +137,12 @@ module Solargraph
139
137
  params = first_param_hash(stack)
140
138
  result = []
141
139
  if rules.require_type_tags?
142
- pin.parameters.each do |par|
143
- break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
144
- unless params[par.name]
145
- result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
140
+ pin.signatures.each do |sig|
141
+ sig.parameters.each do |par|
142
+ break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
143
+ unless params[par.name]
144
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
145
+ end
146
146
  end
147
147
  end
148
148
  end
@@ -184,7 +184,7 @@ module Solargraph
184
184
  elsif declared_externally?(pin)
185
185
  ignored_pins.push pin
186
186
  end
187
- elsif !pin.is_a?(Pin::Parameter)
187
+ elsif !pin.is_a?(Pin::Parameter) && !resolved_constant?(pin)
188
188
  result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
189
189
  end
190
190
  else
@@ -243,7 +243,7 @@ module Solargraph
243
243
  end
244
244
  closest = found.typify(api_map) if found
245
245
  if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
246
- unless ignored_pins.include?(found)
246
+ unless closest.parameterized? || ignored_pins.include?(found)
247
247
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
248
248
  @marked_ranges.push rng
249
249
  end
@@ -273,34 +273,44 @@ module Solargraph
273
273
  end
274
274
  break unless rules.validate_calls?
275
275
  params = first_param_hash(pins)
276
- pin.parameters.each_with_index do |par, idx|
277
- argchain = base.links.last.arguments[idx]
278
- if argchain.nil? && par.decl == :arg
279
- result.push Problem.new(location, "Not enough arguments to #{pin.path}")
280
- break
281
- end
282
- if argchain
283
- if par.decl != :arg
284
- result.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
285
- break
286
- else
287
- ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
288
- if ptype.nil?
289
- # @todo Some level (strong, I guess) should require the param here
276
+
277
+ all_errors = []
278
+ pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
279
+ errors = []
280
+ sig.parameters.each_with_index do |par, idx|
281
+ argchain = base.links.last.arguments[idx]
282
+ if argchain.nil? && par.decl == :arg
283
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
284
+ next
285
+ end
286
+ if argchain
287
+ if par.decl != :arg
288
+ errors.concat kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, idx
289
+ next
290
290
  else
291
- argtype = argchain.infer(api_map, block_pin, locals)
292
- if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
293
- result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
291
+ ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
292
+ if ptype.nil?
293
+ # @todo Some level (strong, I guess) should require the param here
294
+ else
295
+ argtype = argchain.infer(api_map, block_pin, locals)
296
+ if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
297
+ errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
298
+ next
299
+ end
294
300
  end
295
301
  end
302
+ elsif par.decl == :kwarg
303
+ errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
304
+ next
296
305
  end
297
- elsif par.rest?
298
- next
299
- elsif par.decl == :kwarg
300
- result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
306
+ end
307
+ if errors.empty?
308
+ all_errors.clear
301
309
  break
302
310
  end
311
+ all_errors.concat errors
303
312
  end
313
+ result.concat all_errors
304
314
  end
305
315
  base = base.base
306
316
  end
@@ -310,7 +320,7 @@ module Solargraph
310
320
  def kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, first
311
321
  result = []
312
322
  kwargs = convert_hash(argchain.node)
313
- pin.parameters[first..-1].each_with_index do |par, cur|
323
+ pin.signatures.first.parameters[first..-1].each_with_index do |par, cur|
314
324
  idx = first + cur
315
325
  argchain = kwargs[par.name.to_sym]
316
326
  if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
@@ -381,8 +391,10 @@ module Solargraph
381
391
  pin.location && api_map.bundled?(pin.location.filename)
382
392
  end
383
393
 
394
+ # True if the pin is either internal (part of the workspace) or from the core/stdlib
384
395
  def internal_or_core? pin
385
- internal?(pin) || api_map.yard_map.core_pins.include?(pin) || api_map.yard_map.stdlib_pins.include?(pin)
396
+ # @todo RBS pins are not necessarily core/stdlib pins
397
+ internal?(pin) || pin.source == :rbs
386
398
  end
387
399
 
388
400
  # @param pin [Pin::Base]
@@ -417,20 +429,20 @@ module Solargraph
417
429
  true
418
430
  end
419
431
 
420
- # @param pin [Pin::Method]
421
- def arity_problems_for(pin, arguments, location)
422
- ([pin] + pin.overloads).map do |p|
423
- result = pin_arity_problems_for(p, arguments, location)
424
- return [] if result.empty?
425
- result
426
- end.flatten.uniq(&:message)
432
+ def arity_problems_for pin, arguments, location
433
+ results = pin.signatures.map do |sig|
434
+ r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
435
+ return [] if r.empty?
436
+ r
437
+ end
438
+ results.first
427
439
  end
428
440
 
429
- # @param pin [Pin::Method]
430
- def pin_arity_problems_for(pin, arguments, location)
441
+ def parameterized_arity_problems_for(pin, parameters, arguments, location)
431
442
  return [] unless pin.explicit?
432
- return [] if pin.parameters.empty? && arguments.empty?
433
- if pin.parameters.empty?
443
+ return [] if parameters.empty? && arguments.empty?
444
+ return [] if pin.anon_splat?
445
+ if parameters.empty?
434
446
  # Functions tagged param_tuple accepts two arguments (e.g., Hash#[]=)
435
447
  return [] if pin.docstring.tag(:param_tuple) && arguments.length == 2
436
448
  return [] if arguments.length == 1 && arguments.last.links.last.is_a?(Source::Chain::BlockVariable)
@@ -438,21 +450,21 @@ module Solargraph
438
450
  end
439
451
  unchecked = arguments.clone
440
452
  add_params = 0
441
- if unchecked.empty? && pin.parameters.any? { |param| param.decl == :kwarg }
453
+ if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
442
454
  return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
443
455
  end
444
456
  settled_kwargs = 0
445
457
  unless unchecked.empty?
446
458
  if any_splatted_call?(unchecked.map(&:node))
447
- settled_kwargs = pin.parameters.count(&:keyword?)
459
+ settled_kwargs = parameters.count(&:keyword?)
448
460
  else
449
461
  kwargs = convert_hash(unchecked.last.node)
450
- if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
462
+ if parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
451
463
  if kwargs.empty?
452
464
  add_params += 1
453
465
  else
454
466
  unchecked.pop
455
- pin.parameters.each do |param|
467
+ parameters.each do |param|
456
468
  next unless param.keyword?
457
469
  if kwargs.key?(param.name.to_sym)
458
470
  kwargs.delete param.name.to_sym
@@ -462,7 +474,7 @@ module Solargraph
462
474
  return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
463
475
  end
464
476
  end
465
- kwargs.clear if pin.parameters.any?(&:kwrestarg?)
477
+ kwargs.clear if parameters.any?(&:kwrestarg?)
466
478
  unless kwargs.empty?
467
479
  return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
468
480
  end
@@ -470,18 +482,18 @@ module Solargraph
470
482
  end
471
483
  end
472
484
  end
473
- req = required_param_count(pin)
485
+ req = required_param_count(parameters)
474
486
  if req + add_params < unchecked.length
475
- return [] if pin.parameters.any?(&:rest?)
476
- opt = optional_param_count(pin)
487
+ return [] if parameters.any?(&:rest?)
488
+ opt = optional_param_count(parameters)
477
489
  return [] if unchecked.length <= req + opt
478
490
  if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
479
491
  return []
480
492
  end
481
- if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (pin.parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
493
+ if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
482
494
  return []
483
495
  end
484
- return [] if arguments.length - req == pin.parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
496
+ return [] if arguments.length - req == parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
485
497
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
486
498
  elsif unchecked.length < req - settled_kwargs && (arguments.empty? || (!arguments.last.splat? && !arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash)))
487
499
  # HACK: Kernel#raise signature is incorrect in Ruby 2.7 core docs.
@@ -493,19 +505,13 @@ module Solargraph
493
505
  []
494
506
  end
495
507
 
496
- # @param pin [Pin::Method]
497
- def required_param_count(pin)
498
- pin.parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
508
+ def required_param_count(parameters)
509
+ parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
499
510
  end
500
511
 
501
512
  # @param pin [Pin::Method]
502
- def optional_param_count(pin)
503
- count = 0
504
- pin.parameters.each do |param|
505
- next unless param.decl == :optarg
506
- count += 1
507
- end
508
- count
513
+ def optional_param_count(parameters)
514
+ parameters.select { |p| p.decl == :optarg }.length
509
515
  end
510
516
 
511
517
  def abstract? pin
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.47.2'
4
+ VERSION = '0.50.0'
5
5
  end
@@ -30,10 +30,10 @@
30
30
  Solargraph Version: <%= Solargraph::VERSION %>
31
31
  </li>
32
32
  <li>
33
- Core Documentation Version: <%= Solargraph::YardMap::CoreDocs.best_match %>
33
+ Core Documentation Version: N/A <%# @todo Fix %>
34
34
  </li>
35
35
  <li>
36
- Core Cache Directory: <%= Solargraph::YardMap::CoreDocs.cache_dir %>
36
+ Core Cache Directory: N/A <%# @todo Fix %>
37
37
  </li>
38
38
  <% unless Solargraph::Parser.rubyvm? %>
39
39
  <li>
@@ -46,24 +46,21 @@ module Solargraph
46
46
  #
47
47
  # @param source [Solargraph::Source]
48
48
  # @return [Boolean] True if the source was added to the workspace
49
- def merge source
50
- unless directory == '*' || source_hash.key?(source.filename)
49
+ def merge *sources
50
+ unless directory == '*' || sources.all? { |source| source_hash.key?(source.filename) }
51
51
  # Reload the config to determine if a new source should be included
52
52
  @config = Solargraph::Workspace::Config.new(directory)
53
- return false unless config.calculated.include?(source.filename)
54
53
  end
55
- source_hash[source.filename] = source
56
- true
57
- end
58
54
 
59
- # Determine whether a file would be merged into the workspace.
60
- #
61
- # @param filename [String]
62
- # @return [Boolean]
63
- def would_merge? filename
64
- return true if directory == '*' || source_hash.include?(filename)
65
- @config = Solargraph::Workspace::Config.new(directory)
66
- config.calculated.include?(filename)
55
+ includes_any = false
56
+ sources.each do |source|
57
+ if directory == "*" || config.calculated.include?(source.filename)
58
+ source_hash[source.filename] = source
59
+ includes_any = true
60
+ end
61
+ end
62
+
63
+ includes_any
67
64
  end
68
65
 
69
66
  # Remove a source from the workspace. The source will not be removed if
@@ -13,16 +13,19 @@ module Solargraph
13
13
  )
14
14
  location = object_location(code_object, spec)
15
15
  comments = code_object.docstring ? code_object.docstring.all.to_s : ''
16
- Pin::Method.new(
16
+ pin = Pin::Method.new(
17
17
  location: location,
18
18
  closure: closure,
19
19
  name: name || code_object.name.to_s,
20
20
  comments: comments,
21
21
  scope: scope || code_object.scope,
22
22
  visibility: visibility || code_object.visibility,
23
- parameters: get_parameters(code_object, location, comments),
23
+ # @todo Might need to convert overloads to signatures
24
+ parameters: [],
24
25
  explicit: code_object.is_explicit?
25
26
  )
27
+ pin.parameters.concat get_parameters(code_object, location, comments, pin)
28
+ pin
26
29
  end
27
30
 
28
31
  class << self
@@ -30,7 +33,7 @@ module Solargraph
30
33
 
31
34
  # @param code_object [YARD::CodeObjects::Base]
32
35
  # @return [Array<Solargraph::Pin::Parameter>]
33
- def get_parameters code_object, location, comments
36
+ def get_parameters code_object, location, comments, pin
34
37
  return [] unless code_object.is_a?(YARD::CodeObjects::MethodObject)
35
38
  # HACK: Skip `nil` and `self` parameters that are sometimes emitted
36
39
  # for methods defined in C
@@ -38,7 +41,7 @@ module Solargraph
38
41
  code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
39
42
  Solargraph::Pin::Parameter.new(
40
43
  location: location,
41
- closure: self,
44
+ closure: pin,
42
45
  comments: comments,
43
46
  name: arg_name(a),
44
47
  presence: nil,