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