solargraph 0.47.2 → 0.49.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 (67) 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 +20 -0
  5. data/LICENSE +1 -1
  6. data/README.md +8 -0
  7. data/SPONSORS.md +2 -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 +51 -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 +30 -1
  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.rb +22 -18
  19. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  20. data/lib/solargraph/language_server/message/initialize.rb +2 -0
  21. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -1
  22. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  23. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  24. data/lib/solargraph/library.rb +21 -20
  25. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +12 -2
  26. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +24 -3
  27. data/lib/solargraph/parser/rubyvm/class_methods.rb +6 -1
  28. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +13 -2
  29. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +20 -8
  30. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +14 -3
  31. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +14 -3
  32. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +4 -2
  33. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  34. data/lib/solargraph/pin/base.rb +5 -2
  35. data/lib/solargraph/pin/conversions.rb +2 -6
  36. data/lib/solargraph/pin/method.rb +100 -10
  37. data/lib/solargraph/pin/namespace.rb +4 -1
  38. data/lib/solargraph/pin/parameter.rb +8 -3
  39. data/lib/solargraph/pin/signature.rb +23 -0
  40. data/lib/solargraph/pin.rb +1 -0
  41. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  42. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  43. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  44. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  45. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  46. data/lib/solargraph/rbs_map.rb +73 -0
  47. data/lib/solargraph/shell.rb +38 -30
  48. data/lib/solargraph/source/chain/call.rb +34 -23
  49. data/lib/solargraph/source/chain.rb +21 -6
  50. data/lib/solargraph/source_map/clip.rb +5 -0
  51. data/lib/solargraph/source_map/mapper.rb +2 -0
  52. data/lib/solargraph/type_checker.rb +71 -65
  53. data/lib/solargraph/version.rb +1 -1
  54. data/lib/solargraph/views/environment.erb +2 -2
  55. data/lib/solargraph/workspace.rb +11 -14
  56. data/lib/solargraph/yard_map/mapper/to_method.rb +7 -4
  57. data/lib/solargraph/yard_map.rb +34 -193
  58. data/lib/solargraph.rb +2 -2
  59. data/solargraph.gemspec +8 -6
  60. metadata +43 -36
  61. data/lib/solargraph/compat.rb +0 -37
  62. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  63. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  64. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  65. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  66. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  67. data/yardoc/2.2.2.tar.gz +0 -0
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+ require 'set'
5
+
6
+ module Solargraph
7
+ class RbsMap
8
+ autoload :Conversions, 'solargraph/rbs_map/conversions'
9
+ autoload :CoreMap, 'solargraph/rbs_map/core_map'
10
+ autoload :CoreFills, 'solargraph/rbs_map/core_fills'
11
+ autoload :CoreSigns, 'solargraph/rbs_map/core_signs'
12
+ autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
13
+
14
+ include Conversions
15
+
16
+ # @type [Hash{String => RbsMap}]
17
+ @@rbs_maps_hash = {}
18
+
19
+ attr_reader :library
20
+
21
+ # @param library [String]
22
+ def initialize library
23
+ @library = library
24
+ loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
25
+ add_library loader, library
26
+ return unless resolved?
27
+ environment = RBS::Environment.from_loader(loader).resolve_type_names
28
+ environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
29
+ end
30
+
31
+ def path_pin path
32
+ pins.find { |p| p.path == path }
33
+ end
34
+
35
+ def path_pins path
36
+ pins.select { |p| p.path == path }
37
+ end
38
+
39
+ def resolved?
40
+ @resolved
41
+ end
42
+
43
+ # @param library [String]
44
+ # @return [RbsMap]
45
+ def self.load library
46
+ @@rbs_maps_hash[library] ||= RbsMap.new(library)
47
+ end
48
+
49
+ def repository
50
+ @repository ||= RBS::Repository.new(no_stdlib: true)
51
+ end
52
+
53
+ private
54
+
55
+ # @param loader [RBS::EnvironmentLoader]
56
+ # @param library [String]
57
+ # @return [Boolean] true if adding the library succeeded
58
+ def add_library loader, library
59
+ @resolved = if loader.has_library?(library: library, version: nil)
60
+ loader.add library: library
61
+ Solargraph.logger.info "#{short_name} successfully loaded library #{library}"
62
+ true
63
+ else
64
+ Solargraph.logger.info "#{short_name} failed to load library #{library}"
65
+ false
66
+ end
67
+ end
68
+
69
+ def short_name
70
+ self.class.name.split('::').last
71
+ end
72
+ end
73
+ end
@@ -71,43 +71,47 @@ module Solargraph
71
71
  STDOUT.puts "Configuration file initialized."
