solargraph 0.54.4 → 0.57.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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +125 -0
  3. data/.github/workflows/plugins.yml +149 -5
  4. data/.github/workflows/rspec.yml +39 -4
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +2627 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +104 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/lib/solargraph/api_map/cache.rb +3 -2
  16. data/lib/solargraph/api_map/constants.rb +218 -0
  17. data/lib/solargraph/api_map/index.rb +44 -42
  18. data/lib/solargraph/api_map/source_to_yard.rb +10 -4
  19. data/lib/solargraph/api_map/store.rb +165 -32
  20. data/lib/solargraph/api_map.rb +319 -243
  21. data/lib/solargraph/bench.rb +18 -1
  22. data/lib/solargraph/complex_type/type_methods.rb +7 -1
  23. data/lib/solargraph/complex_type/unique_type.rb +105 -16
  24. data/lib/solargraph/complex_type.rb +40 -7
  25. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  26. data/lib/solargraph/convention/base.rb +20 -3
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  29. data/lib/solargraph/convention/data_definition.rb +105 -0
  30. data/lib/solargraph/convention/gemspec.rb +3 -2
  31. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  32. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  33. data/lib/solargraph/convention/struct_definition.rb +164 -0
  34. data/lib/solargraph/convention.rb +35 -4
  35. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  36. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -1
  37. data/lib/solargraph/doc_map.rb +313 -65
  38. data/lib/solargraph/environ.rb +9 -2
  39. data/lib/solargraph/gem_pins.rb +60 -38
  40. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  41. data/lib/solargraph/language_server/host/message_worker.rb +13 -7
  42. data/lib/solargraph/language_server/host.rb +14 -3
  43. data/lib/solargraph/language_server/message/base.rb +2 -1
  44. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  45. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  46. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  47. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/text_document/formatting.rb +16 -2
  49. data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
  50. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  51. data/lib/solargraph/language_server/progress.rb +8 -0
  52. data/lib/solargraph/language_server/request.rb +1 -0
  53. data/lib/solargraph/library.rb +53 -32
  54. data/lib/solargraph/location.rb +23 -0
  55. data/lib/solargraph/logging.rb +12 -2
  56. data/lib/solargraph/page.rb +4 -0
  57. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  58. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  59. data/lib/solargraph/parser/node_methods.rb +16 -2
  60. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  61. data/lib/solargraph/parser/node_processor.rb +26 -9
  62. data/lib/solargraph/parser/parser_gem/class_methods.rb +17 -15
  63. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  64. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  65. data/lib/solargraph/parser/parser_gem/node_methods.rb +8 -4
  66. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  67. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  68. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  70. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  73. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  74. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  75. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  76. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  77. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  80. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +42 -0
  81. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  83. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
  84. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +63 -30
  85. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  86. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  89. data/lib/solargraph/parser/region.rb +4 -1
  90. data/lib/solargraph/parser/snippet.rb +2 -0
  91. data/lib/solargraph/parser.rb +1 -0
  92. data/lib/solargraph/pin/base.rb +360 -30
  93. data/lib/solargraph/pin/base_variable.rb +16 -10
  94. data/lib/solargraph/pin/block.rb +2 -0
  95. data/lib/solargraph/pin/breakable.rb +9 -0
  96. data/lib/solargraph/pin/callable.rb +83 -3
  97. data/lib/solargraph/pin/closure.rb +20 -1
  98. data/lib/solargraph/pin/common.rb +10 -1
  99. data/lib/solargraph/pin/constant.rb +2 -0
  100. data/lib/solargraph/pin/delegated_method.rb +21 -1
  101. data/lib/solargraph/pin/documenting.rb +16 -0
  102. data/lib/solargraph/pin/keyword.rb +7 -2
  103. data/lib/solargraph/pin/local_variable.rb +18 -6
  104. data/lib/solargraph/pin/method.rb +175 -46
  105. data/lib/solargraph/pin/method_alias.rb +3 -0
  106. data/lib/solargraph/pin/namespace.rb +17 -9
  107. data/lib/solargraph/pin/parameter.rb +78 -19
  108. data/lib/solargraph/pin/proxy_type.rb +13 -6
  109. data/lib/solargraph/pin/reference/override.rb +24 -6
  110. data/lib/solargraph/pin/reference/require.rb +2 -2
  111. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  112. data/lib/solargraph/pin/reference.rb +26 -0
  113. data/lib/solargraph/pin/search.rb +3 -1
  114. data/lib/solargraph/pin/signature.rb +44 -0
  115. data/lib/solargraph/pin/singleton.rb +1 -1
  116. data/lib/solargraph/pin/symbol.rb +8 -2
  117. data/lib/solargraph/pin/until.rb +18 -0
  118. data/lib/solargraph/pin/while.rb +18 -0
  119. data/lib/solargraph/pin.rb +4 -1
  120. data/lib/solargraph/pin_cache.rb +245 -0
  121. data/lib/solargraph/position.rb +11 -0
  122. data/lib/solargraph/range.rb +10 -0
  123. data/lib/solargraph/rbs_map/conversions.rb +226 -70
  124. data/lib/solargraph/rbs_map/core_fills.rb +32 -16
  125. data/lib/solargraph/rbs_map/core_map.rb +37 -11
  126. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  127. data/lib/solargraph/rbs_map.rb +88 -18
  128. data/lib/solargraph/shell.rb +20 -18
  129. data/lib/solargraph/source/chain/array.rb +11 -7
  130. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  131. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  132. data/lib/solargraph/source/chain/call.rb +53 -23
  133. data/lib/solargraph/source/chain/constant.rb +1 -1
  134. data/lib/solargraph/source/chain/hash.rb +4 -3
  135. data/lib/solargraph/source/chain/head.rb +1 -1
  136. data/lib/solargraph/source/chain/if.rb +1 -1
  137. data/lib/solargraph/source/chain/link.rb +12 -1
  138. data/lib/solargraph/source/chain/literal.rb +22 -2
  139. data/lib/solargraph/source/chain/or.rb +1 -1
  140. data/lib/solargraph/source/chain/z_super.rb +1 -1
  141. data/lib/solargraph/source/chain.rb +84 -47
  142. data/lib/solargraph/source/change.rb +2 -2
  143. data/lib/solargraph/source/cursor.rb +2 -3
  144. data/lib/solargraph/source/source_chainer.rb +3 -3
  145. data/lib/solargraph/source.rb +5 -2
  146. data/lib/solargraph/source_map/clip.rb +4 -2
  147. data/lib/solargraph/source_map/data.rb +4 -0
  148. data/lib/solargraph/source_map/mapper.rb +13 -7
  149. data/lib/solargraph/source_map.rb +21 -31
  150. data/lib/solargraph/type_checker/checks.rb +4 -0
  151. data/lib/solargraph/type_checker/param_def.rb +2 -0
  152. data/lib/solargraph/type_checker/rules.rb +8 -0
  153. data/lib/solargraph/type_checker.rb +208 -128
  154. data/lib/solargraph/version.rb +1 -1
  155. data/lib/solargraph/views/_method.erb +10 -10
  156. data/lib/solargraph/views/_namespace.erb +3 -3
  157. data/lib/solargraph/views/document.erb +10 -10
  158. data/lib/solargraph/workspace/config.rb +1 -3
  159. data/lib/solargraph/workspace/require_paths.rb +98 -0
  160. data/lib/solargraph/workspace.rb +38 -52
  161. data/lib/solargraph/yard_map/helpers.rb +29 -1
  162. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  163. data/lib/solargraph/yard_map/mapper/to_method.rb +53 -18
  164. data/lib/solargraph/yard_map/mapper/to_namespace.rb +9 -7
  165. data/lib/solargraph/yard_map/mapper.rb +4 -3
  166. data/lib/solargraph/yard_map/to_method.rb +4 -2
  167. data/lib/solargraph/yardoc.rb +22 -10
  168. data/lib/solargraph.rb +34 -1
  169. data/rbs/fills/tuple.rbs +149 -0
  170. data/rbs_collection.yaml +19 -0
  171. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  172. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  173. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  174. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  175. data/solargraph.gemspec +15 -4
  176. metadata +157 -15
  177. data/lib/.rubocop.yml +0 -22
  178. data/lib/solargraph/cache.rb +0 -77
