solargraph 0.53.0 → 0.54.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 +45 -0
- data/lib/solargraph/api_map/cache.rb +2 -12
- data/lib/solargraph/api_map/source_to_yard.rb +17 -10
- data/lib/solargraph/api_map/store.rb +11 -6
- data/lib/solargraph/api_map.rb +80 -38
- data/lib/solargraph/bench.rb +1 -0
- data/lib/solargraph/complex_type/type_methods.rb +62 -30
- data/lib/solargraph/complex_type/unique_type.rb +149 -75
- data/lib/solargraph/complex_type.rb +41 -25
- data/lib/solargraph/doc_map.rb +65 -24
- data/lib/solargraph/gem_pins.rb +10 -2
- data/lib/solargraph/language_server/host/dispatch.rb +13 -2
- data/lib/solargraph/language_server/host/sources.rb +1 -61
- data/lib/solargraph/language_server/host.rb +41 -69
- data/lib/solargraph/language_server/message/base.rb +1 -1
- data/lib/solargraph/language_server/message/initialize.rb +14 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
- data/lib/solargraph/language_server/progress.rb +118 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +149 -97
- data/lib/solargraph/page.rb +6 -0
- data/lib/solargraph/parser/node_processor/base.rb +3 -2
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +0 -4
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -19
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
- data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
- data/lib/solargraph/pin/base_variable.rb +35 -6
- data/lib/solargraph/pin/block.rb +70 -32
- data/lib/solargraph/pin/delegated_method.rb +5 -1
- data/lib/solargraph/pin/documenting.rb +2 -0
- data/lib/solargraph/pin/method.rb +4 -2
- data/lib/solargraph/pin/parameter.rb +5 -28
- data/lib/solargraph/rbs_map/conversions.rb +16 -47
- data/lib/solargraph/rbs_map/core_fills.rb +12 -6
- data/lib/solargraph/rbs_map/core_map.rb +2 -13
- data/lib/solargraph/rbs_map.rb +17 -7
- data/lib/solargraph/shell.rb +18 -13
- data/lib/solargraph/source/chain.rb +20 -0
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +0 -44
- data/lib/solargraph/source_map/clip.rb +3 -2
- data/lib/solargraph/source_map/mapper.rb +3 -2
- data/lib/solargraph/source_map.rb +8 -6
- data/lib/solargraph/type_checker.rb +58 -13
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +2 -1
- data/lib/solargraph/workspace.rb +27 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -2
- metadata +4 -4
- data/lib/solargraph/language_server/host/cataloger.rb +0 -57
- data/lib/solargraph/rbs_map/core_signs.rb +0 -35
|
@@ -8,7 +8,7 @@ module Solargraph
|
|
|
8
8
|
class UniqueType
|
|
9
9
|
include TypeMethods
|
|
10
10
|
|
|
11
|
-
attr_reader :all_params
|
|
11
|
+
attr_reader :all_params, :subtypes, :key_types
|
|
12
12
|
|
|
13
13
|
# Create a UniqueType with the specified name and an optional substring.
|
|
14
14
|
# The substring is the parameter section of a parametrized type, e.g.,
|
|
@@ -17,43 +17,61 @@ module Solargraph
|
|
|
17
17
|
#
|
|
18
18
|
# @param name [String] The name of the type
|
|
19
19
|
# @param substring [String] The substring of the type
|
|
20
|
-
|
|
20
|
+
# @param make_rooted [Boolean, nil]
|
|
21
|
+
# @return [UniqueType]
|
|
22
|
+
def self.parse name, substring = '', make_rooted: nil
|
|
23
|
+
if name.start_with?(':::')
|
|
24
|
+
raise "Illegal prefix: #{name}"
|
|
25
|
+
end
|
|
21
26
|
if name.start_with?('::')
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
name = name[2..-1]
|
|
28
|
+
rooted = true
|
|
24
29
|
else
|
|
25
|
-
|
|
26
|
-
@rooted = false
|
|
30
|
+
rooted = false
|
|
27
31
|
end
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# @type [Array<ComplexType>]
|
|
31
|
-
@key_types = []
|
|
32
|
+
rooted = make_rooted unless make_rooted.nil?
|
|
33
|
+
|
|
32
34
|
# @type [Array<ComplexType>]
|
|
33
|
-
|
|
35
|
+
key_types = []
|
|
34
36
|
# @type [Array<ComplexType>]
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
subtypes = []
|
|
38
|
+
parameters_type = nil
|
|
39
|
+
unless substring.empty?
|
|
40
|
+
subs = ComplexType.parse(substring[1..-2], partial: true)
|
|
41
|
+
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
|
42
|
+
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)
|
|
44
|
+
# @todo should be able to resolve map; both types have it
|
|
45
|
+
# with same return type
|
|
46
|
+
# @sg-ignore
|
|
47
|
+
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
|
48
|
+
# @sg-ignore
|
|
49
|
+
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
|
50
|
+
else
|
|
51
|
+
subtypes.concat subs
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @param name [String]
|
|
58
|
+
# @param key_types [Array<ComplexType>]
|
|
59
|
+
# @param subtypes [Array<ComplexType>]
|
|
60
|
+
# @param rooted [Boolean]
|
|
61
|
+
# @param parameters_type [Symbol, nil]
|
|
62
|
+
def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)
|
|
63
|
+
if parameters_type.nil?
|
|
64
|
+
raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
|
|
54
65
|
end
|
|
55
|
-
|
|
56
|
-
@
|
|
66
|
+
raise "Please remove leading :: and set rooted instead - #{name}" if name.start_with?('::')
|
|
67
|
+
@name = name
|
|
68
|
+
@key_types = key_types
|
|
69
|
+
@subtypes = subtypes
|
|
70
|
+
@rooted = rooted
|
|
71
|
+
@all_params = []
|
|
72
|
+
@all_params.concat key_types
|
|
73
|
+
@all_params.concat subtypes
|
|
74
|
+
@parameters_type = parameters_type
|
|
57
75
|
end
|
|
58
76
|
|
|
59
77
|
def to_s
|
|
@@ -76,7 +94,17 @@ module Solargraph
|
|
|
76
94
|
|
|
77
95
|
# @return [String]
|
|
78
96
|
def to_rbs
|
|
79
|
-
if
|
|
97
|
+
if duck_type?
|
|
98
|
+
'untyped'
|
|
99
|
+
elsif name == 'Boolean'
|
|
100
|
+
'bool'
|
|
101
|
+
elsif name.downcase == 'nil'
|
|
102
|
+
'nil'
|
|
103
|
+
elsif name == GENERIC_TAG_NAME
|
|
104
|
+
all_params.first.name
|
|
105
|
+
elsif ['Class', 'Module'].include?(name)
|
|
106
|
+
rbs_name
|
|
107
|
+
elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
|
|
80
108
|
# tuples don't have a name; they're just [foo, bar, baz].
|
|
81
109
|
if substring == '()'
|
|
82
110
|
# but there are no zero element tuples, so we go with an array
|
|
@@ -90,28 +118,45 @@ module Solargraph
|
|
|
90
118
|
end
|
|
91
119
|
end
|
|
92
120
|
|
|
121
|
+
# @return [Boolean]
|
|
122
|
+
def parameters?
|
|
123
|
+
!all_params.empty?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @param types [Array<UniqueType, ComplexType>]
|
|
127
|
+
# @return [String]
|
|
128
|
+
def rbs_union(types)
|
|
129
|
+
if types.length == 1
|
|
130
|
+
types.first.to_rbs
|
|
131
|
+
else
|
|
132
|
+
"(#{types.map(&:to_rbs).join(' | ')})"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
93
136
|
# @return [String]
|
|
94
137
|
def parameters_as_rbs
|
|
95
|
-
|
|
138
|
+
return '' unless parameters?
|
|
139
|
+
|
|
140
|
+
return "[#{all_params.map(&:to_rbs).join(', ')}]" if key_types.empty?
|
|
141
|
+
|
|
142
|
+
# handle, e.g., Hash[K, V] case
|
|
143
|
+
key_types_str = rbs_union(key_types)
|
|
144
|
+
subtypes_str = rbs_union(subtypes)
|
|
145
|
+
"[#{key_types_str}, #{subtypes_str}]"
|
|
96
146
|
end
|
|
97
147
|
|
|
98
148
|
def generic?
|
|
99
149
|
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
|
100
150
|
end
|
|
101
151
|
|
|
102
|
-
|
|
103
152
|
# @param generics_to_resolve [Enumerable<String>]
|
|
104
153
|
# @param context_type [UniqueType, nil]
|
|
105
154
|
# @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
|
|
106
155
|
# @return [UniqueType, ComplexType]
|
|
107
156
|
def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
new_binding = false
|
|
112
|
-
|
|
113
|
-
type_param = t.subtypes.first&.name
|
|
114
|
-
next t unless generics_to_resolve.include? type_param
|
|
157
|
+
if name == ComplexType::GENERIC_TAG_NAME
|
|
158
|
+
type_param = subtypes.first&.name
|
|
159
|
+
return self unless generics_to_resolve.include? type_param
|
|
115
160
|
unless context_type.nil? || !resolved_generic_values[type_param].nil?
|
|
116
161
|
new_binding = true
|
|
117
162
|
resolved_generic_values[type_param] = context_type
|
|
@@ -121,7 +166,34 @@ module Solargraph
|
|
|
121
166
|
complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
|
|
122
167
|
end
|
|
123
168
|
end
|
|
124
|
-
resolved_generic_values[type_param] ||
|
|
169
|
+
return resolved_generic_values[type_param] || self
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @todo typechecking should complain when the method being called has no @yieldparam tag
|
|
173
|
+
new_key_types = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:key_types)
|
|
174
|
+
new_subtypes = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:subtypes)
|
|
175
|
+
recreate(new_key_types: new_key_types, new_subtypes: new_subtypes)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# @param generics_to_resolve [Enumerable<String>]
|
|
179
|
+
# @param context_type [UniqueType]
|
|
180
|
+
# @param resolved_generic_values [Hash{String => ComplexType}]
|
|
181
|
+
# @yieldreturn [Array<ComplexType>]
|
|
182
|
+
# @return [Array<ComplexType>]
|
|
183
|
+
def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)
|
|
184
|
+
types = yield self
|
|
185
|
+
types.each_with_index.flat_map do |ct, i|
|
|
186
|
+
ct.items.flat_map do |ut|
|
|
187
|
+
context_params = yield context_type if context_type
|
|
188
|
+
if context_params && context_params[i]
|
|
189
|
+
type_arg = context_params[i]
|
|
190
|
+
type_arg.map do |new_unique_context_type|
|
|
191
|
+
ut.resolve_generics_from_context generics_to_resolve, new_unique_context_type, resolved_generic_values: resolved_generic_values
|
|
192
|
+
end
|
|
193
|
+
else
|
|
194
|
+
ut.resolve_generics_from_context generics_to_resolve, nil, resolved_generic_values: resolved_generic_values
|
|
195
|
+
end
|
|
196
|
+
end
|
|
125
197
|
end
|
|
126
198
|
end
|
|
127
199
|
|
|
@@ -159,39 +231,34 @@ module Solargraph
|
|
|
159
231
|
end
|
|
160
232
|
|
|
161
233
|
# @param new_name [String, nil]
|
|
234
|
+
# @param make_rooted [Boolean, nil]
|
|
162
235
|
# @param new_key_types [Array<UniqueType>, nil]
|
|
236
|
+
# @param rooted [Boolean, nil]
|
|
163
237
|
# @param new_subtypes [Array<UniqueType>, nil]
|
|
164
238
|
# @return [self]
|
|
165
|
-
def recreate(new_name: nil, new_key_types: nil, new_subtypes: nil)
|
|
239
|
+
def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
|
|
240
|
+
raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
|
|
166
241
|
new_name ||= name
|
|
167
242
|
new_key_types ||= @key_types
|
|
168
243
|
new_subtypes ||= @subtypes
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
# Array<(String), Integer> is not ambiguous if we accept
|
|
188
|
-
# (String) as a tuple type, but not currently understood
|
|
189
|
-
# by Solargraph.
|
|
190
|
-
UniqueType.new(new_name, "<(#{new_subtypes.join(', ')})>")
|
|
191
|
-
elsif fixed_parameters?
|
|
192
|
-
UniqueType.new(new_name, "(#{new_subtypes.join(', ')})")
|
|
193
|
-
else
|
|
194
|
-
UniqueType.new(new_name, "<#{new_subtypes.join(', ')}>")
|
|
244
|
+
make_rooted = @rooted if make_rooted.nil?
|
|
245
|
+
UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# @return [String]
|
|
249
|
+
def rooted_tags
|
|
250
|
+
rooted_tag
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# @return [String]
|
|
254
|
+
def tags
|
|
255
|
+
tag
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# @return [self]
|
|
259
|
+
def force_rooted
|
|
260
|
+
transform do |t|
|
|
261
|
+
t.recreate(make_rooted: true)
|
|
195
262
|
end
|
|
196
263
|
end
|
|
197
264
|
|
|
@@ -202,9 +269,16 @@ module Solargraph
|
|
|
202
269
|
# @yieldreturn [self]
|
|
203
270
|
# @return [self]
|
|
204
271
|
def transform(new_name = nil, &transform_type)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
272
|
+
raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
|
|
273
|
+
if name == ComplexType::GENERIC_TAG_NAME
|
|
274
|
+
# doesn't make sense to manipulate the name of the generic
|
|
275
|
+
new_key_types = @key_types
|
|
276
|
+
new_subtypes = @subtypes
|
|
277
|
+
else
|
|
278
|
+
new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
279
|
+
new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
280
|
+
end
|
|
281
|
+
new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes)
|
|
208
282
|
yield new_type
|
|
209
283
|
end
|
|
210
284
|
|
|
@@ -222,8 +296,8 @@ module Solargraph
|
|
|
222
296
|
@name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
|
|
223
297
|
end
|
|
224
298
|
|
|
225
|
-
UNDEFINED = UniqueType.new('undefined')
|
|
226
|
-
BOOLEAN = UniqueType.new('Boolean')
|
|
299
|
+
UNDEFINED = UniqueType.new('undefined', rooted: false)
|
|
300
|
+
BOOLEAN = UniqueType.new('Boolean', rooted: true)
|
|
227
301
|
end
|
|
228
302
|
end
|
|
229
303
|
end
|
|
@@ -11,7 +11,7 @@ module Solargraph
|
|
|
11
11
|
autoload :TypeMethods, 'solargraph/complex_type/type_methods'
|
|
12
12
|
autoload :UniqueType, 'solargraph/complex_type/unique_type'
|
|
13
13
|
|
|
14
|
-
# @param types [Array<
|
|
14
|
+
# @param types [Array<UniqueType, ComplexType>]
|
|
15
15
|
def initialize types = [UniqueType::UNDEFINED]
|
|
16
16
|
# @todo @items here should not need an annotation
|
|
17
17
|
# @type [Array<UniqueType>]
|
|
@@ -86,6 +86,10 @@ module Solargraph
|
|
|
86
86
|
@items
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def tags
|
|
90
|
+
@items.map(&:tag).join(', ')
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
# @param index [Integer]
|
|
90
94
|
# @return [UniqueType]
|
|
91
95
|
def [](index)
|
|
@@ -126,6 +130,10 @@ module Solargraph
|
|
|
126
130
|
map(&:tag).join(', ')
|
|
127
131
|
end
|
|
128
132
|
|
|
133
|
+
def rooted_tags
|
|
134
|
+
map(&:rooted_tag).join(', ')
|
|
135
|
+
end
|
|
136
|
+
|
|
129
137
|
def all? &block
|
|
130
138
|
@items.all? &block
|
|
131
139
|
end
|
|
@@ -147,15 +155,23 @@ module Solargraph
|
|
|
147
155
|
# @yieldreturn [UniqueType]
|
|
148
156
|
# @return [ComplexType]
|
|
149
157
|
def transform(new_name = nil, &transform_type)
|
|
158
|
+
raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
|
|
150
159
|
ComplexType.new(map { |ut| ut.transform(new_name, &transform_type) })
|
|
151
160
|
end
|
|
152
161
|
|
|
162
|
+
# @return [self]
|
|
163
|
+
def force_rooted
|
|
164
|
+
transform do |t|
|
|
165
|
+
t.recreate(make_rooted: true)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
153
169
|
# @param definitions [Pin::Namespace, Pin::Method]
|
|
154
170
|
# @param context_type [ComplexType]
|
|
155
171
|
# @return [ComplexType]
|
|
156
172
|
def resolve_generics definitions, context_type
|
|
157
173
|
result = @items.map { |i| i.resolve_generics(definitions, context_type) }
|
|
158
|
-
ComplexType.
|
|
174
|
+
ComplexType.try_parse(*result.map(&:tag))
|
|
159
175
|
end
|
|
160
176
|
|
|
161
177
|
# @param dst [String]
|
|
@@ -164,7 +180,7 @@ module Solargraph
|
|
|
164
180
|
return self unless selfy?
|
|
165
181
|
red = reduce_class(dst)
|
|
166
182
|
result = @items.map { |i| i.self_to red }
|
|
167
|
-
ComplexType.
|
|
183
|
+
ComplexType.try_parse(*result.map(&:tag))
|
|
168
184
|
end
|
|
169
185
|
|
|
170
186
|
def nullable?
|
|
@@ -190,21 +206,6 @@ module Solargraph
|
|
|
190
206
|
@items.all?(&:bot?)
|
|
191
207
|
end
|
|
192
208
|
|
|
193
|
-
private
|
|
194
|
-
|
|
195
|
-
# @todo This is a quick and dirty hack that forces `self` keywords
|
|
196
|
-
# to reference an instance of their class and never the class itself.
|
|
197
|
-
# This behavior may change depending on which result is expected
|
|
198
|
-
# from YARD conventions. See https://github.com/lsegal/yard/issues/1257
|
|
199
|
-
# @param dst [String]
|
|
200
|
-
# @return [String]
|
|
201
|
-
def reduce_class dst
|
|
202
|
-
while dst =~ /^(Class|Module)\<(.*?)\>$/
|
|
203
|
-
dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
|
|
204
|
-
end
|
|
205
|
-
dst
|
|
206
|
-
end
|
|
207
|
-
|
|
208
209
|
class << self
|
|
209
210
|
# Parse type strings into a ComplexType.
|
|
210
211
|
#
|
|
@@ -250,7 +251,7 @@ module Solargraph
|
|
|
250
251
|
elsif base.end_with?('=')
|
|
251
252
|
raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
|
|
252
253
|
# types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
|
|
253
|
-
types.push UniqueType.
|
|
254
|
+
types.push UniqueType.parse(base[0..-2].strip, subtype_string)
|
|
254
255
|
# @todo this should either expand key_type's type
|
|
255
256
|
# automatically or complain about not being
|
|
256
257
|
# compatible with key_type's type in type checking
|
|
@@ -281,7 +282,7 @@ module Solargraph
|
|
|
281
282
|
next
|
|
282
283
|
elsif char == ',' && point_stack == 0 && curly_stack == 0 && paren_stack == 0
|
|
283
284
|
# types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
|
|
284
|
-
types.push UniqueType.
|
|
285
|
+
types.push UniqueType.parse(base.strip, subtype_string.strip)
|
|
285
286
|
base.clear
|
|
286
287
|
subtype_string.clear
|
|
287
288
|
next
|
|
@@ -294,7 +295,7 @@ module Solargraph
|
|
|
294
295
|
end
|
|
295
296
|
raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 || curly_stack != 0 || paren_stack != 0
|
|
296
297
|
# types.push ComplexType.new([UniqueType.new(base, subtype_string)])
|
|
297
|
-
types.push UniqueType.
|
|
298
|
+
types.push UniqueType.parse(base.strip, subtype_string.strip)
|
|
298
299
|
end
|
|
299
300
|
unless key_types.nil?
|
|
300
301
|
raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
|
|
@@ -311,18 +312,33 @@ module Solargraph
|
|
|
311
312
|
def try_parse *strings
|
|
312
313
|
parse *strings
|
|
313
314
|
rescue ComplexTypeError => e
|
|
314
|
-
Solargraph.logger.info "Error parsing complex type
|
|
315
|
+
Solargraph.logger.info "Error parsing complex type `#{strings.join(', ')}`: #{e.message}"
|
|
315
316
|
ComplexType::UNDEFINED
|
|
316
317
|
end
|
|
317
318
|
end
|
|
318
319
|
|
|
319
320
|
VOID = ComplexType.parse('void')
|
|
320
321
|
UNDEFINED = ComplexType.parse('undefined')
|
|
321
|
-
SYMBOL = ComplexType.parse('Symbol')
|
|
322
|
-
ROOT = ComplexType.parse('Class<>')
|
|
322
|
+
SYMBOL = ComplexType.parse('::Symbol')
|
|
323
|
+
ROOT = ComplexType.parse('::Class<>')
|
|
323
324
|
NIL = ComplexType.parse('nil')
|
|
324
325
|
SELF = ComplexType.parse('self')
|
|
325
|
-
BOOLEAN = ComplexType.parse('Boolean')
|
|
326
|
+
BOOLEAN = ComplexType.parse('::Boolean')
|
|
326
327
|
BOT = ComplexType.parse('bot')
|
|
328
|
+
|
|
329
|
+
private
|
|
330
|
+
|
|
331
|
+
# @todo This is a quick and dirty hack that forces `self` keywords
|
|
332
|
+
# to reference an instance of their class and never the class itself.
|
|
333
|
+
# This behavior may change depending on which result is expected
|
|
334
|
+
# from YARD conventions. See https://github.com/lsegal/yard/issues/1257
|
|
335
|
+
# @param dst [String]
|
|
336
|
+
# @return [String]
|
|
337
|
+
def reduce_class dst
|
|
338
|
+
while dst =~ /^(Class|Module)\<(.*?)\>$/
|
|
339
|
+
dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
|
|
340
|
+
end
|
|
341
|
+
dst
|
|
342
|
+
end
|
|
327
343
|
end
|
|
328
344
|
end
|
data/lib/solargraph/doc_map.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Solargraph
|
|
|
8
8
|
attr_reader :requires
|
|
9
9
|
|
|
10
10
|
# @return [Array<Gem::Specification>]
|
|
11
|
-
attr_reader :
|
|
11
|
+
attr_reader :preferences
|
|
12
12
|
|
|
13
13
|
# @return [Array<Pin::Base>]
|
|
14
14
|
attr_reader :pins
|
|
@@ -17,10 +17,12 @@ module Solargraph
|
|
|
17
17
|
attr_reader :uncached_gemspecs
|
|
18
18
|
|
|
19
19
|
# @param requires [Array<String>]
|
|
20
|
-
# @param
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@
|
|
20
|
+
# @param preferences [Array<Gem::Specification>]
|
|
21
|
+
# @param rbs_path [String, Pathname, nil]
|
|
22
|
+
def initialize(requires, preferences, rbs_path = nil)
|
|
23
|
+
@requires = requires.compact
|
|
24
|
+
@preferences = preferences.compact
|
|
25
|
+
@rbs_path = rbs_path
|
|
24
26
|
generate
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -39,17 +41,12 @@ module Solargraph
|
|
|
39
41
|
@gems_in_memory ||= {}
|
|
40
42
|
end
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def required_gem_map
|
|
46
|
-
@required_gem_map ||= requires.to_h { |path| [path, resolve_path_to_gemspec(path)] }
|
|
44
|
+
# @return [Set<Gem::Specification>]
|
|
45
|
+
def dependencies
|
|
46
|
+
@dependencies ||= (gemspecs.flat_map { |spec| fetch_dependencies(spec) } - gemspecs).to_set
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
def dependency_map
|
|
51
|
-
@dependency_map ||= dependencies.to_h { |gemspec| [gemspec.name, gemspec] }
|
|
52
|
-
end
|
|
49
|
+
private
|
|
53
50
|
|
|
54
51
|
# @return [void]
|
|
55
52
|
def generate
|
|
@@ -62,6 +59,18 @@ module Solargraph
|
|
|
62
59
|
try_stdlib_map path
|
|
63
60
|
end
|
|
64
61
|
end
|
|
62
|
+
dependencies.each { |dep| try_cache dep }
|
|
63
|
+
@uncached_gemspecs.uniq!
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Hash{String => Gem::Specification, nil}]
|
|
67
|
+
def required_gem_map
|
|
68
|
+
@required_gem_map ||= requires.to_h { |path| [path, resolve_path_to_gemspec(path)] }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [Hash{String => Gem::Specification}]
|
|
72
|
+
def preference_map
|
|
73
|
+
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
|
65
74
|
end
|
|
66
75
|
|
|
67
76
|
# @param gemspec [Gem::Specification]
|
|
@@ -70,7 +79,8 @@ module Solargraph
|
|
|
70
79
|
return if try_gem_in_memory(gemspec)
|
|
71
80
|
cache_file = File.join('gems', "#{gemspec.name}-#{gemspec.version}.ser")
|
|
72
81
|
if Cache.exist?(cache_file)
|
|
73
|
-
|
|
82
|
+
cached = Cache.load(cache_file)
|
|
83
|
+
gempins = update_from_collection(gemspec, cached)
|
|
74
84
|
self.class.gems_in_memory[gemspec] = gempins
|
|
75
85
|
@pins.concat gempins
|
|
76
86
|
else
|
|
@@ -88,7 +98,7 @@ module Solargraph
|
|
|
88
98
|
@pins.concat map.pins
|
|
89
99
|
else
|
|
90
100
|
# @todo Temporarily ignoring unresolved `require 'set'`
|
|
91
|
-
Solargraph.logger.
|
|
101
|
+
Solargraph.logger.debug "Require path #{path} could not be resolved" unless path == 'set'
|
|
92
102
|
end
|
|
93
103
|
end
|
|
94
104
|
|
|
@@ -102,9 +112,22 @@ module Solargraph
|
|
|
102
112
|
true
|
|
103
113
|
end
|
|
104
114
|
|
|
115
|
+
def update_from_collection gemspec, gempins
|
|
116
|
+
return gempins unless @rbs_path && File.directory?(@rbs_path)
|
|
117
|
+
return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
|
|
118
|
+
|
|
119
|
+
rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [@rbs_path])
|
|
120
|
+
return gempins unless rbs_map.resolved?
|
|
121
|
+
|
|
122
|
+
Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
|
|
123
|
+
GemPins.combine(gempins, rbs_map)
|
|
124
|
+
end
|
|
125
|
+
|
|
105
126
|
# @param path [String]
|
|
106
127
|
# @return [Gem::Specification, nil]
|
|
107
128
|
def resolve_path_to_gemspec path
|
|
129
|
+
return nil if path.empty?
|
|
130
|
+
|
|
108
131
|
gemspec = Gem::Specification.find_by_path(path)
|
|
109
132
|
if gemspec.nil?
|
|
110
133
|
gem_name_guess = path.split('/').first
|
|
@@ -121,16 +144,16 @@ module Solargraph
|
|
|
121
144
|
nil
|
|
122
145
|
end
|
|
123
146
|
end
|
|
124
|
-
|
|
147
|
+
gemspec_or_preference gemspec
|
|
148
|
+
end
|
|
125
149
|
|
|
126
|
-
|
|
127
|
-
|
|
150
|
+
# @param gemspec [Gem::Specification, nil]
|
|
151
|
+
# @return [Gem::Specification, nil]
|
|
152
|
+
def gemspec_or_preference gemspec
|
|
153
|
+
return gemspec unless gemspec && preference_map.key?(gemspec.name)
|
|
154
|
+
return gemspec if gemspec.version == preference_map[gemspec.name].version
|
|
128
155
|
|
|
129
|
-
|
|
130
|
-
else
|
|
131
|
-
Solargraph.logger.warn "Gem #{gemspec.name} is not an expected dependency"
|
|
132
|
-
gemspec
|
|
133
|
-
end
|
|
156
|
+
change_gemspec_version gemspec, preference_map[by_path.name].version
|
|
134
157
|
end
|
|
135
158
|
|
|
136
159
|
# @param gemspec [Gem::Specification]
|
|
@@ -142,5 +165,23 @@ module Solargraph
|
|
|
142
165
|
Solargraph.logger.info "Gem #{gemspec.name} version #{version} not found. Using #{gemspec.version} instead"
|
|
143
166
|
gemspec
|
|
144
167
|
end
|
|
168
|
+
|
|
169
|
+
# @param gemspec [Gem::Specification]
|
|
170
|
+
# @return [Array<Gem::Specification>]
|
|
171
|
+
def fetch_dependencies gemspec
|
|
172
|
+
only_runtime_dependencies(gemspec).each_with_object(Set.new) do |spec, deps|
|
|
173
|
+
Solargraph.logger.info "Adding #{spec.name} dependency for #{gemspec.name}"
|
|
174
|
+
dep = Gem::Specification.find_by_name(spec.name, spec.requirement)
|
|
175
|
+
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
|
176
|
+
rescue Gem::MissingSpecError
|
|
177
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirements} for #{gemspec.name} not found."
|
|
178
|
+
end.to_a
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# @param gemspec [Gem::Specification]
|
|
182
|
+
# @return [Array<Gem::Dependency>]
|
|
183
|
+
def only_runtime_dependencies gemspec
|
|
184
|
+
gemspec.dependencies - gemspec.development_dependencies
|
|
185
|
+
end
|
|
145
186
|
end
|
|
146
187
|
end
|
data/lib/solargraph/gem_pins.rb
CHANGED
|
@@ -16,13 +16,21 @@ module Solargraph
|
|
|
16
16
|
def self.build(gemspec)
|
|
17
17
|
yard_pins = build_yard_pins(gemspec)
|
|
18
18
|
rbs_map = RbsMap.from_gemspec(gemspec)
|
|
19
|
+
combine yard_pins, rbs_map
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param yard_pins [Array<Pin::Base>]
|
|
23
|
+
# @param rbs_map [RbsMap]
|
|
24
|
+
# @return [Array<Pin::Base>]
|
|
25
|
+
def self.combine(yard_pins, rbs_map)
|
|
19
26
|
in_yard = Set.new
|
|
20
27
|
combined = yard_pins.map do |yard|
|
|
21
28
|
in_yard.add yard.path
|
|
22
29
|
next yard unless yard.is_a?(Pin::Method)
|
|
23
|
-
|
|
30
|
+
|
|
31
|
+
rbs = rbs_map.path_pin(yard.path, Pin::Method)
|
|
24
32
|
next yard unless rbs
|
|
25
|
-
|
|
33
|
+
|
|
26
34
|
# @sg-ignore
|
|
27
35
|
yard.class.new(
|
|
28
36
|
location: yard.location,
|
|
@@ -34,7 +34,7 @@ module Solargraph
|
|
|
34
34
|
def update_libraries uri
|
|
35
35
|
src = sources.find(uri)
|
|
36
36
|
using = libraries.select { |lib| lib.contain?(src.filename) }
|
|
37
|
-
using.push
|
|
37
|
+
using.push library_for(uri) if using.empty?
|
|
38
38
|
using.each { |lib| lib.merge src }
|
|
39
39
|
diagnoser.schedule uri
|
|
40
40
|
end
|
|
@@ -95,6 +95,10 @@ module Solargraph
|
|
|
95
95
|
nil
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
def options
|
|
99
|
+
@options ||= {}.freeze
|
|
100
|
+
end
|
|
101
|
+
|
|
98
102
|
# Get a generic library for the given URI and attach the corresponding
|
|
99
103
|
# source.
|
|
100
104
|
#
|
|
@@ -109,7 +113,14 @@ module Solargraph
|
|
|
109
113
|
|
|
110
114
|
# @return [Library]
|
|
111
115
|
def generic_library
|
|
112
|
-
@generic_library ||= Solargraph::Library.new
|
|
116
|
+
@generic_library ||= Solargraph::Library.new(Solargraph::Workspace.new('', nil, options), nil)
|
|
117
|
+
.tap { |lib| lib.add_observer self }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @param library [Solargraph::Library]
|
|
121
|
+
# @return [void]
|
|
122
|
+
def update progress
|
|
123
|
+
progress&.send(self)
|
|
113
124
|
end
|
|
114
125
|
end
|
|
115
126
|
end
|