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
@@ -22,7 +22,7 @@ module Solargraph
22
22
  attr_reader :api_map
23
23
 
24
24
  # @param filename [String]
25
- # @param api_map [ApiMap]
25
+ # @param api_map [ApiMap, nil]
26
26
  # @param level [Symbol]
27
27
  def initialize filename, api_map: nil, level: :normal
28
28
  @filename = filename
@@ -51,6 +51,7 @@ module Solargraph
51
51
 
52
52
  class << self
53
53
  # @param filename [String]
54
+ # @param level [Symbol]
54
55
  # @return [self]
55
56
  def load filename, level = :normal
56
57
  source = Solargraph::Source.load(filename)
@@ -61,6 +62,7 @@ module Solargraph
61
62
 
62
63
  # @param code [String]
63
64
  # @param filename [String, nil]
65
+ # @param level [Symbol]
64
66
  # @return [self]
65
67
  def load_string code, filename = nil, level = :normal
66
68
  source = Solargraph::Source.load_string(code, filename)
@@ -91,7 +93,12 @@ module Solargraph
91
93
  declared = pin.typify(api_map).self_to(pin.full_context.namespace)
92
94
  if declared.undefined?
93
95
  if pin.return_type.undefined? && rules.require_type_tags?
94
- result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
96
+ if pin.attribute?
97
+ inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
98
+ result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
99
+ else
100
+ result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
101
+ end
95
102
  elsif pin.return_type.defined? && !resolved_constant?(pin)
96
103
  result.push Problem.new(pin.location, "Unresolved return type #{pin.return_type} for #{pin.path}", pin: pin)
97
104
  elsif rules.must_tag_or_infer? && pin.probe(api_map).undefined?
@@ -120,14 +127,17 @@ module Solargraph
120
127
  # @param pin [Pin::Base]
121
128
  # @return [Boolean]
122
129
  def resolved_constant? pin
123
- api_map.get_constants('', pin.binder.tag)
124
- .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
130
+ return true if pin.typify(api_map).defined?
131
+ constant_pins = api_map.get_constants('', *pin.closure.gates)
132
+ .select { |p| p.name == pin.return_type.namespace }
133
+ return true if constant_pins.find { |p| p.typify(api_map).defined? }
134
+ # will need to probe when a constant name is assigned to a
135
+ # class/module (alias)
136
+ return true if constant_pins.find { |p| p.probe(api_map).defined? }
137
+ false
129
138
  end
130
139
 
140
+ # @param pin [Pin::Base]
131
141
  def virtual_pin? pin
132
142
  pin.location && source_map.source.comment_at?(pin.location.range.ending)
133
143
  end
@@ -139,14 +149,27 @@ module Solargraph
139
149
  params = first_param_hash(stack)
140
150
  result = []
141
151
  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)
152
+ pin.signatures.each do |sig|
153
+ sig.parameters.each do |par|
154
+ break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
155
+ unless params[par.name]
156
+ if pin.attribute?
157
+ inferred = pin.probe(api_map).self_to(pin.full_context.namespace)
158
+ if inferred.undefined?
159
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
160
+ end
161
+ else
162
+ result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
163
+ end
164
+ end
146
165
  end
147
166
  end
148
167
  end
168
+ # @todo Should be able to probe type of name and data here
169
+ # @param name [String]
170
+ # @param data [Hash{Symbol => BasicObject}]
149
171
  params.each_pair do |name, data|
172
+ # @type [ComplexType]
150
173
  type = data[:qualified]
151
174
  if type.undefined?
152
175
  result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
@@ -155,6 +178,7 @@ module Solargraph
155
178
  result
156
179
  end
157
180
 
181
+ # @return [Array<Pin::Base>]
158
182
  def ignored_pins
159
183
  @ignored_pins ||= []
160
184
  end
@@ -184,7 +208,7 @@ module Solargraph
184
208
  elsif declared_externally?(pin)