@@ -12,6 +12,8 @@ module Solargraph
12
12
  # @return [Symbol]
13
13
  attr_reader :type
14
14
 
15
+ # @param name [String]
16
+ # @param type [Symbol] The type of parameter, such as :req, :opt, :rest, etc.
15
17
  def initialize name, type
16
18
  @name = name
17
19
  @type = type
@@ -57,6 +57,14 @@ module Solargraph
57
57
  def require_all_return_types_match_inferred?
58
58
  rank >= LEVELS[:alpha]
59
59
  end
60
+
61
+ # We keep this at strong because if you added an @ sg-ignore to
62
+ # address a strong-level issue, then ran at a lower level, you'd
63
+ # get a false positive - we don't run stronger level checks than
64
+ # requested for performance reasons
65
+ def validate_sg_ignores?
66
+ rank >= LEVELS[:strong]
67
+ end
60
68
  end
61
69
  end
62
70
  end
@@ -38,15 +38,20 @@ module Solargraph
38
38
  @source_map ||= api_map.source_map(filename)
39
39
  end
40
40
 
41
+ # @return [Source]
42
+ def source
43
+ @source_map.source
44
+ end
45
+
41
46
  # @return [Array<Problem>]
42
47
  def problems
43
48
  @problems ||= begin
44
- without_ignored(
45
- method_tag_problems
46
- .concat variable_type_tag_problems
47
- .concat const_problems
48
- .concat call_problems
49
- )
49
+ all = method_tag_problems
50
+ .concat(variable_type_tag_problems)
51
+ .concat(const_problems)
52
+ .concat(call_problems)
53
+ unignored = without_ignored(all)
54
+ unignored.concat(unneeded_sgignore_problems)
50
55
  end
