solargraph 0.58.1 → 0.58.2
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/CHANGELOG.md +7 -1
- data/lib/solargraph/api_map/cache.rb +110 -110
- data/lib/solargraph/api_map/constants.rb +279 -279
- data/lib/solargraph/api_map/index.rb +193 -193
- data/lib/solargraph/api_map/source_to_yard.rb +97 -97
- data/lib/solargraph/api_map/store.rb +384 -384
- data/lib/solargraph/api_map.rb +945 -945
- data/lib/solargraph/complex_type/type_methods.rb +228 -228
- data/lib/solargraph/complex_type/unique_type.rb +482 -482
- data/lib/solargraph/complex_type.rb +444 -444
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -91
- data/lib/solargraph/convention/data_definition.rb +105 -105
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -61
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -102
- data/lib/solargraph/convention/struct_definition.rb +164 -164
- data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
- data/lib/solargraph/diagnostics/rubocop.rb +118 -118
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -68
- data/lib/solargraph/diagnostics/type_check.rb +55 -55
- data/lib/solargraph/doc_map.rb +439 -439
- data/lib/solargraph/equality.rb +34 -34
- data/lib/solargraph/gem_pins.rb +98 -98
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +130 -130
- data/lib/solargraph/language_server/host/message_worker.rb +112 -112
- data/lib/solargraph/language_server/host/sources.rb +99 -99
- data/lib/solargraph/language_server/host.rb +878 -878
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -114
- data/lib/solargraph/language_server/message/extended/document.rb +23 -23
- data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
- data/lib/solargraph/language_server/message/text_document/definition.rb +40 -40
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
- data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -148
- data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -25
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
- data/lib/solargraph/library.rb +683 -683
- data/lib/solargraph/location.rb +82 -82
- data/lib/solargraph/logging.rb +37 -37
- data/lib/solargraph/parser/comment_ripper.rb +69 -69
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -255
- data/lib/solargraph/parser/node_processor/base.rb +92 -92
- data/lib/solargraph/parser/node_processor.rb +62 -62
- data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -149
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -166
- data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -486
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -59
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -53
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -23
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -40
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -59
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -38
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -52
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -291
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -29
- data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -70
- data/lib/solargraph/parser/region.rb +69 -69
- data/lib/solargraph/parser/snippet.rb +17 -17
- data/lib/solargraph/pin/base.rb +729 -729
- data/lib/solargraph/pin/base_variable.rb +126 -126
- data/lib/solargraph/pin/block.rb +104 -104
- data/lib/solargraph/pin/breakable.rb +9 -9
- data/lib/solargraph/pin/callable.rb +231 -231
- data/lib/solargraph/pin/closure.rb +72 -72
- data/lib/solargraph/pin/common.rb +79 -79
- data/lib/solargraph/pin/conversions.rb +123 -123
- data/lib/solargraph/pin/delegated_method.rb +120 -120
- data/lib/solargraph/pin/documenting.rb +114 -114
- data/lib/solargraph/pin/instance_variable.rb +34 -34
- data/lib/solargraph/pin/keyword.rb +20 -20
- data/lib/solargraph/pin/local_variable.rb +75 -75
- data/lib/solargraph/pin/method.rb +672 -672
- data/lib/solargraph/pin/method_alias.rb +34 -34
- data/lib/solargraph/pin/namespace.rb +115 -115
- data/lib/solargraph/pin/parameter.rb +275 -275
- data/lib/solargraph/pin/proxy_type.rb +39 -39
- data/lib/solargraph/pin/reference/override.rb +47 -47
- data/lib/solargraph/pin/reference/superclass.rb +15 -15
- data/lib/solargraph/pin/reference.rb +39 -39
- data/lib/solargraph/pin/search.rb +61 -61
- data/lib/solargraph/pin/signature.rb +61 -61
- data/lib/solargraph/pin/symbol.rb +53 -53
- data/lib/solargraph/pin/until.rb +18 -18
- data/lib/solargraph/pin/while.rb +18 -18
- data/lib/solargraph/pin.rb +44 -44
- data/lib/solargraph/pin_cache.rb +245 -245
- data/lib/solargraph/position.rb +132 -119
- data/lib/solargraph/range.rb +112 -112
- data/lib/solargraph/rbs_map/conversions.rb +823 -823
- data/lib/solargraph/rbs_map/core_map.rb +58 -58
- data/lib/solargraph/rbs_map/stdlib_map.rb +43 -43
- data/lib/solargraph/rbs_map.rb +163 -163
- data/lib/solargraph/shell.rb +352 -352
- data/lib/solargraph/source/chain/call.rb +337 -337
- data/lib/solargraph/source/chain/constant.rb +26 -26
- data/lib/solargraph/source/chain/hash.rb +34 -34
- data/lib/solargraph/source/chain/if.rb +28 -28
- data/lib/solargraph/source/chain/instance_variable.rb +13 -13
- data/lib/solargraph/source/chain/literal.rb +48 -48
- data/lib/solargraph/source/chain/or.rb +23 -23
- data/lib/solargraph/source/chain.rb +291 -291
- data/lib/solargraph/source/change.rb +82 -82
- data/lib/solargraph/source/cursor.rb +166 -166
- data/lib/solargraph/source/source_chainer.rb +194 -194
- data/lib/solargraph/source/updater.rb +55 -55
- data/lib/solargraph/source.rb +498 -498
- data/lib/solargraph/source_map/clip.rb +226 -226
- data/lib/solargraph/source_map/data.rb +34 -34
- data/lib/solargraph/source_map/mapper.rb +259 -259
- data/lib/solargraph/source_map.rb +212 -212
- data/lib/solargraph/type_checker/checks.rb +124 -124
- data/lib/solargraph/type_checker/param_def.rb +37 -37
- data/lib/solargraph/type_checker/problem.rb +32 -32
- data/lib/solargraph/type_checker/rules.rb +84 -84
- data/lib/solargraph/type_checker.rb +814 -814
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +255 -255
- data/lib/solargraph/workspace/require_paths.rb +97 -97
- data/lib/solargraph/workspace.rb +220 -220
- data/lib/solargraph/yard_map/helpers.rb +44 -44
- data/lib/solargraph/yard_map/mapper/to_method.rb +130 -130
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -31
- data/lib/solargraph/yard_map/mapper.rb +79 -79
- data/lib/solargraph/yard_map/to_method.rb +89 -89
- data/lib/solargraph/yardoc.rb +87 -87
- data/lib/solargraph.rb +105 -105
- data/rbs_collection.yaml +1 -1
- metadata +12 -12
- /data/{sig → rbs}/shims/ast/0/node.rbs +0 -0
- /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
|
@@ -1,337 +1,337 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Solargraph
|
|
4
|
-
class Source
|
|
5
|
-
class Chain
|
|
6
|
-
#
|
|
7
|
-
# Handles both method calls and local variable references by
|
|
8
|
-
# first looking for a variable with the name 'word', then
|
|
9
|
-
# proceeding to method signature resolution if not found.
|
|
10
|
-
#
|
|
11
|
-
class Call < Chain::Link
|
|
12
|
-
include Solargraph::Parser::NodeMethods
|
|
13
|
-
|
|
14
|
-
# @return [String]
|
|
15
|
-
attr_reader :word
|
|
16
|
-
|
|
17
|
-
# @return [Location]
|
|
18
|
-
attr_reader :location
|
|
19
|
-
|
|
20
|
-
# @return [::Array<Chain>]
|
|
21
|
-
attr_reader :arguments
|
|
22
|
-
|
|
23
|
-
# @return [Chain, nil]
|
|
24
|
-
attr_reader :block
|
|
25
|
-
|
|
26
|
-
# @param word [String]
|
|
27
|
-
# @param location [Location, nil]
|
|
28
|
-
# @param arguments [::Array<Chain>]
|
|
29
|
-
# @param block [Chain, nil]
|
|
30
|
-
def initialize word, location = nil, arguments = [], block = nil
|
|
31
|
-
@word = word
|
|
32
|
-
@location = location
|
|
33
|
-
@arguments = arguments
|
|
34
|
-
@block = block
|
|
35
|
-
fix_block_pass
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
39
|
-
protected def equality_fields
|
|
40
|
-
super + [arguments, block]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def with_block?
|
|
44
|
-
!!@block
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# @param api_map [ApiMap]
|
|
48
|
-
# @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
|
|
49
|
-
# @param locals [::Array<Pin::LocalVariable>]
|
|
50
|
-
def resolve api_map, name_pin, locals
|
|
51
|
-
return super_pins(api_map, name_pin) if word == 'super'
|
|
52
|
-
return yield_pins(api_map, name_pin) if word == 'yield'
|
|
53
|
-
found = if head?
|
|
54
|
-
api_map.visible_pins(locals, word, name_pin, location)
|
|
55
|
-
else
|
|
56
|
-
[]
|
|
57
|
-
end
|
|
58
|
-
return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
|
|
59
|
-
pins = name_pin.binder.each_unique_type.flat_map do |context|
|
|
60
|
-
ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
|
|
61
|
-
stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
|
|
62
|
-
[stack.first].compact
|
|
63
|
-
end
|
|
64
|
-
return [] if pins.empty?
|
|
65
|
-
inferred_pins(pins, api_map, name_pin, locals)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
# @param pins [::Enumerable<Pin::Method>]
|
|
71
|
-
# @param api_map [ApiMap]
|
|
72
|
-
# @param name_pin [Pin::Base]
|
|
73
|
-
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
74
|
-
# @return [::Array<Pin::Base>]
|
|
75
|
-
def inferred_pins pins, api_map, name_pin, locals
|
|
76
|
-
result = pins.map do |p|
|
|
77
|
-
next p unless p.is_a?(Pin::Method)
|
|
78
|
-
overloads = p.signatures
|
|
79
|
-
# next p if overloads.empty?
|
|
80
|
-
type = ComplexType::UNDEFINED
|
|
81
|
-
# start with overloads that require blocks; if we are
|
|
82
|
-
# passing a block, we want to find a signature that will
|
|
83
|
-
# use it. If we didn't pass a block, the logic below will
|
|
84
|
-
# reject it regardless
|
|
85
|
-
|
|
86
|
-
with_block, without_block = overloads.partition(&:block?)
|
|
87
|
-
sorted_overloads = with_block + without_block
|
|
88
|
-
# @type [Pin::Signature, nil]
|
|
89
|
-
new_signature_pin = nil
|
|
90
|
-
sorted_overloads.each do |ol|
|
|
91
|
-
next unless ol.arity_matches?(arguments, with_block?)
|
|
92
|
-
match = true
|
|
93
|
-
|
|
94
|
-
atypes = []
|
|
95
|
-
arguments.each_with_index do |arg, idx|
|
|
96
|
-
param = ol.parameters[idx]
|
|
97
|
-
if param.nil?
|
|
98
|
-
match = ol.parameters.any?(&:restarg?)
|
|
99
|
-
break
|
|
100
|
-
end
|
|
101
|
-
arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
|
|
102
|
-
gates: name_pin.gates,
|
|
103
|
-
source: :chain)
|
|
104
|
-
atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
|
|
105
|
-
unless param.compatible_arg?(atype, api_map) || param.restarg?
|
|
106
|
-
match = false
|
|
107
|
-
break
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
if match
|
|
111
|
-
if ol.block && with_block?
|
|
112
|
-
block_atypes = ol.block.parameters.map(&:return_type)
|
|
113
|
-
if block.links.map(&:class) == [BlockSymbol]
|
|
114
|
-
# like the bar in foo(&:bar)
|
|
115
|
-
blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
|
|
116
|
-
else
|
|
117
|
-
blocktype = block_call_type(api_map, name_pin, locals)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
# @type new_signature_pin [Pin::Signature]
|
|
121
|
-
new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
|
|
122
|
-
new_return_type = new_signature_pin.return_type
|
|
123
|
-
if head?
|
|
124
|
-
# If we're at the head of the chain, we called a
|
|
125
|
-
# method somewhere that marked itself as returning
|
|
126
|
-
# self. Given we didn't invoke this on an object,
|
|
127
|
-
# this must be a method in this same class - so we
|
|
128
|
-
# use our own self type
|
|
129
|
-
self_type = name_pin.context
|
|
130
|
-
else
|
|
131
|
-
# if we're past the head in the chain, whatever the
|
|
132
|
-
# type of the lhs side is what 'self' will be in its
|
|
133
|
-
# declaration - we can't just use the type of the
|
|
134
|
-
# method pin, as this might be a subclass of the
|
|
135
|
-
# place where the method is defined
|
|
136
|
-
self_type = name_pin.binder
|
|
137
|
-
end
|
|
138
|
-
# This same logic applies to the YARD work done by
|
|
139
|
-
# 'with_params()'.
|
|
140
|
-
#
|
|
141
|
-
# qualify(), however, happens in the namespace where
|
|
142
|
-
# the docs were written - from the method pin.
|
|
143
|
-
type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, *p.gates) if new_return_type.defined?
|
|
144
|
-
type ||= ComplexType::UNDEFINED
|
|
145
|
-
end
|
|
146
|
-
break if type.defined?
|
|
147
|
-
end
|
|
148
|
-
p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
|
|
149
|
-
next p.proxy(type) if type.defined?
|
|
150
|
-
if !p.macros.empty?
|
|
151
|
-
result = process_macro(p, api_map, name_pin.context, locals)
|
|
152
|
-
next result unless result.return_type.undefined?
|
|
153
|
-
elsif !p.directives.empty?
|
|
154
|
-
result = process_directive(p, api_map, name_pin.context, locals)
|
|
155
|
-
next result unless result.return_type.undefined?
|
|
156
|
-
end
|
|
157
|
-
p
|
|
158
|
-
end
|
|
159
|
-
logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
|
|
160
|
-
out = result.map do |pin|
|
|
161
|
-
if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
|
|
162
|
-
reduced_context = name_pin.binder.reduce_class_type
|
|
163
|
-
pin.proxy(reduced_context)
|
|
164
|
-
else
|
|
165
|
-
next pin if pin.return_type.undefined?
|
|
166
|
-
selfy = pin.return_type.self_to_type(name_pin.binder)
|
|
167
|
-
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# @param pin [Pin::Base]
|
|
173
|
-
# @param api_map [ApiMap]
|
|
174
|
-
# @param context [ComplexType]
|
|
175
|
-
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
176
|
-
# @return [Pin::Base]
|
|
177
|
-
def process_macro pin, api_map, context, locals
|
|
178
|
-
pin.macros.each do |macro|
|
|
179
|
-
# @todo 'Wrong argument type for
|
|
180
|
-
# Solargraph::Source::Chain::Call#inner_process_macro:
|
|
181
|
-
# macro expected YARD::Tags::MacroDirective, received
|
|
182
|
-
# generic<Elem>' is because we lose 'rooted' information
|
|
183
|
-
# in the 'Chain::Array' class internally, leaving
|
|
184
|
-
# ::Array#each shadowed when it shouldn't be.
|
|
185
|
-
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
186
|
-
return result unless result.return_type.undefined?
|
|
187
|
-
end
|
|
188
|
-
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# @param pin [Pin::Method]
|
|
192
|
-
# @param api_map [ApiMap]
|
|
193
|
-
# @param context [ComplexType]
|
|
194
|
-
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
195
|
-
# @return [Pin::ProxyType]
|
|
196
|
-
def process_directive pin, api_map, context, locals
|
|
197
|
-
pin.directives.each do |dir|
|
|
198
|
-
macro = api_map.named_macro(dir.tag.name)
|
|
199
|
-
next if macro.nil?
|
|
200
|
-
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
201
|
-
return result unless result.return_type.undefined?
|
|
202
|
-
end
|
|
203
|
-
Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
# @param pin [Pin::Base]
|
|
207
|
-
# @param macro [YARD::Tags::MacroDirective]
|
|
208
|
-
# @param api_map [ApiMap]
|
|
209
|
-
# @param context [ComplexType]
|
|
210
|
-
# @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
|
|
211
|
-
# @return [Pin::ProxyType]
|
|
212
|
-
def inner_process_macro pin, macro, api_map, context, locals
|
|
213
|
-
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
|
|
214
|
-
txt = macro.tag.text.clone
|
|
215
|
-
if txt.empty? && macro.tag.name
|
|
216
|
-
named = api_map.named_macro(macro.tag.name)
|
|
217
|
-
txt = named.tag.text.clone if named
|
|
218
|
-
end
|
|
219
|
-
i = 1
|
|
220
|
-
vals.each do |v|
|
|
221
|
-
txt.gsub!(/\$#{i}/, v.context.namespace)
|
|
222
|
-
i += 1
|
|
223
|
-
end
|
|
224
|
-
docstring = Solargraph::Source.parse_docstring(txt).to_docstring
|
|
225
|
-
tag = docstring.tag(:return)
|
|
226
|
-
unless tag.nil? || tag.types.nil?
|
|
227
|
-
return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
|
|
228
|
-
end
|
|
229
|
-
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
# @param docstring [YARD::Docstring]
|
|
233
|
-
# @param context [ComplexType]
|
|
234
|
-
# @return [ComplexType, nil]
|
|
235
|
-
def extra_return_type docstring, context
|
|
236
|
-
if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
|
|
237
|
-
return context.subtypes.first || ComplexType::UNDEFINED
|
|
238
|
-
elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
|
|
239
|
-
return context.value_types.first
|
|
240
|
-
end
|
|
241
|
-
nil
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
# @param name_pin [Pin::Base]
|
|
245
|
-
# @return [Pin::Method, nil]
|
|
246
|
-
def find_method_pin(name_pin)
|
|
247
|
-
method_pin = name_pin
|
|
248
|
-
until method_pin.is_a?(Pin::Method)
|
|
249
|
-
method_pin = method_pin.closure
|
|
250
|
-
return if method_pin.nil?
|
|
251
|
-
end
|
|
252
|
-
method_pin
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
# @param api_map [ApiMap]
|
|
256
|
-
# @param name_pin [Pin::Base]
|
|
257
|
-
# @return [::Array<Pin::Base>]
|
|
258
|
-
def super_pins api_map, name_pin
|
|
259
|
-
method_pin = find_method_pin(name_pin)
|
|
260
|
-
return [] if method_pin.nil?
|
|
261
|
-
pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
|
|
262
|
-
pins.reject{|p| p.path == name_pin.path}
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
# @param api_map [ApiMap]
|
|
266
|
-
# @param name_pin [Pin::Base]
|
|
267
|
-
# @return [::Array<Pin::Base>]
|
|
268
|
-
def yield_pins api_map, name_pin
|
|
269
|
-
method_pin = find_method_pin(name_pin)
|
|
270
|
-
return [] unless method_pin
|
|
271
|
-
|
|
272
|
-
# @param signature_pin [Pin::Signature]
|
|
273
|
-
method_pin.signatures.map(&:block).compact.map do |signature_pin|
|
|
274
|
-
return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
|
|
275
|
-
signature_pin.proxy(return_type)
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
# @param type [ComplexType]
|
|
280
|
-
# @param context [ComplexType]
|
|
281
|
-
# @return [ComplexType]
|
|
282
|
-
def with_params type, context
|
|
283
|
-
return type unless type.to_s.include?('$')
|
|
284
|
-
ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
# @return [void]
|
|
288
|
-
def fix_block_pass
|
|
289
|
-
argument = @arguments.last&.links&.first
|
|
290
|
-
@block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
# @param api_map [ApiMap]
|
|
294
|
-
# @param context [ComplexType]
|
|
295
|
-
# @param block_parameter_types [::Array<ComplexType>]
|
|
296
|
-
# @param locals [::Array<Pin::LocalVariable>]
|
|
297
|
-
# @return [ComplexType, nil]
|
|
298
|
-
def block_symbol_call_type(api_map, context, block_parameter_types, locals)
|
|
299
|
-
# Ruby's shorthand for sending the passed in method name
|
|
300
|
-
# to the first yield parameter with no arguments
|
|
301
|
-
block_symbol_name = block.links.first.word
|
|
302
|
-
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
|
303
|
-
callee = api_map.get_path_pins(block_symbol_call_path).first
|
|
304
|
-
return_type = callee&.return_type
|
|
305
|
-
# @todo: Figure out why we get unresolved generics at
|
|
306
|
-
# this point and need to assume method return types
|
|
307
|
-
# based on the generic type
|
|
308
|
-
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
|
309
|
-
return_type || ComplexType::UNDEFINED
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
# @param api_map [ApiMap]
|
|
313
|
-
# @return [Pin::Block, nil]
|
|
314
|
-
def find_block_pin(api_map)
|
|
315
|
-
node_location = Solargraph::Location.from_node(block.node)
|
|
316
|
-
return if node_location.nil?
|
|
317
|
-
block_pins = api_map.get_block_pins
|
|
318
|
-
block_pins.find { |pin| pin.location.contain?(node_location) }
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
# @param api_map [ApiMap]
|
|
322
|
-
# @param name_pin [Pin::Base]
|
|
323
|
-
# @param block_parameter_types [::Array<ComplexType>]
|
|
324
|
-
# @param locals [::Array<Pin::LocalVariable>]
|
|
325
|
-
# @return [ComplexType, nil]
|
|
326
|
-
def block_call_type(api_map, name_pin, locals)
|
|
327
|
-
return nil unless with_block?
|
|
328
|
-
|
|
329
|
-
block_context_pin = name_pin
|
|
330
|
-
block_pin = find_block_pin(api_map)
|
|
331
|
-
block_context_pin = block_pin.closure if block_pin
|
|
332
|
-
block.infer(api_map, block_context_pin, locals)
|
|
333
|
-
end
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class Source
|
|
5
|
+
class Chain
|
|
6
|
+
#
|
|
7
|
+
# Handles both method calls and local variable references by
|
|
8
|
+
# first looking for a variable with the name 'word', then
|
|
9
|
+
# proceeding to method signature resolution if not found.
|
|
10
|
+
#
|
|
11
|
+
class Call < Chain::Link
|
|
12
|
+
include Solargraph::Parser::NodeMethods
|
|
13
|
+
|
|
14
|
+
# @return [String]
|
|
15
|
+
attr_reader :word
|
|
16
|
+
|
|
17
|
+
# @return [Location]
|
|
18
|
+
attr_reader :location
|
|
19
|
+
|
|
20
|
+
# @return [::Array<Chain>]
|
|
21
|
+
attr_reader :arguments
|
|
22
|
+
|
|
23
|
+
# @return [Chain, nil]
|
|
24
|
+
attr_reader :block
|
|
25
|
+
|
|
26
|
+
# @param word [String]
|
|
27
|
+
# @param location [Location, nil]
|
|
28
|
+
# @param arguments [::Array<Chain>]
|
|
29
|
+
# @param block [Chain, nil]
|
|
30
|
+
def initialize word, location = nil, arguments = [], block = nil
|
|
31
|
+
@word = word
|
|
32
|
+
@location = location
|
|
33
|
+
@arguments = arguments
|
|
34
|
+
@block = block
|
|
35
|
+
fix_block_pass
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
39
|
+
protected def equality_fields
|
|
40
|
+
super + [arguments, block]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def with_block?
|
|
44
|
+
!!@block
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @param api_map [ApiMap]
|
|
48
|
+
# @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
|
|
49
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
|
50
|
+
def resolve api_map, name_pin, locals
|
|
51
|
+
return super_pins(api_map, name_pin) if word == 'super'
|
|
52
|
+
return yield_pins(api_map, name_pin) if word == 'yield'
|
|
53
|
+
found = if head?
|
|
54
|
+
api_map.visible_pins(locals, word, name_pin, location)
|
|
55
|
+
else
|
|
56
|
+
[]
|
|
57
|
+
end
|
|
58
|
+
return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
|
|
59
|
+
pins = name_pin.binder.each_unique_type.flat_map do |context|
|
|
60
|
+
ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
|
|
61
|
+
stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
|
|
62
|
+
[stack.first].compact
|
|
63
|
+
end
|
|
64
|
+
return [] if pins.empty?
|
|
65
|
+
inferred_pins(pins, api_map, name_pin, locals)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# @param pins [::Enumerable<Pin::Method>]
|
|
71
|
+
# @param api_map [ApiMap]
|
|
72
|
+
# @param name_pin [Pin::Base]
|
|
73
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
74
|
+
# @return [::Array<Pin::Base>]
|
|
75
|
+
def inferred_pins pins, api_map, name_pin, locals
|
|
76
|
+
result = pins.map do |p|
|
|
77
|
+
next p unless p.is_a?(Pin::Method)
|
|
78
|
+
overloads = p.signatures
|
|
79
|
+
# next p if overloads.empty?
|
|
80
|
+
type = ComplexType::UNDEFINED
|
|
81
|
+
# start with overloads that require blocks; if we are
|
|
82
|
+
# passing a block, we want to find a signature that will
|
|
83
|
+
# use it. If we didn't pass a block, the logic below will
|
|
84
|
+
# reject it regardless
|
|
85
|
+
|
|
86
|
+
with_block, without_block = overloads.partition(&:block?)
|
|
87
|
+
sorted_overloads = with_block + without_block
|
|
88
|
+
# @type [Pin::Signature, nil]
|
|
89
|
+
new_signature_pin = nil
|
|
90
|
+
sorted_overloads.each do |ol|
|
|
91
|
+
next unless ol.arity_matches?(arguments, with_block?)
|
|
92
|
+
match = true
|
|
93
|
+
|
|
94
|
+
atypes = []
|
|
95
|
+
arguments.each_with_index do |arg, idx|
|
|
96
|
+
param = ol.parameters[idx]
|
|
97
|
+
if param.nil?
|
|
98
|
+
match = ol.parameters.any?(&:restarg?)
|
|
99
|
+
break
|
|
100
|
+
end
|
|
101
|
+
arg_name_pin = Pin::ProxyType.anonymous(name_pin.context,
|
|
102
|
+
gates: name_pin.gates,
|
|
103
|
+
source: :chain)
|
|
104
|
+
atype = atypes[idx] ||= arg.infer(api_map, arg_name_pin, locals)
|
|
105
|
+
unless param.compatible_arg?(atype, api_map) || param.restarg?
|
|
106
|
+
match = false
|
|
107
|
+
break
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
if match
|
|
111
|
+
if ol.block && with_block?
|
|
112
|
+
block_atypes = ol.block.parameters.map(&:return_type)
|
|
113
|
+
if block.links.map(&:class) == [BlockSymbol]
|
|
114
|
+
# like the bar in foo(&:bar)
|
|
115
|
+
blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
|
|
116
|
+
else
|
|
117
|
+
blocktype = block_call_type(api_map, name_pin, locals)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
# @type new_signature_pin [Pin::Signature]
|
|
121
|
+
new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
|
|
122
|
+
new_return_type = new_signature_pin.return_type
|
|
123
|
+
if head?
|
|
124
|
+
# If we're at the head of the chain, we called a
|
|
125
|
+
# method somewhere that marked itself as returning
|
|
126
|
+
# self. Given we didn't invoke this on an object,
|
|
127
|
+
# this must be a method in this same class - so we
|
|
128
|
+
# use our own self type
|
|
129
|
+
self_type = name_pin.context
|
|
130
|
+
else
|
|
131
|
+
# if we're past the head in the chain, whatever the
|
|
132
|
+
# type of the lhs side is what 'self' will be in its
|
|
133
|
+
# declaration - we can't just use the type of the
|
|
134
|
+
# method pin, as this might be a subclass of the
|
|
135
|
+
# place where the method is defined
|
|
136
|
+
self_type = name_pin.binder
|
|
137
|
+
end
|
|
138
|
+
# This same logic applies to the YARD work done by
|
|
139
|
+
# 'with_params()'.
|
|
140
|
+
#
|
|
141
|
+
# qualify(), however, happens in the namespace where
|
|
142
|
+
# the docs were written - from the method pin.
|
|
143
|
+
type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, *p.gates) if new_return_type.defined?
|
|
144
|
+
type ||= ComplexType::UNDEFINED
|
|
145
|
+
end
|
|
146
|
+
break if type.defined?
|
|
147
|
+
end
|
|
148
|
+
p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
|
|
149
|
+
next p.proxy(type) if type.defined?
|
|
150
|
+
if !p.macros.empty?
|
|
151
|
+
result = process_macro(p, api_map, name_pin.context, locals)
|
|
152
|
+
next result unless result.return_type.undefined?
|
|
153
|
+
elsif !p.directives.empty?
|
|
154
|
+
result = process_directive(p, api_map, name_pin.context, locals)
|
|
155
|
+
next result unless result.return_type.undefined?
|
|
156
|
+
end
|
|
157
|
+
p
|
|
158
|
+
end
|
|
159
|
+
logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
|
|
160
|
+
out = result.map do |pin|
|
|
161
|
+
if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
|
|
162
|
+
reduced_context = name_pin.binder.reduce_class_type
|
|
163
|
+
pin.proxy(reduced_context)
|
|
164
|
+
else
|
|
165
|
+
next pin if pin.return_type.undefined?
|
|
166
|
+
selfy = pin.return_type.self_to_type(name_pin.binder)
|
|
167
|
+
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @param pin [Pin::Base]
|
|
173
|
+
# @param api_map [ApiMap]
|
|
174
|
+
# @param context [ComplexType]
|
|
175
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
176
|
+
# @return [Pin::Base]
|
|
177
|
+
def process_macro pin, api_map, context, locals
|
|
178
|
+
pin.macros.each do |macro|
|
|
179
|
+
# @todo 'Wrong argument type for
|
|
180
|
+
# Solargraph::Source::Chain::Call#inner_process_macro:
|
|
181
|
+
# macro expected YARD::Tags::MacroDirective, received
|
|
182
|
+
# generic<Elem>' is because we lose 'rooted' information
|
|
183
|
+
# in the 'Chain::Array' class internally, leaving
|
|
184
|
+
# ::Array#each shadowed when it shouldn't be.
|
|
185
|
+
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
186
|
+
return result unless result.return_type.undefined?
|
|
187
|
+
end
|
|
188
|
+
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# @param pin [Pin::Method]
|
|
192
|
+
# @param api_map [ApiMap]
|
|
193
|
+
# @param context [ComplexType]
|
|
194
|
+
# @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
|
|
195
|
+
# @return [Pin::ProxyType]
|
|
196
|
+
def process_directive pin, api_map, context, locals
|
|
197
|
+
pin.directives.each do |dir|
|
|
198
|
+
macro = api_map.named_macro(dir.tag.name)
|
|
199
|
+
next if macro.nil?
|
|
200
|
+
result = inner_process_macro(pin, macro, api_map, context, locals)
|
|
201
|
+
return result unless result.return_type.undefined?
|
|
202
|
+
end
|
|
203
|
+
Pin::ProxyType.anonymous ComplexType::UNDEFINED, source: :chain
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# @param pin [Pin::Base]
|
|
207
|
+
# @param macro [YARD::Tags::MacroDirective]
|
|
208
|
+
# @param api_map [ApiMap]
|
|
209
|
+
# @param context [ComplexType]
|
|
210
|
+
# @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
|
|
211
|
+
# @return [Pin::ProxyType]
|
|
212
|
+
def inner_process_macro pin, macro, api_map, context, locals
|
|
213
|
+
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals), source: :chain) }
|
|
214
|
+
txt = macro.tag.text.clone
|
|
215
|
+
if txt.empty? && macro.tag.name
|
|
216
|
+
named = api_map.named_macro(macro.tag.name)
|
|
217
|
+
txt = named.tag.text.clone if named
|
|
218
|
+
end
|
|
219
|
+
i = 1
|
|
220
|
+
vals.each do |v|
|
|
221
|
+
txt.gsub!(/\$#{i}/, v.context.namespace)
|
|
222
|
+
i += 1
|
|
223
|
+
end
|
|
224
|
+
docstring = Solargraph::Source.parse_docstring(txt).to_docstring
|
|
225
|
+
tag = docstring.tag(:return)
|
|
226
|
+
unless tag.nil? || tag.types.nil?
|
|
227
|
+
return Pin::ProxyType.anonymous(ComplexType.try_parse(*tag.types), source: :chain)
|
|
228
|
+
end
|
|
229
|
+
Pin::ProxyType.anonymous(ComplexType::UNDEFINED, source: :chain)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# @param docstring [YARD::Docstring]
|
|
233
|
+
# @param context [ComplexType]
|
|
234
|
+
# @return [ComplexType, nil]
|
|
235
|
+
def extra_return_type docstring, context
|
|
236
|
+
if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
|
|
237
|
+
return context.subtypes.first || ComplexType::UNDEFINED
|
|
238
|
+
elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
|
|
239
|
+
return context.value_types.first
|
|
240
|
+
end
|
|
241
|
+
nil
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# @param name_pin [Pin::Base]
|
|
245
|
+
# @return [Pin::Method, nil]
|
|
246
|
+
def find_method_pin(name_pin)
|
|
247
|
+
method_pin = name_pin
|
|
248
|
+
until method_pin.is_a?(Pin::Method)
|
|
249
|
+
method_pin = method_pin.closure
|
|
250
|
+
return if method_pin.nil?
|
|
251
|
+
end
|
|
252
|
+
method_pin
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# @param api_map [ApiMap]
|
|
256
|
+
# @param name_pin [Pin::Base]
|
|
257
|
+
# @return [::Array<Pin::Base>]
|
|
258
|
+
def super_pins api_map, name_pin
|
|
259
|
+
method_pin = find_method_pin(name_pin)
|
|
260
|
+
return [] if method_pin.nil?
|
|
261
|
+
pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
|
|
262
|
+
pins.reject{|p| p.path == name_pin.path}
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# @param api_map [ApiMap]
|
|
266
|
+
# @param name_pin [Pin::Base]
|
|
267
|
+
# @return [::Array<Pin::Base>]
|
|
268
|
+
def yield_pins api_map, name_pin
|
|
269
|
+
method_pin = find_method_pin(name_pin)
|
|
270
|
+
return [] unless method_pin
|
|
271
|
+
|
|
272
|
+
# @param signature_pin [Pin::Signature]
|
|
273
|
+
method_pin.signatures.map(&:block).compact.map do |signature_pin|
|
|
274
|
+
return_type = signature_pin.return_type.qualify(api_map, *name_pin.gates)
|
|
275
|
+
signature_pin.proxy(return_type)
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @param type [ComplexType]
|
|
280
|
+
# @param context [ComplexType]
|
|
281
|
+
# @return [ComplexType]
|
|
282
|
+
def with_params type, context
|
|
283
|
+
return type unless type.to_s.include?('$')
|
|
284
|
+
ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @return [void]
|
|
288
|
+
def fix_block_pass
|
|
289
|
+
argument = @arguments.last&.links&.first
|
|
290
|
+
@block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# @param api_map [ApiMap]
|
|
294
|
+
# @param context [ComplexType]
|
|
295
|
+
# @param block_parameter_types [::Array<ComplexType>]
|
|
296
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
|
297
|
+
# @return [ComplexType, nil]
|
|
298
|
+
def block_symbol_call_type(api_map, context, block_parameter_types, locals)
|
|
299
|
+
# Ruby's shorthand for sending the passed in method name
|
|
300
|
+
# to the first yield parameter with no arguments
|
|
301
|
+
block_symbol_name = block.links.first.word
|
|
302
|
+
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
|
303
|
+
callee = api_map.get_path_pins(block_symbol_call_path).first
|
|
304
|
+
return_type = callee&.return_type
|
|
305
|
+
# @todo: Figure out why we get unresolved generics at
|
|
306
|
+
# this point and need to assume method return types
|
|
307
|
+
# based on the generic type
|
|
308
|
+
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
|
309
|
+
return_type || ComplexType::UNDEFINED
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# @param api_map [ApiMap]
|
|
313
|
+
# @return [Pin::Block, nil]
|
|
314
|
+
def find_block_pin(api_map)
|
|
315
|
+
node_location = Solargraph::Location.from_node(block.node)
|
|
316
|
+
return if node_location.nil?
|
|
317
|
+
block_pins = api_map.get_block_pins
|
|
318
|
+
block_pins.find { |pin| pin.location.contain?(node_location) }
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# @param api_map [ApiMap]
|
|
322
|
+
# @param name_pin [Pin::Base]
|
|
323
|
+
# @param block_parameter_types [::Array<ComplexType>]
|
|
324
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
|
325
|
+
# @return [ComplexType, nil]
|
|
326
|
+
def block_call_type(api_map, name_pin, locals)
|
|
327
|
+
return nil unless with_block?
|
|
328
|
+
|
|
329
|
+
block_context_pin = name_pin
|
|
330
|
+
block_pin = find_block_pin(api_map)
|
|
331
|
+
block_context_pin = block_pin.closure if block_pin
|
|
332
|
+
block.infer(api_map, block_context_pin, locals)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|