185
209
  ignored_pins.push pin
186
210
  end
187
- elsif !pin.is_a?(Pin::Parameter)
211
+ elsif !pin.is_a?(Pin::Parameter) && !resolved_constant?(pin)
188
212
  result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
189
213
  end
190
214
  else
@@ -202,6 +226,7 @@ module Solargraph
202
226
  source_map.pins_by_class(Pin::BaseVariable) + source_map.locals.select { |pin| pin.is_a?(Pin::LocalVariable) }
203
227
  end
204
228
 
229
+ # @return [Array<Problem>]
205
230
  def const_problems
206
231
  return [] unless rules.validate_consts?
207
232
  result = []
@@ -220,6 +245,7 @@ module Solargraph
220
245
  result
221
246
  end
222
247
 
248
+ # @return [Array<Problem>]
223
249
  def call_problems
224
250
  result = []
225
251
  Solargraph::Parser::NodeMethods.call_nodes_from(source_map.source.node).each do |call|
@@ -243,7 +269,7 @@ module Solargraph
243
269
  end
244
270
  closest = found.typify(api_map) if found
245
271
  if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
246
- unless ignored_pins.include?(found)
272
+ unless closest.generic? || ignored_pins.include?(found)
247
273
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
248
274
  @marked_ranges.push rng
249
275
  end
@@ -254,16 +280,33 @@ module Solargraph
254
280
  result
255
281
  end
256
282
 
283
+ # @param chain [Solargraph::Source::Chain]
284
+ # @param api_map [Solargraph::ApiMap]
285
+ # @param block_pin [Solargraph::Pin::Base]
286
+ # @param locals [Array<Solargraph::Pin::Base>]
287
+ # @param location [Solargraph::Location]
288
+ # @return [Array<Problem>]
257
289
  def argument_problems_for chain, api_map, block_pin, locals, location
258
290
  result = []
259
291
  base = chain
260
292
  until base.links.length == 1 && base.undefined?
261
293
  pins = base.define(api_map, block_pin, locals)
262
- if pins.first.is_a?(Pin::Method)
294
+
295
+ if pins.first.is_a?(Pin::DelegatedMethod) && !pins.first.resolvable?(api_map)
296
+ # Do nothing, as we can't find the actual method implementation
297
+ elsif pins.first.is_a?(Pin::Method)
263
298
  # @type [Pin::Method]
264
299
  pin = pins.first
265
300
  ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
266
301
  arity_problems_for(pin, fake_args_for(block_pin), location)
302
+ elsif pin.path == 'Class#new'
303
+ fqns = if base.links.one?
304
+ block_pin.namespace
305
+ else
306
+ base.base.infer(api_map, block_pin, locals).namespace
307
+ end
308
+ init = api_map.get_method_stack(fqns, 'initialize').first
309
+ init ? arity_problems_for(init, base.links.last.arguments, location) : []
267
310
  else
268
311
  arity_problems_for(pin, base.links.last.arguments, location)
269
312
  end
@@ -271,71 +314,119 @@ module Solargraph
271
314
  result.concat ap
272
315
  break
273
316
  end
274
- break unless rules.validate_calls?
317
+ break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
318
+
275
319
  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
320
+
321
+ all_errors = []
322
+ pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
323
+ errors = []
324
+ # @todo these should be able to be probed
325
+ # @param par [Parameter]
326
+ # @param idx [Integer]
327
+ sig.parameters.each_with_index do |par, idx|
328
+ argchain = base.links.last.arguments[idx]
329
+ if argchain.nil?
330
+ if par.decl == :arg
331
+ last = base.links.last.arguments.last
332
+ if last && last.node.type == :splat
333
+ argchain = last
334
+ next # don't try to apply the type of the splat - unlikely to be specific enough
335
+ else
336
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
337
+ next
338
+ end
339
+ else
340
+ last = base.links.last.arguments.last
341
+ argchain = last if last && [:kwsplat, :hash].include?(last.node.type)
342
+ end
343
+ end
344
+ if argchain
345
+ if par.decl != :arg
346
+ errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
347
+ next
290
348
  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}")