51
56
  end
52
57
 
@@ -140,7 +145,7 @@ module Solargraph
140
145
 
141
146
  # @param pin [Pin::Base]
142
147
  def virtual_pin? pin
143
- pin.location && source_map.source.comment_at?(pin.location.range.ending)
148
+ pin.location && source.comment_at?(pin.location.range.ending)
144
149
  end
145
150
 
146
151
  # @param pin [Pin::Method]
@@ -231,7 +236,7 @@ module Solargraph
231
236
  def const_problems
232
237
  return [] unless rules.validate_consts?
233
238
  result = []
234
- Solargraph::Parser::NodeMethods.const_nodes_from(source_map.source.node).each do |const|
239
+ Solargraph::Parser::NodeMethods.const_nodes_from(source.node).each do |const|
235
240
  rng = Solargraph::Range.from_node(const)
236
241
  chain = Solargraph::Parser.chain(const, filename)
237
242
  block_pin = source_map.locate_block_pin(rng.start.line, rng.start.column)
@@ -249,7 +254,7 @@ module Solargraph
249
254
  # @return [Array<Problem>]
250
255
  def call_problems
251
256
  result = []
252
- Solargraph::Parser::NodeMethods.call_nodes_from(source_map.source.node).each do |call|
257
+ Solargraph::Parser::NodeMethods.call_nodes_from(source.node).each do |call|
253
258
  rng = Solargraph::Range.from_node(call)
254
259
  next if @marked_ranges.any? { |d| d.contain?(rng.start) }
255
260
  chain = Solargraph::Parser.chain(call, filename)
@@ -272,7 +277,11 @@ module Solargraph
272
277
  # @todo remove the internal_or_core? check at a higher-than-strict level
273
278
  if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
274
279
  unless closest.generic? || ignored_pins.include?(found)
275
- result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
280
+ if closest.defined?
281
+ result.push Problem.new(location, "Unresolved call to #{missing.links.last.word} on #{closest}")
282
+ else
283
+ result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
284
+ end
276
285
  @marked_ranges.push rng
277
286
  end
278
287
  end
@@ -284,127 +293,136 @@ module Solargraph
284
293
 
285
294
  # @param chain [Solargraph::Source::Chain]
286
295
  # @param api_map [Solargraph::ApiMap]
287
- # @param block_pin [Solargraph::Pin::Base]
296
+ # @param closure_pin [Solargraph::Pin::Closure]
288
297
  # @param locals [Array<Solargraph::Pin::Base>]