72
72
  end
73
73
 
74
- desc 'download-core [VERSION]', 'Download core documentation'
75
- def download_core version = nil
76
- ver = version || Solargraph::YardMap::CoreDocs.best_download
77
- if RUBY_VERSION != ver
78
- puts "Documentation for #{RUBY_VERSION} is not available. Reverting to closest match..."
79
- end
80
- puts "Downloading docs for #{ver}..."
81
- Solargraph::YardMap::CoreDocs.download ver
82
- # Clear cached documentation if it exists
83
- FileUtils.rm_rf Dir.glob(File.join(Solargraph::YardMap::CoreDocs.cache_dir, ver, '*.ser'))
84
- puts "Download complete."
85
- rescue ArgumentError => e
86
- STDERR.puts "ERROR: #{e.message}"
87
- STDERR.puts "Run `solargraph available-cores` for a list."
88
- exit 1
74
+ desc 'download-core [VERSION]', 'Download core documentation [deprecated]'
75
+ long_desc %(
76
+ The `download-core` command is deprecated. Current versions of Solargraph
77
+ use RBS for core and stdlib documentation.
78
+ )
79
+ # @deprecated
80
+ def download_core _version = nil
81
+ puts 'The `download-core` command is deprecated.'
82
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
89
83
  end
90
84
 
91
- desc 'list-cores', 'List the local documentation versions'
85
+ desc 'list-cores', 'List the local documentation versions [deprecated]'
86
+ long_desc %(
87
+ The `list-cores` command is deprecated. Current versions of Solargraph use
88
+ RBS for core and stdlib documentation.
89
+ )
90
+ # @deprecated
92
91
  def list_cores
93
- puts Solargraph::YardMap::CoreDocs.versions.join("\n")
92
+ puts 'The `list-cores` command is deprecated.'
93
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
94
94
  end
95
95
 
96
- desc 'available-cores', 'List available documentation versions'
96
+ desc 'available-cores', 'List available documentation versions [deprecated]'
97
+ long_desc %(
98
+ The `available-cores` command is deprecated. Current versions of Solargraph
99
+ use RBS for core and stdlib documentation.
100
+ )
101
+ # @deprecated
97
102
  def available_cores
98
- puts Solargraph::YardMap::CoreDocs.available.join("\n")
103
+ puts 'The `available-cores` command is deprecated.'
104
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
99
105
  end
100
106
 
101
107
  desc 'clear', 'Delete all cached documentation'
102
108
  long_desc %(
103
109
  This command will delete all core and gem documentation from the cache.
104
- You can also delete specific gem caches with the `uncache` command or
105
- update documentation for specific Ruby versions with the `download-core`
106
- command.
107
110
  )
111
+ # @deprecated
108
112
  def clear
109
113
  puts "Deleting the cached documentation"
110
- Solargraph::YardMap::CoreDocs.clear
114
+ Solargraph::Cache.clear
111
115
  end
112
116
  map 'clear-cache' => :clear
113
117
  map 'clear-cores' => :clear
@@ -191,18 +195,22 @@ module Solargraph
191
195
  puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
192
196
  end
193
197
 
194
- desc 'bundle', 'Generate documentation for bundled gems'
198
+ desc 'bundle', 'Generate documentation for bundled gems [deprecated]'
199
+ long_desc %(
200
+ The `bundle` command is deprecated. Solargraph currently uses RBS instead.
201
+ )
195
202
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
196
203
  option :rebuild, type: :boolean, aliases: :r, desc: 'Rebuild existing documentation', default: false
197
204
  def bundle
198
- Documentor.new(options[:directory], rebuild: options[:rebuild], out: STDOUT).document
205
+ puts 'The `bundle` command is deprecated. Solargraph currently uses RBS instead.'
199
206
  end
200
207
 
