solargraph 0.32.5 → 0.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +2 -11
- data/lib/solargraph.rb +1 -2
- data/lib/solargraph/api_map.rb +93 -63
- data/lib/solargraph/api_map/cache.rb +16 -1
- data/lib/solargraph/api_map/source_to_yard.rb +16 -7
- data/lib/solargraph/api_map/store.rb +55 -12
- data/lib/solargraph/complex_type.rb +58 -14
- data/lib/solargraph/complex_type/type_methods.rb +2 -2
- data/lib/solargraph/complex_type/unique_type.rb +33 -4
- data/lib/solargraph/core_fills.rb +40 -12
- data/lib/solargraph/diagnostics.rb +4 -3
- data/lib/solargraph/diagnostics/base.rb +6 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +17 -10
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
- data/lib/solargraph/diagnostics/type_check.rb +51 -0
- data/lib/solargraph/diagnostics/update_errors.rb +1 -0
- data/lib/solargraph/language_server/host.rb +55 -25
- data/lib/solargraph/language_server/host/diagnoser.rb +1 -2
- data/lib/solargraph/language_server/host/dispatch.rb +4 -8
- data/lib/solargraph/language_server/host/sources.rb +1 -1
- data/lib/solargraph/language_server/message.rb +1 -0
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +4 -2
- data/lib/solargraph/language_server/message/initialize.rb +9 -0
- data/lib/solargraph/language_server/message/initialized.rb +1 -0
- data/lib/solargraph/language_server/message/text_document.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/code_action.rb +15 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +25 -5
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +4 -0
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -4
- data/lib/solargraph/language_server/transport/adapter.rb +12 -15
- data/lib/solargraph/library.rb +23 -6
- data/lib/solargraph/location.rb +4 -0
- data/lib/solargraph/pin.rb +7 -3
- data/lib/solargraph/pin/attribute.rb +14 -13
- data/lib/solargraph/pin/base.rb +56 -43
- data/lib/solargraph/pin/base_method.rb +41 -18
- data/lib/solargraph/pin/base_variable.rb +17 -15
- data/lib/solargraph/pin/block.rb +22 -4
- data/lib/solargraph/pin/closure.rb +28 -0
- data/lib/solargraph/pin/common.rb +59 -0
- data/lib/solargraph/pin/constant.rb +4 -4
- data/lib/solargraph/pin/conversions.rb +8 -8
- data/lib/solargraph/pin/duck_method.rb +3 -3
- data/lib/solargraph/pin/instance_variable.rb +30 -0
- data/lib/solargraph/pin/keyword.rb +1 -1
- data/lib/solargraph/pin/local_variable.rb +3 -3
- data/lib/solargraph/pin/localized.rb +9 -5
- data/lib/solargraph/pin/method.rb +26 -40
- data/lib/solargraph/pin/method_alias.rb +9 -6
- data/lib/solargraph/pin/namespace.rb +33 -10
- data/lib/solargraph/pin/parameter.rb +150 -0
- data/lib/solargraph/pin/proxy_type.rb +8 -8
- data/lib/solargraph/pin/reference.rb +1 -12
- data/lib/solargraph/pin/reference/override.rb +18 -0
- data/lib/solargraph/pin/reference/require.rb +2 -1
- data/lib/solargraph/pin/singleton.rb +9 -0
- data/lib/solargraph/pin/symbol.rb +9 -4
- data/lib/solargraph/pin/yard_pin/constant.rb +12 -3
- data/lib/solargraph/pin/yard_pin/method.rb +18 -6
- data/lib/solargraph/pin/yard_pin/namespace.rb +13 -1
- data/lib/solargraph/position.rb +1 -1
- data/lib/solargraph/range.rb +4 -0
- data/lib/solargraph/shell.rb +83 -4
- data/lib/solargraph/source.rb +32 -12
- data/lib/solargraph/source/chain.rb +48 -28
- data/lib/solargraph/source/chain/call.rb +37 -38
- data/lib/solargraph/source/chain/constant.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +2 -8
- data/lib/solargraph/source/chain/instance_variable.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +2 -0
- data/lib/solargraph/source/cursor.rb +59 -24
- data/lib/solargraph/source/node_chainer.rb +0 -2
- data/lib/solargraph/source/node_methods.rb +12 -6
- data/lib/solargraph/source/source_chainer.rb +38 -44
- data/lib/solargraph/source_map.rb +11 -18
- data/lib/solargraph/source_map/clip.rb +13 -15
- data/lib/solargraph/source_map/mapper.rb +37 -26
- data/lib/solargraph/source_map/node_processor.rb +13 -8
- data/lib/solargraph/source_map/node_processor/alias_node.rb +8 -8
- data/lib/solargraph/source_map/node_processor/args_node.rb +10 -16
- data/lib/solargraph/source_map/node_processor/base.rb +47 -4
- data/lib/solargraph/source_map/node_processor/block_node.rb +9 -4
- data/lib/solargraph/source_map/node_processor/casgn_node.rb +7 -2
- data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +8 -3
- data/lib/solargraph/source_map/node_processor/def_node.rb +45 -38
- data/lib/solargraph/source_map/node_processor/defs_node.rb +16 -6
- data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +8 -1
- data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +20 -6
- data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +10 -4
- data/lib/solargraph/source_map/node_processor/namespace_node.rb +18 -12
- data/lib/solargraph/source_map/node_processor/orasgn_node.rb +1 -1
- data/lib/solargraph/source_map/node_processor/resbody_node.rb +30 -0
- data/lib/solargraph/source_map/node_processor/sclass_node.rb +7 -1
- data/lib/solargraph/source_map/node_processor/send_node.rb +102 -52
- data/lib/solargraph/source_map/node_processor/sym_node.rb +4 -1
- data/lib/solargraph/source_map/region.rb +9 -8
- data/lib/solargraph/type_checker.rb +282 -0
- data/lib/solargraph/type_checker/param_def.rb +47 -0
- data/lib/solargraph/type_checker/problem.rb +25 -0
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +1 -1
- data/lib/solargraph/workspace.rb +2 -2
- data/lib/solargraph/workspace/config.rb +0 -8
- data/lib/solargraph/yard_map.rb +25 -69
- data/lib/solargraph/yard_map/core_docs.rb +8 -3
- data/lib/solargraph/yard_map/core_gen.rb +1 -3
- data/lib/solargraph/yard_map/mapper.rb +85 -0
- data/lib/yard-solargraph.rb +2 -0
- metadata +14 -14
- data/lib/solargraph/diagnostics/type_not_defined.rb +0 -108
- data/lib/solargraph/live_map.rb +0 -126
- data/lib/solargraph/live_map/cache.rb +0 -38
- data/lib/solargraph/pin/block_parameter.rb +0 -103
- data/lib/solargraph/pin/method_parameter.rb +0 -40
- data/lib/solargraph/pin/plugin/method.rb +0 -25
- data/lib/solargraph/plugin.rb +0 -8
- data/lib/solargraph/plugin/base.rb +0 -41
- data/lib/solargraph/plugin/canceler.rb +0 -11
- data/lib/solargraph/plugin/process.rb +0 -172
- data/lib/solargraph/plugin/runtime.rb +0 -134
- data/lib/yard-coregen.rb +0 -16
@@ -4,8 +4,9 @@ module Solargraph
|
|
4
4
|
# @param location [Solargraph::Location]
|
5
5
|
# @param name [String]
|
6
6
|
def initialize location, name
|
7
|
-
|
8
|
-
@
|
7
|
+
super(location: location, name: name)
|
8
|
+
# @name = name
|
9
|
+
# @location = location
|
9
10
|
end
|
10
11
|
|
11
12
|
def namespace
|
@@ -28,14 +29,18 @@ module Solargraph
|
|
28
29
|
''
|
29
30
|
end
|
30
31
|
|
31
|
-
def
|
32
|
-
@
|
32
|
+
def return_type
|
33
|
+
@return_type ||= Solargraph::ComplexType::SYMBOL
|
33
34
|
end
|
34
35
|
|
35
36
|
def directives
|
36
37
|
[]
|
37
38
|
end
|
38
39
|
|
40
|
+
def visibility
|
41
|
+
:public
|
42
|
+
end
|
43
|
+
|
39
44
|
def deprecated?
|
40
45
|
false
|
41
46
|
end
|
@@ -4,11 +4,20 @@ module Solargraph
|
|
4
4
|
class Constant < Pin::Constant
|
5
5
|
include YardMixin
|
6
6
|
|
7
|
-
def initialize code_object, location
|
8
|
-
|
7
|
+
def initialize code_object, location, closure = nil
|
8
|
+
@code_object = code_object
|
9
|
+
closure ||= Solargraph::Pin::Namespace.new(
|
10
|
+
name: code_object.namespace.to_s
|
11
|
+
)
|
12
|
+
super(
|
13
|
+
location: location,
|
14
|
+
closure: closure,
|
15
|
+
name: code_object.name.to_s,
|
16
|
+
comments: comments_from(code_object),
|
17
|
+
visibility: code_object.visibility
|
18
|
+
)
|
9
19
|
end
|
10
20
|
end
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
14
|
-
map = Solargraph::ApiMap.new
|
@@ -4,15 +4,27 @@ module Solargraph
|
|
4
4
|
class Method < Pin::Method
|
5
5
|
include YardMixin
|
6
6
|
|
7
|
-
def initialize code_object, location, name = nil, scope = nil, visibility = nil
|
7
|
+
def initialize code_object, location, name = nil, scope = nil, visibility = nil, closure = nil
|
8
|
+
@code_object = code_object
|
8
9
|
comments = (code_object.docstring ? code_object.docstring.all : nil)
|
9
|
-
|
10
|
+
closure ||= Solargraph::Pin::Namespace.new(
|
11
|
+
name: code_object.namespace.to_s
|
12
|
+
)
|
13
|
+
super(
|
14
|
+
location: location,
|
15
|
+
closure: closure,
|
16
|
+
name: name || code_object.name.to_s,
|
17
|
+
comments: comments,
|
18
|
+
scope: scope || code_object.scope,
|
19
|
+
visibility: visibility || code_object.visibility,
|
20
|
+
args: get_parameters(code_object)
|
21
|
+
)
|
10
22
|
end
|
11
23
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
end
|
24
|
+
# def return_type
|
25
|
+
# @return_type ||= Solargraph::ComplexType.try_parse(Solargraph::CoreFills::CUSTOM_RETURN_TYPES[path]) if Solargraph::CoreFills::CUSTOM_RETURN_TYPES.has_key?(path)
|
26
|
+
# super
|
27
|
+
# end
|
16
28
|
|
17
29
|
private
|
18
30
|
|
@@ -5,7 +5,19 @@ module Solargraph
|
|
5
5
|
include YardMixin
|
6
6
|
|
7
7
|
def initialize code_object, location
|
8
|
-
|
8
|
+
@code_object = code_object
|
9
|
+
closure = Solargraph::Pin::Namespace.new(
|
10
|
+
name: code_object.namespace.to_s,
|
11
|
+
closure: Pin::ROOT_PIN
|
12
|
+
)
|
13
|
+
super(
|
14
|
+
location: location,
|
15
|
+
name: code_object.name.to_s,
|
16
|
+
comments: comments_from(code_object),
|
17
|
+
type: namespace_type(code_object),
|
18
|
+
visibility: code_object.visibility,
|
19
|
+
closure: closure
|
20
|
+
)
|
9
21
|
end
|
10
22
|
|
11
23
|
private
|
data/lib/solargraph/position.rb
CHANGED
data/lib/solargraph/range.rb
CHANGED
data/lib/solargraph/shell.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
|
-
require 'json'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'rubygems/package'
|
5
|
-
require 'zlib'
|
6
2
|
require 'backport'
|
3
|
+
require 'benchmark'
|
7
4
|
|
8
5
|
module Solargraph
|
9
6
|
class Shell < Thor
|
@@ -77,6 +74,10 @@ module Solargraph
|
|
77
74
|
ver = version || Solargraph::YardMap::CoreDocs.best_download
|
78
75
|
puts "Downloading docs for #{ver}..."
|
79
76
|
Solargraph::YardMap::CoreDocs.download ver
|
77
|
+
rescue ArgumentError => e
|
78
|
+
STDERR.puts "ERROR: #{e.message}"
|
79
|
+
STDERR.puts "Run `solargraph available-cores` for a list."
|
80
|
+
exit 1
|
80
81
|
end
|
81
82
|
|
82
83
|
desc 'list-cores', 'List the local documentation versions'
|
@@ -98,5 +99,83 @@ module Solargraph
|
|
98
99
|
def reporters
|
99
100
|
puts Solargraph::Diagnostics.reporters
|
100
101
|
end
|
102
|
+
|
103
|
+
desc 'typecheck [FILE]', 'Run the type checker'
|
104
|
+
long_desc %(
|
105
|
+
Perform type checking on one or more files is a workspace.
|
106
|
+
A normal check reports problems with type definitions in method
|
107
|
+
parameters and return values. A strict check performs static analysis of
|
108
|
+
code to validate return types and arguments in method calls.
|
109
|
+
)
|
110
|
+
option :strict, type: :boolean, aliases: :s, desc: 'Use strict typing', default: false
|
111
|
+
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
112
|
+
def typecheck *files
|
113
|
+
directory = File.realpath(options[:directory])
|
114
|
+
api_map = Solargraph::ApiMap.load(directory)
|
115
|
+
if files.empty?
|
116
|
+
files = api_map.source_maps.map(&:filename)
|
117
|
+
else
|
118
|
+
files.map! { |file| File.realpath(file) }
|
119
|
+
end
|
120
|
+
probcount = 0
|
121
|
+
filecount = 0
|
122
|
+
files.each do |file|
|
123
|
+
checker = TypeChecker.new(file, api_map: api_map)
|
124
|
+
problems = checker.param_type_problems + checker.return_type_problems
|
125
|
+
problems.concat checker.strict_type_problems if options[:strict]
|
126
|
+
next if problems.empty?
|
127
|
+
problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
|
128
|
+
puts problems.map { |prob| "#{prob.location.filename}:#{prob.location.range.start.line + 1} - #{prob.message}" }.join("\n")
|
129
|
+
filecount += 1
|
130
|
+
probcount += problems.length
|
131
|
+
end
|
132
|
+
puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
|
133
|
+
end
|
134
|
+
|
135
|
+
desc 'scan', 'Test the workspace for problems'
|
136
|
+
long_desc %(
|
137
|
+
A scan loads the entire workspace to make sure that the ASTs and
|
138
|
+
maps do not raise errors during analysis. It does not perform any type
|
139
|
+
checking or validation; it only confirms that the analysis itself is
|
140
|
+
error-free.
|
141
|
+
)
|
142
|
+
option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
|
143
|
+
option :verbose, type: :boolean, aliases: :v, desc: 'Verbose output', default: false
|
144
|
+
def scan
|
145
|
+
directory = File.realpath(options[:directory])
|
146
|
+
api_map = nil
|
147
|
+
time = Benchmark.measure {
|
148
|
+
api_map = Solargraph::ApiMap.load(directory)
|
149
|
+
api_map.pins.each do |pin|
|
150
|
+
begin
|
151
|
+
puts pin_description(pin) if options[:verbose]
|
152
|
+
pin.typify api_map
|
153
|
+
pin.probe api_map
|
154
|
+
rescue Exception => e
|
155
|
+
STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
|
156
|
+
STDERR.puts "[#{e.class}]: #{e.message}"
|
157
|
+
STDERR.puts e.backtrace.join("\n")
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
end
|
161
|
+
}
|
162
|
+
puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
# @param pin [Solargraph::Pin::Base]
|
168
|
+
# @return [String]
|
169
|
+
def pin_description pin
|
170
|
+
if pin.path.nil? || pin.path.empty?
|
171
|
+
if pin.closure
|
172
|
+
"#{pin.closure.path} | #{pin.name}"
|
173
|
+
else
|
174
|
+
"#{pin.context.namespace} | #{pin.name}"
|
175
|
+
end
|
176
|
+
else
|
177
|
+
pin.path
|
178
|
+
end
|
179
|
+
end
|
101
180
|
end
|
102
181
|
end
|
data/lib/solargraph/source.rb
CHANGED
@@ -56,8 +56,8 @@ module Solargraph
|
|
56
56
|
@comments = []
|
57
57
|
@parsed = false
|
58
58
|
rescue Exception => e
|
59
|
-
|
60
|
-
|
59
|
+
Solargraph.logger.warn "[#{e.class}] #{e.message}"
|
60
|
+
Solargraph.logger.warn e.backtrace.join("\n")
|
61
61
|
raise "Error parsing #{filename || '(source)'}: [#{e.class}] #{e.message}"
|
62
62
|
ensure
|
63
63
|
@code.freeze
|
@@ -191,8 +191,22 @@ module Solargraph
|
|
191
191
|
# @param position [Position]
|
192
192
|
# @return [Boolean]
|
193
193
|
def string_at? position
|
194
|
-
|
195
|
-
|
194
|
+
return false if Position.to_offset(code, position) >= code.length
|
195
|
+
string_nodes.each do |node|
|
196
|
+
range = Range.from_node(node)
|
197
|
+
next if range.ending.line < position.line
|
198
|
+
break if range.ending.line > position.line
|
199
|
+
return true if node.type == :str && range.include?(position) && range.start != position
|
200
|
+
if node.type == :dstr
|
201
|
+
inner = node_at(position.line, position.column)
|
202
|
+
next if inner.nil?
|
203
|
+
inner_range = Range.from_node(inner)
|
204
|
+
next unless range.include?(inner_range.ending)
|
205
|
+
return true if inner.type == :str
|
206
|
+
inner_code = at(Solargraph::Range.new(inner_range.start, position))
|
207
|
+
return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
|
208
|
+
(inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
|
209
|
+
end
|
196
210
|
break if range.ending.line > position.line
|
197
211
|
end
|
198
212
|
false
|
@@ -290,7 +304,7 @@ module Solargraph
|
|
290
304
|
@associated_comments ||= begin
|
291
305
|
result = {}
|
292
306
|
Parser::Source::Comment.associate_locations(node, comments).each_pair do |loc, all|
|
293
|
-
block = all
|
307
|
+
block = all.select { |l| l.loc.line < loc.line }
|
294
308
|
next if block.empty?
|
295
309
|
result[loc.line] ||= []
|
296
310
|
result[loc.line].concat block
|
@@ -351,9 +365,9 @@ module Solargraph
|
|
351
365
|
@stringified_comments ||= {}
|
352
366
|
end
|
353
367
|
|
354
|
-
# @return [Array<
|
355
|
-
def
|
356
|
-
@
|
368
|
+
# @return [Array<Parser::AST::Node>]
|
369
|
+
def string_nodes
|
370
|
+
@string_nodes ||= string_nodes_in(@node)
|
357
371
|
end
|
358
372
|
|
359
373
|
# @return [Array<Range>]
|
@@ -393,18 +407,24 @@ module Solargraph
|
|
393
407
|
result
|
394
408
|
end
|
395
409
|
|
396
|
-
|
410
|
+
# @param n [Parser::AST::Node]
|
411
|
+
# @return [Array<Parser::AST::Node>]
|
412
|
+
def string_nodes_in n
|
397
413
|
result = []
|
398
414
|
if n.is_a?(Parser::AST::Node)
|
399
|
-
if n.type == :str
|
400
|
-
result.push
|
415
|
+
if n.type == :str || n.type == :dstr
|
416
|
+
result.push n
|
401
417
|
else
|
402
|
-
n.children.each{ |c| result.concat
|
418
|
+
n.children.each{ |c| result.concat string_nodes_in(c) }
|
403
419
|
end
|
404
420
|
end
|
405
421
|
result
|
406
422
|
end
|
407
423
|
|
424
|
+
# @param node [Parser::AST::Node]
|
425
|
+
# @param position [Position]
|
426
|
+
# @param stack [Array<Parser::AST::Node>]
|
427
|
+
# @return [void]
|
408
428
|
def inner_tree_at node, position, stack
|
409
429
|
return if node.nil?
|
410
430
|
here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
|
@@ -17,9 +17,7 @@ module Solargraph
|
|
17
17
|
autoload :Literal, 'solargraph/source/chain/literal'
|
18
18
|
autoload :Head, 'solargraph/source/chain/head'
|
19
19
|
|
20
|
-
|
21
|
-
# See Chain#active_signature for more information.
|
22
|
-
@@inference_stack = []
|
20
|
+
@@inference_depth = 0
|
23
21
|
|
24
22
|
UNDEFINED_CALL = Chain::Call.new('<undefined>')
|
25
23
|
UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
|
@@ -43,16 +41,18 @@ module Solargraph
|
|
43
41
|
# @param locals [Array<Pin::Base>]
|
44
42
|
# @return [Array<Pin::Base>]
|
45
43
|
def define api_map, name_pin, locals
|
44
|
+
rebind_block name_pin, api_map, locals
|
46
45
|
return [] if undefined?
|
47
46
|
working_pin = name_pin
|
48
47
|
links[0..-2].each do |link|
|
49
48
|
pins = link.resolve(api_map, working_pin, locals)
|
50
49
|
# Locals are only used when resolving the first link
|
51
50
|
locals = []
|
52
|
-
type = infer_first_defined(pins, api_map)
|
51
|
+
type = infer_first_defined(pins, working_pin, api_map)
|
53
52
|
return [] if type.undefined?
|
54
53
|
working_pin = Pin::ProxyType.anonymous(type)
|
55
54
|
end
|
55
|
+
links.last.last_context = working_pin
|
56
56
|
links.last.resolve(api_map, working_pin, locals)
|
57
57
|
end
|
58
58
|
|
@@ -61,16 +61,10 @@ module Solargraph
|
|
61
61
|
# @param locals [Array<Pin::Base>]
|
62
62
|
# @return [ComplexType]
|
63
63
|
def infer api_map, name_pin, locals
|
64
|
-
|
65
|
-
@@inference_stack.push active_signature(name_pin)
|
64
|
+
rebind_block name_pin, api_map, locals
|
66
65
|
type = ComplexType::UNDEFINED
|
67
66
|
pins = define(api_map, name_pin, locals)
|
68
|
-
pins.
|
69
|
-
type = pin.typify(api_map)
|
70
|
-
break unless type.undefined?
|
71
|
-
end
|
72
|
-
type = pins.first.probe(api_map) unless type.defined? || pins.empty?
|
73
|
-
@@inference_stack.pop
|
67
|
+
type = infer_first_defined(pins, links.last.last_context, api_map)
|
74
68
|
type
|
75
69
|
end
|
76
70
|
|
@@ -91,29 +85,55 @@ module Solargraph
|
|
91
85
|
|
92
86
|
private
|
93
87
|
|
94
|
-
# Get a signature for this chain that includes the current context
|
95
|
-
# where it's being analyzed. Chain#infer uses this value to detect
|
96
|
-
# recursive inference into the same chain, e.g., when two variables
|
97
|
-
# reference each other in their assignments.
|
98
|
-
#
|
99
|
-
# @param pin [Pin::Base] The named pin context
|
100
|
-
# @return [String]
|
101
|
-
def active_signature(pin)
|
102
|
-
"#{pin.path}|#{links.map(&:word).join('.')}"
|
103
|
-
end
|
104
|
-
|
105
88
|
# @param pins [Array<Pin::Base>]
|
106
89
|
# @param api_map [ApiMap]
|
107
90
|
# @return [ComplexType]
|
108
|
-
def infer_first_defined pins, api_map
|
91
|
+
def infer_first_defined pins, context, api_map
|
109
92
|
type = ComplexType::UNDEFINED
|
93
|
+
return type if @@inference_depth >= 3
|
94
|
+
@@inference_depth += 1
|
110
95
|
pins.each do |pin|
|
111
|
-
# type = pin.infer(api_map)
|
112
96
|
type = pin.typify(api_map)
|
113
|
-
break
|
97
|
+
break if type.defined?
|
98
|
+
end
|
99
|
+
if type.undefined?
|
100
|
+
pins.each do |pin|
|
101
|
+
type = pin.probe(api_map)
|
102
|
+
break if type.defined?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@@inference_depth -= 1
|
106
|
+
return type if context.nil? || context.return_type.undefined?
|
107
|
+
type.self_to(context.return_type.namespace)
|
108
|
+
end
|
109
|
+
|
110
|
+
def skippable_block_receivers api_map
|
111
|
+
@@skippable_block_receivers ||= (
|
112
|
+
api_map.get_methods('Array', deep: false).map(&:name) +
|
113
|
+
api_map.get_methods('Enumerable', deep: false).map(&:name) +
|
114
|
+
api_map.get_methods('Hash', deep: false).map(&:name) +
|
115
|
+
['new']
|
116
|
+
).to_set
|
117
|
+
end
|
118
|
+
|
119
|
+
def rebind_block pin, api_map, locals
|
120
|
+
return unless pin.is_a?(Pin::Block) && pin.receiver && !pin.rebound?
|
121
|
+
# This first rebind just sets the block pin's rebound state
|
122
|
+
pin.rebind ComplexType::UNDEFINED
|
123
|
+
chain = Solargraph::Source::NodeChainer.chain(pin.receiver, pin.location.filename)
|
124
|
+
return if skippable_block_receivers(api_map).include?(chain.links.last.word)
|
125
|
+
if ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec'].include?(chain.links.last.word)
|
126
|
+
type = chain.base.infer(api_map, pin, locals)
|
127
|
+
pin.rebind type
|
128
|
+
else
|
129
|
+
receiver_pin = chain.define(api_map, pin, locals).first
|
130
|
+
return if receiver_pin.nil? || receiver_pin.docstring.nil?
|
131
|
+
ys = receiver_pin.docstring.tag(:yieldself)
|
132
|
+
unless ys.nil? || ys.types.nil? || ys.types.empty?
|
133
|
+
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
134
|
+
pin.rebind ysct
|
135
|
+
end
|
114
136
|
end
|
115
|
-
type = pins.first.probe(api_map) unless type.defined? || pins.empty?
|
116
|
-
type
|
117
137
|
end
|
118
138
|
end
|
119
139
|
end
|