289
298
  # @param location [Solargraph::Location]
290
299
  # @return [Array<Problem>]
291
- def argument_problems_for chain, api_map, block_pin, locals, location
300
+ def argument_problems_for chain, api_map, closure_pin, locals, location
292
301
  result = []
293
302
  base = chain
294
- until base.links.length == 1 && base.undefined?
295
- last_base_link = base.links.last
296
- break unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
297
-
298
- arguments = last_base_link.arguments
299
-
300
- pins = base.define(api_map, block_pin, locals)
301
-
302
- first_pin = pins.first
303
- if first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
304
- # Do nothing, as we can't find the actual method implementation
305
- elsif first_pin.is_a?(Pin::Method)
306
- # @type [Pin::Method]
307
- pin = first_pin
308
- ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
309
- arity_problems_for(pin, fake_args_for(block_pin), location)
310
- elsif pin.path == 'Class#new'
311
- fqns = if base.links.one?
312
- block_pin.namespace
303
+ # @type last_base_link [Solargraph::Source::Chain::Call]
304
+ last_base_link = base.links.last
305
+ return [] unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
306
+
307
+ arguments = last_base_link.arguments
308
+
309
+ pins = base.define(api_map, closure_pin, locals)
310
+
311
+ first_pin = pins.first
312
+ unresolvable = first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
313
+ if !unresolvable && first_pin.is_a?(Pin::Method)
314
+ # @type [Pin::Method]
315
+ pin = first_pin
316
+ ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
317
+ arity_problems_for(pin, fake_args_for(closure_pin), location)
318
+ elsif pin.path == 'Class#new'
319
+ fqns = if base.links.one?
320
+ closure_pin.namespace
321
+ else
322
+ base.base.infer(api_map, closure_pin, locals).namespace
323
+ end
324
+ init = api_map.get_method_stack(fqns, 'initialize').first
325
+
326
+ init ? arity_problems_for(init, arguments, location) : []
327
+ else
328
+ arity_problems_for(pin, arguments, location)
329
+ end
330
+ return ap unless ap.empty?
331
+ return [] if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
332
+
333
+ params = first_param_hash(pins)
334
+
335
+ all_errors = []
336
+ pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
337
+ signature_errors = signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
338
+ if signature_errors.empty?
339
+ # we found a signature that works - meaning errors from
340
+ # other signatures don't matter.
341
+ return []
342
+ end
343
+ all_errors.concat signature_errors
344
+ end
345
+ result.concat all_errors
346
+ end
347
+ result
348
+ end
349
+
350
+ # @param location [Location]
351
+ # @param locals [Array<Pin::LocalVariable>]
352
+ # @param closure_pin [Pin::Closure]
353
+ # @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
354
+ # @param arguments [Array<Source::Chain>]
355
+ # @param sig [Pin::Signature]
356
+ # @param pin [Pin::Method]
357
+ # @param pins [Array<Pin::Method>]
358
+ #
359
+ # @return [Array<Problem>]
360
+ def signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
361
+ errors = []
362
+ # @todo add logic mapping up restarg parameters with
363
+ # arguments (including restarg arguments). Use tuples
364
+ # when possible, and when not, ensure provably
365
+ # incorrect situations are detected.
366
+ sig.parameters.each_with_index do |par, idx|
367
+ return errors if par.decl == :restarg # bail out and assume the rest is valid pending better arg processing
368
+ argchain = arguments[idx]
369
+ if argchain.nil?
370
+ if par.decl == :arg
371
+ final_arg = arguments.last
372
+ if final_arg && final_arg.node.type == :splat
373
+ argchain = final_arg
374
+ return errors
313
375
  else
314
- base.base.infer(api_map, block_pin, locals).namespace
376
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
315
377
  end
316
- init = api_map.get_method_stack(fqns, 'initialize').first
317
- init ? arity_problems_for(init, arguments, location) : []
318
378
  else
319
- arity_problems_for(pin, arguments, location)
320
- end
321
- unless ap.empty?
322
- result.concat ap
323
- break
379
+ final_arg = arguments.last
380
+ argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
324
381
  end
