solargraph 0.57.0 → 0.58.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/workflows/linting.yml +4 -2
- data/.github/workflows/plugins.yml +61 -27
- data/.github/workflows/rspec.yml +19 -4
- data/.github/workflows/typecheck.yml +2 -2
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +90 -1438
- data/CHANGELOG.md +27 -0
- data/Rakefile +1 -1
- data/bin/solargraph +8 -5
- data/lib/solargraph/api_map/constants.rb +107 -46
- data/lib/solargraph/api_map/index.rb +32 -8
- data/lib/solargraph/api_map/source_to_yard.rb +5 -2
- data/lib/solargraph/api_map/store.rb +22 -12
- data/lib/solargraph/api_map.rb +27 -33
- data/lib/solargraph/complex_type/type_methods.rb +5 -0
- data/lib/solargraph/complex_type/unique_type.rb +12 -5
- data/lib/solargraph/complex_type.rb +19 -2
- data/lib/solargraph/convention/active_support_concern.rb +1 -1
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +1 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -2
- data/lib/solargraph/doc_map.rb +9 -6
- data/lib/solargraph/environ.rb +1 -1
- data/lib/solargraph/equality.rb +1 -0
- data/lib/solargraph/gem_pins.rb +4 -0
- data/lib/solargraph/language_server/host.rb +10 -4
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -2
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -1
- data/lib/solargraph/language_server/progress.rb +1 -1
- data/lib/solargraph/language_server/request.rb +3 -1
- data/lib/solargraph/library.rb +3 -3
- data/lib/solargraph/location.rb +1 -0
- data/lib/solargraph/page.rb +0 -1
- data/lib/solargraph/parser/flow_sensitive_typing.rb +1 -1
- data/lib/solargraph/parser/parser_gem/class_methods.rb +2 -12
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -14
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +64 -8
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +4 -5
- data/lib/solargraph/pin/base.rb +29 -8
- data/lib/solargraph/pin/base_variable.rb +5 -3
- data/lib/solargraph/pin/block.rb +3 -2
- data/lib/solargraph/pin/callable.rb +6 -2
- data/lib/solargraph/pin/closure.rb +3 -7
- data/lib/solargraph/pin/delegated_method.rb +0 -1
- data/lib/solargraph/pin/local_variable.rb +0 -4
- data/lib/solargraph/pin/method.rb +20 -4
- data/lib/solargraph/pin/parameter.rb +6 -2
- data/lib/solargraph/pin/proxy_type.rb +4 -1
- data/lib/solargraph/pin/reference.rb +2 -11
- data/lib/solargraph/pin/search.rb +3 -0
- data/lib/solargraph/pin_cache.rb +5 -5
- data/lib/solargraph/position.rb +1 -0
- data/lib/solargraph/range.rb +4 -0
- data/lib/solargraph/rbs_map/conversions.rb +22 -1
- data/lib/solargraph/rbs_map/core_fills.rb +18 -0
- data/lib/solargraph/rbs_map/core_map.rb +11 -7
- data/lib/solargraph/rbs_map.rb +2 -2
- data/lib/solargraph/shell.rb +82 -1
- data/lib/solargraph/source/chain/call.rb +7 -3
- data/lib/solargraph/source/chain/constant.rb +3 -66
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +1 -1
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +2 -0
- data/lib/solargraph/source.rb +1 -1
- data/lib/solargraph/source_map/clip.rb +17 -25
- data/lib/solargraph/source_map/mapper.rb +0 -2
- data/lib/solargraph/source_map.rb +8 -3
- data/lib/solargraph/type_checker/rules.rb +23 -9
- data/lib/solargraph/type_checker.rb +133 -71
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +21 -3
- data/lib/solargraph/workspace/require_paths.rb +0 -1
- data/lib/solargraph/workspace.rb +14 -19
- data/lib/solargraph/yard_map/mapper/to_method.rb +2 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/to_method.rb +2 -1
- data/lib/solargraph/yardoc.rb +27 -4
- data/rbs/fills/bundler/0/bundler.rbs +4271 -0
- data/rbs/fills/open3/0/open3.rbs +172 -0
- data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
- data/rbs/fills/rubygems/0/errors.rbs +364 -0
- data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
- data/rbs/fills/rubygems/0/specification.rbs +1753 -0
- data/rbs_collection.yaml +4 -4
- data/sig/shims/ast/0/node.rbs +5 -0
- data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
- data/sig/shims/ast/2.4/ast.rbs +73 -0
- data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
- data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
- data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
- data/solargraph.gemspec +15 -4
- metadata +66 -12
- data/lib/solargraph/parser/node_methods.rb +0 -97
- /data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +0 -0
|
@@ -41,11 +41,13 @@ module Solargraph
|
|
|
41
41
|
# solargraph-rails is known to use this method to get the document symbols. It should probably be removed.
|
|
42
42
|
@document_symbols = nil
|
|
43
43
|
self.convention_pins = conventions_environ.pins
|
|
44
|
+
# @type [Hash{Class<Pin::Base> => Array<Pin::Base>}]
|
|
44
45
|
@pin_select_cache = {}
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
# @generic T
|
|
48
49
|
# @param klass [Class<generic<T>>]
|
|
50
|
+
#
|
|
49
51
|
# @return [Array<generic<T>>]
|
|
50
52
|
def pins_by_class klass
|
|
51
53
|
@pin_select_cache[klass] ||= pin_class_hash.select { |key, _| key <= klass }.values.flatten
|
|
@@ -124,10 +126,13 @@ module Solargraph
|
|
|
124
126
|
# @param line [Integer]
|
|
125
127
|
# @param character [Integer]
|
|
126
128
|
# @return [Pin::Namespace,Pin::Method,Pin::Block]
|
|
127
|
-
def
|
|
128
|
-
_locate_pin line, character, Pin::
|
|
129
|
+
def locate_closure_pin line, character
|
|
130
|
+
_locate_pin line, character, Pin::Closure
|
|
129
131
|
end
|
|
130
132
|
|
|
133
|
+
# @deprecated Please use locate_closure_pin instead
|
|
134
|
+
alias locate_block_pin locate_closure_pin
|
|
135
|
+
|
|
131
136
|
# @param name [String]
|
|
132
137
|
# @return [Array<Location>]
|
|
133
138
|
def references name
|
|
@@ -168,10 +173,10 @@ module Solargraph
|
|
|
168
173
|
|
|
169
174
|
private
|
|
170
175
|
|
|
171
|
-
# @return [Hash{Class => Array<Pin::Base>}]
|
|
172
176
|
# @return [Array<Pin::Base>]
|
|
173
177
|
attr_writer :convention_pins
|
|
174
178
|
|
|
179
|
+
# @return [Hash{Class<Pin::Base> => Array<Pin::Base>}]
|
|
175
180
|
def pin_class_hash
|
|
176
181
|
@pin_class_hash ||= pins.to_set.classify(&:class).transform_values(&:to_a)
|
|
177
182
|
end
|
|
@@ -20,7 +20,8 @@ module Solargraph
|
|
|
20
20
|
attr_reader :rank
|
|
21
21
|
|
|
22
22
|
# @param level [Symbol]
|
|
23
|
-
|
|
23
|
+
# @param overrides [Hash{Symbol => Symbol}]
|
|
24
|
+
def initialize level, overrides
|
|
24
25
|
@rank = if LEVELS.key?(level)
|
|
25
26
|
LEVELS[level]
|
|
26
27
|
else
|
|
@@ -28,34 +29,39 @@ module Solargraph
|
|
|
28
29
|
0
|
|
29
30
|
end
|
|
30
31
|
@level = LEVELS[LEVELS.values.index(@rank)]
|
|
32
|
+
@overrides = overrides
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def ignore_all_undefined?
|
|
34
|
-
|
|
36
|
+
!report_undefined?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def report_undefined?
|
|
40
|
+
report?(:report_undefined, :strict)
|
|
35
41
|
end
|
|
36
42
|
|
|
37
43
|
def validate_consts?
|
|
38
|
-
|
|
44
|
+
report?(:validate_consts, :strict)
|
|
39
45
|
end
|
|
40
46
|
|
|
41
47
|
def validate_calls?
|
|
42
|
-
|
|
48
|
+
report?(:validate_calls, :strict)
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
def require_type_tags?
|
|
46
|
-
|
|
52
|
+
report?(:validate_type_tags, :strong)
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
def must_tag_or_infer?
|
|
50
|
-
|
|
56
|
+
report?(:must_tag_or_infer, :strict)
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
def validate_tags?
|
|
54
|
-
|
|
60
|
+
report?(:validate_tags, :typed)
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
def require_all_return_types_match_inferred?
|
|
58
|
-
|
|
64
|
+
report?(:require_all_return_types_match_inferred, :alpha)
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
# We keep this at strong because if you added an @ sg-ignore to
|
|
@@ -63,7 +69,15 @@ module Solargraph
|
|
|
63
69
|
# get a false positive - we don't run stronger level checks than
|
|
64
70
|
# requested for performance reasons
|
|
65
71
|
def validate_sg_ignores?
|
|
66
|
-
|
|
72
|
+
report?(:validate_sg_ignores, :strong)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# @param type [Symbol]
|
|
78
|
+
# @param level [Symbol]
|
|
79
|
+
def report?(type, level)
|
|
80
|
+
rank >= LEVELS[@overrides.fetch(type, level)]
|
|
67
81
|
end
|
|
68
82
|
end
|
|
69
83
|
end
|
|
@@ -21,14 +21,23 @@ module Solargraph
|
|
|
21
21
|
# @return [ApiMap]
|
|
22
22
|
attr_reader :api_map
|
|
23
23
|
|
|
24
|
-
# @param filename [String]
|
|
24
|
+
# @param filename [String, nil]
|
|
25
25
|
# @param api_map [ApiMap, nil]
|
|
26
|
-
# @param level [Symbol]
|
|
27
|
-
|
|
26
|
+
# @param level [Symbol] Don't complain about anything above this level
|
|
27
|
+
# @param workspace [Workspace, nil] Workspace to use for loading
|
|
28
|
+
# type checker rules modified by user config
|
|
29
|
+
# @param type_checker_rules [Hash{Symbol => Symbol}] Overrides for
|
|
30
|
+
# type checker rules - e.g., :report_undefined => :strong
|
|
31
|
+
# @param rules [Rules] Type checker rules object
|
|
32
|
+
def initialize filename,
|
|
33
|
+
api_map: nil,
|
|
34
|
+
level: :normal,
|
|
35
|
+
workspace: filename ? Workspace.new(File.dirname(filename)) : nil,
|
|
36
|
+
rules: workspace ? workspace.rules(level) : Rules.new(level, {})
|
|
28
37
|
@filename = filename
|
|
29
38
|
# @todo Smarter directory resolution
|
|
30
39
|
@api_map = api_map || Solargraph::ApiMap.load(File.dirname(filename))
|
|
31
|
-
@rules =
|
|
40
|
+
@rules = rules
|
|
32
41
|
# @type [Array<Range>]
|
|
33
42
|
@marked_ranges = []
|
|
34
43
|
end
|
|
@@ -96,7 +105,7 @@ module Solargraph
|
|
|
96
105
|
def method_return_type_problems_for pin
|
|
97
106
|
return [] if pin.is_a?(Pin::MethodAlias)
|
|
98
107
|
result = []
|
|
99
|
-
declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, pin.
|
|
108
|
+
declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, *pin.gates)
|
|
100
109
|
if declared.undefined?
|
|
101
110
|
if pin.return_type.undefined? && rules.require_type_tags?
|
|
102
111
|
if pin.attribute?
|
|
@@ -152,33 +161,32 @@ module Solargraph
|
|
|
152
161
|
# @return [Array<Problem>]
|
|
153
162
|
def method_param_type_problems_for pin
|
|
154
163
|
stack = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
|
|
155
|
-
params = first_param_hash(stack)
|
|
156
164
|
result = []
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
pin.signatures.each do |sig|
|
|
166
|
+
params = param_details_from_stack(sig, stack)
|
|
167
|
+
if rules.require_type_tags?
|
|
168
|
+
sig.parameters.each do |par|
|
|
169
|
+
break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
|
|
170
|
+
unless params[par.name]
|
|
171
|
+
if pin.attribute?
|
|
172
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
|
173
|
+
if inferred.undefined?
|
|
174
|
+
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
175
|
+
end
|
|
176
|
+
else
|
|
165
177
|
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
166
178
|
end
|
|
167
|
-
else
|
|
168
|
-
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
169
179
|
end
|
|
170
180
|
end
|
|
171
|
-
end
|
|
172
181
|
end
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
|
|
182
|
+
# @param name [String]
|
|
183
|
+
# @param data [Hash{Symbol => BasicObject}]
|
|
184
|
+
params.each_pair do |name, data|
|
|
185
|
+
# @type [ComplexType]
|
|
186
|
+
type = data[:qualified]
|
|
187
|
+
if type.undefined?
|
|
188
|
+
result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
|
|
189
|
+
end
|
|
182
190
|
end
|
|
183
191
|
end
|
|
184
192
|
result
|
|
@@ -196,7 +204,7 @@ module Solargraph
|
|
|
196
204
|
if pin.return_type.defined?
|
|
197
205
|
declared = pin.typify(api_map)
|
|
198
206
|
next if declared.duck_type?
|
|
199
|
-
if declared.defined?
|
|
207
|
+
if declared.defined? && pin.assignment
|
|
200
208
|
if rules.validate_tags?
|
|
201
209
|
inferred = pin.probe(api_map)
|
|
202
210
|
if inferred.undefined?
|
|
@@ -217,7 +225,7 @@ module Solargraph
|
|
|
217
225
|
elsif !pin.is_a?(Pin::Parameter) && !resolved_constant?(pin)
|
|
218
226
|
result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
|
|
219
227
|
end
|
|
220
|
-
|
|
228
|
+
elsif pin.assignment
|
|
221
229
|
inferred = pin.probe(api_map)
|
|
222
230
|
if inferred.undefined? && declared_externally?(pin)
|
|
223
231
|
ignored_pins.push pin
|
|
@@ -239,10 +247,11 @@ module Solargraph
|
|
|
239
247
|
Solargraph::Parser::NodeMethods.const_nodes_from(source.node).each do |const|
|
|
240
248
|
rng = Solargraph::Range.from_node(const)
|
|
241
249
|
chain = Solargraph::Parser.chain(const, filename)
|
|
242
|
-
|
|
250
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
251
|
+
closure_pin.rebind(api_map)
|
|
243
252
|
location = Location.new(filename, rng)
|
|
244
253
|
locals = source_map.locals_at(location)
|
|
245
|
-
pins = chain.define(api_map,
|
|
254
|
+
pins = chain.define(api_map, closure_pin, locals)
|
|
246
255
|
if pins.empty?
|
|
247
256
|
result.push Problem.new(location, "Unresolved constant #{Solargraph::Parser::NodeMethods.unpack_name(const)}")
|
|
248
257
|
@marked_ranges.push location.range
|
|
@@ -258,17 +267,25 @@ module Solargraph
|
|
|
258
267
|
rng = Solargraph::Range.from_node(call)
|
|
259
268
|
next if @marked_ranges.any? { |d| d.contain?(rng.start) }
|
|
260
269
|
chain = Solargraph::Parser.chain(call, filename)
|
|
261
|
-
|
|
270
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
271
|
+
namespace_pin = closure_pin
|
|
272
|
+
if call.type == :block
|
|
273
|
+
# blocks in the AST include the method call as well, so the
|
|
274
|
+
# node returned by #call_nodes_from needs to be backed out
|
|
275
|
+
# one closure
|
|
276
|
+
closure_pin = closure_pin.closure
|
|
277
|
+
end
|
|
278
|
+
closure_pin.rebind(api_map)
|
|
262
279
|
location = Location.new(filename, rng)
|
|
263
280
|
locals = source_map.locals_at(location)
|
|
264
|
-
type = chain.infer(api_map,
|
|
281
|
+
type = chain.infer(api_map, closure_pin, locals)
|
|
265
282
|
if type.undefined? && !rules.ignore_all_undefined?
|
|
266
283
|
base = chain
|
|
267
284
|
missing = chain
|
|
268
285
|
found = nil
|
|
269
286
|
closest = ComplexType::UNDEFINED
|
|
270
287
|
until base.links.first.undefined?
|
|
271
|
-
found = base.define(api_map,
|
|
288
|
+
found = base.define(api_map, closure_pin, locals).first
|
|
272
289
|
break if found
|
|
273
290
|
missing = base
|
|
274
291
|
base = base.base
|
|
@@ -286,7 +303,7 @@ module Solargraph
|
|
|
286
303
|
end
|
|
287
304
|
end
|
|
288
305
|
end
|
|
289
|
-
result.concat argument_problems_for(chain, api_map,
|
|
306
|
+
result.concat argument_problems_for(chain, api_map, closure_pin, locals, location)
|
|
290
307
|
end
|
|
291
308
|
result
|
|
292
309
|
end
|
|
@@ -309,8 +326,9 @@ module Solargraph
|
|
|
309
326
|
pins = base.define(api_map, closure_pin, locals)
|
|
310
327
|
|
|
311
328
|
first_pin = pins.first
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
if first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
|
|
330
|
+
# Do nothing, as we can't find the actual method implementation
|
|
331
|
+
elsif first_pin.is_a?(Pin::Method)
|
|
314
332
|
# @type [Pin::Method]
|
|
315
333
|
pin = first_pin
|
|
316
334
|
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
@@ -322,7 +340,6 @@ module Solargraph
|
|
|
322
340
|
base.base.infer(api_map, closure_pin, locals).namespace
|
|
323
341
|
end
|
|
324
342
|
init = api_map.get_method_stack(fqns, 'initialize').first
|
|
325
|
-
|
|
326
343
|
init ? arity_problems_for(init, arguments, location) : []
|
|
327
344
|
else
|
|
328
345
|
arity_problems_for(pin, arguments, location)
|
|
@@ -330,11 +347,12 @@ module Solargraph
|
|
|
330
347
|
return ap unless ap.empty?
|
|
331
348
|
return [] if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
332
349
|
|
|
333
|
-
params = first_param_hash(pins)
|
|
334
|
-
|
|
335
350
|
all_errors = []
|
|
336
351
|
pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
|
|
352
|
+
params = param_details_from_stack(sig, pins)
|
|
353
|
+
|
|
337
354
|
signature_errors = signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
|
|
355
|
+
|
|
338
356
|
if signature_errors.empty?
|
|
339
357
|
# we found a signature that works - meaning errors from
|
|
340
358
|
# other signatures don't matter.
|
|
@@ -411,6 +429,7 @@ module Solargraph
|
|
|
411
429
|
# @todo Some level (strong, I guess) should require the param here
|
|
412
430
|
else
|
|
413
431
|
argtype = argchain.infer(api_map, closure_pin, locals)
|
|
432
|
+
argtype = argtype.self_to_type(closure_pin.context)
|
|
414
433
|
if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
|
|
415
434
|
errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
416
435
|
return errors
|
|
@@ -428,7 +447,7 @@ module Solargraph
|
|
|
428
447
|
# @param sig [Pin::Signature]
|
|
429
448
|
# @param argchain [Source::Chain]
|
|
430
449
|
# @param api_map [ApiMap]
|
|
431
|
-
# @param
|
|
450
|
+
# @param closure_pin [Pin::Closure]
|
|
432
451
|
# @param locals [Array<Pin::LocalVariable>]
|
|
433
452
|
# @param location [Location]
|
|
434
453
|
# @param pin [Pin::Method]
|
|
@@ -436,13 +455,13 @@ module Solargraph
|
|
|
436
455
|
# @param idx [Integer]
|
|
437
456
|
#
|
|
438
457
|
# @return [Array<Problem>]
|
|
439
|
-
def kwarg_problems_for sig, argchain, api_map,
|
|
458
|
+
def kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
|
|
440
459
|
result = []
|
|
441
460
|
kwargs = convert_hash(argchain.node)
|
|
442
461
|
par = sig.parameters[idx]
|
|
443
462
|
argchain = kwargs[par.name.to_sym]
|
|
444
463
|
if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
|
|
445
|
-
result.concat kwrestarg_problems_for(api_map,
|
|
464
|
+
result.concat kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
|
|
446
465
|
else
|
|
447
466
|
if argchain
|
|
448
467
|
data = params[par.name]
|
|
@@ -450,8 +469,11 @@ module Solargraph
|
|
|
450
469
|
# @todo Some level (strong, I guess) should require the param here
|
|
451
470
|
else
|
|
452
471
|
ptype = data[:qualified]
|
|
472
|
+
ptype = ptype.self_to_type(pin.context)
|
|
453
473
|
unless ptype.undefined?
|
|
454
|
-
|
|
474
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1127
|
|
475
|
+
argtype = argchain.infer(api_map, closure_pin, locals).self_to_type(closure_pin.context)
|
|
476
|
+
# @sg-ignore Unresolved call to defined?
|
|
455
477
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
|
456
478
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
457
479
|
end
|
|
@@ -465,19 +487,21 @@ module Solargraph
|
|
|
465
487
|
end
|
|
466
488
|
|
|
467
489
|
# @param api_map [ApiMap]
|
|
468
|
-
# @param
|
|
490
|
+
# @param closure_pin [Pin::Closure]
|
|
469
491
|
# @param locals [Array<Pin::LocalVariable>]
|
|
470
492
|
# @param location [Location]
|
|
471
493
|
# @param pin [Pin::Method]
|
|
472
494
|
# @param params [Hash{String => [nil, Hash]}]
|
|
473
495
|
# @param kwargs [Hash{Symbol => Source::Chain}]
|
|
474
496
|
# @return [Array<Problem>]
|
|
475
|
-
def kwrestarg_problems_for(api_map,
|
|
497
|
+
def kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
|
|
476
498
|
result = []
|
|
477
499
|
kwargs.each_pair do |pname, argchain|
|
|
478
500
|
next unless params.key?(pname.to_s)
|
|
479
501
|
ptype = params[pname.to_s][:qualified]
|
|
480
|
-
|
|
502
|
+
ptype = ptype.self_to_type(pin.context)
|
|
503
|
+
argtype = argchain.infer(api_map, closure_pin, locals)
|
|
504
|
+
argtype = argtype.self_to_type(closure_pin.context)
|
|
481
505
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
|
482
506
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
|
|
483
507
|
end
|
|
@@ -485,9 +509,32 @@ module Solargraph
|
|
|
485
509
|
result
|
|
486
510
|
end
|
|
487
511
|
|
|
488
|
-
# @param
|
|
512
|
+
# @param param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
513
|
+
# @param pin [Pin::Method, Pin::Signature]
|
|
514
|
+
# @param relevant_pin [Pin::Method, Pin::Signature] the pin which is under inspection
|
|
515
|
+
# @return [void]
|
|
516
|
+
def add_restkwarg_param_tag_details(param_details, pin, relevant_pin)
|
|
517
|
+
# see if we have additional tags to pay attention to from YARD -
|
|
518
|
+
# e.g., kwargs in a **restkwargs splat
|
|
519
|
+
tags = pin.docstring.tags(:param)
|
|
520
|
+
tags.each do |tag|
|
|
521
|
+
next if param_details.key? tag.name.to_s
|
|
522
|
+
next if tag.types.nil?
|
|
523
|
+
details = {
|
|
524
|
+
tagged: tag.types.join(', '),
|
|
525
|
+
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
|
|
526
|
+
}
|
|
527
|
+
# don't complain about a param that didn't come from the pin we're looking at anyway
|
|
528
|
+
if details[:qualified].defined? ||
|
|
529
|
+
relevant_pin.parameter_names.include?(tag.name.to_s)
|
|
530
|
+
param_details[tag.name.to_s] = details
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
# @param pin [Pin::Signature]
|
|
489
536
|
# @return [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
490
|
-
def
|
|
537
|
+
def signature_param_details(pin)
|
|
491
538
|
# @type [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
492
539
|
result = {}
|
|
493
540
|
pin.parameters.each do |param|
|
|
@@ -506,36 +553,50 @@ module Solargraph
|
|
|
506
553
|
next if tag.types.nil?
|
|
507
554
|
result[tag.name.to_s] = {
|
|
508
555
|
tagged: tag.types.join(', '),
|
|
509
|
-
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.
|
|
556
|
+
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, *pin.closure.gates)
|
|
510
557
|
}
|
|
511
558
|
end
|
|
512
559
|
result
|
|
513
560
|
end
|
|
514
561
|
|
|
515
|
-
#
|
|
562
|
+
# The original signature defines the parameters, but other
|
|
563
|
+
# signatures and method pins can help by adding type information
|
|
564
|
+
#
|
|
565
|
+
# @param param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
566
|
+
# @param param_names [Array<String>]
|
|
567
|
+
# @param new_param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
568
|
+
#
|
|
569
|
+
# @return [void]
|
|
570
|
+
def add_to_param_details(param_details, param_names, new_param_details)
|
|
571
|
+
new_param_details.each do |param_name, details|
|
|
572
|
+
next unless param_names.include?(param_name)
|
|
573
|
+
|
|
574
|
+
param_details[param_name] ||= {}
|
|
575
|
+
param_details[param_name][:tagged] ||= details[:tagged]
|
|
576
|
+
param_details[param_name][:qualified] ||= details[:qualified]
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# @param signature [Pin::Signature]
|
|
581
|
+
# @param method_pin_stack [Array<Pin::Method>]
|
|
516
582
|
# @return [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
517
|
-
def
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
param_names =
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
# @type [Hash{String => Hash{Symbol => BasicObject}}]
|
|
583
|
+
def param_details_from_stack(signature, method_pin_stack)
|
|
584
|
+
signature_type = signature.typify(api_map)
|
|
585
|
+
signature = signature.proxy signature_type
|
|
586
|
+
param_details = signature_param_details(signature)
|
|
587
|
+
param_names = signature.parameter_names
|
|
588
|
+
|
|
589
|
+
method_pin_stack.each do |method_pin|
|
|
590
|
+
add_restkwarg_param_tag_details(param_details, method_pin, signature)
|
|
526
591
|
|
|
527
592
|
# documentation of types in superclasses should fail back to
|
|
528
593
|
# subclasses if the subclass hasn't documented something
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
results[param_name] ||= {}
|
|
534
|
-
results[param_name][:tagged] ||= details[:tagged]
|
|
535
|
-
results[param_name][:qualified] ||= details[:qualified]
|
|
594
|
+
method_pin.signatures.each do |sig|
|
|
595
|
+
add_restkwarg_param_tag_details(param_details, sig, signature)
|
|
596
|
+
add_to_param_details param_details, param_names, signature_param_details(sig)
|
|
536
597
|
end
|
|
537
598
|
end
|
|
538
|
-
|
|
599
|
+
param_details
|
|
539
600
|
end
|
|
540
601
|
|
|
541
602
|
# @param pin [Pin::Base]
|
|
@@ -558,20 +619,21 @@ module Solargraph
|
|
|
558
619
|
|
|
559
620
|
# @param pin [Pin::BaseVariable]
|
|
560
621
|
def declared_externally? pin
|
|
561
|
-
|
|
622
|
+
raise "No assignment found" if pin.assignment.nil?
|
|
623
|
+
|
|
562
624
|
chain = Solargraph::Parser.chain(pin.assignment, filename)
|
|
563
625
|
rng = Solargraph::Range.from_node(pin.assignment)
|
|
564
|
-
|
|
626
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
565
627
|
location = Location.new(filename, Range.from_node(pin.assignment))
|
|
566
628
|
locals = source_map.locals_at(location)
|
|
567
|
-
type = chain.infer(api_map,
|
|
629
|
+
type = chain.infer(api_map, closure_pin, locals)
|
|
568
630
|
if type.undefined? && !rules.ignore_all_undefined?
|
|
569
631
|
base = chain
|
|
570
632
|
missing = chain
|
|
571
633
|
found = nil
|
|
572
634
|
closest = ComplexType::UNDEFINED
|
|
573
635
|
until base.links.first.undefined?
|
|
574
|
-
found = base.define(api_map,
|
|
636
|
+
found = base.define(api_map, closure_pin, locals).first
|
|
575
637
|
break if found
|
|
576
638
|
missing = base
|
|
577
639
|
base = base.base
|
data/lib/solargraph/version.rb
CHANGED
|
@@ -14,8 +14,8 @@ module Solargraph
|
|
|
14
14
|
# @return [String]
|
|
15
15
|
attr_reader :directory
|
|
16
16
|
|
|
17
|
-
# @todo To make
|
|
18
|
-
# @return [Hash{String =>
|
|
17
|
+
# @todo To make JSON strongly typed we'll need a record syntax
|
|
18
|
+
# @return [Hash{String => undefined, nil}]
|
|
19
19
|
attr_reader :raw_data
|
|
20
20
|
|
|
21
21
|
# @param directory [String]
|
|
@@ -63,6 +63,7 @@ module Solargraph
|
|
|
63
63
|
# namespace. It's typically used to identify available DSLs.
|
|
64
64
|
#
|
|
65
65
|
# @return [Array<String>]
|
|
66
|
+
# @sg-ignore Need to validate config
|
|
66
67
|
def domains
|
|
67
68
|
raw_data['domains']
|
|
68
69
|
end
|
|
@@ -70,6 +71,7 @@ module Solargraph
|
|
|
70
71
|
# An array of required paths to add to the workspace.
|
|
71
72
|
#
|
|
72
73
|
# @return [Array<String>]
|
|
74
|
+
# @sg-ignore Need to validate config
|
|
73
75
|
def required
|
|
74
76
|
raw_data['require']
|
|
75
77
|
end
|
|
@@ -83,6 +85,7 @@ module Solargraph
|
|
|
83
85
|
|
|
84
86
|
# An array of reporters to use for diagnostics.
|
|
85
87
|
#
|
|
88
|
+
# @sg-ignore Need to validate config
|
|
86
89
|
# @return [Array<String>]
|
|
87
90
|
def reporters
|
|
88
91
|
raw_data['reporters']
|
|
@@ -90,6 +93,7 @@ module Solargraph
|
|
|
90
93
|
|
|
91
94
|
# A hash of options supported by the formatter
|
|
92
95
|
#
|
|
96
|
+
# @sg-ignore Need to validate config
|
|
93
97
|
# @return [Hash]
|
|
94
98
|
def formatter
|
|
95
99
|
raw_data['formatter']
|
|
@@ -97,6 +101,7 @@ module Solargraph
|
|
|
97
101
|
|
|
98
102
|
# An array of plugins to require.
|
|
99
103
|
#
|
|
104
|
+
# @sg-ignore Need to validate config
|
|
100
105
|
# @return [Array<String>]
|
|
101
106
|
def plugins
|
|
102
107
|
raw_data['plugins']
|
|
@@ -104,11 +109,21 @@ module Solargraph
|
|
|
104
109
|
|
|
105
110
|
# The maximum number of files to parse from the workspace.
|
|
106
111
|
#
|
|
112
|
+
# @sg-ignore Need to validate config
|
|
107
113
|
# @return [Integer]
|
|
108
114
|
def max_files
|
|
109
115
|
raw_data['max_files']
|
|
110
116
|
end
|
|
111
117
|
|
|
118
|
+
# @return [Hash{Symbol => Symbol}]
|
|
119
|
+
def type_checker_rules
|
|
120
|
+
# @type [Hash{String => String}]
|
|
121
|
+
raw_rules = raw_data.fetch('type_checker', {}).fetch('rules', {})
|
|
122
|
+
raw_rules.to_h do |k, v|
|
|
123
|
+
[k.to_sym, v.to_sym]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
112
127
|
private
|
|
113
128
|
|
|
114
129
|
# @return [String]
|
|
@@ -123,7 +138,7 @@ module Solargraph
|
|
|
123
138
|
File.join(@directory, '.solargraph.yml')
|
|
124
139
|
end
|
|
125
140
|
|
|
126
|
-
# @return [Hash{String =>
|
|
141
|
+
# @return [Hash{String => undefined}]
|
|
127
142
|
def config_data
|
|
128
143
|
workspace_config = read_config(workspace_config_path)
|
|
129
144
|
global_config = read_config(global_config_path)
|
|
@@ -162,6 +177,9 @@ module Solargraph
|
|
|
162
177
|
'extra_args' =>[]
|
|
163
178
|
}
|
|
164
179
|
},
|
|
180
|
+
'type_checker' => {
|
|
181
|
+
'rules' => { }
|
|
182
|
+
},
|
|
165
183
|
'require_paths' => [],
|
|
166
184
|
'plugins' => [],
|
|
167
185
|
'max_files' => MAX_FILES
|
|
@@ -76,7 +76,6 @@ module Solargraph
|
|
|
76
76
|
"spec = eval(File.read('#{gemspec_file_path}'), TOPLEVEL_BINDING, '#{gemspec_file_path}'); " \
|
|
77
77
|
'return unless Gem::Specification === spec; ' \
|
|
78
78
|
'puts({name: spec.name, paths: spec.require_paths}.to_json)']
|
|
79
|
-
# @sg-ignore Unresolved call to capture3 on Module<Open3>
|
|
80
79
|
o, e, s = Open3.capture3(*cmd)
|
|
81
80
|
if s.success?
|
|
82
81
|
begin
|
data/lib/solargraph/workspace.rb
CHANGED
|
@@ -19,11 +19,17 @@ module Solargraph
|
|
|
19
19
|
attr_reader :gemnames
|
|
20
20
|
alias source_gems gemnames
|
|
21
21
|
|
|
22
|
-
# @param directory [String]
|
|
22
|
+
# @param directory [String] TODO: Remove '' and '*' special cases
|
|
23
23
|
# @param config [Config, nil]
|
|
24
24
|
# @param server [Hash]
|
|
25
25
|
def initialize directory = '', config = nil, server = {}
|
|
26
|
-
|
|
26
|
+
raise ArgumentError, 'directory must be a String' unless directory.is_a?(String)
|
|
27
|
+
|
|
28
|
+
@directory = if ['*', ''].include?(directory)
|
|
29
|
+
directory
|
|
30
|
+
else
|
|
31
|
+
File.absolute_path(directory)
|
|
32
|
+
end
|
|
27
33
|
@config = config
|
|
28
34
|
@server = server
|
|
29
35
|
load_sources
|
|
@@ -44,6 +50,12 @@ module Solargraph
|
|
|
44
50
|
@config ||= Solargraph::Workspace::Config.new(directory)
|
|
45
51
|
end
|
|
46
52
|
|
|
53
|
+
# @param level [Symbol]
|
|
54
|
+
# @return [TypeChecker::Rules]
|
|
55
|
+
def rules(level)
|
|
56
|
+
@rules ||= TypeChecker::Rules.new(level, config.type_checker_rules)
|
|
57
|
+
end
|
|
58
|
+
|
|
47
59
|
# Merge the source. A merge will update the existing source for the file
|
|
48
60
|
# or add it to the sources if the workspace is configured to include it.
|
|
49
61
|
# The source is ignored if the configuration excludes it.
|
|
@@ -114,23 +126,6 @@ module Solargraph
|
|
|
114
126
|
false
|
|
115
127
|
end
|
|
116
128
|
|
|
117
|
-
# True if the workspace contains at least one gemspec file.
|
|
118
|
-
#
|
|
119
|
-
# @return [Boolean]
|
|
120
|
-
def gemspec?
|
|
121
|
-
!gemspecs.empty?
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# Get an array of all gemspec files in the workspace.
|
|
125
|
-
#
|
|
126
|
-
# @return [Array<String>]
|
|
127
|
-
def gemspecs
|
|
128
|
-
return [] if directory.empty? || directory == '*'
|
|
129
|
-
@gemspecs ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
|
|
130
|
-
config.allow? gs
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
129
|
# @return [String, nil]
|
|
135
130
|
def rbs_collection_path
|
|
136
131
|
@gem_rbs_collection ||= read_rbs_collection_path
|