201
- desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation'
202
- def rdoc gem, version = '>= 0'
203
- spec = Gem::Specification.find_by_name(gem, version)
204
- puts "Caching #{spec.name} #{spec.version} from RDoc"
205
- Solargraph::YardMap::RdocToYard.run(spec)
208
+ desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation [deprecated]'
209
+ long_desc %(
210
+ The `rdoc` command is deprecated. Solargraph currently uses RBS instead.
211
+ )
212
+ def rdoc _gem, _version = '>= 0'
213
+ puts 'The `rdoc` command is deprecated. Solargraph currently uses RBS instead.'
206
214
  end
207
215
 
208
216
  private
@@ -35,7 +35,10 @@ module Solargraph
35
35
  []
36
36
  end
37
37
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
38
- pins = api_map.get_method_stack(name_pin.binder.namespace, word, scope: name_pin.binder.scope)
38
+ # @param [ComplexType::UniqueType]
39
+ pins = name_pin.binder.each_unique_type.flat_map do |context|
40
+ api_map.get_method_stack(context.namespace, word, scope: context.scope)
41
+ end
39
42
  return [] if pins.empty?
40
43
  inferred_pins(pins, api_map, name_pin.context, locals)
41
44
  end
@@ -49,36 +52,32 @@ module Solargraph
49
52
  # @return [Array<Pin::Base>]
50
53
  def inferred_pins pins, api_map, context, locals
51
54
  result = pins.map do |p|
52
- overloads = p.docstring.tags(:overload)
55
+ next p unless p.is_a?(Pin::Method)
56
+ overloads = p.signatures
53
57
  # next p if overloads.empty?
54
58
  type = ComplexType::UNDEFINED
55
- # @param [YARD::Tags::OverloadTag]
56
59
  overloads.each do |ol|
57
- next unless arguments_match(arguments, ol.parameters)
58
- next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
60
+ next unless arguments_match(arguments, ol)
61
+ # next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
59
62
  match = true
60
63
  arguments.each_with_index do |arg, idx|
61
- achain = arguments[idx]
62
- next if achain.nil?
63
64
  param = ol.parameters[idx]
64
65
  if param.nil?
65
- match = false unless ol.parameters.last && ol.parameters.last.first.start_with?('*')
66
+ match = false unless ol.parameters.any?(&:restarg?)
66
67
  break
67
68
  end
68
- par = ol.tags(:param).select { |pp| pp.name == param.first }.first
69
- next if par.nil? || par.types.nil? || par.types.empty?
70
- atype = achain.infer(api_map, Pin::ProxyType.anonymous(context), locals)
71
- other = ComplexType.try_parse(*par.types)
69
+ atype = arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
72
70
  # @todo Weak type comparison
73
- unless atype.tag == other.tag || api_map.super_and_sub?(other.tag, atype.tag)
71
+ # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
72
+ unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name)
74
73
  match = false
75
74
  break
76
75
  end
77
76
  end
78
77
  if match
79
- type = extra_return_type(ol, context)
78
+ type = extra_return_type(p.docstring, context)
80
79
  break if type
81
- type = ComplexType.try_parse(*ol.tag(:return).types).self_to(context.to_s).qualify(api_map, context.namespace) if ol.has_tag?(:return) && ol.tag(:return).types && !ol.tag(:return).types.empty? && (type.nil? || type.undefined?)
80
+ type = with_params(ol.return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if ol.return_type.defined?
82
81
  type ||= ComplexType::UNDEFINED
83
82
  end
84
83
  break if type.defined?
@@ -107,9 +106,13 @@ module Solargraph
107
106
  p
108
107
  end
109
108
  result.map do |pin|
110
- next pin if pin.return_type.undefined?
111
- selfy = pin.return_type.self_to(context.tag)
112
- selfy == pin.return_type ? pin : pin.proxy(selfy)
109
+ if pin.path == 'Class#new' && context.tag != 'Class'
110
+ pin.proxy(ComplexType.try_parse(context.namespace))
111
+ else
112
+ next pin if pin.return_type.undefined?
113
+ selfy = pin.return_type.self_to(context.tag)
114
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
115
+ end
113
116
  end
114
117
  end
115
118
 
@@ -180,14 +183,15 @@ module Solargraph
180
183
  end
181
184
 
182
185
  # @param arguments [Array<Chain>]
183
- # @param parameters [Array<String>]
186
+ # @param signature [Pin::Signature]
184
187
  # @return [Boolean]
185
- def arguments_match arguments, parameters
188
+ def arguments_match arguments, signature
189
+ parameters = signature.parameters
186
190
  argcount = arguments.length
187
- # argcount -= 1 if !arguments.empty? && arguments.last.links.first.word.start_with?('&')
188
191
  parcount = parameters.length
189
- parcount -= 1 if !parameters.empty? && parameters.last.first.start_with?('&')
190
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.first.start_with?('*'))
192
+ parcount -= 1 if !parameters.empty? && parameters.last.block?
193
+ return false if signature.block? && !with_block?
194
+ return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
191
195
  true