325
- break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
326
-
327
- params = first_param_hash(pins)
328
-
329
- all_errors = []
330
- pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
331
- errors = []
332
- sig.parameters.each_with_index do |par, idx|
333
- # @todo add logic mapping up restarg parameters with
334
- # arguments (including restarg arguments). Use tuples
335
- # when possible, and when not, ensure provably
336
- # incorrect situations are detected.
337
- break if par.decl == :restarg # bail out pending better arg processing
338
- argchain = arguments[idx]
339
- if argchain.nil?
340
- if par.decl == :arg
341
- final_arg = arguments.last
342
- if final_arg && final_arg.node.type == :splat
343
- argchain = final_arg
344
- next # don't try to apply the type of the splat - unlikely to be specific enough
345
- else
346
- errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
347
- next
348
- end
349
- else
350
- final_arg = arguments.last
351
- argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
352
- end
353
- end
354
- if argchain
355
- if par.decl != :arg
356
- errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
357
- next
358
- else
359
- if argchain.node.type == :splat && argchain == arguments.last
360
- final_arg = argchain
361
- end
362
- if (final_arg && final_arg.node.type == :splat)
363
- # The final argument given has been seen and was a
364
- # splat, which doesn't give us useful types or
365
- # arities against positional parameters, so let's
366
- # continue on in case there are any required
367
- # kwargs we should warn about
368
- next
369
- end
370
-
371
- if argchain.node.type == :splat && par != sig.parameters.last
372
- # we have been given a splat and there are more
373
- # arguments to come.
374
-
375
- # @todo Improve this so that we can skip past the
376
- # rest of the positional parameters here but still
377
- # process the kwargs
378
- break
379
- end
380
- ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
381
- ptype = ptype.self_to_type(par.context)
382
- if ptype.nil?
383
- # @todo Some level (strong, I guess) should require the param here
384
- else
385
- argtype = argchain.infer(api_map, block_pin, locals)
386
- if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
387
- errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
388
- next
389
- end
390
- end
391
- end
392
- elsif par.decl == :kwarg
393
- errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
394
- next
395
- end
382
+ end
383
+ if argchain
384
+ if par.decl != :arg
385
+ errors.concat kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
386
+ next
387
+ else
388
+ if argchain.node.type == :splat && argchain == arguments.last
389
+ final_arg = argchain
390
+ end
391
+ if (final_arg && final_arg.node.type == :splat)
392
+ # The final argument given has been seen and was a
393
+ # splat, which doesn't give us useful types or
394
+ # arities against positional parameters, so let's
395
+ # continue on in case there are any required
396
+ # kwargs we should warn about
397
+ next
398
+ end
399
+ if argchain.node.type == :splat && par != sig.parameters.last
400
+ # we have been given a splat and there are more
401
+ # arguments to come.
402
+
403
+ # @todo Improve this so that we can skip past the
404
+ # rest of the positional parameters here but still
405
+ # process the kwargs
406
+ return errors
396
407
  end
397
- if errors.empty?
398
- all_errors.clear
399
- break
408
+ ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
409
+ ptype = ptype.self_to_type(par.context)
410
+ if ptype.nil?
411
+ # @todo Some level (strong, I guess) should require the param here
412
+ else
413
+ argtype = argchain.infer(api_map, closure_pin, locals)
414
+ if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
415
+ errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
416
+ return errors
417
+ end
400
418
  end
401
- all_errors.concat errors
402
419
  end
403
- result.concat all_errors
420
+ elsif par.decl == :kwarg
421
+ errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
422
+ next
404
423
  end
405
- base = base.base
406
424
  end
407
- result
425
+ errors
408
426
  end
409
427
 
410
428
  # @param sig [Pin::Signature]
@@ -470,12 +488,22 @@ module Solargraph
470
488
  # @param pin [Pin::Method]
471
489
  # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
472
490
  def param_hash(pin)
473
- tags = pin.docstring.tags(:param)
474
- return {} if tags.empty?
475
491
  # @type [Hash{String => Hash{Symbol => String, ComplexType}}]
476
492
  result = {}
