solargraph 0.32.5 → 0.33.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/.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
|