349
+ last = base.links.last.arguments.last
350
+ if last && last.node.type == :splat
351
+ next # don't try to apply the type of the splat - unlikely to be specific enough
352
+ end
353
+ ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
354
+ ptype = ptype.self_to(par.context.namespace)
355
+ if ptype.nil?
356
+ # @todo Some level (strong, I guess) should require the param here
357
+ else
358
+ argtype = argchain.infer(api_map, block_pin, locals)
359
+ if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
360
+ errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
361
+ next
362
+ end
294
363
  end
295
364
  end
365
+ elsif par.decl == :kwarg
366
+ errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
367
+ next
296
368
  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}")
369
+ end
370
+ if errors.empty?
371
+ all_errors.clear
301
372
  break
302
373
  end
374
+ all_errors.concat errors
303
375
  end
376
+ result.concat all_errors
304
377
  end
305
378
  base = base.base
306
379
  end
307
380
  result
308
381
  end
309
382
 
310
- def kwarg_problems_for argchain, api_map, block_pin, locals, location, pin, params, first
383
+ # @param sig [Pin::Signature]
384
+ # @param argchain [Source::Chain]
385
+ # @param api_map [ApiMap]
386
+ # @param block_pin [Pin::Block]
387
+ # @param locals [Array<Pin::LocalVariable>]
388
+ # @param location [Location]
389
+ # @param pin [Pin::Method]
390
+ # @param params [Hash{String => [nil, Hash]}]
391
+ # @param idx [Integer]
392
+ #
393
+ # @return [Array<Problem>]
394
+ def kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
311
395
  result = []
312
396
  kwargs = convert_hash(argchain.node)
313
- pin.parameters[first..-1].each_with_index do |par, cur|
314
- idx = first + cur
315
- argchain = kwargs[par.name.to_sym]
316
- if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
317
- result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
318
- else
319
- if argchain
320
- data = params[par.name]
321
- if data.nil?
322
- # @todo Some level (strong, I guess) should require the param here
323
- else
324
- ptype = data[:qualified]
325
- next if ptype.undefined?
397
+ par = sig.parameters[idx]
398
+ argchain = kwargs[par.name.to_sym]
399
+ if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
400
+ result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
401
+ else
402
+ if argchain
403
+ data = params[par.name]
404
+ if data.nil?
405
+ # @todo Some level (strong, I guess) should require the param here
406
+ else
407
+ ptype = data[:qualified]
408
+ unless ptype.undefined?
326
409
  argtype = argchain.infer(api_map, block_pin, locals)
327
410
  if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
328
411
  result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
329
412
  end
330
413
  end
331
- elsif par.decl == :kwarg
332
- result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
333
414
  end
415
+ elsif par.decl == :kwarg
416
+ result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
334
417
  end
335
418
  end
336
419
  result
337
420
  end
338
421
 
422
+ # @param api_map [ApiMap]
423
+ # @param block_pin [Pin::Block]
424
+ # @param locals [Array<Pin::LocalVariable>]
425
+ # @param location [Location]
426
+ # @param pin [Pin::Method]
427
+ # @param params [Hash{String => [nil, Hash]}]
428
+ # @param kwargs [Hash{Symbol => Source::Chain}]
429
+ # @return [Array<Problem>]
339
430
  def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
340
431
  result = []
341
432
  kwargs.each_pair do |pname, argchain|
@@ -349,8 +440,8 @@ module Solargraph
349
440
  result
350
441
  end
351
442
 
352
- # @param [Pin::Method]
353
- # @return [Hash]
443
+ # @param pin [Pin::Method]
444
+ # @return [Hash{String => Hash{Symbol => BaseObject}}]
354
445
  def param_hash(pin)
