solargraph 0.54.0 → 0.55.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/lib/solargraph/api_map/cache.rb +10 -1
- data/lib/solargraph/api_map/index.rb +167 -0
- data/lib/solargraph/api_map/store.rb +75 -122
- data/lib/solargraph/api_map.rb +109 -41
- data/lib/solargraph/bench.rb +17 -1
- data/lib/solargraph/complex_type/type_methods.rb +17 -11
- data/lib/solargraph/complex_type/unique_type.rb +181 -17
- data/lib/solargraph/complex_type.rb +103 -24
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +51 -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 +2 -0
- data/lib/solargraph/doc_map.rb +43 -18
- data/lib/solargraph/equality.rb +33 -0
- data/lib/solargraph/language_server/host/message_worker.rb +51 -5
- data/lib/solargraph/language_server/host.rb +13 -11
- data/lib/solargraph/language_server/message/base.rb +19 -12
- data/lib/solargraph/language_server/message/initialize.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +19 -2
- data/lib/solargraph/library.rb +31 -41
- data/lib/solargraph/location.rb +29 -1
- data/lib/solargraph/parser/comment_ripper.rb +11 -6
- data/lib/solargraph/parser/flow_sensitive_typing.rb +226 -0
- data/lib/solargraph/parser/node_methods.rb +15 -1
- data/lib/solargraph/parser/parser_gem/class_methods.rb +11 -6
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +10 -10
- data/lib/solargraph/parser/parser_gem/node_methods.rb +6 -4
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +21 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +26 -5
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +28 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +28 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
- data/lib/solargraph/parser.rb +3 -5
- data/lib/solargraph/pin/base.rb +47 -17
- data/lib/solargraph/pin/base_variable.rb +11 -4
- data/lib/solargraph/pin/block.rb +8 -26
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +8 -3
- data/lib/solargraph/pin/common.rb +2 -6
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/local_variable.rb +7 -1
- data/lib/solargraph/pin/method.rb +76 -48
- data/lib/solargraph/pin/namespace.rb +14 -11
- data/lib/solargraph/pin/parameter.rb +24 -17
- data/lib/solargraph/pin/proxy_type.rb +13 -7
- data/lib/solargraph/pin/signature.rb +3 -129
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +7 -1
- data/lib/solargraph/position.rb +7 -0
- data/lib/solargraph/range.rb +9 -4
- data/lib/solargraph/rbs_map/conversions.rb +84 -45
- data/lib/solargraph/rbs_map/core_fills.rb +16 -9
- data/lib/solargraph/rbs_map.rb +1 -0
- data/lib/solargraph/shell.rb +19 -2
- data/lib/solargraph/source/chain/array.rb +10 -8
- 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 +125 -61
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/hash.rb +8 -2
- data/lib/solargraph/source/chain/if.rb +5 -0
- data/lib/solargraph/source/chain/link.rb +28 -5
- data/lib/solargraph/source/chain/literal.rb +27 -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 +131 -63
- data/lib/solargraph/source/cursor.rb +3 -2
- data/lib/solargraph/source/source_chainer.rb +2 -2
- data/lib/solargraph/source.rb +104 -86
- data/lib/solargraph/source_map/clip.rb +8 -6
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +48 -21
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +7 -3
- data/lib/solargraph/workspace.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
- data/lib/solargraph/yard_map/mapper/to_method.rb +42 -15
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/mapper.rb +1 -0
- data/lib/solargraph/yardoc.rb +1 -1
- data/lib/solargraph.rb +1 -0
- data/solargraph.gemspec +5 -5
- metadata +41 -25
|
@@ -7,9 +7,15 @@ module Solargraph
|
|
|
7
7
|
#
|
|
8
8
|
class UniqueType
|
|
9
9
|
include TypeMethods
|
|
10
|
+
include Equality
|
|
10
11
|
|
|
11
12
|
attr_reader :all_params, :subtypes, :key_types
|
|
12
13
|
|
|
14
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
15
|
+
protected def equality_fields
|
|
16
|
+
[@name, @all_params, @subtypes, @key_types]
|
|
17
|
+
end
|
|
18
|
+
|
|
13
19
|
# Create a UniqueType with the specified name and an optional substring.
|
|
14
20
|
# The substring is the parameter section of a parametrized type, e.g.,
|
|
15
21
|
# for the type `Array<String>`, the name is `Array` and the substring is
|
|
@@ -21,11 +27,13 @@ module Solargraph
|
|
|
21
27
|
# @return [UniqueType]
|
|
22
28
|
def self.parse name, substring = '', make_rooted: nil
|
|
23
29
|
if name.start_with?(':::')
|
|
24
|
-
raise "Illegal prefix: #{name}"
|
|
30
|
+
raise ComplexTypeError, "Illegal prefix: #{name}"
|
|
25
31
|
end
|
|
26
32
|
if name.start_with?('::')
|
|
27
33
|
name = name[2..-1]
|
|
28
34
|
rooted = true
|
|
35
|
+
elsif !can_root_name?(name)
|
|
36
|
+
rooted = true
|
|
29
37
|
else
|
|
30
38
|
rooted = false
|
|
31
39
|
end
|
|
@@ -40,7 +48,7 @@ module Solargraph
|
|
|
40
48
|
subs = ComplexType.parse(substring[1..-2], partial: true)
|
|
41
49
|
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
|
42
50
|
if parameters_type == :hash
|
|
43
|
-
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)
|
|
44
52
|
# @todo should be able to resolve map; both types have it
|
|
45
53
|
# with same return type
|
|
46
54
|
# @sg-ignore
|
|
@@ -63,21 +71,83 @@ module Solargraph
|
|
|
63
71
|
if parameters_type.nil?
|
|
64
72
|
raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
|
|
65
73
|
end
|
|
66
|
-
raise "Please remove leading :: and set rooted instead - #{name}" if name.start_with?('::')
|
|
74
|
+
raise "Please remove leading :: and set rooted instead - #{name.inspect}" if name.start_with?('::')
|
|
67
75
|
@name = name
|
|
68
|
-
@
|
|
69
|
-
|
|
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
|
|
70
84
|
@rooted = rooted
|
|
71
85
|
@all_params = []
|
|
72
|
-
@all_params.concat key_types
|
|
73
|
-
@all_params.concat subtypes
|
|
74
|
-
|
|
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
|
|
75
95
|
end
|
|
76
96
|
|
|
77
97
|
def to_s
|
|
78
98
|
tag
|
|
79
99
|
end
|
|
80
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
|
+
|
|
133
|
+
def eql?(other)
|
|
134
|
+
self.class == other.class &&
|
|
135
|
+
@name == other.name &&
|
|
136
|
+
@key_types == other.key_types &&
|
|
137
|
+
@subtypes == other.subtypes &&
|
|
138
|
+
@rooted == other.rooted? &&
|
|
139
|
+
@all_params == other.all_params &&
|
|
140
|
+
@parameters_type == other.parameters_type
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def ==(other)
|
|
144
|
+
eql?(other)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def hash
|
|
148
|
+
[self.class, @name, @key_types, @sub_types, @rooted, @all_params, @parameters_type].hash
|
|
149
|
+
end
|
|
150
|
+
|
|
81
151
|
# @return [Array<UniqueType>]
|
|
82
152
|
def items
|
|
83
153
|
[self]
|
|
@@ -87,11 +157,17 @@ module Solargraph
|
|
|
87
157
|
def rbs_name
|
|
88
158
|
if name == 'undefined'
|
|
89
159
|
'untyped'
|
|
160
|
+
elsif literal?
|
|
161
|
+
name
|
|
90
162
|
else
|
|
91
163
|
rooted_name
|
|
92
164
|
end
|
|
93
165
|
end
|
|
94
166
|
|
|
167
|
+
def desc
|
|
168
|
+
rooted_tags
|
|
169
|
+
end
|
|
170
|
+
|
|
95
171
|
# @return [String]
|
|
96
172
|
def to_rbs
|
|
97
173
|
if duck_type?
|
|
@@ -108,7 +184,11 @@ module Solargraph
|
|
|
108
184
|
# tuples don't have a name; they're just [foo, bar, baz].
|
|
109
185
|
if substring == '()'
|
|
110
186
|
# but there are no zero element tuples, so we go with an array
|
|
111
|
-
|
|
187
|
+
if rooted?
|
|
188
|
+
'::Array[]'
|
|
189
|
+
else
|
|
190
|
+
'Array[]'
|
|
191
|
+
end
|
|
112
192
|
else
|
|
113
193
|
# already generated surrounded by []
|
|
114
194
|
parameters_as_rbs
|
|
@@ -149,6 +229,23 @@ module Solargraph
|
|
|
149
229
|
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
|
150
230
|
end
|
|
151
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
|
+
|
|
152
249
|
# @param generics_to_resolve [Enumerable<String>]
|
|
153
250
|
# @param context_type [UniqueType, nil]
|
|
154
251
|
# @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
|
|
@@ -211,7 +308,23 @@ module Solargraph
|
|
|
211
308
|
if t.name == GENERIC_TAG_NAME
|
|
212
309
|
idx = definitions.generics.index(t.subtypes.first&.name)
|
|
213
310
|
next t if idx.nil?
|
|
214
|
-
context_type.
|
|
311
|
+
if context_type.parameters_type == :hash
|
|
312
|
+
if idx == 0
|
|
313
|
+
next ComplexType.new(context_type.key_types)
|
|
314
|
+
elsif idx == 1
|
|
315
|
+
next ComplexType.new(context_type.subtypes)
|
|
316
|
+
else
|
|
317
|
+
next ComplexType::UNDEFINED
|
|
318
|
+
end
|
|
319
|
+
elsif context_type.all?(&:implicit_union?)
|
|
320
|
+
if idx == 0 && !context_type.all_params.empty?
|
|
321
|
+
ComplexType.new(context_type.all_params)
|
|
322
|
+
else
|
|
323
|
+
ComplexType::UNDEFINED
|
|
324
|
+
end
|
|
325
|
+
else
|
|
326
|
+
context_type.all_params[idx] || ComplexType::UNDEFINED
|
|
327
|
+
end
|
|
215
328
|
else
|
|
216
329
|
t
|
|
217
330
|
end
|
|
@@ -238,6 +351,7 @@ module Solargraph
|
|
|
238
351
|
# @return [self]
|
|
239
352
|
def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
|
|
240
353
|
raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
|
|
354
|
+
|
|
241
355
|
new_name ||= name
|
|
242
356
|
new_key_types ||= @key_types
|
|
243
357
|
new_subtypes ||= @subtypes
|
|
@@ -278,17 +392,26 @@ module Solargraph
|
|
|
278
392
|
new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
279
393
|
new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
280
394
|
end
|
|
281
|
-
new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes)
|
|
395
|
+
new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes, make_rooted: @rooted)
|
|
282
396
|
yield new_type
|
|
283
397
|
end
|
|
284
398
|
|
|
285
|
-
#
|
|
286
|
-
#
|
|
287
|
-
# @
|
|
288
|
-
|
|
399
|
+
# Generate a ComplexType that fully qualifies this type's namespaces.
|
|
400
|
+
#
|
|
401
|
+
# @param api_map [ApiMap] The ApiMap that performs qualification
|
|
402
|
+
# @param context [String] The namespace from which to resolve names
|
|
403
|
+
# @return [self, ComplexType, UniqueType] The generated ComplexType
|
|
404
|
+
def qualify api_map, context = ''
|
|
289
405
|
transform do |t|
|
|
290
|
-
next t if t.name
|
|
291
|
-
t.
|
|
406
|
+
next t if t.name == GENERIC_TAG_NAME
|
|
407
|
+
next t if t.duck_type? || t.void? || t.undefined?
|
|
408
|
+
recon = (t.rooted? ? '' : context)
|
|
409
|
+
fqns = api_map.qualify(t.name, recon)
|
|
410
|
+
if fqns.nil?
|
|
411
|
+
next UniqueType::BOOLEAN if t.tag == 'Boolean'
|
|
412
|
+
next UniqueType::UNDEFINED
|
|
413
|
+
end
|
|
414
|
+
t.recreate(new_name: fqns, make_rooted: true)
|
|
292
415
|
end
|
|
293
416
|
end
|
|
294
417
|
|
|
@@ -296,8 +419,49 @@ module Solargraph
|
|
|
296
419
|
@name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
|
|
297
420
|
end
|
|
298
421
|
|
|
422
|
+
# @param dst [ComplexType]
|
|
423
|
+
# @return [self]
|
|
424
|
+
def self_to_type dst
|
|
425
|
+
object_type_dst = dst.reduce_class_type
|
|
426
|
+
transform do |t|
|
|
427
|
+
next t if t.name != 'self'
|
|
428
|
+
object_type_dst
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def all_rooted?
|
|
433
|
+
return true if name == GENERIC_TAG_NAME
|
|
434
|
+
rooted? && all_params.all?(&:rooted?)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def rooted?
|
|
438
|
+
!can_root_name? || @rooted
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def can_root_name?(name_to_check = name)
|
|
442
|
+
self.class.can_root_name?(name_to_check)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# @param name [String]
|
|
446
|
+
def self.can_root_name?(name)
|
|
447
|
+
# name is not lowercase
|
|
448
|
+
!name.empty? && name != name.downcase
|
|
449
|
+
end
|
|
450
|
+
|
|
299
451
|
UNDEFINED = UniqueType.new('undefined', rooted: false)
|
|
300
452
|
BOOLEAN = UniqueType.new('Boolean', rooted: true)
|
|
453
|
+
TRUE = UniqueType.new('true', rooted: true)
|
|
454
|
+
FALSE = UniqueType.new('false', rooted: true)
|
|
455
|
+
NIL = UniqueType.new('nil', rooted: true)
|
|
456
|
+
# @type [Hash{String => UniqueType}]
|
|
457
|
+
SINGLE_SUBTYPE = {
|
|
458
|
+
'::TrueClass' => UniqueType::TRUE,
|
|
459
|
+
'::FalseClass' => UniqueType::FALSE,
|
|
460
|
+
'::NilClass' => UniqueType::NIL
|
|
461
|
+
}.freeze
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
include Logging
|
|
301
465
|
end
|
|
302
466
|
end
|
|
303
467
|
end
|
|
@@ -7,6 +7,7 @@ module Solargraph
|
|
|
7
7
|
GENERIC_TAG_NAME = 'generic'.freeze
|
|
8
8
|
# @!parse
|
|
9
9
|
# include TypeMethods
|
|
10
|
+
include Equality
|
|
10
11
|
|
|
11
12
|
autoload :TypeMethods, 'solargraph/complex_type/type_methods'
|
|
12
13
|
autoload :UniqueType, 'solargraph/complex_type/unique_type'
|
|
@@ -15,7 +16,18 @@ module Solargraph
|
|
|
15
16
|
def initialize types = [UniqueType::UNDEFINED]
|
|
16
17
|
# @todo @items here should not need an annotation
|
|
17
18
|
# @type [Array<UniqueType>]
|
|
18
|
-
|
|
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
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
29
|
+
protected def equality_fields
|
|
30
|
+
[self.class, items]
|
|
19
31
|
end
|
|
20
32
|
|
|
21
33
|
# @param api_map [ApiMap]
|
|
@@ -24,7 +36,8 @@ module Solargraph
|
|
|
24
36
|
def qualify api_map, context = ''
|
|
25
37
|
red = reduce_object
|
|
26
38
|
types = red.items.map do |t|
|
|
27
|
-
next t if ['
|
|
39
|
+
next t if ['nil', 'void', 'undefined'].include?(t.name)
|
|
40
|
+
next t if ['::Boolean'].include?(t.rooted_name)
|
|
28
41
|
t.qualify api_map, context
|
|
29
42
|
end
|
|
30
43
|
ComplexType.new(types).reduce_object
|
|
@@ -52,8 +65,18 @@ module Solargraph
|
|
|
52
65
|
(@items.length > 1 ? ')' : ''))
|
|
53
66
|
end
|
|
54
67
|
|
|
68
|
+
# @param dst [ComplexType]
|
|
69
|
+
# @return [ComplexType]
|
|
70
|
+
def self_to_type dst
|
|
71
|
+
object_type_dst = dst.reduce_class_type
|
|
72
|
+
transform do |t|
|
|
73
|
+
next t if t.name != 'self'
|
|
74
|
+
object_type_dst
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
55
78
|
# @yieldparam [UniqueType]
|
|
56
|
-
# @return [Array]
|
|
79
|
+
# @return [Array<UniqueType>]
|
|
57
80
|
def map &block
|
|
58
81
|
@items.map &block
|
|
59
82
|
end
|
|
@@ -76,6 +99,12 @@ module Solargraph
|
|
|
76
99
|
end
|
|
77
100
|
end
|
|
78
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
|
+
|
|
79
108
|
# @return [Integer]
|
|
80
109
|
def length
|
|
81
110
|
@items.length
|
|
@@ -86,10 +115,6 @@ module Solargraph
|
|
|
86
115
|
@items
|
|
87
116
|
end
|
|
88
117
|
|
|
89
|
-
def tags
|
|
90
|
-
@items.map(&:tag).join(', ')
|
|
91
|
-
end
|
|
92
|
-
|
|
93
118
|
# @param index [Integer]
|
|
94
119
|
# @return [UniqueType]
|
|
95
120
|
def [](index)
|
|
@@ -130,14 +155,39 @@ module Solargraph
|
|
|
130
155
|
map(&:tag).join(', ')
|
|
131
156
|
end
|
|
132
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
|
+
|
|
175
|
+
def desc
|
|
176
|
+
rooted_tags
|
|
177
|
+
end
|
|
178
|
+
|
|
133
179
|
def rooted_tags
|
|
134
180
|
map(&:rooted_tag).join(', ')
|
|
135
181
|
end
|
|
136
182
|
|
|
183
|
+
# @yieldparam [UniqueType]
|
|
137
184
|
def all? &block
|
|
138
185
|
@items.all? &block
|
|
139
186
|
end
|
|
140
187
|
|
|
188
|
+
# @yieldparam [UniqueType]
|
|
189
|
+
# @yieldreturn [Boolean]
|
|
190
|
+
# @return [Boolean]
|
|
141
191
|
def any? &block
|
|
142
192
|
@items.compact.any? &block
|
|
143
193
|
end
|
|
@@ -150,6 +200,10 @@ module Solargraph
|
|
|
150
200
|
any?(&:generic?)
|
|
151
201
|
end
|
|
152
202
|
|
|
203
|
+
def simplify_literals
|
|
204
|
+
ComplexType.new(map(&:simplify_literals))
|
|
205
|
+
end
|
|
206
|
+
|
|
153
207
|
# @param new_name [String, nil]
|
|
154
208
|
# @yieldparam t [UniqueType]
|
|
155
209
|
# @yieldreturn [UniqueType]
|
|
@@ -171,16 +225,7 @@ module Solargraph
|
|
|
171
225
|
# @return [ComplexType]
|
|
172
226
|
def resolve_generics definitions, context_type
|
|
173
227
|
result = @items.map { |i| i.resolve_generics(definitions, context_type) }
|
|
174
|
-
ComplexType.
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
# @param dst [String]
|
|
178
|
-
# @return [ComplexType]
|
|
179
|
-
def self_to dst
|
|
180
|
-
return self unless selfy?
|
|
181
|
-
red = reduce_class(dst)
|
|
182
|
-
result = @items.map { |i| i.self_to red }
|
|
183
|
-
ComplexType.try_parse(*result.map(&:tag))
|
|
228
|
+
ComplexType.new(result)
|
|
184
229
|
end
|
|
185
230
|
|
|
186
231
|
def nullable?
|
|
@@ -192,14 +237,43 @@ module Solargraph
|
|
|
192
237
|
@items.first.all_params || []
|
|
193
238
|
end
|
|
194
239
|
|
|
240
|
+
# @return [ComplexType]
|
|
241
|
+
def reduce_class_type
|
|
242
|
+
new_items = items.flat_map do |type|
|
|
243
|
+
next type unless ['Module', 'Class'].include?(type.name)
|
|
244
|
+
|
|
245
|
+
type.all_params
|
|
246
|
+
end
|
|
247
|
+
ComplexType.new(new_items)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# every type and subtype in this union have been resolved to be
|
|
251
|
+
# fully qualified
|
|
252
|
+
def all_rooted?
|
|
253
|
+
all?(&:all_rooted?)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# every top-level type has resolved to be fully qualified; see
|
|
257
|
+
# #all_rooted? to check their subtypes as well
|
|
258
|
+
def rooted?
|
|
259
|
+
all?(&:rooted?)
|
|
260
|
+
end
|
|
261
|
+
|
|
195
262
|
attr_reader :items
|
|
196
263
|
|
|
264
|
+
def rooted?
|
|
265
|
+
@items.all?(&:rooted?)
|
|
266
|
+
end
|
|
267
|
+
|
|
197
268
|
protected
|
|
198
269
|
|
|
199
270
|
# @return [ComplexType]
|
|
200
271
|
def reduce_object
|
|
201
|
-
|
|
202
|
-
|
|
272
|
+
new_items = items.flat_map do |ut|
|
|
273
|
+
next [ut] if ut.name != 'Object' || ut.subtypes.empty?
|
|
274
|
+
ut.subtypes
|
|
275
|
+
end
|
|
276
|
+
ComplexType.new(new_items)
|
|
203
277
|
end
|
|
204
278
|
|
|
205
279
|
def bottom?
|
|
@@ -219,12 +293,17 @@ module Solargraph
|
|
|
219
293
|
# Consumers should not need to use this parameter; it should only be
|
|
220
294
|
# used internally.
|
|
221
295
|
#
|
|
222
|
-
# @param
|
|
296
|
+
# @param strings [Array<String>] The type definitions to parse
|
|
223
297
|
# @return [ComplexType]
|
|
224
|
-
# @overload parse(*strings, partial: false)
|
|
225
|
-
# @todo Need ability to use a literal true as a type below
|
|
226
|
-
# @param partial [Boolean] True if the string is part of a another type
|
|
227
|
-
# @return [Array<UniqueType>]
|
|
298
|
+
# # @overload parse(*strings, partial: false)
|
|
299
|
+
# # @todo Need ability to use a literal true as a type below
|
|
300
|
+
# # @param partial [Boolean] True if the string is part of a another type
|
|
301
|
+
# # @return [Array<UniqueType>]
|
|
302
|
+
# @sg-ignore
|
|
303
|
+
# @todo To be able to select the right signature above,
|
|
304
|
+
# Chain::Call needs to know the decl type (:arg, :optarg,
|
|
305
|
+
# :kwarg, etc) of the arguments given, instead of just having
|
|
306
|
+
# an array of Chains as the arguments.
|
|
228
307
|
def parse *strings, partial: false
|
|
229
308
|
# @type [Hash{Array<String> => ComplexType}]
|
|
230
309
|
@cache ||= {}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
struct_node = node.children[2].children[0]
|
|
29
|
+
|
|
30
|
+
struct_definition_node?(struct_node)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def class_name
|
|
35
|
+
if node.children[0]
|
|
36
|
+
Parser::NodeMethods.unpack_name(node.children[0]) + "::#{node.children[1]}"
|
|
37
|
+
else
|
|
38
|
+
node.children[1].to_s
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# @return [Parser::AST::Node]
|
|
45
|
+
def struct_node
|
|
46
|
+
node.children[2].children[0]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
module Convention
|
|
5
|
+
module StructDefinition
|
|
6
|
+
# A node wrapper for a Struct definition via inheritance.
|
|
7
|
+
# @example
|
|
8
|
+
# class MyStruct < Struct.new(:bar, :baz)
|
|
9
|
+
# def foo
|
|
10
|
+
# end
|
|
11
|
+
# end
|
|
12
|
+
class StructDefintionNode
|
|
13
|
+
class << self
|
|
14
|
+
# @example
|
|
15
|
+
# s(:class,
|
|
16
|
+
# s(:const, nil, :Foo),
|
|
17
|
+
# s(:send,
|
|
18
|
+
# s(:const, nil, :Struct), :new,
|
|
19
|
+
# s(:sym, :bar),
|
|
20
|
+
# s(:sym, :baz)),
|
|
21
|
+
# s(:hash,
|
|
22
|
+
# s(:pair,
|
|
23
|
+
# s(:sym, :keyword_init),
|
|
24
|
+
# s(:true)))),
|
|
25
|
+
# s(:def, :foo,
|
|
26
|
+
# s(:args),
|
|
27
|
+
# s(:send, nil, :bar)))
|
|
28
|
+
def valid?(node)
|
|
29
|
+
return false unless node&.type == :class
|
|
30
|
+
|
|
31
|
+
struct_definition_node?(node.children[1])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# @param struct_node [Parser::AST::Node]
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def struct_definition_node?(struct_node)
|
|
39
|
+
return false unless struct_node.is_a?(::Parser::AST::Node)
|
|
40
|
+
return false unless struct_node&.type == :send
|
|
41
|
+
return false unless struct_node.children[0]&.type == :const
|
|
42
|
+
return false unless struct_node.children[0].children[1] == :Struct
|
|
43
|
+
return false unless struct_node.children[1] == :new
|
|
44
|
+
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Parser::AST::Node]
|
|
50
|
+
def initialize(node)
|
|
51
|
+
@node = node
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [String]
|
|
55
|
+
def class_name
|
|
56
|
+
Parser::NodeMethods.unpack_name(node)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Array<Array(Parser::AST::Node, String)>]
|
|
60
|
+
def attributes
|
|
61
|
+
struct_attribute_nodes.map do |struct_def_param|
|
|
62
|
+
next unless struct_def_param.type == :sym
|
|
63
|
+
[struct_def_param, struct_def_param.children[0].to_s]
|
|
64
|
+
end.compact
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def keyword_init?
|
|
68
|
+
keyword_init_param = struct_attribute_nodes.find do |struct_def_param|
|
|
69
|
+
struct_def_param.type == :hash && struct_def_param.children[0].type == :pair &&
|
|
70
|
+
struct_def_param.children[0].children[0].children[0] == :keyword_init
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return false if keyword_init_param.nil?
|
|
74
|
+
|
|
75
|
+
keyword_init_param.children[0].children[1].type == :true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [Parser::AST::Node]
|
|
79
|
+
def body_node
|
|
80
|
+
node.children[2]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# @return [Parser::AST::Node]
|
|
86
|
+
attr_reader :node
|
|
87
|
+
|
|
88
|
+
# @return [Parser::AST::Node]
|
|
89
|
+
def struct_node
|
|
90
|
+
node.children[1]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [Array<Parser::AST::Node>]
|
|
94
|
+
def struct_attribute_nodes
|
|
95
|
+
struct_node.children[2..-1]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|