192
196
  end
193
197
 
@@ -198,6 +202,13 @@ module Solargraph
198
202
  pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
199
203
  pins.reject{|p| p.path == name_pin.path}
200
204
  end
205
+
206
+ # @param type [ComplexType]
207
+ # @param context [ComplexType]
208
+ def with_params type, context
209
+ return type unless type.to_s.include?('$')
210
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
211
+ end
201
212
  end
202
213
  end
203
214
  end
@@ -63,11 +63,11 @@ module Solargraph
63
63
  working_pin = name_pin
64
64
  links[0..-2].each do |link|
65
65
  pins = link.resolve(api_map, working_pin, locals)
66
- type = infer_first_defined(pins, working_pin, api_map)
66
+ type = infer_first_defined(pins, working_pin, api_map, locals)
67
67
  return [] if type.undefined?
68
68
  working_pin = Pin::ProxyType.anonymous(type)
69
69
  end
70
- links.last.last_context = working_pin
70
+ links.last.last_context = name_pin
71
71
  links.last.resolve(api_map, working_pin, locals)
72
72
  end
73
73
 
@@ -76,8 +76,12 @@ module Solargraph
76
76
  # @param locals [Array<Pin::Base>]
77
77
  # @return [ComplexType]
78
78
  def infer api_map, name_pin, locals
79
+ from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
80
+ if from_here
81
+ name_pin = name_pin.proxy(from_here)
82
+ end
79
83
  pins = define(api_map, name_pin, locals)
80
- type = infer_first_defined(pins, links.last.last_context, api_map)
84
+ type = infer_first_defined(pins, links.last.last_context, api_map, locals)
81
85
  maybe_nil(type)
82
86
  end
83
87
 
@@ -110,9 +114,10 @@ module Solargraph
110
114
  private
111
115
 
112
116
  # @param pins [Array<Pin::Base>]
117
+ # @param context [Pin::Base]
113
118
  # @param api_map [ApiMap]
114
119
  # @return [ComplexType]
115
- def infer_first_defined pins, context, api_map
120
+ def infer_first_defined pins, context, api_map, locals
116
121
  possibles = []
117
122
  pins.each do |pin|
118
123
  # Avoid infinite recursion
@@ -121,8 +126,18 @@ module Solargraph
121
126
  type = pin.typify(api_map)
122
127
  @@inference_stack.pop
123
128
  if type.defined?
124
- possibles.push type
125
- break if pin.is_a?(Pin::Method)
129
+ if type.parameterized?
130
+ type = type.resolve_parameters(pin.closure, context)
131
+ # idx = pin.closure.parameters.index(type.subtypes.first.name)
132
+ # next if idx.nil?
133
+ # param_type = context.return_type.all_params[idx]
134
+ # next unless param_type
135
+ # type = ComplexType.try_parse(param_type.to_s)
136
+ end
137
+ if type.defined?
138
+ possibles.push type
139
+ break if pin.is_a?(Pin::Method)
140
+ end
126
141
  end
127
142
  end
128
143
  if possibles.empty?
@@ -43,6 +43,11 @@ module Solargraph
43
43
  # @return [ComplexType]
44
44
  def infer
45
45
  result = cursor.chain.infer(api_map, block, locals)
46
+ if result.tag == 'Class'
47
+ # HACK: Exception to return Object from Class#new
48
+ dfn = cursor.chain.define(api_map, block, locals).first
49
+ return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
50
+ end
46
51
  return result unless result.tag == 'self'
47
52
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).namespace)
48
53
  end
@@ -24,6 +24,8 @@ module Solargraph
24
24
  @code = source.code
25
25
  @comments = source.comments
26
26
  @pins, @locals = Parser.map(source)
27
+ @pins.each { |p| p.source = :code }
28
+ @locals.each { |l| l.source = :code }
27
29
  process_comment_directives
28
30
  [@pins, @locals]
29
31
  # rescue Exception => e
@@ -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.49.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>