493
+ pin.parameters.each do |param|
494
+ type = param.typify(api_map)
495
+ next if type.nil? || type.undefined?
496
+ result[param.name.to_s] = {
497
+ tagged: type.tags,
498
+ qualified: type
499
+ }
500
+ end
501
+ # see if we have additional tags to pay attention to from YARD -
502
+ # e.g., kwargs in a **restkwargs splat
503
+ tags = pin.docstring.tags(:param)
477
504
  tags.each do |tag|
478
- next if tag.types.nil? || tag.types.empty?
505
+ next if result.key? tag.name.to_s
506
+ next if tag.types.nil?
479
507
  result[tag.name.to_s] = {
480
508
  tagged: tag.types.join(', '),
481
509
  qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
@@ -487,11 +515,27 @@ module Solargraph
487
515
  # @param pins [Array<Pin::Method>]
488
516
  # @return [Hash{String => Hash{Symbol => String, ComplexType}}]
489
517
  def first_param_hash(pins)
490
- pins.each do |pin|
491
- result = param_hash(pin)
492
- return result unless result.empty?
518
+ return {} if pins.empty?
519
+ first_pin_type = pins.first.typify(api_map)
520
+ first_pin = pins.first.proxy first_pin_type
521
+ param_names = first_pin.parameter_names
522
+ results = param_hash(first_pin)
523
+ pins[1..].each do |pin|
524
+ # @todo this assignment from parametric use of Hash should not lose its generic
525
+ # @type [Hash{String => Hash{Symbol => BasicObject}}]
526
+
527
+ # documentation of types in superclasses should fail back to
528
+ # subclasses if the subclass hasn't documented something
529
+ superclass_results = param_hash(pin)
530
+ superclass_results.each do |param_name, details|
531
+ next unless param_names.include?(param_name)
532
+
533
+ results[param_name] ||= {}
534
+ results[param_name][:tagged] ||= details[:tagged]
535
+ results[param_name][:qualified] ||= details[:qualified]
536
+ end
493
537
  end
494
- {}
538
+ results
495
539
  end
496
540
 
497
541
  # @param pin [Pin::Base]
@@ -584,7 +628,8 @@ module Solargraph
584
628
  kwargs.delete param.name.to_sym
585
629
  settled_kwargs += 1
586
630
  elsif param.decl == :kwarg
587
- return [] if arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash) && arguments.last.links.last.splatted?
631
+ last_arg_last_link = arguments.last.links.last
632
+ return [] if last_arg_last_link.is_a?(Solargraph::Source::Chain::Hash) && last_arg_last_link.splatted?
588
633
  return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
589
634
  end
590
635
  end
@@ -619,7 +664,6 @@ module Solargraph
619
664
  # @param parameters [Enumerable<Pin::Parameter>]
620
665
  # @todo need to use generic types in method to choose correct
621
666
  # signature and generate Integer as return type
622
- # @sg-ignore
623
667
  # @return [Integer]
624
668
  def required_param_count(parameters)
625
669
  parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
@@ -660,12 +704,48 @@ module Solargraph
660
704
  args
661
705
  end
662
706
 
707
+ # @return [Set<Integer>]
708
+ def sg_ignore_lines_processed
709
+ @sg_ignore_lines_processed ||= Set.new
710
+ end
711
+
712
+ # @return [Set<Integer>]
713
+ def all_sg_ignore_lines
714
+ source.associated_comments.select do |_line, text|
715
+ text.include?('@sg-ignore')
716
+ end.keys.to_set
717
+ end
718
+
719
+ # @return [Array<Integer>]
720
+ def unprocessed_sg_ignore_lines
721
+ (all_sg_ignore_lines - sg_ignore_lines_processed).to_a.sort
722
+ end
723
+
724
+ # @return [Array<Problem>]
725
+ def unneeded_sgignore_problems
726
+ return [] unless rules.validate_sg_ignores?
727
+
728
+ unprocessed_sg_ignore_lines.map do |line|
729
+ Problem.new(
730
+ Location.new(filename, Range.from_to(line, 0, line, 0)),
731
+ 'Unneeded @sg-ignore comment'
732
+ )
733
+ end
734
+ end
735
+
663
736
  # @param problems [Array<Problem>]
