solargraph 0.47.2 → 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/.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 +166 -3
- data/LICENSE +1 -1
- data/README.md +19 -16
- data/SPONSORS.md +2 -9
- data/lib/solargraph/api_map/cache.rb +50 -20
- data/lib/solargraph/api_map/source_to_yard.rb +17 -10
- data/lib/solargraph/api_map/store.rb +68 -15
- data/lib/solargraph/api_map.rb +238 -112
- data/lib/solargraph/bench.rb +3 -2
- data/lib/solargraph/cache.rb +77 -0
- data/lib/solargraph/complex_type/type_methods.rb +116 -35
- data/lib/solargraph/complex_type/unique_type.rb +261 -33
- data/lib/solargraph/complex_type.rb +149 -30
- 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 +187 -0
- data/lib/solargraph/gem_pins.rb +72 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
- data/lib/solargraph/language_server/host/dispatch.rb +22 -5
- data/lib/solargraph/language_server/host/message_worker.rb +4 -0
- data/lib/solargraph/language_server/host/sources.rb +8 -65
- data/lib/solargraph/language_server/host.rb +88 -93
- data/lib/solargraph/language_server/message/base.rb +1 -1
- 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 +27 -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 +5 -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/progress.rb +118 -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/language_server.rb +1 -0
- data/lib/solargraph/library.rb +231 -104
- 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 +11 -1
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
- 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 +495 -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/{rubyvm → 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/parser_gem/node_processors/masgn_node.rb +47 -0
- 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 +7 -5
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -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 +40 -7
- data/lib/solargraph/pin/block.rb +81 -33
- 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 +101 -0
- data/lib/solargraph/pin/documenting.rb +25 -32
- data/lib/solargraph/pin/instance_variable.rb +4 -0
- data/lib/solargraph/pin/local_variable.rb +13 -1
- data/lib/solargraph/pin/method.rb +273 -17
- data/lib/solargraph/pin/namespace.rb +17 -1
- data/lib/solargraph/pin/parameter.rb +40 -28
- 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 +607 -0
- data/lib/solargraph/rbs_map/core_fills.rb +50 -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 +92 -0
- data/lib/solargraph/shell.rb +85 -59
- 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 +64 -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/updater.rb +1 -0
- data/lib/solargraph/source.rb +18 -63
- data/lib/solargraph/source_map/clip.rb +31 -23
- data/lib/solargraph/source_map/mapper.rb +23 -7
- data/lib/solargraph/source_map.rb +36 -11
- data/lib/solargraph/type_checker/checks.rb +10 -2
- data/lib/solargraph/type_checker.rb +229 -100
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +2 -2
- data/lib/solargraph/workspace/config.rb +15 -11
- data/lib/solargraph/workspace.rb +41 -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 +23 -7
- 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 +164 -99
- 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/language_server/host/cataloger.rb +0 -56
- 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/cvasgn_node.rb +0 -23
- 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/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|
|
@@ -242,8 +268,9 @@ module Solargraph
|
|
242
268
|
base = base.base
|
243
269
|
end
|
244
270
|
closest = found.typify(api_map) if found
|
271
|
+
# @todo remove the internal_or_core? check at a higher-than-strict level
|
245
272
|
if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
|
246
|
-
unless ignored_pins.include?(found)
|
273
|
+
unless closest.generic? || ignored_pins.include?(found)
|
247
274
|
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
|
248
275
|
@marked_ranges.push rng
|
249
276
|
end
|
@@ -254,88 +281,178 @@ module Solargraph
|
|
254
281
|
result
|
255
282
|
end
|
256
283
|
|
284
|
+
# @param chain [Solargraph::Source::Chain]
|
285
|
+
# @param api_map [Solargraph::ApiMap]
|
286
|
+
# @param block_pin [Solargraph::Pin::Base]
|
287
|
+
# @param locals [Array<Solargraph::Pin::Base>]
|
288
|
+
# @param location [Solargraph::Location]
|
289
|
+
# @return [Array<Problem>]
|
257
290
|
def argument_problems_for chain, api_map, block_pin, locals, location
|
258
291
|
result = []
|
259
292
|
base = chain
|
260
293
|
until base.links.length == 1 && base.undefined?
|
294
|
+
last_base_link = base.links.last
|
295
|
+
break unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
|
296
|
+
|
297
|
+
arguments = last_base_link.arguments
|
298
|
+
|
261
299
|
pins = base.define(api_map, block_pin, locals)
|
262
|
-
|
300
|
+
|
301
|
+
first_pin = pins.first
|
302
|
+
if first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
|
303
|
+
# Do nothing, as we can't find the actual method implementation
|
304
|
+
elsif first_pin.is_a?(Pin::Method)
|
263
305
|
# @type [Pin::Method]
|
264
|
-
pin =
|
306
|
+
pin = first_pin
|
265
307
|
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
266
308
|
arity_problems_for(pin, fake_args_for(block_pin), location)
|
309
|
+
elsif pin.path == 'Class#new'
|
310
|
+
fqns = if base.links.one?
|
311
|
+
block_pin.namespace
|
312
|
+
else
|
313
|
+
base.base.infer(api_map, block_pin, locals).namespace
|
314
|
+
end
|
315
|
+
init = api_map.get_method_stack(fqns, 'initialize').first
|
316
|
+
init ? arity_problems_for(init, arguments, location) : []
|
267
317
|
else
|
268
|
-
arity_problems_for(pin,
|
318
|
+
arity_problems_for(pin, arguments, location)
|
269
319
|
end
|
270
320
|
unless ap.empty?
|
271
321
|
result.concat ap
|
272
322
|
break
|
273
323
|
end
|
274
|
-
break
|
324
|
+
break if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
|
325
|
+
|
275
326
|
params = first_param_hash(pins)
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
if
|
289
|
-
|
327
|
+
|
328
|
+
all_errors = []
|
329
|
+
pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
|
330
|
+
errors = []
|
331
|
+
sig.parameters.each_with_index do |par, idx|
|
332
|
+
# @todo add logic mapping up restarg parameters with
|
333
|
+
# arguments (including restarg arguments). Use tuples
|
334
|
+
# when possible, and when not, ensure provably
|
335
|
+
# incorrect situations are detected.
|
336
|
+
break if par.decl == :restarg # bail out pending better arg processing
|
337
|
+
argchain = arguments[idx]
|
338
|
+
if argchain.nil?
|
339
|
+
if par.decl == :arg
|
340
|
+
final_arg = arguments.last
|
341
|
+
if final_arg && final_arg.node.type == :splat
|
342
|
+
argchain = final_arg
|
343
|
+
next # don't try to apply the type of the splat - unlikely to be specific enough
|
344
|
+
else
|
345
|
+
errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
|
346
|
+
next
|
347
|
+
end
|
348
|
+
else
|
349
|
+
final_arg = arguments.last
|
350
|
+
argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
if argchain
|
354
|
+
if par.decl != :arg
|
355
|
+
errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
356
|
+
next
|
290
357
|
else
|
291
|
-
|
292
|
-
|
293
|
-
|
358
|
+
if argchain.node.type == :splat && argchain == arguments.last
|
359
|
+
final_arg = argchain
|
360
|
+
end
|
361
|
+
if (final_arg && final_arg.node.type == :splat)
|
362
|
+
# The final argument given has been seen and was a
|
363
|
+
# splat, which doesn't give us useful types or
|
364
|
+
# arities against positional parameters, so let's
|
365
|
+
# continue on in case there are any required
|
366
|
+
# kwargs we should warn about
|
367
|
+
next
|
368
|
+
end
|
369
|
+
|
370
|
+
if argchain.node.type == :splat && par != sig.parameters.last
|
371
|
+
# we have been given a splat and there are more
|
372
|
+
# arguments to come.
|
373
|
+
|
374
|
+
# @todo Improve this so that we can skip past the
|
375
|
+
# rest of the positional parameters here but still
|
376
|
+
# process the kwargs
|
377
|
+
break
|
378
|
+
end
|
379
|
+
ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
|
380
|
+
ptype = ptype.self_to(par.context.namespace)
|
381
|
+
if ptype.nil?
|
382
|
+
# @todo Some level (strong, I guess) should require the param here
|
383
|
+
else
|
384
|
+
argtype = argchain.infer(api_map, block_pin, locals)
|
385
|
+
if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
|
386
|
+
errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
387
|
+
next
|
388
|
+
end
|
294
389
|
end
|
295
390
|
end
|
391
|
+
elsif par.decl == :kwarg
|
392
|
+
errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
393
|
+
next
|
296
394
|
end
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
395
|
+
end
|
396
|
+
if errors.empty?
|
397
|
+
all_errors.clear
|
301
398
|
break
|
302
399
|
end
|
400
|
+
all_errors.concat errors
|
303
401
|
end
|
402
|
+
result.concat all_errors
|
304
403
|
end
|
305
404
|
base = base.base
|
306
405
|
end
|
307
406
|
result
|
308
407
|
end
|
309
408
|
|
310
|
-
|
409
|
+
# @param sig [Pin::Signature]
|
410
|
+
# @param argchain [Source::Chain]
|
411
|
+
# @param api_map [ApiMap]
|
412
|
+
# @param block_pin [Pin::Block]
|
413
|
+
# @param locals [Array<Pin::LocalVariable>]
|
414
|
+
# @param location [Location]
|
415
|
+
# @param pin [Pin::Method]
|
416
|
+
# @param params [Hash{String => [nil, Hash]}]
|
417
|
+
# @param idx [Integer]
|
418
|
+
#
|
419
|
+
# @return [Array<Problem>]
|
420
|
+
def kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
311
421
|
result = []
|
312
422
|
kwargs = convert_hash(argchain.node)
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
next if ptype.undefined?
|
423
|
+
par = sig.parameters[idx]
|
424
|
+
argchain = kwargs[par.name.to_sym]
|
425
|
+
if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
|
426
|
+
result.concat kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
427
|
+
else
|
428
|
+
if argchain
|
429
|
+
data = params[par.name]
|
430
|
+
if data.nil?
|
431
|
+
# @todo Some level (strong, I guess) should require the param here
|
432
|
+
else
|
433
|
+
ptype = data[:qualified]
|
434
|
+
unless ptype.undefined?
|
326
435
|
argtype = argchain.infer(api_map, block_pin, locals)
|
327
436
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
328
437
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
329
438
|
end
|
330
439
|
end
|
331
|
-
elsif par.decl == :kwarg
|
332
|
-
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
333
440
|
end
|
441
|
+
elsif par.decl == :kwarg
|
442
|
+
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
334
443
|
end
|
335
444
|
end
|
336
445
|
result
|
337
446
|
end
|
338
447
|
|
448
|
+
# @param api_map [ApiMap]
|
449
|
+
# @param block_pin [Pin::Block]
|
450
|
+
# @param locals [Array<Pin::LocalVariable>]
|
451
|
+
# @param location [Location]
|
452
|
+
# @param pin [Pin::Method]
|
453
|
+
# @param params [Hash{String => [nil, Hash]}]
|
454
|
+
# @param kwargs [Hash{Symbol => Source::Chain}]
|
455
|
+
# @return [Array<Problem>]
|
339
456
|
def kwrestarg_problems_for(api_map, block_pin, locals, location, pin, params, kwargs)
|
340
457
|
result = []
|
341
458
|
kwargs.each_pair do |pname, argchain|
|
@@ -349,8 +466,8 @@ module Solargraph
|
|
349
466
|
result
|
350
467
|
end
|
351
468
|
|
352
|
-
# @param [Pin::Method]
|
353
|
-
# @return [Hash]
|
469
|
+
# @param pin [Pin::Method]
|
470
|
+
# @return [Hash{String => Hash{Symbol => BaseObject}}]
|
354
471
|
def param_hash(pin)
|
355
472
|
tags = pin.docstring.tags(:param)
|
356
473
|
return {} if tags.empty?
|
@@ -365,10 +482,12 @@ module Solargraph
|
|
365
482
|
result
|
366
483
|
end
|
367
484
|
|
368
|
-
# @param [Array<Pin::Method>]
|
369
|
-
# @return [Hash]
|
485
|
+
# @param pins [Array<Pin::Method>]
|
486
|
+
# @return [Hash{String => Hash{Symbol => BasicObject}}]
|
370
487
|
def first_param_hash(pins)
|
371
488
|
pins.each do |pin|
|
489
|
+
# @todo this assignment from parametric use of Hash should not lose its generic
|
490
|
+
# @type [Hash{String => Hash{Symbol => BasicObject}}]
|
372
491
|
result = param_hash(pin)
|
373
492
|
return result unless result.empty?
|
374
493
|
end
|
@@ -381,8 +500,11 @@ module Solargraph
|
|
381
500
|
pin.location && api_map.bundled?(pin.location.filename)
|
382
501
|
end
|
383
502
|
|
503
|
+
# True if the pin is either internal (part of the workspace) or from the core/stdlib
|
504
|
+
# @param pin [Pin::Base]
|
384
505
|
def internal_or_core? pin
|
385
|
-
|
506
|
+
# @todo RBS pins are not necessarily core/stdlib pins
|
507
|
+
internal?(pin) || pin.source == :rbs
|
386
508
|
end
|
387
509
|
|
388
510
|
# @param pin [Pin::Base]
|
@@ -390,6 +512,7 @@ module Solargraph
|
|
390
512
|
!internal? pin
|
391
513
|
end
|
392
514
|
|
515
|
+
# @param pin [Pin::Base]
|
393
516
|
def declared_externally? pin
|
394
517
|
return true if pin.assignment.nil?
|
395
518
|
chain = Solargraph::Parser.chain(pin.assignment, filename)
|
@@ -418,41 +541,44 @@ module Solargraph
|
|
418
541
|
end
|
419
542
|
|
420
543
|
# @param pin [Pin::Method]
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
544
|
+
# @param arguments [Array<Source::Chain>]
|
545
|
+
# @param location [Location]
|
546
|
+
# @return [Array<Problem>]
|
547
|
+
def arity_problems_for pin, arguments, location
|
548
|
+
results = pin.signatures.map do |sig|
|
549
|
+
r = parameterized_arity_problems_for(pin, sig.parameters, arguments, location)
|
550
|
+
return [] if r.empty?
|
551
|
+
r
|
552
|
+
end
|
553
|
+
results.first
|
427
554
|
end
|
428
555
|
|
429
556
|
# @param pin [Pin::Method]
|
430
|
-
|
557
|
+
# @param parameters [Array<Pin::Parameter>]
|
558
|
+
# @param arguments [Array<Source::Chain>]
|
559
|
+
# @param location [Location]
|
560
|
+
# @return [Array<Problem>]
|
561
|
+
def parameterized_arity_problems_for(pin, parameters, arguments, location)
|
431
562
|
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
|
563
|
+
return [] if parameters.empty? && arguments.empty?
|
564
|
+
return [] if pin.anon_splat?
|
439
565
|
unchecked = arguments.clone
|
440
566
|
add_params = 0
|
441
|
-
if unchecked.empty? &&
|
567
|
+
if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
|
442
568
|
return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
|
443
569
|
end
|
444
570
|
settled_kwargs = 0
|
445
571
|
unless unchecked.empty?
|
446
572
|
if any_splatted_call?(unchecked.map(&:node))
|
447
|
-
settled_kwargs =
|
573
|
+
settled_kwargs = parameters.count(&:keyword?)
|
448
574
|
else
|
449
575
|
kwargs = convert_hash(unchecked.last.node)
|
450
|
-
if
|
576
|
+
if parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
|
451
577
|
if kwargs.empty?
|
452
578
|
add_params += 1
|
453
579
|
else
|
454
580
|
unchecked.pop
|
455
|
-
|
581
|
+
parameters.each do |param|
|
456
582
|
next unless param.keyword?
|
457
583
|
if kwargs.key?(param.name.to_sym)
|
458
584
|
kwargs.delete param.name.to_sym
|
@@ -462,7 +588,7 @@ module Solargraph
|
|
462
588
|
return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
|
463
589
|
end
|
464
590
|
end
|
465
|
-
kwargs.clear if
|
591
|
+
kwargs.clear if parameters.any?(&:kwrestarg?)
|
466
592
|
unless kwargs.empty?
|
467
593
|
return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
|
468
594
|
end
|
@@ -470,18 +596,15 @@ module Solargraph
|
|
470
596
|
end
|
471
597
|
end
|
472
598
|
end
|
473
|
-
req = required_param_count(
|
599
|
+
req = required_param_count(parameters)
|
474
600
|
if req + add_params < unchecked.length
|
475
|
-
return [] if
|
476
|
-
opt = optional_param_count(
|
601
|
+
return [] if parameters.any?(&:rest?)
|
602
|
+
opt = optional_param_count(parameters)
|
477
603
|
return [] if unchecked.length <= req + opt
|
478
|
-
if
|
604
|
+
if req + add_params + 1 == unchecked.length && any_splatted_call?(unchecked.map(&:node)) && (parameters.map(&:decl) & [:kwarg, :kwoptarg, :kwrestarg]).any?
|
479
605
|
return []
|
480
606
|
end
|
481
|
-
|
482
|
-
return []
|
483
|
-
end
|
484
|
-
return [] if arguments.length - req == pin.parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
|
607
|
+
return [] if arguments.length - req == parameters.select { |p| [:optarg, :kwoptarg].include?(p.decl) }.length
|
485
608
|
return [Problem.new(location, "Too many arguments to #{pin.path}")]
|
486
609
|
elsif unchecked.length < req - settled_kwargs && (arguments.empty? || (!arguments.last.splat? && !arguments.last.links.last.is_a?(Solargraph::Source::Chain::Hash)))
|
487
610
|
# HACK: Kernel#raise signature is incorrect in Ruby 2.7 core docs.
|
@@ -493,26 +616,30 @@ module Solargraph
|
|
493
616
|
[]
|
494
617
|
end
|
495
618
|
|
496
|
-
# @param
|
497
|
-
|
498
|
-
|
619
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
620
|
+
# @todo need to use generic types in method to choose correct
|
621
|
+
# signature and generate Integer as return type
|
622
|
+
# @sg-ignore
|
623
|
+
# @return [Integer]
|
624
|
+
def required_param_count(parameters)
|
625
|
+
parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
|
499
626
|
end
|
500
627
|
|
628
|
+
# @param parameters [Enumerable<Pin::Parameter>]
|
501
629
|
# @param pin [Pin::Method]
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
next unless param.decl == :optarg
|
506
|
-
count += 1
|
507
|
-
end
|
508
|
-
count
|
630
|
+
# @return [Integer]
|
631
|
+
def optional_param_count(parameters)
|
632
|
+
parameters.select { |p| p.decl == :optarg }.length
|
509
633
|
end
|
510
634
|
|
635
|
+
# @param pin [Pin::Method]
|
511
636
|
def abstract? pin
|
512
|
-
pin.docstring.has_tag?(
|
513
|
-
(pin.closure && pin.closure.docstring.has_tag?(
|
637
|
+
pin.docstring.has_tag?('abstract') ||
|
638
|
+
(pin.closure && pin.closure.docstring.has_tag?('abstract'))
|
514
639
|
end
|
515
640
|
|
641
|
+
# @param pin [Pin::Base]
|
642
|
+
# @return [Array<Source::Chain>]
|
516
643
|
def fake_args_for(pin)
|
517
644
|
args = []
|
518
645
|
with_opts = false
|
@@ -533,10 +660,12 @@ module Solargraph
|
|
533
660
|
args
|
534
661
|
end
|
535
662
|
|
663
|
+
# @param problems [Array<Problem>]
|
664
|
+
# @return [Array<Problem>]
|
536
665
|
def without_ignored problems
|
537
666
|
problems.reject do |problem|
|
538
667
|
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')
|
668
|
+
node && source_map.source.comments_for(node)&.include?('@sg-ignore')
|
540
669
|
end
|
541
670
|
end
|
542
671
|
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,13 @@ module Solargraph
|
|
14
14
|
# @return [String]
|
15
15
|
attr_reader :directory
|
16
16
|
|
17
|
-
# @
|
17
|
+
# @todo To make this strongly typed we'll need a record syntax
|
18
|
+
# @return [Hash{String => undefined}]
|
18
19
|
attr_reader :raw_data
|
19
20
|
|
20
21
|
# @param directory [String]
|
21
22
|
def initialize directory = ''
|
22
|
-
@directory = directory
|
23
|
+
@directory = File.absolute_path(directory)
|
23
24
|
@raw_data = config_data
|
24
25
|
included
|
25
26
|
excluded
|
@@ -41,8 +42,10 @@ module Solargraph
|
|
41
42
|
@excluded ||= process_exclusions(@raw_data['exclude'])
|
42
43
|
end
|
43
44
|
|
45
|
+
# @param filename [String]
|
44
46
|
def allow? filename
|
45
|
-
filename.
|
47
|
+
filename = File.absolute_path(filename, directory)
|
48
|
+
filename.start_with?(directory) &&
|
46
49
|
!excluded.include?(filename) &&
|
47
50
|
excluded_directories.none? { |d| filename.start_with?(d) }
|
48
51
|
end
|
@@ -110,7 +113,7 @@ module Solargraph
|
|
110
113
|
|
111
114
|
# @return [String]
|
112
115
|
def global_config_path
|
113
|
-
ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
|
116
|
+
ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
|
114
117
|
File.join(Dir.home, '.config', 'solargraph', 'config.yml')
|
115
118
|
end
|
116
119
|
|
@@ -120,7 +123,7 @@ module Solargraph
|
|
120
123
|
File.join(@directory, '.solargraph.yml')
|
121
124
|
end
|
122
125
|
|
123
|
-
# @return [Hash]
|
126
|
+
# @return [Hash{String => Array, Hash, Integer}]
|
124
127
|
def config_data
|
125
128
|
workspace_config = read_config(workspace_config_path)
|
126
129
|
global_config = read_config(global_config_path)
|
@@ -135,15 +138,15 @@ module Solargraph
|
|
135
138
|
|
136
139
|
# Read a .solargraph yaml config
|
137
140
|
#
|
138
|
-
# @param
|
139
|
-
# @return [Hash, nil]
|
141
|
+
# @param config_path [String]
|
142
|
+
# @return [Hash{String => Array, Hash, Integer}, nil]
|
140
143
|
def read_config config_path = ''
|
141
144
|
return nil if config_path.empty?
|
142
145
|
return nil unless File.file?(config_path)
|
143
146
|
YAML.safe_load(File.read(config_path))
|
144
147
|
end
|
145
148
|
|
146
|
-
# @return [Hash]
|
149
|
+
# @return [Hash{String => Array, Hash, Integer}]
|
147
150
|
def default_config
|
148
151
|
{
|
149
152
|
'include' => ['**/*.rb'],
|
@@ -171,7 +174,7 @@ module Solargraph
|
|
171
174
|
# @return [Array<String>]
|
172
175
|
def process_globs globs
|
173
176
|
result = globs.flat_map do |glob|
|
174
|
-
Dir[File.
|
177
|
+
Dir[File.absolute_path(glob, directory)]
|
175
178
|
.map{ |f| f.gsub(/\\/, '/') }
|
176
179
|
.select { |f| File.file?(f) }
|
177
180
|
end
|
@@ -186,7 +189,7 @@ module Solargraph
|
|
186
189
|
def process_exclusions globs
|
187
190
|
remainder = globs.select do |glob|
|
188
191
|
if glob_is_directory?(glob)
|
189
|
-
exdir = File.
|
192
|
+
exdir = File.absolute_path(glob_to_directory(glob), directory)
|
190
193
|
included.delete_if { |file| file.start_with?(exdir) }
|
191
194
|
false
|
192
195
|
else
|
@@ -221,10 +224,11 @@ module Solargraph
|
|
221
224
|
glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
|
222
225
|
end
|
223
226
|
|
227
|
+
# @return [Array<String>]
|
224
228
|
def excluded_directories
|
225
229
|
@raw_data['exclude']
|
226
230
|
.select { |g| glob_is_directory?(g) }
|
227
|
-
.map { |g| File.
|
231
|
+
.map { |g| File.absolute_path(glob_to_directory(g), directory) }
|
228
232
|
end
|
229
233
|
end
|
230
234
|
end
|