355
446
  tags = pin.docstring.tags(:param)
356
447
  return {} if tags.empty?
@@ -365,10 +456,12 @@ module Solargraph
365
456
  result
366
457
  end
367
458
 
368
- # @param [Array<Pin::Method>]
369
- # @return [Hash]
459
+ # @param pins [Array<Pin::Method>]
460
+ # @return [Hash{String => Hash{Symbol => BasicObject}}]
370
461
  def first_param_hash(pins)
371
462
  pins.each do |pin|
463
+ # @todo this assignment from parametric use of Hash should not lose its generic
464
+ # @type [Hash{String => Hash{Symbol => BasicObject}]
372
465
  result = param_hash(pin)
373
466
  return result unless result.empty?
374
467
  end
@@ -381,8 +474,11 @@ module Solargraph
381
474
  pin.location && api_map.bundled?(pin.location.filename)
382
475
  end
383
476
 
477
+ # True if the pin is either internal (part of the workspace) or from the core/stdlib
478
+ # @param pin [Pin::Base]
384
479
  def internal_or_core? pin
385
- internal?(pin) || api_map.yard_map.core_pins.include?(pin) || api_map.yard_map.stdlib_pins.include?(pin)
480
+ # @todo RBS pins are not necessarily core/stdlib pins
481
+ internal?(pin) || pin.source == :rbs
386
482
  end
387
483
 
388
484
  # @param pin [Pin::Base]
@@ -390,6 +486,7 @@ module Solargraph
390
486
  !internal? pin
391
487
  end
392
488
 
489
+ # @param pin [Pin::Base]
393
490
  def declared_externally? pin
394
491
  return true if pin.assignment.nil?
395
492
  chain = Solargraph::Parser.chain(pin.assignment, filename)
@@ -418,41 +515,44 @@ module Solargraph
418
515
  end
419
516
 
420
517
  # @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)
518
+ # @param arguments [Array<Source::Chain>]
519
+ # @param location [Location]
520
+ # @return [Array<Problem>]
521
+ def arity_problems_for pin, arguments, location
522
+ results = pin.signatures.map do |sig|
523
+ r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
524
+ return [] if r.empty?
525
+ r
526
+ end
527
+ results.first
427
528
  end
428
529
 
429
530
  # @param pin [Pin::Method]
430
- def pin_arity_problems_for(pin, arguments, location)
531
+ # @param parameters [Array<Pin::Parameter>]
532
+ # @param arguments [Array<Source::Chain>]
533
+ # @param location [Location]
534
+ # @return [Array<Problem>]
535
+ def parameterized_arity_problems_for(pin, parameters, arguments, location)
431
536
  return [] unless pin.explicit?
432
- return [] if pin.parameters.empty? && arguments.empty?
433
- if pin.parameters.empty?
434
- # Functions tagged param_tuple accepts two arguments (e.g., Hash#[]=)
435
- return [] if pin.docstring.tag(:param_tuple) && arguments.length == 2
436
- return [] if arguments.length == 1 && arguments.last.links.last.is_a?(Source::Chain::BlockVariable)
437
- return [Problem.new(location, "Too many arguments to #{pin.path}")]
438
- end
537
+ return [] if parameters.empty? && arguments.empty?
538
+ return [] if pin.anon_splat?
439
539
  unchecked = arguments.clone
440
540
  add_params = 0
441
- if unchecked.empty? && pin.parameters.any? { |param| param.decl == :kwarg }
541
+ if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
442
542
  return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
443
543
  end
444
544
  settled_kwargs = 0
445
545
  unless unchecked.empty?
446
546
  if any_splatted_call?(unchecked.map(&:node))
447
- settled_kwargs = pin.parameters.count(&:keyword?)
547
+ settled_kwargs = parameters.count(&:keyword?)
448
548
  else