664
737
  # @return [Array<Problem>]
665
738
  def without_ignored problems
666
739
  problems.reject do |problem|
667
- node = source_map.source.node_at(problem.location.range.start.line, problem.location.range.start.column)
668
- node && source_map.source.comments_for(node)&.include?('@sg-ignore')
740
+ node = source.node_at(problem.location.range.start.line, problem.location.range.start.column)
741
+ ignored = node && source.comments_for(node)&.include?('@sg-ignore')
742
+ unless !ignored || all_sg_ignore_lines.include?(problem.location.range.start.line)
743
+ # :nocov:
744
+ Solargraph.assert_or_log(:sg_ignore) { "@sg-ignore accounting issue - node is #{node}" }
745
+ # :nocov:
746
+ end
747
+ sg_ignore_lines_processed.add problem.location.range.start.line if ignored
748
+ ignored
669
749
  end
670
750
  end
671
751
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.54.4'
4
+ VERSION = '0.57.0'
5
5
  end
@@ -2,33 +2,33 @@
2
2
  Namespace:
3
3
  </h2>
4
4
  <p>
5
- <a href="solargraph:/document?query=<%= CGI.escape object.namespace.path %>"><%= object.namespace %></a>
5
+ <a href="solargraph:/document?query=<%= CGI.escape pin.namespace.path %>"><%= pin.namespace %></a>
6
6
  </p>
7
7
  <h2>
8
8
  Overview:
9
9
  </h2>
10
- <%= htmlify object.docstring %>
10
+ <%= htmlify pin.docstring %>
11
11
  <p class="document-section">
12
- <big><strong>Visibility:</strong></big> <%= object.visibility %>
12
+ <big><strong>Visibility:</strong></big> <%= pin.visibility %>
13
13
  </p>
14
- <% unless object.tags(:param).empty? %>
14
+ <% unless pin.docstring.tags(:param).empty? %>
15
15
  <h2>
16
16
  Parameters:
17
17
  </h2>
18
18
  <ul>
19
- <% object.tags(:param).each do |tag| %>
19
+ <% pin.docstring.tags(:param).each do |tag| %>
20
20
  <li>
21
21
  <%= erb :_name_type_tag, layout: false, locals: {tag: tag} %>
22
22
  </li>
23
23
  <% end %>
24
24
  </ul>
25
25
  <% end %>
26
- <% unless object.tags(:raise).empty? %>
26
+ <% unless pin.docstring.tags(:raise).empty? %>
27
27
  <h2>
28
28
  Raises:
29
29
  </h2>
30
30
  <ul>
31
- <% object.tags(:raise).each do |tag| %>
31
+ <% pin.docstring.tags(:raise).each do |tag| %>
32
32
  <li>
33
33
  <%= erb :_name_type_tag, layout: false, locals: {tag: tag} %>
34
34
  </li>
@@ -38,20 +38,20 @@
38
38
  <h2>
39
39
  Returns:
40
40
  </h2>
41
- <% if object.tag(:return).nil? %>
41
+ <% if pin.docstring.tag(:return).nil? %>
42
42
  <p>
43
43
  Undefined/unknown
44
44
  </p>
45
45
  <% else %>
46
46
  <ul>
47
- <% object.tags(:return).each do |tag| %>
47
+ <% pin.tags(:return).each do |tag| %>
48
48
  <li>
49
49
  <%= erb :_name_type_tag, layout: false, locals: {tag: tag} %>
50
50
  </li>
51
51
  <% end %>
52
52
  </ul>
53
53
  <% end %>
54
- <% examples = object.tags(:example) %>
54
+ <% examples = pin.docstring.tags(:example) %>
55
55
  <% unless examples.nil? %>
56
56
  <% examples.each do |example| %>
57
57
  <h2>
@@ -1,12 +1,12 @@
1
1
  <h2>
2
2
  Overview:
3
3
  </h2>
4
- <%= htmlify object.docstring %>
4
+ <%= htmlify pin.docstring %>
5
5
  <h2>
6
6
  Class Methods
7
7
  </h2>
8
8
  <ul class="doc-list">
