solargraph 0.54.5 → 0.55.4
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.
- checksums.yaml +4 -4
- data/.github/workflows/typecheck.yml +1 -1
- data/CHANGELOG.md +27 -0
- data/lib/solargraph/api_map/store.rb +9 -4
- data/lib/solargraph/api_map.rb +116 -39
- data/lib/solargraph/complex_type/type_methods.rb +1 -0
- data/lib/solargraph/complex_type/unique_type.rb +91 -9
- data/lib/solargraph/complex_type.rb +35 -6
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +60 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
- data/lib/solargraph/convention/struct_definition.rb +101 -0
- data/lib/solargraph/convention.rb +1 -0
- data/lib/solargraph/doc_map.rb +83 -23
- data/lib/solargraph/gem_pins.rb +2 -1
- data/lib/solargraph/language_server/host/message_worker.rb +10 -7
- data/lib/solargraph/language_server/host.rb +3 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -0
- data/lib/solargraph/location.rb +8 -0
- data/lib/solargraph/logging.rb +1 -0
- data/lib/solargraph/parser/comment_ripper.rb +12 -6
- data/lib/solargraph/parser/flow_sensitive_typing.rb +227 -0
- data/lib/solargraph/parser/node_methods.rb +14 -0
- data/lib/solargraph/parser/node_processor.rb +3 -2
- data/lib/solargraph/parser/parser_gem/class_methods.rb +9 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +10 -10
- data/lib/solargraph/parser/parser_gem/node_methods.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +23 -2
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +29 -6
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +4 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +28 -16
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser.rb +1 -0
- data/lib/solargraph/pin/base.rb +34 -5
- data/lib/solargraph/pin/base_variable.rb +7 -1
- data/lib/solargraph/pin/block.rb +2 -0
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +5 -3
- data/lib/solargraph/pin/closure.rb +6 -1
- data/lib/solargraph/pin/common.rb +5 -0
- data/lib/solargraph/pin/delegated_method.rb +20 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +7 -1
- data/lib/solargraph/pin/method.rb +34 -27
- data/lib/solargraph/pin/namespace.rb +17 -9
- data/lib/solargraph/pin/parameter.rb +17 -5
- data/lib/solargraph/pin/proxy_type.rb +12 -6
- data/lib/solargraph/pin/reference/override.rb +10 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/signature.rb +4 -0
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +3 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/rbs_map/conversions.rb +172 -56
- data/lib/solargraph/rbs_map/core_fills.rb +32 -16
- data/lib/solargraph/rbs_map/core_map.rb +3 -2
- data/lib/solargraph/shell.rb +1 -0
- data/lib/solargraph/source/chain/array.rb +11 -7
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +53 -23
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +4 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +2 -0
- data/lib/solargraph/source/chain/literal.rb +22 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +78 -48
- data/lib/solargraph/source/source_chainer.rb +2 -2
- data/lib/solargraph/source_map/clip.rb +3 -1
- data/lib/solargraph/source_map/mapper.rb +9 -5
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker.rb +35 -8
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +4 -2
- data/lib/solargraph/yard_map/mapper/to_method.rb +55 -15
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +4 -2
- data/lib/solargraph/yard_map/mapper.rb +4 -3
- data/lib/solargraph/yard_map/to_method.rb +4 -2
- data/lib/solargraph.rb +20 -0
- data/rbs/fills/tuple.rbs +150 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e00ddc5e4b665c4527099b496d2caf414a0fe5c1cdb44e71b4af16a7c5521d34
|
4
|
+
data.tar.gz: 494b003c5260150a4c66952c0e4c512374197a52b528249027100b48a3deb4c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b56ff99aecf4a656722a8a55cdcf521b9dba1066c53e22dd344840f173dfb302fb560daba2b828af01ad0789f7defab7976511509484613df13687854b90bf77
|
7
|
+
data.tar.gz: 2cc74269454a5290c0c98e89f55942bdc36f916b622bfc37a42d4aeaf30d023f497a6be585f725b4397991a5083fdc43dedf90c05526a3739bb2c4a78266daf0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
## 0.55.4 - June 27, 2025
|
2
|
+
- Flatten results of DocMap external bundle query (#981)
|
3
|
+
|
4
|
+
## 0.55.3 - June 25, 2025
|
5
|
+
- Nil guards in flow-sensitive typing (patch release) (#980)
|
6
|
+
|
7
|
+
## 0.55.2 - June 21, 2025
|
8
|
+
- Require external bundle (#972)
|
9
|
+
|
10
|
+
## 0.55.1 - June 8, 2025
|
11
|
+
- Fix inline Struct definition (#962)
|
12
|
+
- Ensure DocMap requires bundler when loading gemspecs (#963)
|
13
|
+
- DelegatedMethod improvements (#953)
|
14
|
+
|
15
|
+
## 0.55.0 - June 3, 2025
|
16
|
+
- Flow-sensitive typing - automatically downcast from is_a? calls (#856)
|
17
|
+
- Tuple enabler: infer literal types and use them for signature selection (#836)
|
18
|
+
- Signature selection improvements (#907)
|
19
|
+
- Add support for Ruby Structs (#939)
|
20
|
+
- [regression] Fix interface change breaking solargraph-rails (#940)
|
21
|
+
- [regression] Add back bundler/require support for solargraph-rails (#941)
|
22
|
+
- Add specs for initialize capabilities (#955)
|
23
|
+
- Create MethodAlias pins from YARD (#945)
|
24
|
+
- MessageWorker prioritizes synchronization (#956)
|
25
|
+
- initialize/new method pin cleanups (#949)
|
26
|
+
- Clip rebinds blocks when cursor is not part of receiver (#958)
|
27
|
+
|
1
28
|
## 0.54.5 - May 17, 2025
|
2
29
|
- Repair unknown encoding errors (#936, #935)
|
3
30
|
- Index arbitrary pinsets (#937)
|
@@ -66,13 +66,18 @@ module Solargraph
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
# @param
|
69
|
+
# @param fq_tag [String]
|
70
70
|
# @return [String, nil]
|
71
|
-
def get_superclass
|
72
|
-
raise "Do not prefix fully qualified
|
71
|
+
def get_superclass fq_tag
|
72
|
+
raise "Do not prefix fully qualified tags with '::' - #{fq_tag.inspect}" if fq_tag.start_with?('::')
|
73
|
+
sub = ComplexType.parse(fq_tag)
|
74
|
+
fqns = sub.namespace
|
75
|
+
return superclass_references[fq_tag].first if superclass_references.key?(fq_tag)
|
73
76
|
return superclass_references[fqns].first if superclass_references.key?(fqns)
|
74
77
|
return 'Object' if fqns != 'BasicObject' && namespace_exists?(fqns)
|
75
78
|
return 'Object' if fqns == 'Boolean'
|
79
|
+
simplified_literal_name = ComplexType.parse("#{fqns}").simplify_literals.name
|
80
|
+
return simplified_literal_name if simplified_literal_name != fqns
|
76
81
|
nil
|
77
82
|
end
|
78
83
|
|
@@ -112,7 +117,7 @@ module Solargraph
|
|
112
117
|
# @param fqns [String]
|
113
118
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
114
119
|
def get_class_variables(fqns)
|
115
|
-
namespace_children(fqns).select{|pin| pin.is_a?(Pin::ClassVariable)}
|
120
|
+
namespace_children(fqns).select { |pin| pin.is_a?(Pin::ClassVariable)}
|
116
121
|
end
|
117
122
|
|
118
123
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -94,7 +94,7 @@ module Solargraph
|
|
94
94
|
end
|
95
95
|
unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).to_a.compact.uniq
|
96
96
|
if @unresolved_requires != unresolved_requires || @doc_map&.uncached_gemspecs&.any?
|
97
|
-
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace
|
97
|
+
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace) # @todo Implement gem preferences
|
98
98
|
@unresolved_requires = unresolved_requires
|
99
99
|
end
|
100
100
|
@cache.clear if store.update(@@core_map.pins, @doc_map.pins, implicit.pins, iced_pins, live_pins)
|
@@ -264,15 +264,19 @@ module Solargraph
|
|
264
264
|
# Should not be prefixed with '::'.
|
265
265
|
# @return [String, nil] fully qualified tag
|
266
266
|
def qualify tag, context_tag = ''
|
267
|
-
return tag if ['self', nil].include?(tag)
|
267
|
+
return tag if ['Boolean', 'self', nil].include?(tag)
|
268
268
|
|
269
|
-
context_type = ComplexType.
|
269
|
+
context_type = ComplexType.try_parse(context_tag).force_rooted
|
270
270
|
return unless context_type
|
271
271
|
|
272
272
|
type = ComplexType.try_parse(tag)
|
273
273
|
return unless type
|
274
|
+
return tag if type.literal?
|
274
275
|
|
275
|
-
|
276
|
+
context_type = ComplexType.try_parse(context_tag)
|
277
|
+
return unless context_type
|
278
|
+
|
279
|
+
fqns = qualify_namespace(type.rooted_namespace, context_type.rooted_namespace)
|
276
280
|
return unless fqns
|
277
281
|
|
278
282
|
fqns + type.substring
|
@@ -319,6 +323,11 @@ module Solargraph
|
|
319
323
|
result
|
320
324
|
end
|
321
325
|
|
326
|
+
# @see Solargraph::Parser::FlowSensitiveTyping#visible_pins
|
327
|
+
def visible_pins(*args, **kwargs, &blk)
|
328
|
+
Solargraph::Parser::FlowSensitiveTyping.visible_pins(*args, **kwargs, &blk)
|
329
|
+
end
|
330
|
+
|
322
331
|
# Get an array of class variable pins for a namespace.
|
323
332
|
#
|
324
333
|
# @param namespace [String] A fully qualified namespace
|
@@ -350,6 +359,11 @@ module Solargraph
|
|
350
359
|
# @param deep [Boolean] True to include superclasses, mixins, etc.
|
351
360
|
# @return [Array<Solargraph::Pin::Method>]
|
352
361
|
def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
|
362
|
+
if rooted_tag.start_with? 'Array('
|
363
|
+
# Array() are really tuples - use our fill, as the RBS repo
|
364
|
+
# does not give us definitions for it
|
365
|
+
rooted_tag = "Solargraph::Fills::Tuple(#{rooted_tag[6..-2]})"
|
366
|
+
end
|
353
367
|
rooted_type = ComplexType.try_parse(rooted_tag)
|
354
368
|
fqns = rooted_type.namespace
|
355
369
|
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
@@ -376,18 +390,36 @@ module Solargraph
|
|
376
390
|
init_pin = get_method_stack(rooted_tag, 'initialize').first
|
377
391
|
next pin unless init_pin
|
378
392
|
|
379
|
-
type = ComplexType
|
380
|
-
Pin::Method.new(
|
393
|
+
type = ComplexType::SELF
|
394
|
+
new_pin = Pin::Method.new(
|
381
395
|
name: 'new',
|
382
396
|
scope: :class,
|
383
397
|
location: init_pin.location,
|
384
|
-
parameters: init_pin.parameters,
|
385
|
-
signatures: init_pin.signatures.map { |sig| sig.proxy(type) },
|
386
398
|
return_type: type,
|
387
399
|
comments: init_pin.comments,
|
388
|
-
closure: init_pin.closure
|
389
|
-
|
390
|
-
|
400
|
+
closure: init_pin.closure,
|
401
|
+
source: init_pin.source,
|
402
|
+
type_location: init_pin.type_location,
|
403
|
+
)
|
404
|
+
new_pin.parameters = init_pin.parameters.map do |init_param|
|
405
|
+
param = init_param.clone
|
406
|
+
param.closure = new_pin
|
407
|
+
param.reset_generated!
|
408
|
+
param
|
409
|
+
end.freeze
|
410
|
+
new_pin.signatures = init_pin.signatures.map do |init_sig|
|
411
|
+
sig = init_sig.proxy(type)
|
412
|
+
sig.parameters = init_sig.parameters.map do |param|
|
413
|
+
param = param.clone
|
414
|
+
param.closure = new_pin
|
415
|
+
param.reset_generated!
|
416
|
+
param
|
417
|
+
end.freeze
|
418
|
+
sig.closure = new_pin
|
419
|
+
sig.reset_generated!
|
420
|
+
sig
|
421
|
+
end.freeze
|
422
|
+
new_pin
|
391
423
|
end
|
392
424
|
end
|
393
425
|
result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
|
@@ -426,7 +458,7 @@ module Solargraph
|
|
426
458
|
result = Set.new
|
427
459
|
complex_type.each do |type|
|
428
460
|
if type.duck_type?
|
429
|
-
result.add Pin::DuckMethod.new(name: type.to_s[1..-1])
|
461
|
+
result.add Pin::DuckMethod.new(name: type.to_s[1..-1], source: :api_map)
|
430
462
|
result.merge get_methods('Object')
|
431
463
|
else
|
432
464
|
unless type.nil? || type.name == 'void'
|
@@ -643,29 +675,20 @@ module Solargraph
|
|
643
675
|
if scope == :instance
|
644
676
|
store.get_includes(fqns).reverse.each do |include_tag|
|
645
677
|
rooted_include_tag = qualify(include_tag, rooted_tag)
|
646
|
-
|
647
|
-
# relative to the generics passed to the include. e.g.,
|
648
|
-
# Foo<String> might include Enumerable<String>
|
649
|
-
#
|
650
|
-
# @todo perform the same translation in the other areas
|
651
|
-
# here after adding a spec and handling things correctly
|
652
|
-
# in ApiMap::Store and RbsMap::Conversions
|
653
|
-
resolved_include_type = ComplexType.parse(rooted_include_tag).force_rooted.resolve_generics(namespace_pin, rooted_type)
|
654
|
-
methods = inner_get_methods(resolved_include_type.tag, scope, visibility, deep, skip, true)
|
655
|
-
result.concat methods
|
678
|
+
result.concat inner_get_methods_from_reference(rooted_include_tag, namespace_pin, rooted_type, scope, visibility, deep, skip, true)
|
656
679
|
end
|
657
|
-
|
658
|
-
unless
|
659
|
-
result.concat
|
680
|
+
rooted_sc_tag = qualify_superclass(rooted_tag)
|
681
|
+
unless rooted_sc_tag.nil?
|
682
|
+
result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, no_core)
|
660
683
|
end
|
661
684
|
else
|
662
685
|
store.get_extends(fqns).reverse.each do |em|
|
663
686
|
fqem = qualify(em, fqns)
|
664
687
|
result.concat inner_get_methods(fqem, :instance, visibility, deep, skip, true) unless fqem.nil?
|
665
688
|
end
|
666
|
-
|
667
|
-
unless
|
668
|
-
result.concat
|
689
|
+
rooted_sc_tag = qualify_superclass(rooted_tag)
|
690
|
+
unless rooted_sc_tag.nil?
|
691
|
+
result.concat inner_get_methods_from_reference(rooted_sc_tag, namespace_pin, rooted_type, scope, visibility, true, skip, true)
|
669
692
|
end
|
670
693
|
unless no_core || fqns.empty?
|
671
694
|
type = get_namespace_type(fqns)
|
@@ -681,6 +704,41 @@ module Solargraph
|
|
681
704
|
result
|
682
705
|
end
|
683
706
|
|
707
|
+
# @param fq_reference_tag [String] A fully qualified whose method should be pulled in
|
708
|
+
# @param namespace_pin [Pin::Base] Namespace pin for the rooted_type
|
709
|
+
# parameter - used to pull generics information
|
710
|
+
# @param type [ComplexType] The type which is having its
|
711
|
+
# methods supplemented from fq_reference_tag
|
712
|
+
# @param scope [Symbol] :class or :instance
|
713
|
+
# @param visibility [Array<Symbol>] :public, :protected, and/or :private
|
714
|
+
# @param deep [Boolean]
|
715
|
+
# @param skip [Set<String>]
|
716
|
+
# @param no_core [Boolean] Skip core classes if true
|
717
|
+
# @return [Array<Pin::Base>]
|
718
|
+
def inner_get_methods_from_reference(fq_reference_tag, namespace_pin, type, scope, visibility, deep, skip, no_core)
|
719
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) starting" }
|
720
|
+
|
721
|
+
# Ensure the types returned by the methods in the referenced
|
722
|
+
# type are relative to the generic values passed in the
|
723
|
+
# reference. e.g., Foo<String> might include Enumerable<String>
|
724
|
+
#
|
725
|
+
# @todo perform the same translation in the other areas
|
726
|
+
# here after adding a spec and handling things correctly
|
727
|
+
# in ApiMap::Store and RbsMap::Conversions for each
|
728
|
+
resolved_reference_type = ComplexType.parse(fq_reference_tag).force_rooted.resolve_generics(namespace_pin, type)
|
729
|
+
# @todo Can inner_get_methods be cached? Lots of lookups of base types going on.
|
730
|
+
methods = inner_get_methods(resolved_reference_type.tag, scope, visibility, deep, skip, no_core)
|
731
|
+
if namespace_pin && !resolved_reference_type.all_params.empty?
|
732
|
+
reference_pin = store.get_path_pins(resolved_reference_type.name).select { |p| p.is_a?(Pin::Namespace) }.first
|
733
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolving generics with #{reference_pin.generics}, #{resolved_reference_type.rooted_tags}" }
|
734
|
+
methods = methods.map do |method_pin|
|
735
|
+
method_pin.resolve_generics(reference_pin, resolved_reference_type)
|
736
|
+
end
|
737
|
+
end
|
738
|
+
# logger.debug { "ApiMap#add_methods_from_reference(type=#{type}) - resolved_reference_type: #{resolved_reference_type} for type=#{type}: #{methods.map(&:name)}" }
|
739
|
+
methods
|
740
|
+
end
|
741
|
+
|
684
742
|
# @param fqns [String]
|
685
743
|
# @param visibility [Array<Symbol>]
|
686
744
|
# @param skip [Set<String>]
|
@@ -716,15 +774,19 @@ module Solargraph
|
|
716
774
|
qualify namespace, context.split('::')[0..-2].join('::')
|
717
775
|
end
|
718
776
|
|
719
|
-
# @param
|
777
|
+
# @param fq_tag [String]
|
720
778
|
# @return [String, nil]
|
721
|
-
def qualify_superclass
|
722
|
-
|
723
|
-
|
724
|
-
|
779
|
+
def qualify_superclass fq_sub_tag
|
780
|
+
fq_sub_type = ComplexType.try_parse(fq_sub_tag)
|
781
|
+
fq_sub_ns = fq_sub_type.name
|
782
|
+
sup_tag = store.get_superclass(fq_sub_tag)
|
783
|
+
sup_type = ComplexType.try_parse(sup_tag)
|
784
|
+
sup_ns = sup_type.name
|
785
|
+
return nil if sup_tag.nil?
|
786
|
+
parts = fq_sub_ns.split('::')
|
725
787
|
last = parts.pop
|
726
|
-
parts.pop if last ==
|
727
|
-
qualify(
|
788
|
+
parts.pop if last == sup_ns
|
789
|
+
qualify(sup_tag, parts.join('::'))
|
728
790
|
end
|
729
791
|
|
730
792
|
# @param name [String] Namespace to fully qualify
|
@@ -814,23 +876,38 @@ module Solargraph
|
|
814
876
|
return pin unless pin.is_a?(Pin::MethodAlias)
|
815
877
|
return nil if @method_alias_stack.include?(pin.path)
|
816
878
|
@method_alias_stack.push pin.path
|
817
|
-
origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope).first
|
879
|
+
origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope, preserve_generics: true).first
|
818
880
|
@method_alias_stack.pop
|
819
881
|
return nil if origin.nil?
|
820
882
|
args = {
|
821
883
|
location: pin.location,
|
884
|
+
type_location: origin.type_location,
|
822
885
|
closure: pin.closure,
|
823
886
|
name: pin.name,
|
824
887
|
comments: origin.comments,
|
825
888
|
scope: origin.scope,
|
826
889
|
# context: pin.context,
|
827
890
|
visibility: origin.visibility,
|
828
|
-
signatures: origin.signatures,
|
891
|
+
signatures: origin.signatures.map(&:clone).freeze,
|
829
892
|
attribute: origin.attribute?,
|
830
|
-
generics: origin.generics,
|
893
|
+
generics: origin.generics.clone,
|
831
894
|
return_type: origin.return_type,
|
895
|
+
source: :resolve_method_alias
|
832
896
|
}
|
833
|
-
Pin::Method.new **args
|
897
|
+
out = Pin::Method.new **args
|
898
|
+
out.signatures.each do |sig|
|
899
|
+
sig.parameters = sig.parameters.map(&:clone).freeze
|
900
|
+
sig.source = :resolve_method_alias
|
901
|
+
sig.parameters.each do |param|
|
902
|
+
param.closure = out
|
903
|
+
param.source = :resolve_method_alias
|
904
|
+
param.reset_generated!
|
905
|
+
end
|
906
|
+
sig.closure = out
|
907
|
+
sig.reset_generated!
|
908
|
+
end
|
909
|
+
logger.debug { "ApiMap#resolve_method_alias(pin=#{pin}) - returning #{out} from #{origin}" }
|
910
|
+
out
|
834
911
|
end
|
835
912
|
|
836
913
|
include Logging
|
@@ -27,7 +27,7 @@ module Solargraph
|
|
27
27
|
# @return [UniqueType]
|
28
28
|
def self.parse name, substring = '', make_rooted: nil
|
29
29
|
if name.start_with?(':::')
|
30
|
-
raise "Illegal prefix: #{name}"
|
30
|
+
raise ComplexTypeError, "Illegal prefix: #{name}"
|
31
31
|
end
|
32
32
|
if name.start_with?('::')
|
33
33
|
name = name[2..-1]
|
@@ -48,7 +48,7 @@ module Solargraph
|
|
48
48
|
subs = ComplexType.parse(substring[1..-2], partial: true)
|
49
49
|
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
50
50
|
if parameters_type == :hash
|
51
|
-
raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
|
51
|
+
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring}" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
|
52
52
|
# @todo should be able to resolve map; both types have it
|
53
53
|
# with same return type
|
54
54
|
# @sg-ignore
|
@@ -73,19 +73,63 @@ module Solargraph
|
|
73
73
|
end
|
74
74
|
raise "Please remove leading :: and set rooted instead - #{name.inspect}" if name.start_with?('::')
|
75
75
|
@name = name
|
76
|
-
@
|
77
|
-
|
76
|
+
@parameters_type = parameters_type
|
77
|
+
if implicit_union?
|
78
|
+
@key_types = key_types.uniq
|
79
|
+
@subtypes = subtypes.uniq
|
80
|
+
else
|
81
|
+
@key_types = key_types
|
82
|
+
@subtypes = subtypes
|
83
|
+
end
|
78
84
|
@rooted = rooted
|
79
85
|
@all_params = []
|
80
|
-
@all_params.concat key_types
|
81
|
-
@all_params.concat subtypes
|
82
|
-
|
86
|
+
@all_params.concat @key_types
|
87
|
+
@all_params.concat @subtypes
|
88
|
+
end
|
89
|
+
|
90
|
+
def implicit_union?
|
91
|
+
# @todo use api_map to establish number of generics in type;
|
92
|
+
# if only one is allowed but multiple are passed in, treat
|
93
|
+
# those as implicit unions
|
94
|
+
['Hash', 'Array', 'Set', '_ToAry', 'Enumerable', '_Each'].include?(name) && parameters_type != :fixed
|
83
95
|
end
|
84
96
|
|
85
97
|
def to_s
|
86
98
|
tag
|
87
99
|
end
|
88
100
|
|
101
|
+
def simplify_literals
|
102
|
+
transform do |t|
|
103
|
+
next t unless t.literal?
|
104
|
+
t.recreate(new_name: t.non_literal_name)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def literal?
|
109
|
+
non_literal_name != name
|
110
|
+
end
|
111
|
+
|
112
|
+
def non_literal_name
|
113
|
+
@non_literal_name ||= determine_non_literal_name
|
114
|
+
end
|
115
|
+
|
116
|
+
def determine_non_literal_name
|
117
|
+
# https://github.com/ruby/rbs/blob/master/docs/syntax.md
|
118
|
+
#
|
119
|
+
# _literal_ ::= _string-literal_
|
120
|
+
# | _symbol-literal_
|
121
|
+
# | _integer-literal_
|
122
|
+
# | `true`
|
123
|
+
# | `false`
|
124
|
+
return name if name.empty?
|
125
|
+
return 'NilClass' if name == 'nil'
|
126
|
+
return 'Boolean' if ['true', 'false'].include?(name)
|
127
|
+
return 'Symbol' if name[0] == ':'
|
128
|
+
return 'String' if ['"', "'"].include?(name[0])
|
129
|
+
return 'Integer' if name.match?(/^-?\d+$/)
|
130
|
+
name
|
131
|
+
end
|
132
|
+
|
89
133
|
def eql?(other)
|
90
134
|
self.class == other.class &&
|
91
135
|
@name == other.name &&
|
@@ -113,6 +157,8 @@ module Solargraph
|
|
113
157
|
def rbs_name
|
114
158
|
if name == 'undefined'
|
115
159
|
'untyped'
|
160
|
+
elsif literal?
|
161
|
+
name
|
116
162
|
else
|
117
163
|
rooted_name
|
118
164
|
end
|
@@ -183,6 +229,23 @@ module Solargraph
|
|
183
229
|
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
184
230
|
end
|
185
231
|
|
232
|
+
# @param api_map [ApiMap] The ApiMap that performs qualification
|
233
|
+
# @param atype [ComplexType] type which may be assigned to this type
|
234
|
+
def can_assign?(api_map, atype)
|
235
|
+
logger.debug { "UniqueType#can_assign?(self=#{rooted_tags.inspect}, atype=#{atype.rooted_tags.inspect})" }
|
236
|
+
downcasted_atype = atype.downcast_to_literal_if_possible
|
237
|
+
out = downcasted_atype.all? do |autype|
|
238
|
+
autype.name == name || api_map.super_and_sub?(name, autype.name)
|
239
|
+
end
|
240
|
+
logger.debug { "UniqueType#can_assign?(self=#{rooted_tags.inspect}, atype=#{atype.rooted_tags.inspect}) => #{out}" }
|
241
|
+
out
|
242
|
+
end
|
243
|
+
|
244
|
+
# @return [UniqueType]
|
245
|
+
def downcast_to_literal_if_possible
|
246
|
+
SINGLE_SUBTYPE.fetch(rooted_tag, self)
|
247
|
+
end
|
248
|
+
|
186
249
|
# @param generics_to_resolve [Enumerable<String>]
|
187
250
|
# @param context_type [UniqueType, nil]
|
188
251
|
# @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
|
@@ -243,7 +306,8 @@ module Solargraph
|
|
243
306
|
|
244
307
|
transform(name) do |t|
|
245
308
|
if t.name == GENERIC_TAG_NAME
|
246
|
-
|
309
|
+
generic_name = t.subtypes.first&.name
|
310
|
+
idx = definitions.generics.index(generic_name)
|
247
311
|
next t if idx.nil?
|
248
312
|
if context_type.parameters_type == :hash
|
249
313
|
if idx == 0
|
@@ -253,8 +317,14 @@ module Solargraph
|
|
253
317
|
else
|
254
318
|
next ComplexType::UNDEFINED
|
255
319
|
end
|
320
|
+
elsif context_type.all?(&:implicit_union?)
|
321
|
+
if idx == 0 && !context_type.all_params.empty?
|
322
|
+
ComplexType.new(context_type.all_params)
|
323
|
+
else
|
324
|
+
ComplexType::UNDEFINED
|
325
|
+
end
|
256
326
|
else
|
257
|
-
context_type.all_params[idx] || ComplexType::UNDEFINED
|
327
|
+
context_type.all_params[idx] || definitions.generic_defaults[generic_name] || ComplexType::UNDEFINED
|
258
328
|
end
|
259
329
|
else
|
260
330
|
t
|
@@ -381,6 +451,18 @@ module Solargraph
|
|
381
451
|
|
382
452
|
UNDEFINED = UniqueType.new('undefined', rooted: false)
|
383
453
|
BOOLEAN = UniqueType.new('Boolean', rooted: true)
|
454
|
+
TRUE = UniqueType.new('true', rooted: true)
|
455
|
+
FALSE = UniqueType.new('false', rooted: true)
|
456
|
+
NIL = UniqueType.new('nil', rooted: true)
|
457
|
+
# @type [Hash{String => UniqueType}]
|
458
|
+
SINGLE_SUBTYPE = {
|
459
|
+
'::TrueClass' => UniqueType::TRUE,
|
460
|
+
'::FalseClass' => UniqueType::FALSE,
|
461
|
+
'::NilClass' => UniqueType::NIL
|
462
|
+
}.freeze
|
463
|
+
|
464
|
+
|
465
|
+
include Logging
|
384
466
|
end
|
385
467
|
end
|
386
468
|
end
|
@@ -16,7 +16,13 @@ module Solargraph
|
|
16
16
|
def initialize types = [UniqueType::UNDEFINED]
|
17
17
|
# @todo @items here should not need an annotation
|
18
18
|
# @type [Array<UniqueType>]
|
19
|
-
|
19
|
+
items = types.flat_map(&:items).uniq(&:to_s)
|
20
|
+
if items.any? { |i| i.name == 'false' } && items.any? { |i| i.name == 'true' }
|
21
|
+
items.delete_if { |i| i.name == 'false' || i.name == 'true' }
|
22
|
+
items.unshift(ComplexType::BOOLEAN)
|
23
|
+
end
|
24
|
+
items = [UniqueType::UNDEFINED] if items.any?(&:undefined?)
|
25
|
+
@items = items
|
20
26
|
end
|
21
27
|
|
22
28
|
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
@@ -70,7 +76,7 @@ module Solargraph
|
|
70
76
|
end
|
71
77
|
|
72
78
|
# @yieldparam [UniqueType]
|
73
|
-
# @return [Array]
|
79
|
+
# @return [Array<UniqueType>]
|
74
80
|
def map &block
|
75
81
|
@items.map &block
|
76
82
|
end
|
@@ -93,6 +99,12 @@ module Solargraph
|
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
102
|
+
# @param atype [ComplexType] type which may be assigned to this type
|
103
|
+
# @param api_map [ApiMap] The ApiMap that performs qualification
|
104
|
+
def can_assign?(api_map, atype)
|
105
|
+
any? { |ut| ut.can_assign?(api_map, atype) }
|
106
|
+
end
|
107
|
+
|
96
108
|
# @return [Integer]
|
97
109
|
def length
|
98
110
|
@items.length
|
@@ -103,10 +115,6 @@ module Solargraph
|
|
103
115
|
@items
|
104
116
|
end
|
105
117
|
|
106
|
-
def tags
|
107
|
-
@items.map(&:tag).join(', ')
|
108
|
-
end
|
109
|
-
|
110
118
|
# @param index [Integer]
|
111
119
|
# @return [UniqueType]
|
112
120
|
def [](index)
|
@@ -147,6 +155,23 @@ module Solargraph
|
|
147
155
|
map(&:tag).join(', ')
|
148
156
|
end
|
149
157
|
|
158
|
+
def tags
|
159
|
+
map(&:tag).join(', ')
|
160
|
+
end
|
161
|
+
|
162
|
+
def simple_tags
|
163
|
+
simplify_literals.tags
|
164
|
+
end
|
165
|
+
|
166
|
+
def literal?
|
167
|
+
@items.any?(&:literal?)
|
168
|
+
end
|
169
|
+
|
170
|
+
# @return [ComplexType]
|
171
|
+
def downcast_to_literal_if_possible
|
172
|
+
ComplexType.new(items.map(&:downcast_to_literal_if_possible))
|
173
|
+
end
|
174
|
+
|
150
175
|
def desc
|
151
176
|
rooted_tags
|
152
177
|
end
|
@@ -175,6 +200,10 @@ module Solargraph
|
|
175
200
|
any?(&:generic?)
|
176
201
|
end
|
177
202
|
|
203
|
+
def simplify_literals
|
204
|
+
ComplexType.new(map(&:simplify_literals))
|
205
|
+
end
|
206
|
+
|
178
207
|
# @param new_name [String, nil]
|
179
208
|
# @yieldparam t [UniqueType]
|
180
209
|
# @yieldreturn [UniqueType]
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solargraph
|
4
|
+
module Convention
|
5
|
+
module StructDefinition
|
6
|
+
# A node wrapper for a Struct definition via const assignment.
|
7
|
+
# @example
|
8
|
+
# MyStruct = Struct.new(:bar, :baz) do
|
9
|
+
# def foo
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
class StructAssignmentNode < StructDefintionNode
|
13
|
+
class << self
|
14
|
+
# @example
|
15
|
+
# s(:casgn, nil, :Foo,
|
16
|
+
# s(:block,
|
17
|
+
# s(:send,
|
18
|
+
# s(:const, nil, :Struct), :new,
|
19
|
+
# s(:sym, :bar),
|
20
|
+
# s(:sym, :baz)),
|
21
|
+
# s(:args),
|
22
|
+
# s(:def, :foo,
|
23
|
+
# s(:args),
|
24
|
+
# s(:send, nil, :bar))))
|
25
|
+
def valid?(node)
|
26
|
+
return false unless node&.type == :casgn
|
27
|
+
return false if node.children[2].nil?
|
28
|
+
|
29
|
+
struct_node = if node.children[2].type == :block
|
30
|
+
node.children[2].children[0]
|
31
|
+
else
|
32
|
+
node.children[2]
|
33
|
+
end
|
34
|
+
|
35
|
+
struct_definition_node?(struct_node)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def class_name
|
40
|
+
if node.children[0]
|
41
|
+
Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
|
42
|
+
else
|
43
|
+
node.children[1].to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @return [Parser::AST::Node]
|
50
|
+
def struct_node
|
51
|
+
if node.children[2].type == :block
|
52
|
+
node.children[2].children[0]
|
53
|
+
else
|
54
|
+
node.children[2]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|