449
549
  kwargs = convert_hash(unchecked.last.node)
450
- if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
550
+ if parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
451
551
  if kwargs.empty?
452
552
  add_params += 1
453
553
  else
454
554
  unchecked.pop
455
- pin.parameters.each do |param|
555
+ parameters.each do |param|
456
556
  next unless param.keyword?
457
557
  if kwargs.key?(param.name.to_sym)
458
558
  kwargs.delete param.name.to_sym
@@ -462,7 +562,7 @@ module Solargraph
462
562
  return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
463
563
  end
464
564
  end
465
- kwargs.clear if pin.parameters.any?(&:kwrestarg?)
565
+ kwargs.clear if parameters.any?(&:kwrestarg?)
466
566
  unless kwargs.empty?
467
567
  return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
468
568
  end
@@ -470,18 +570,15 @@ module Solargraph
470
570
  end
471
571
  end
472
572
  end
473
- req = required_param_count(pin)
573
+ req = required_param_count(parameters)
474
574
  if req + add_params < unchecked.length
475
- return [] if pin.parameters.any?(&:rest?)
476
- opt = optional_param_count(pin)
575
+ return [] if parameters.any?(&:rest?)
576
+ opt = optional_param_count(parameters)
477
577
  return [] if unchecked.length <= req + opt
478
- if unchecked.length == req + opt + 1 && unchecked.last.links.last.is_a?(Source::Chain::BlockVariable)
479
- return []
480
- end
481
- if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (pin.parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
578
+ if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
482
579
  return []
483
580
  end
484
- return [] if arguments.length - req == pin.parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
581
+ return [] if arguments.length - req == parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
485
582
  return [Problem.new(location, "Too many arguments to #{pin.path}")]
486
583
  elsif unchecked.length < req - settled_kwargs && (arguments.empty? || (!arguments.last.splat? && !arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash)))
487
584
  # HACK: Kernel#raise signature is incorrect in Ruby 2.7 core docs.
@@ -493,26 +590,30 @@ module Solargraph
493
590
  []
494
591
  end
495
592
 
496
- # @param pin [Pin::Method]
497
- def required_param_count(pin)
498
- pin.parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
593
+ # @param parameters [Enumerable<Pin::Parameter>]
594
+ # @todo need to use generic types in method to choose correct
595
+ # signature and generate Integer as return type
596
+ # @sg-ignore
597
+ # @return [Integer]
598
+ def required_param_count(parameters)
599
+ parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
499
600
  end
500
601
 
602
+ # @param parameters [Enumerable<Pin::Parameter>]
501
603
  # @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
604
+ # @return [Integer]
605
+ def optional_param_count(parameters)
606
+ parameters.select { |p| p.decl == :optarg }.length
509
607
  end
510
608
 
609
+ # @param pin [Pin::Method]
511
610
  def abstract? pin
512
- pin.docstring.has_tag?(:abstract) ||
513
- (pin.closure && pin.closure.docstring.has_tag?(:abstract))
611
+ pin.docstring.has_tag?('abstract') ||
612
+ (pin.closure && pin.closure.docstring.has_tag?('abstract'))
514
613
  end
515
614
 
615
+ # @param pin [Pin::Base]
616
+ # @return [Array<Source::Chain>]
516
617
  def fake_args_for(pin)
517
618
  args = []
518
619
  with_opts = false
@@ -533,10 +634,12 @@ module Solargraph
533
634
  args
534
635
  end
535
636
 
637
+ # @param problems [Array<Problem>]
638
+ # @return [Array<Problem>]
536
639
  def without_ignored problems
537
640
  problems.reject do |problem|
538
641
  node = source_map.source.node_at(problem.location.range.start.line, problem.location.range.start.column)
539
- source_map.source.comments_for(node)&.include?('@sg-ignore')
642
+ node && source_map.source.comments_for(node)&.include?('@sg-ignore')
540
643
  end