9
- <% object.meths(scope: :class).sort{|a, b| a.name <=> b.name}.each do |meth| %>
9
+ <% api_map.get_methods(pin.path, scope: :class, deep: false).sort{|a, b| a.name <=> b.name}.each do |meth| %>
10
10
  <li>
11
11
  <a href="solargraph:/document?query=<%= CGI.escape(meth.path) %>"><%= meth.name %></a>
12
12
  </li>
@@ -16,7 +16,7 @@
16
16
  Instance Methods
17
17
  </h2>
18
18
  <ul class="doc-list">
19
- <% object.meths(scope: :instance).sort{|a, b| a.name <=> b.name}.each do |meth| %>
19
+ <% api_map.get_methods(pin.path, scope: :instance, deep: false).sort{|a, b| a.name <=> b.name}.each do |meth| %>
20
20
  <li>
21
21
  <a href="solargraph:/document?query=<%= CGI.escape(meth.path) %>"><%= meth.name %></a>
22
22
  </li>
@@ -1,23 +1,23 @@
1
- <% objects.reverse.each do |object| %>
1
+ <% pins.each do |pin| %>
2
2
  <h1>
3
- <%= object.name %>
4
- <% if object.is_a?(YARD::CodeObjects::MethodObject) and !object.parameters.empty? %>
5
- <small>(<%= object.parameters.map {|p| "#{p[0]}#{p[1] and p[0].end_with?(':') ? ' ' : (p[1] ? ' = ' : '')}#{p[1]}"}.join(', ') %>)</small>
3
+ <%= pin.name %>
4
+ <% if pin.is_a?(Solargraph::Pin::Method) && !pin.parameters.empty? %>
5
+ <small>(<%= pin.parameters.map {|p| "#{p[0]}#{p[1] and p[0].end_with?(':') ? ' ' : (p[1] ? ' = ' : '')}#{p[1]}"}.join(', ') %>)</small>
6
6
  <% end %>
7
7
  </h1>
8
- <% unless object.files.empty? %>
8
+ <% unless pins.map(&:location).compact.empty? %>
9
9
  <h2>
10
10
  Defined in:
11
11
  </h2>
12
12
  <ul>
13
- <% object.files.each do |f| %>
13
+ <% pins.map(&:location).compact.map(&:filename).each do |f| %>
14
14
  <li><%= f %></li>
15
15
  <% end %>
16
16
  </ul>
17
17
  <% end %>
18
- <% if object.is_a?(YARD::CodeObjects::NamespaceObject) %>
19
- <%= erb :_namespace, layout: false, locals: {object: object} %>
20
- <% elsif object.is_a?(YARD::CodeObjects::MethodObject) %>
21
- <%= erb :_method, layout: false, locals: {object: object} %>
18
+ <% if pin.is_a?(Solargraph::Pin::Namespace) %>
19
+ <%= erb :_namespace, layout: false, locals: {api_map: api_map, pin: pin} %>
20
+ <% elsif pin.is_a?(Solargraph::Pin::Method) %>
21
+ <%= erb :_method, layout: false, locals: {api_map: api_map, pin: pin} %>
22
22
  <% end %>
23
23
  <% end %>
@@ -90,7 +90,6 @@ module Solargraph
90
90
 
91
91
  # A hash of options supported by the formatter
92
92
  #
93
- # @sg-ignore pending https://github.com/castwide/solargraph/pull/905
94
93
  # @return [Hash]
95
94
  def formatter
96
95
  raw_data['formatter']
@@ -105,7 +104,6 @@ module Solargraph
105
104
 
106
105
  # The maximum number of files to parse from the workspace.
107
106
  #
108
- # @sg-ignore pending https://github.com/castwide/solargraph/pull/905
109
107
  # @return [Integer]
110
108
  def max_files
111
109
  raw_data['max_files']
@@ -151,7 +149,7 @@ module Solargraph
151
149
  # @return [Hash{String => Array, Hash, Integer}]
152
150
  def default_config
153
151
  {
154
- 'include' => ['**/*.rb'],
152
+ 'include' => ['Rakefile', 'Gemfile', '*.gemspec', '**/*.rb'],
155
153
  'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
156
154
  'require' => [],
157
155
  'domains' => [],