solargraph 0.58.2 → 0.59.0.dev.1
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/.envrc +3 -0
- data/.github/workflows/linting.yml +4 -5
- data/.github/workflows/plugins.yml +40 -36
- data/.github/workflows/rspec.yml +45 -13
- data/.github/workflows/typecheck.yml +2 -2
- data/.gitignore +0 -1
- data/.rubocop_todo.yml +27 -49
- data/CHANGELOG.md +1 -7
- data/README.md +3 -3
- data/Rakefile +1 -0
- data/lib/solargraph/api_map/cache.rb +3 -3
- data/lib/solargraph/api_map/constants.rb +13 -3
- data/lib/solargraph/api_map/index.rb +22 -11
- data/lib/solargraph/api_map/source_to_yard.rb +13 -1
- data/lib/solargraph/api_map/store.rb +11 -8
- data/lib/solargraph/api_map.rb +105 -50
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +16 -2
- data/lib/solargraph/complex_type/unique_type.rb +170 -20
- data/lib/solargraph/complex_type.rb +119 -14
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
- data/lib/solargraph/convention/data_definition.rb +4 -1
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition.rb +5 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/doc_map.rb +134 -373
- data/lib/solargraph/equality.rb +1 -1
- data/lib/solargraph/gem_pins.rb +14 -15
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +1 -0
- data/lib/solargraph/language_server/host/message_worker.rb +2 -1
- data/lib/solargraph/language_server/host/sources.rb +1 -0
- data/lib/solargraph/language_server/host.rb +6 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
- data/lib/solargraph/language_server/message/extended/document.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
- data/lib/solargraph/library.rb +59 -13
- data/lib/solargraph/location.rb +9 -4
- data/lib/solargraph/logging.rb +21 -1
- data/lib/solargraph/parser/comment_ripper.rb +7 -0
- data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
- data/lib/solargraph/parser/node_processor/base.rb +32 -2
- data/lib/solargraph/parser/node_processor.rb +7 -6
- data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
- data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/region.rb +9 -3
- data/lib/solargraph/parser/snippet.rb +1 -1
- data/lib/solargraph/pin/base.rb +53 -21
- data/lib/solargraph/pin/base_variable.rb +312 -20
- data/lib/solargraph/pin/block.rb +26 -4
- data/lib/solargraph/pin/breakable.rb +5 -1
- data/lib/solargraph/pin/callable.rb +50 -3
- data/lib/solargraph/pin/closure.rb +2 -6
- data/lib/solargraph/pin/common.rb +20 -5
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/conversions.rb +2 -1
- data/lib/solargraph/pin/delegated_method.rb +15 -4
- data/lib/solargraph/pin/documenting.rb +1 -0
- data/lib/solargraph/pin/instance_variable.rb +5 -1
- data/lib/solargraph/pin/keyword.rb +0 -4
- data/lib/solargraph/pin/local_variable.rb +13 -57
- data/lib/solargraph/pin/method.rb +90 -42
- data/lib/solargraph/pin/method_alias.rb +8 -0
- data/lib/solargraph/pin/namespace.rb +7 -1
- data/lib/solargraph/pin/parameter.rb +76 -13
- data/lib/solargraph/pin/proxy_type.rb +2 -1
- data/lib/solargraph/pin/reference/override.rb +1 -1
- data/lib/solargraph/pin/reference/superclass.rb +2 -0
- data/lib/solargraph/pin/reference.rb +2 -0
- data/lib/solargraph/pin/search.rb +1 -0
- data/lib/solargraph/pin/signature.rb +8 -0
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/until.rb +1 -1
- data/lib/solargraph/pin/while.rb +1 -1
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin_cache.rb +477 -57
- data/lib/solargraph/position.rb +12 -26
- data/lib/solargraph/range.rb +6 -6
- data/lib/solargraph/rbs_map/conversions.rb +33 -10
- data/lib/solargraph/rbs_map/core_map.rb +24 -17
- data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
- data/lib/solargraph/rbs_map.rb +74 -20
- data/lib/solargraph/shell.rb +73 -28
- data/lib/solargraph/source/chain/call.rb +52 -17
- data/lib/solargraph/source/chain/constant.rb +2 -0
- data/lib/solargraph/source/chain/hash.rb +1 -0
- data/lib/solargraph/source/chain/if.rb +1 -0
- data/lib/solargraph/source/chain/instance_variable.rb +22 -1
- data/lib/solargraph/source/chain/literal.rb +5 -0
- data/lib/solargraph/source/chain/or.rb +9 -1
- data/lib/solargraph/source/chain.rb +25 -22
- data/lib/solargraph/source/change.rb +9 -2
- data/lib/solargraph/source/cursor.rb +7 -1
- data/lib/solargraph/source/source_chainer.rb +13 -3
- data/lib/solargraph/source/updater.rb +4 -0
- data/lib/solargraph/source.rb +33 -7
- data/lib/solargraph/source_map/clip.rb +13 -2
- data/lib/solargraph/source_map/data.rb +4 -1
- data/lib/solargraph/source_map/mapper.rb +24 -1
- data/lib/solargraph/source_map.rb +14 -6
- data/lib/solargraph/type_checker/problem.rb +3 -1
- data/lib/solargraph/type_checker/rules.rb +75 -2
- data/lib/solargraph/type_checker.rb +111 -30
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +3 -1
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +1 -0
- data/lib/solargraph/workspace.rb +158 -16
- data/lib/solargraph/yard_map/helpers.rb +2 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/mapper.rb +5 -0
- data/lib/solargraph/yardoc.rb +33 -23
- data/lib/solargraph.rb +24 -3
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +1 -1
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/solargraph.gemspec +2 -1
- metadata +12 -7
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
data/lib/solargraph/shell.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'benchmark'
|
|
4
4
|
require 'thor'
|
|
5
5
|
require 'yard'
|
|
6
|
+
require 'yaml'
|
|
6
7
|
|
|
7
8
|
module Solargraph
|
|
8
9
|
class Shell < Thor
|
|
@@ -104,9 +105,8 @@ module Solargraph
|
|
|
104
105
|
# @param gem [String]
|
|
105
106
|
# @param version [String, nil]
|
|
106
107
|
def cache gem, version = nil
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
|
|
108
|
+
gems(gem + (version ? "=#{version}" : ''))
|
|
109
|
+
# '
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
|
|
@@ -119,39 +119,83 @@ module Solargraph
|
|
|
119
119
|
# @return [void]
|
|
120
120
|
def uncache *gems
|
|
121
121
|
raise ArgumentError, 'No gems specified.' if gems.empty?
|
|
122
|
+
workspace = Solargraph::Workspace.new(Dir.pwd)
|
|
123
|
+
|
|
122
124
|
gems.each do |gem|
|
|
123
125
|
if gem == 'core'
|
|
124
|
-
PinCache.uncache_core
|
|
126
|
+
PinCache.uncache_core(out: $stdout)
|
|
125
127
|
next
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
if gem == 'stdlib'
|
|
129
|
-
PinCache.uncache_stdlib
|
|
131
|
+
PinCache.uncache_stdlib(out: $stdout)
|
|
130
132
|
next
|
|
131
133
|
end
|
|
132
134
|
|
|
133
|
-
spec =
|
|
134
|
-
|
|
135
|
+
spec = workspace.find_gem(gem)
|
|
136
|
+
raise Thor::InvocationError, "Gem '#{gem}' not found" if spec.nil?
|
|
137
|
+
|
|
138
|
+
# @sg-ignore flow sensitive typing needs to handle 'raise if'
|
|
139
|
+
workspace.uncache_gem(spec, out: $stdout)
|
|
135
140
|
end
|
|
136
141
|
end
|
|
137
142
|
|
|
138
|
-
desc 'gems [GEM[=VERSION]]', 'Cache documentation for
|
|
143
|
+
desc 'gems [GEM[=VERSION]...] [STDLIB...] [core]', 'Cache documentation for
|
|
144
|
+
installed libraries'
|
|
145
|
+
long_desc %( This command will cache the
|
|
146
|
+
generated type documentation for the specified libraries. While
|
|
147
|
+
Solargraph will generate this on the fly when needed, it takes
|
|
148
|
+
time. This command will generate it in advance, which can be
|
|
149
|
+
useful for CI scenarios.
|
|
150
|
+
|
|
151
|
+
With no arguments, it will cache all libraries in the current
|
|
152
|
+
workspace. If a gem or standard library name is specified, it
|
|
153
|
+
will cache that library's type documentation.
|
|
154
|
+
|
|
155
|
+
An equals sign after a gem will allow a specific gem version
|
|
156
|
+
to be cached.
|
|
157
|
+
|
|
158
|
+
The 'core' argument can be used to cache the type
|
|
159
|
+
documentation for the core Ruby libraries.
|
|
160
|
+
|
|
161
|
+
If the library is already cached, it will be rebuilt if the
|
|
162
|
+
--rebuild option is set.
|
|
163
|
+
|
|
164
|
+
Cached documentation is stored in #{PinCache.base_dir}, which
|
|
165
|
+
can be stored between CI runs.
|
|
166
|
+
)
|
|
139
167
|
option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
|
|
140
168
|
# @param names [Array<String>]
|
|
141
169
|
# @return [void]
|
|
142
170
|
def gems *names
|
|
143
|
-
|
|
171
|
+
# print time with ms
|
|
172
|
+
workspace = Solargraph::Workspace.new('.')
|
|
173
|
+
|
|
144
174
|
if names.empty?
|
|
145
|
-
|
|
146
|
-
STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
|
|
175
|
+
workspace.cache_all_for_workspace!($stdout, rebuild: options[:rebuild])
|
|
147
176
|
else
|
|
177
|
+
$stderr.puts("Caching these gems: #{names}")
|
|
148
178
|
names.each do |name|
|
|
149
|
-
|
|
150
|
-
|
|
179
|
+
if name == 'core'
|
|
180
|
+
PinCache.cache_core(out: $stdout) if !PinCache.core? || options[:rebuild]
|
|
181
|
+
next
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
gemspec = workspace.find_gem(*name.split('='))
|
|
185
|
+
if gemspec.nil?
|
|
186
|
+
warn "Gem '#{name}' not found"
|
|
187
|
+
else
|
|
188
|
+
workspace.cache_gem(gemspec, rebuild: options[:rebuild], out: $stdout)
|
|
189
|
+
end
|
|
151
190
|
rescue Gem::MissingSpecError
|
|
152
191
|
warn "Gem '#{name}' not found"
|
|
192
|
+
rescue Gem::Requirement::BadRequirementError => e
|
|
193
|
+
warn "Gem '#{name}' failed while loading"
|
|
194
|
+
warn e.message
|
|
195
|
+
# @sg-ignore Need to add nil check here
|
|
196
|
+
warn e.backtrace.join("\n")
|
|
153
197
|
end
|
|
154
|
-
|
|
198
|
+
$stderr.puts "Documentation cached for #{names.count} gems."
|
|
155
199
|
end
|
|
156
200
|
end
|
|
157
201
|
|
|
@@ -176,7 +220,10 @@ module Solargraph
|
|
|
176
220
|
workspace = Solargraph::Workspace.new(directory)
|
|
177
221
|
level = options[:level].to_sym
|
|
178
222
|
rules = workspace.rules(level)
|
|
179
|
-
api_map =
|
|
223
|
+
api_map =
|
|
224
|
+
Solargraph::ApiMap.load_with_cache(directory, $stdout,
|
|
225
|
+
loose_unions:
|
|
226
|
+
!rules.require_all_unique_types_support_call?)
|
|
180
227
|
probcount = 0
|
|
181
228
|
if files.empty?
|
|
182
229
|
files = api_map.source_maps.map(&:filename)
|
|
@@ -184,10 +231,9 @@ module Solargraph
|
|
|
184
231
|
files.map! { |file| File.realpath(file) }
|
|
185
232
|
end
|
|
186
233
|
filecount = 0
|
|
187
|
-
|
|
188
234
|
time = Benchmark.measure {
|
|
189
235
|
files.each do |file|
|
|
190
|
-
checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym, workspace: workspace)
|
|
236
|
+
checker = TypeChecker.new(file, api_map: api_map, rules: rules, level: options[:level].to_sym, workspace: workspace)
|
|
191
237
|
problems = checker.problems
|
|
192
238
|
next if problems.empty?
|
|
193
239
|
problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
|
|
@@ -195,7 +241,6 @@ module Solargraph
|
|
|
195
241
|
filecount += 1
|
|
196
242
|
probcount += problems.length
|
|
197
243
|
end
|
|
198
|
-
# "
|
|
199
244
|
}
|
|
200
245
|
puts "Typecheck finished in #{time.real} seconds."
|
|
201
246
|
puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
|
|
@@ -219,19 +264,25 @@ module Solargraph
|
|
|
219
264
|
api_map = nil
|
|
220
265
|
time = Benchmark.measure {
|
|
221
266
|
api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
|
|
267
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
222
268
|
api_map.pins.each do |pin|
|
|
223
269
|
begin
|
|
224
270
|
puts pin_description(pin) if options[:verbose]
|
|
225
271
|
pin.typify api_map
|
|
226
272
|
pin.probe api_map
|
|
227
273
|
rescue StandardError => e
|
|
274
|
+
# @todo to add nil check here
|
|
275
|
+
# @todo should warn on nil dereference below
|
|
228
276
|
STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
|
|
229
277
|
STDERR.puts "[#{e.class}]: #{e.message}"
|
|
278
|
+
# @todo Need to add nil check here
|
|
279
|
+
# @todo flow sensitive typing should be able to handle redefinition
|
|
230
280
|
STDERR.puts e.backtrace.join("\n")
|
|
231
281
|
exit 1
|
|
232
282
|
end
|
|
233
283
|
end
|
|
234
284
|
}
|
|
285
|
+
# @sg-ignore Need to add nil check here
|
|
235
286
|
puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
|
|
236
287
|
end
|
|
237
288
|
|
|
@@ -279,6 +330,7 @@ module Solargraph
|
|
|
279
330
|
exit 1
|
|
280
331
|
when Pin::Namespace
|
|
281
332
|
if options[:references]
|
|
333
|
+
# @sg-ignore Need to add nil check here
|
|
282
334
|
superclass_tag = api_map.qualify_superclass(pin.return_type.tag)
|
|
283
335
|
superclass_pin = api_map.get_path_pins(superclass_tag).first if superclass_tag
|
|
284
336
|
references[:superclass] = superclass_pin if superclass_pin
|
|
@@ -309,6 +361,7 @@ module Solargraph
|
|
|
309
361
|
def pin_description pin
|
|
310
362
|
desc = if pin.path.nil? || pin.path.empty?
|
|
311
363
|
if pin.closure
|
|
364
|
+
# @sg-ignore Need to add nil check here
|
|
312
365
|
"#{pin.closure.path} | #{pin.name}"
|
|
313
366
|
else
|
|
314
367
|
"#{pin.context.namespace} | #{pin.name}"
|
|
@@ -316,20 +369,12 @@ module Solargraph
|
|
|
316
369
|
else
|
|
317
370
|
pin.path
|
|
318
371
|
end
|
|
372
|
+
# @sg-ignore Need to add nil check here
|
|
319
373
|
desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
|
|
320
374
|
desc
|
|
321
375
|
end
|
|
322
376
|
|
|
323
|
-
# @param
|
|
324
|
-
# @param api_map [ApiMap]
|
|
325
|
-
# @return [void]
|
|
326
|
-
def do_cache gemspec, api_map
|
|
327
|
-
# @todo if the rebuild: option is passed as a positional arg,
|
|
328
|
-
# typecheck doesn't complain on the below line
|
|
329
|
-
api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
# @param type [ComplexType]
|
|
377
|
+
# @param type [ComplexType, ComplexType::UniqueType]
|
|
333
378
|
# @return [void]
|
|
334
379
|
def print_type(type)
|
|
335
380
|
if options[:rbs]
|
|
@@ -37,6 +37,7 @@ module Solargraph
|
|
|
37
37
|
|
|
38
38
|
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
39
39
|
protected def equality_fields
|
|
40
|
+
# @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
|
|
40
41
|
super + [arguments, block]
|
|
41
42
|
end
|
|
42
43
|
|
|
@@ -50,24 +51,35 @@ module Solargraph
|
|
|
50
51
|
def resolve api_map, name_pin, locals
|
|
51
52
|
return super_pins(api_map, name_pin) if word == 'super'
|
|
52
53
|
return yield_pins(api_map, name_pin) if word == 'yield'
|
|
53
|
-
found = if head?
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
found = api_map.var_at_location(locals, word, name_pin, location) if head?
|
|
55
|
+
|
|
56
|
+
return inferred_pins([found], api_map, name_pin, locals) unless found.nil?
|
|
57
|
+
binder = name_pin.binder
|
|
58
|
+
# this is a q_call - i.e., foo&.bar - assume result of call
|
|
59
|
+
# will be nil or result as if binder were not nil -
|
|
60
|
+
# chain.rb#maybe_nil will add the nil type later, we just
|
|
61
|
+
# need to worry about the not-nil case
|
|
62
|
+
|
|
63
|
+
# @sg-ignore Need to handle duck-typed method calls on union types
|
|
64
|
+
binder = binder.without_nil if nullable?
|
|
65
|
+
# @sg-ignore Need to handle duck-typed method calls on union types
|
|
66
|
+
pin_groups = binder.each_unique_type.map do |context|
|
|
60
67
|
ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
|
|
61
68
|
stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
|
|
62
69
|
[stack.first].compact
|
|
63
70
|
end
|
|
71
|
+
# @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
|
|
72
|
+
if !api_map.loose_unions && pin_groups.any? { |pins| pins.empty? }
|
|
73
|
+
pin_groups = []
|
|
74
|
+
end
|
|
75
|
+
pins = pin_groups.flatten.uniq(&:path)
|
|
64
76
|
return [] if pins.empty?
|
|
65
77
|
inferred_pins(pins, api_map, name_pin, locals)
|
|
66
78
|
end
|
|
67
79
|
|
|
68
80
|
private
|
|
69
81
|
|
|
70
|
-
# @param pins [::Enumerable<Pin::
|
|
82
|
+
# @param pins [::Enumerable<Pin::Base>]
|
|
71
83
|
# @param api_map [ApiMap]
|
|
72
84
|
# @param name_pin [Pin::Base]
|
|
73
85
|
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
@@ -84,9 +96,13 @@ module Solargraph
|
|
|
84
96
|
# reject it regardless
|
|
85
97
|
|
|
86
98
|
with_block, without_block = overloads.partition(&:block?)
|
|
99
|
+
# @sg-ignore flow sensitive typing should handle is_a? and next
|
|
100
|
+
# @type Array<Pin::Signature>
|
|
87
101
|
sorted_overloads = with_block + without_block
|
|
88
102
|
# @type [Pin::Signature, nil]
|
|
89
103
|
new_signature_pin = nil
|
|
104
|
+
# @sg-ignore flow sensitive typing should handle is_a? and next
|
|
105
|
+
# @param ol [Pin::Signature]
|
|
90
106
|
sorted_overloads.each do |ol|
|
|
91
107
|
next unless ol.arity_matches?(arguments, with_block?)
|
|
92
108
|
match = true
|
|
@@ -99,6 +115,7 @@ module Solargraph
|
|
|
99
115
|
break
|
|
100
116
|
end
|
|
101
117
|
arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
|
|
118
|
+
closure: name_pin.closure,
|
|
102
119
|
gates: name_pin.gates,
|
|
103
120
|
source: :chain)
|
|
104
121
|
atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
|
|
@@ -110,6 +127,7 @@ module Solargraph
|
|
|
110
127
|
if match
|
|
111
128
|
if ol.block && with_block?
|
|
112
129
|
block_atypes = ol.block.parameters.map(&:return_type)
|
|
130
|
+
# @todo Need to add nil check here
|
|
113
131
|
if block.links.map(&:class) == [BlockSymbol]
|
|
114
132
|
# like the bar in foo(&:bar)
|
|
115
133
|
blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
|
|
@@ -140,6 +158,7 @@ module Solargraph
|
|
|
140
158
|
#
|
|
141
159
|
# qualify(), however, happens in the namespace where
|
|
142
160
|
# the docs were written - from the method pin.
|
|
161
|
+
# @todo Need to add nil check here
|
|
143
162
|
type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, *p.gates) if new_return_type.defined?
|
|
144
163
|
type ||= ComplexType::UNDEFINED
|
|
145
164
|
end
|
|
@@ -149,9 +168,11 @@ module Solargraph
|
|
|
149
168
|
next p.proxy(type) if type.defined?
|
|
150
169
|
if !p.macros.empty?
|
|
151
170
|
result = process_macro(p, api_map, name_pin.context, locals)
|
|
171
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
152
172
|
next result unless result.return_type.undefined?
|
|
153
173
|
elsif !p.directives.empty?
|
|
154
174
|
result = process_directive(p, api_map, name_pin.context, locals)
|
|
175
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
155
176
|
next result unless result.return_type.undefined?
|
|
156
177
|
end
|
|
157
178
|
p
|
|
@@ -162,8 +183,11 @@ module Solargraph
|
|
|
162
183
|
reduced_context = name_pin.binder.reduce_class_type
|
|
163
184
|
pin.proxy(reduced_context)
|
|
164
185
|
else
|
|
186
|
+
# @sg-ignore Need to add nil check here
|
|
165
187
|
next pin if pin.return_type.undefined?
|
|
188
|
+
# @sg-ignore Need to add nil check here
|
|
166
189
|
selfy = pin.return_type.self_to_type(name_pin.binder)
|
|
190
|
+
# @sg-ignore Need to add nil check here
|
|
167
191
|
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
|
168
192
|
end
|
|
169
193
|
end
|
|
@@ -171,7 +195,7 @@ module Solargraph
|
|
|
171
195
|
|
|
172
196
|
# @param pin [Pin::Base]
|
|
173
197
|
# @param api_map [ApiMap]
|
|
174
|
-
# @param context [ComplexType]
|
|
198
|
+
# @param context [ComplexType, ComplexType::UniqueType]
|
|
175
199
|
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
176
200
|
# @return [Pin::Base]
|
|
177
201
|
def process_macro pin, api_map, context, locals
|
|
@@ -190,7 +214,7 @@ module Solargraph
|
|
|
190
214
|
|
|
191
215
|
# @param pin [Pin::Method]
|
|
192
216
|
# @param api_map [ApiMap]
|
|
193
|
-
# @param context [ComplexType]
|
|
217
|
+
# @param context [ComplexType, ComplexType::UniqueType]
|
|
194
218
|
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
195
219
|
# @return [Pin::ProxyType]
|
|
196
220
|
def process_directive pin, api_map, context, locals
|
|
@@ -206,21 +230,24 @@ module Solargraph
|
|
|
206
230
|
# @param pin [Pin::Base]
|
|
207
231
|
# @param macro [YARD::Tags::MacroDirective]
|
|
208
232
|
# @param api_map [ApiMap]
|
|
209
|
-
# @param context [ComplexType]
|
|
233
|
+
# @param context [ComplexType, ComplexType::UniqueType]
|
|
210
234
|
# @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
|
|
211
235
|
# @return [Pin::ProxyType]
|
|
212
236
|
def inner_process_macro pin, macro, api_map, context, locals
|
|
213
237
|
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
|
|
214
238
|
txt = macro.tag.text.clone
|
|
239
|
+
# @sg-ignore Need to add nil check here
|
|
215
240
|
if txt.empty? && macro.tag.name
|
|
216
241
|
named = api_map.named_macro(macro.tag.name)
|
|
217
242
|
txt = named.tag.text.clone if named
|
|
218
243
|
end
|
|
219
244
|
i = 1
|
|
220
245
|
vals.each do |v|
|
|
246
|
+
# @sg-ignore Need to add nil check here
|
|
221
247
|
txt.gsub!(/\$#{i}/, v.context.namespace)
|
|
222
248
|
i += 1
|
|
223
249
|
end
|
|
250
|
+
# @sg-ignore Need to add nil check here
|
|
224
251
|
docstring = Solargraph::Source.parse_docstring(txt).to_docstring
|
|
225
252
|
tag = docstring.tag(:return)
|
|
226
253
|
unless tag.nil? || tag.types.nil?
|
|
@@ -246,6 +273,7 @@ module Solargraph
|
|
|
246
273
|
def find_method_pin(name_pin)
|
|
247
274
|
method_pin = name_pin
|
|
248
275
|
until method_pin.is_a?(Pin::Method)
|
|
276
|
+
# @sg-ignore Need to support this in flow sensitive typing
|
|
249
277
|
method_pin = method_pin.closure
|
|
250
278
|
return if method_pin.nil?
|
|
251
279
|
end
|
|
@@ -271,13 +299,14 @@ module Solargraph
|
|
|
271
299
|
|
|
272
300
|
# @param signature_pin [Pin::Signature]
|
|
273
301
|
method_pin.signatures.map(&:block).compact.map do |signature_pin|
|
|
302
|
+
# @sg-ignore Need to add nil check here
|
|
274
303
|
return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
|
|
275
304
|
signature_pin.proxy(return_type)
|
|
276
305
|
end
|
|
277
306
|
end
|
|
278
307
|
|
|
279
308
|
# @param type [ComplexType]
|
|
280
|
-
# @param context [ComplexType]
|
|
309
|
+
# @param context [ComplexType, ComplexType::UniqueType]
|
|
281
310
|
# @return [ComplexType]
|
|
282
311
|
def with_params type, context
|
|
283
312
|
return type unless type.to_s.include?('$')
|
|
@@ -291,13 +320,14 @@ module Solargraph
|
|
|
291
320
|
end
|
|
292
321
|
|
|
293
322
|
# @param api_map [ApiMap]
|
|
294
|
-
# @param context [ComplexType]
|
|
323
|
+
# @param context [ComplexType, ComplexType::UniqueType]
|
|
295
324
|
# @param block_parameter_types [::Array<ComplexType>]
|
|
296
325
|
# @param locals [::Array<Pin::LocalVariable>]
|
|
297
326
|
# @return [ComplexType, nil]
|
|
298
327
|
def block_symbol_call_type(api_map, context, block_parameter_types, locals)
|
|
299
328
|
# Ruby's shorthand for sending the passed in method name
|
|
300
329
|
# to the first yield parameter with no arguments
|
|
330
|
+
# @sg-ignore Need to add nil check here
|
|
301
331
|
block_symbol_name = block.links.first.word
|
|
302
332
|
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
|
303
333
|
callee = api_map.get_path_pins(block_symbol_call_path).first
|
|
@@ -305,6 +335,7 @@ module Solargraph
|
|
|
305
335
|
# @todo: Figure out why we get unresolved generics at
|
|
306
336
|
# this point and need to assume method return types
|
|
307
337
|
# based on the generic type
|
|
338
|
+
# @sg-ignore Need to add nil check here
|
|
308
339
|
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
|
309
340
|
return_type || ComplexType::UNDEFINED
|
|
310
341
|
end
|
|
@@ -312,9 +343,11 @@ module Solargraph
|
|
|
312
343
|
# @param api_map [ApiMap]
|
|
313
344
|
# @return [Pin::Block, nil]
|
|
314
345
|
def find_block_pin(api_map)
|
|
346
|
+
# @sg-ignore Need to add nil check here
|
|
315
347
|
node_location = Solargraph::Location.from_node(block.node)
|
|
316
|
-
return if
|
|
348
|
+
return if node_location.nil?
|
|
317
349
|
block_pins = api_map.get_block_pins
|
|
350
|
+
# @sg-ignore Need to add nil check here
|
|
318
351
|
block_pins.find { |pin| pin.location.contain?(node_location) }
|
|
319
352
|
end
|
|
320
353
|
|
|
@@ -326,10 +359,12 @@ module Solargraph
|
|
|
326
359
|
def block_call_type(api_map, name_pin, locals)
|
|
327
360
|
return nil unless with_block?
|
|
328
361
|
|
|
329
|
-
block_context_pin = name_pin
|
|
330
362
|
block_pin = find_block_pin(api_map)
|
|
331
|
-
|
|
332
|
-
block
|
|
363
|
+
# We use the block pin as the closure, as the parameters
|
|
364
|
+
# here will only be defined inside the block itself and we
|
|
365
|
+
# need to be able to see them
|
|
366
|
+
# @sg-ignore Need to add nil check here
|
|
367
|
+
block.infer(api_map, block_pin, locals)
|
|
333
368
|
end
|
|
334
369
|
end
|
|
335
370
|
end
|
|
@@ -4,9 +4,30 @@ module Solargraph
|
|
|
4
4
|
class Source
|
|
5
5
|
class Chain
|
|
6
6
|
class InstanceVariable < Link
|
|
7
|
+
# @param word [String]
|
|
8
|
+
# @param node [Parser::AST::Node, nil] The node representing the variable
|
|
9
|
+
# @param location [Location, nil] The location of the variable reference in the source
|
|
10
|
+
def initialize word, node, location
|
|
11
|
+
super(word)
|
|
12
|
+
@node = node
|
|
13
|
+
@location = location
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @sg-ignore Declared return type
|
|
17
|
+
# ::Array<::Solargraph::Pin::Base> does not match inferred
|
|
18
|
+
# type ::Array<::Solargraph::Pin::BaseVariable, ::NilClass>
|
|
19
|
+
# for Solargraph::Source::Chain::InstanceVariable#resolve
|
|
7
20
|
def resolve api_map, name_pin, locals
|
|
8
|
-
api_map.get_instance_variable_pins(name_pin.
|
|
21
|
+
ivars = api_map.get_instance_variable_pins(name_pin.context.namespace, name_pin.context.scope).select{|p| p.name == word}
|
|
22
|
+
out = api_map.var_at_location(ivars, word, name_pin, location)
|
|
23
|
+
[out].compact
|
|
9
24
|
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# @todo: Missed nil violation
|
|
29
|
+
# @return [Location]
|
|
30
|
+
attr_reader :location
|
|
10
31
|
end
|
|
11
32
|
end
|
|
12
33
|
end
|
|
@@ -16,11 +16,15 @@ module Solargraph
|
|
|
16
16
|
# @param node [Parser::AST::Node, Object]
|
|
17
17
|
def initialize type, node
|
|
18
18
|
if node.is_a?(::Parser::AST::Node)
|
|
19
|
+
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
19
20
|
if node.type == :true
|
|
20
21
|
@value = true
|
|
22
|
+
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
21
23
|
elsif node.type == :false
|
|
22
24
|
@value = false
|
|
25
|
+
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
23
26
|
elsif [:int, :sym].include?(node.type)
|
|
27
|
+
# @sg-ignore flow sensitive typing needs to narrow down type with an if is_a? check
|
|
24
28
|
@value = node.children.first
|
|
25
29
|
end
|
|
26
30
|
end
|
|
@@ -31,6 +35,7 @@ module Solargraph
|
|
|
31
35
|
|
|
32
36
|
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
33
37
|
protected def equality_fields
|
|
38
|
+
# @sg-ignore literal arrays in this module turn into ::Solargraph::Source::Chain::Array
|
|
34
39
|
super + [@value, @type, @literal_type, @complex_type]
|
|
35
40
|
end
|
|
36
41
|
|
|
@@ -8,6 +8,8 @@ module Solargraph
|
|
|
8
8
|
'<or>'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
attr_reader :links
|
|
12
|
+
|
|
11
13
|
# @param links [::Array<Chain>]
|
|
12
14
|
def initialize links
|
|
13
15
|
@links = links
|
|
@@ -15,7 +17,13 @@ module Solargraph
|
|
|
15
17
|
|
|
16
18
|
def resolve api_map, name_pin, locals
|
|
17
19
|
types = @links.map { |link| link.infer(api_map, name_pin, locals) }
|
|
18
|
-
|
|
20
|
+
combined_type = Solargraph::ComplexType.new(types)
|
|
21
|
+
unless types.all?(&:nullable?)
|
|
22
|
+
# @sg-ignore flow sensitive typing should be able to handle redefinition
|
|
23
|
+
combined_type = combined_type.without_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
[Solargraph::Pin::ProxyType.anonymous(combined_type, source: :chain)]
|
|
19
27
|
end
|
|
20
28
|
end
|
|
21
29
|
end
|
|
@@ -71,6 +71,7 @@ module Solargraph
|
|
|
71
71
|
|
|
72
72
|
# @return [Chain]
|
|
73
73
|
def base
|
|
74
|
+
# @sg-ignore Need to add nil check here
|
|
74
75
|
@base ||= Chain.new(links[0..-2])
|
|
75
76
|
end
|
|
76
77
|
|
|
@@ -78,25 +79,25 @@ module Solargraph
|
|
|
78
79
|
#
|
|
79
80
|
# @param api_map [ApiMap]
|
|
80
81
|
#
|
|
81
|
-
# @param name_pin [Pin::Base] A pin
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
82
|
+
# @param name_pin [Pin::Base] A pin representing the closure in
|
|
83
|
+
# which expression is evaluated (e.g., a Method pin, or a
|
|
84
|
+
# Module or Class pin if not run within a method - both in
|
|
85
|
+
# terms of the closure around the chain, as well as the self
|
|
86
|
+
# type used for any method calls in head position.
|
|
86
87
|
#
|
|
87
88
|
# Requirements for name_pin:
|
|
88
89
|
#
|
|
89
90
|
# * name_pin.context: This should be a type representing the
|
|
90
|
-
# namespace where we can look up non-local variables
|
|
91
|
-
#
|
|
92
|
-
#
|
|
91
|
+
# namespace where we can look up non-local variables. If
|
|
92
|
+
# it is a Class<X>, we will look up :class scoped
|
|
93
|
+
# instance variables.
|
|
93
94
|
#
|
|
94
95
|
# * name_pin.binder: Used for method call lookups only
|
|
95
96
|
# (Chain::Call links). For method calls as the first
|
|
96
97
|
# element in the chain, 'name_pin.binder' should be the
|
|
97
98
|
# same as name_pin.context above. For method calls later
|
|
98
|
-
# in the chain (e.g., 'b' in a.b.c
|
|
99
|
-
# 'a'.
|
|
99
|
+
# in the chain, it changes. (e.g., for 'b' in a.b.c, it
|
|
100
|
+
# should represent the type of 'a').
|
|
100
101
|
#
|
|
101
102
|
# @param locals [::Array<Pin::LocalVariable>] Any local
|
|
102
103
|
# variables / method parameters etc visible by the statement
|
|
@@ -113,6 +114,7 @@ module Solargraph
|
|
|
113
114
|
#
|
|
114
115
|
# @todo ProxyType uses 'type' for the binder, but '
|
|
115
116
|
working_pin = name_pin
|
|
117
|
+
# @sg-ignore Need to add nil check here
|
|
116
118
|
links[0..-2].each do |link|
|
|
117
119
|
pins = link.resolve(api_map, working_pin, locals)
|
|
118
120
|
type = infer_from_definitions(pins, working_pin, api_map, locals)
|
|
@@ -138,7 +140,8 @@ module Solargraph
|
|
|
138
140
|
# @return [ComplexType]
|
|
139
141
|
# @sg-ignore
|
|
140
142
|
def infer api_map, name_pin, locals
|
|
141
|
-
|
|
143
|
+
# includes binder as it is mutable in Pin::Block
|
|
144
|
+
cache_key = [node, node&.location, links, name_pin&.return_type, name_pin&.binder, locals]
|
|
142
145
|
if @@inference_invalidation_key == api_map.hash
|
|
143
146
|
cached = @@inference_cache[cache_key]
|
|
144
147
|
return cached if cached
|
|
@@ -154,7 +157,7 @@ module Solargraph
|
|
|
154
157
|
# @param api_map [ApiMap]
|
|
155
158
|
# @param name_pin [Pin::Base]
|
|
156
159
|
# @param locals [::Array<Pin::LocalVariable>]
|
|
157
|
-
# @return [ComplexType]
|
|
160
|
+
# @return [ComplexType, ComplexType::UniqueType]
|
|
158
161
|
def infer_uncached api_map, name_pin, locals
|
|
159
162
|
pins = define(api_map, name_pin, locals)
|
|
160
163
|
if pins.empty?
|
|
@@ -209,12 +212,12 @@ module Solargraph
|
|
|
209
212
|
private
|
|
210
213
|
|
|
211
214
|
# @param pins [::Array<Pin::Base>]
|
|
212
|
-
# @param
|
|
215
|
+
# @param name_pin [Pin::Base]
|
|
213
216
|
# @param api_map [ApiMap]
|
|
214
217
|
# @param locals [::Enumerable<Pin::LocalVariable>]
|
|
215
|
-
# @return [ComplexType]
|
|
216
|
-
def infer_from_definitions pins,
|
|
217
|
-
# @type [::Array<ComplexType>]
|
|
218
|
+
# @return [ComplexType, ComplexType::UniqueType]
|
|
219
|
+
def infer_from_definitions pins, name_pin, api_map, locals
|
|
220
|
+
# @type [::Array<ComplexType, ComplexType::UniqueType>]
|
|
218
221
|
types = []
|
|
219
222
|
unresolved_pins = []
|
|
220
223
|
# @todo this param tag shouldn't be needed to probe the type
|
|
@@ -232,7 +235,8 @@ module Solargraph
|
|
|
232
235
|
# @todo even at strong, no typechecking complaint
|
|
233
236
|
# happens when a [Pin::Base,nil] is passed into a method
|
|
234
237
|
# that accepts only [Pin::Namespace] as an argument
|
|
235
|
-
|
|
238
|
+
# @sg-ignore Need to add nil check here
|
|
239
|
+
type = type.resolve_generics(pin.closure, name_pin.binder)
|
|
236
240
|
end
|
|
237
241
|
types << type
|
|
238
242
|
else
|
|
@@ -271,16 +275,15 @@ module Solargraph
|
|
|
271
275
|
else
|
|
272
276
|
ComplexType.new(types)
|
|
273
277
|
end
|
|
274
|
-
if
|
|
278
|
+
if name_pin.nil? || name_pin.context.undefined?
|
|
275
279
|
# up to downstream to resolve self type
|
|
276
280
|
return type
|
|
277
281
|
end
|
|
278
|
-
|
|
279
|
-
type.self_to_type(context.return_type)
|
|
282
|
+
type.self_to_type(name_pin.context)
|
|
280
283
|
end
|
|
281
284
|
|
|
282
|
-
# @param type [ComplexType]
|
|
283
|
-
# @return [ComplexType]
|
|
285
|
+
# @param type [ComplexType, ComplexType::UniqueType]
|
|
286
|
+
# @return [ComplexType, ComplexType::UniqueType]
|
|
284
287
|
def maybe_nil type
|
|
285
288
|
return type if type.undefined? || type.void? || type.nullable?
|
|
286
289
|
return type unless nullable?
|