541
644
  end
542
645
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.47.2'
4
+ VERSION = '0.53.3'
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>
@@ -14,12 +14,12 @@ module Solargraph
14
14
  # @return [String]
15
15
  attr_reader :directory
16
16
 
17
- # @return [Hash]
17
+ # @return [Hash{String => BasicObject}]
18
18
  attr_reader :raw_data
19
19
 
20
20
  # @param directory [String]
21
21
  def initialize directory = ''
22
- @directory = directory
22
+ @directory = File.absolute_path(directory)
23
23
  @raw_data = config_data
24
24
  included
25
25
  excluded
@@ -41,8 +41,10 @@ module Solargraph
41
41
  @excluded ||= process_exclusions(@raw_data['exclude'])
42
42
  end
43
43
 
44
+ # @param filename [String]
44
45
  def allow? filename
45
- filename.start_with?(directory) &&
46
+ filename = File.absolute_path(filename, directory)
47
+ filename.start_with?(directory) &&
46
48
  !excluded.include?(filename) &&
47
49
  excluded_directories.none? { |d| filename.start_with?(d) }
48
50
  end
@@ -110,7 +112,7 @@ module Solargraph
110
112
 
111
113
  # @return [String]
112
114
  def global_config_path
113
- ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
115
+ ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
114
116
  File.join(Dir.home, '.config', 'solargraph', 'config.yml')
115
117
  end
116
118
 
@@ -120,7 +122,7 @@ module Solargraph
120
122
  File.join(@directory, '.solargraph.yml')
121
123
  end
122
124
 
123
- # @return [Hash]
125
+ # @return [Hash{String => Array, Hash, Integer}]
124
126
  def config_data
125
127
  workspace_config = read_config(workspace_config_path)
126
128
  global_config = read_config(global_config_path)
@@ -135,15 +137,15 @@ module Solargraph
135
137
 
136
138
  # Read a .solargraph yaml config
137
139
  #
138
- # @param directory [String]
139
- # @return [Hash, nil]
140
+ # @param config_path [String]
141
+ # @return [Hash{String => Array, Hash, Integer}, nil]
140
142
  def read_config config_path = ''
141
143
  return nil if config_path.empty?
142
144
  return nil unless File.file?(config_path)
143
145
  YAML.safe_load(File.read(config_path))
144
146
  end
145
147
 
146
- # @return [Hash]
148
+ # @return [Hash{String => Array, Hash, Integer}]
147
149
  def default_config
148
150
  {
149
151
  'include' => ['**/*.rb'],
@@ -171,7 +173,7 @@ module Solargraph
171
173
  # @return [Array<String>]
172
174
  def process_globs globs
173
175
  result = globs.flat_map do |glob|
174
- Dir[File.join directory, glob]
176
+ Dir[File.absolute_path(glob, directory)]
175
177
  .map{ |f| f.gsub(/\\/, '/') }
176
178
  .select { |f| File.file?(f) }
177
179
  end
@@ -186,7 +188,7 @@ module Solargraph
186
188
  def process_exclusions globs
187
189
  remainder = globs.select do |glob|
188
190
  if glob_is_directory?(glob)
189
- exdir = File.join(directory, glob_to_directory(glob))
191
+ exdir = File.absolute_path(glob_to_directory(glob), directory)
190
192
  included.delete_if { |file| file.start_with?(exdir) }
191
193
  false
192
194
  else
@@ -221,10 +223,11 @@ module Solargraph
221
223
  glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
222
224
  end
223
225
 
226
+ # @return [Array<String>]
224
227
  def excluded_directories
225
228
  @raw_data['exclude']
226
229
  .select { |g| glob_is_directory?(g) }
227
- .map { |g| File.join(directory, glob_to_directory(g)) }
230
+ .map { |g| File.absolute_path(glob_to_directory(g), directory) }
228
231
  end
229
232
  end
230
233
  end