solargraph 0.47.2 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/plugins.yml +40 -0
- data/.github/workflows/rspec.yml +4 -8
- data/.github/workflows/typecheck.yml +34 -0
- data/.yardopts +2 -2
- data/CHANGELOG.md +166 -3
- data/LICENSE +1 -1
- data/README.md +19 -16
- data/SPONSORS.md +2 -9
- data/lib/solargraph/api_map/cache.rb +50 -20
- data/lib/solargraph/api_map/source_to_yard.rb +17 -10
- data/lib/solargraph/api_map/store.rb +68 -15
- data/lib/solargraph/api_map.rb +238 -112
- data/lib/solargraph/bench.rb +3 -2
- data/lib/solargraph/cache.rb +77 -0
- data/lib/solargraph/complex_type/type_methods.rb +116 -35
- data/lib/solargraph/complex_type/unique_type.rb +261 -33
- data/lib/solargraph/complex_type.rb +149 -30
- data/lib/solargraph/convention/rakefile.rb +17 -0
- data/lib/solargraph/convention.rb +2 -3
- data/lib/solargraph/converters/dd.rb +5 -0
- data/lib/solargraph/converters/dl.rb +3 -0
- data/lib/solargraph/converters/dt.rb +3 -0
- data/lib/solargraph/diagnostics/rubocop.rb +23 -8
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +4 -1
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/diagnostics.rb +2 -2
- data/lib/solargraph/doc_map.rb +187 -0
- data/lib/solargraph/gem_pins.rb +72 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
- data/lib/solargraph/language_server/host/dispatch.rb +22 -5
- data/lib/solargraph/language_server/host/message_worker.rb +4 -0
- data/lib/solargraph/language_server/host/sources.rb +8 -65
- data/lib/solargraph/language_server/host.rb +88 -93
- data/lib/solargraph/language_server/message/base.rb +1 -1
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
- data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
- data/lib/solargraph/language_server/message/initialize.rb +27 -0
- data/lib/solargraph/language_server/message/initialized.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +4 -1
- data/lib/solargraph/language_server/message/text_document/formatting.rb +5 -4
- data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +24 -0
- data/lib/solargraph/language_server/message/text_document.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
- data/lib/solargraph/language_server/message.rb +1 -0
- data/lib/solargraph/language_server/progress.rb +118 -0
- data/lib/solargraph/language_server/transport/adapter.rb +16 -1
- data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +231 -104
- data/lib/solargraph/location.rb +1 -0
- data/lib/solargraph/page.rb +6 -0
- data/lib/solargraph/parser/comment_ripper.rb +4 -0
- data/lib/solargraph/parser/node_methods.rb +47 -7
- data/lib/solargraph/parser/node_processor/base.rb +11 -1
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
- data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +57 -41
- data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +53 -0
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +14 -4
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/cvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/def_node.rb +7 -20
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +42 -0
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +7 -5
- data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sym_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
- data/lib/solargraph/parser/parser_gem.rb +12 -0
- data/lib/solargraph/parser/region.rb +1 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +9 -10
- data/lib/solargraph/pin/base.rb +69 -11
- data/lib/solargraph/pin/base_variable.rb +40 -7
- data/lib/solargraph/pin/block.rb +81 -33
- data/lib/solargraph/pin/closure.rb +17 -2
- data/lib/solargraph/pin/common.rb +7 -3
- data/lib/solargraph/pin/conversions.rb +34 -8
- data/lib/solargraph/pin/delegated_method.rb +101 -0
- data/lib/solargraph/pin/documenting.rb +25 -32
- data/lib/solargraph/pin/instance_variable.rb +4 -0
- data/lib/solargraph/pin/local_variable.rb +13 -1
- data/lib/solargraph/pin/method.rb +273 -17
- data/lib/solargraph/pin/namespace.rb +17 -1
- data/lib/solargraph/pin/parameter.rb +40 -28
- data/lib/solargraph/pin/reference/override.rb +2 -2
- data/lib/solargraph/pin/reference.rb +8 -0
- data/lib/solargraph/pin/search.rb +4 -4
- data/lib/solargraph/pin/signature.rb +143 -0
- data/lib/solargraph/pin.rb +2 -1
- data/lib/solargraph/range.rb +4 -6
- data/lib/solargraph/rbs_map/conversions.rb +607 -0
- data/lib/solargraph/rbs_map/core_fills.rb +50 -0
- data/lib/solargraph/rbs_map/core_map.rb +28 -0
- data/lib/solargraph/rbs_map/stdlib_map.rb +33 -0
- data/lib/solargraph/rbs_map.rb +92 -0
- data/lib/solargraph/shell.rb +85 -59
- data/lib/solargraph/source/chain/array.rb +32 -0
- data/lib/solargraph/source/chain/block_symbol.rb +13 -0
- data/lib/solargraph/source/chain/call.rb +125 -61
- data/lib/solargraph/source/chain/constant.rb +15 -1
- data/lib/solargraph/source/chain/if.rb +23 -0
- data/lib/solargraph/source/chain/link.rb +8 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain/z_super.rb +3 -3
- data/lib/solargraph/source/chain.rb +64 -14
- data/lib/solargraph/source/change.rb +3 -0
- data/lib/solargraph/source/cursor.rb +2 -0
- data/lib/solargraph/source/source_chainer.rb +8 -5
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +18 -63
- data/lib/solargraph/source_map/clip.rb +31 -23
- data/lib/solargraph/source_map/mapper.rb +23 -7
- data/lib/solargraph/source_map.rb +36 -11
- data/lib/solargraph/type_checker/checks.rb +10 -2
- data/lib/solargraph/type_checker.rb +229 -100
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +2 -2
- data/lib/solargraph/workspace/config.rb +15 -11
- data/lib/solargraph/workspace.rb +41 -17
- data/lib/solargraph/yard_map/cache.rb +6 -0
- data/lib/solargraph/yard_map/helpers.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +23 -7
- data/lib/solargraph/yard_map/mapper.rb +1 -1
- data/lib/solargraph/yard_map/to_method.rb +11 -4
- data/lib/solargraph/yard_map.rb +1 -443
- data/lib/solargraph/yard_tags.rb +20 -0
- data/lib/solargraph/yardoc.rb +52 -0
- data/lib/solargraph.rb +8 -6
- data/solargraph.gemspec +19 -8
- metadata +164 -99
- data/.travis.yml +0 -19
- data/lib/solargraph/api_map/bundler_methods.rb +0 -22
- data/lib/solargraph/compat.rb +0 -37
- data/lib/solargraph/convention/rspec.rb +0 -30
- data/lib/solargraph/documentor.rb +0 -76
- data/lib/solargraph/language_server/host/cataloger.rb +0 -56
- data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
- data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -35
- data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
- data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +0 -23
- data/lib/solargraph/parser/legacy/node_processors/def_node.rb +0 -63
- data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +0 -21
- data/lib/solargraph/parser/legacy/node_processors.rb +0 -54
- data/lib/solargraph/parser/legacy.rb +0 -12
- data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -144
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
- data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -315
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
- data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
- data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -22
- data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -57
- data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
- data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
- data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
- data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
- data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
- data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -45
- data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -21
- data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -277
- data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +0 -18
- data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -63
- data/lib/solargraph/parser/rubyvm.rb +0 -40
- data/lib/solargraph/yard_map/core_docs.rb +0 -170
- data/lib/solargraph/yard_map/core_fills.rb +0 -208
- data/lib/solargraph/yard_map/core_gen.rb +0 -76
- data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
- data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
- data/lib/yard-solargraph.rb +0 -33
- data/yardoc/2.2.2.tar.gz +0 -0
@@ -7,97 +7,100 @@ module Solargraph
|
|
7
7
|
# @return [String]
|
8
8
|
attr_reader :word
|
9
9
|
|
10
|
-
# @return [Array<Chain>]
|
10
|
+
# @return [::Array<Chain>]
|
11
11
|
attr_reader :arguments
|
12
12
|
|
13
|
+
# @return [Chain, nil]
|
14
|
+
attr_reader :block
|
15
|
+
|
13
16
|
# @param word [String]
|
14
|
-
# @param arguments [Array<Chain>]
|
15
|
-
# @param
|
16
|
-
|
17
|
-
def initialize word, arguments = [], with_block = false
|
17
|
+
# @param arguments [::Array<Chain>]
|
18
|
+
# @param block [Chain, nil]
|
19
|
+
def initialize word, arguments = [], block = nil
|
18
20
|
@word = word
|
19
21
|
@arguments = arguments
|
20
|
-
@
|
22
|
+
@block = block
|
23
|
+
fix_block_pass
|
21
24
|
end
|
22
25
|
|
23
26
|
def with_block?
|
24
|
-
|
27
|
+
!!@block
|
25
28
|
end
|
26
29
|
|
27
30
|
# @param api_map [ApiMap]
|
28
31
|
# @param name_pin [Pin::Base]
|
29
|
-
# @param locals [Array<Pin::
|
32
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
30
33
|
def resolve api_map, name_pin, locals
|
31
34
|
return super_pins(api_map, name_pin) if word == 'super'
|
35
|
+
return yield_pins(api_map, name_pin) if word == 'yield'
|
32
36
|
found = if head?
|
33
37
|
locals.select { |p| p.name == word }
|
34
38
|
else
|
35
39
|
[]
|
36
40
|
end
|
37
41
|
return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
|
38
|
-
|
42
|
+
# @param [ComplexType::UniqueType]
|
43
|
+
pins = name_pin.binder.each_unique_type.flat_map do |context|
|
44
|
+
api_map.get_method_stack(context.namespace == '' ? '' : context.tag, word, scope: context.scope)
|
45
|
+
end
|
39
46
|
return [] if pins.empty?
|
40
47
|
inferred_pins(pins, api_map, name_pin.context, locals)
|
41
48
|
end
|
42
49
|
|
43
50
|
private
|
44
51
|
|
45
|
-
# @param pins [
|
52
|
+
# @param pins [::Enumerable<Pin::Method>]
|
46
53
|
# @param api_map [ApiMap]
|
47
54
|
# @param context [ComplexType]
|
48
|
-
# @param locals [Pin::LocalVariable]
|
49
|
-
# @return [Array<Pin::Base>]
|
55
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
56
|
+
# @return [::Array<Pin::Base>]
|
50
57
|
def inferred_pins pins, api_map, context, locals
|
51
58
|
result = pins.map do |p|
|
52
|
-
|
59
|
+
next p unless p.is_a?(Pin::Method)
|
60
|
+
overloads = p.signatures
|
53
61
|
# next p if overloads.empty?
|
54
62
|
type = ComplexType::UNDEFINED
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
63
|
+
# start with overloads that require blocks; if we are
|
64
|
+
# passing a block, we want to find a signature that will
|
65
|
+
# use it. If we didn't pass a block, the logic below will
|
66
|
+
# reject it regardless
|
67
|
+
|
68
|
+
sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
|
69
|
+
new_signature_pin = nil
|
70
|
+
sorted_overloads.each do |ol|
|
71
|
+
next unless arity_matches?(arguments, ol)
|
59
72
|
match = true
|
73
|
+
|
74
|
+
atypes = []
|
60
75
|
arguments.each_with_index do |arg, idx|
|
61
|
-
achain = arguments[idx]
|
62
|
-
next if achain.nil?
|
63
76
|
param = ol.parameters[idx]
|
64
77
|
if param.nil?
|
65
|
-
match =
|
78
|
+
match = ol.parameters.any?(&:restarg?)
|
66
79
|
break
|
67
80
|
end
|
68
|
-
|
69
|
-
next if par.nil? || par.types.nil? || par.types.empty?
|
70
|
-
atype = achain.infer(api_map, Pin::ProxyType.anonymous(context), locals)
|
71
|
-
other = ComplexType.try_parse(*par.types)
|
81
|
+
atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
|
72
82
|
# @todo Weak type comparison
|
73
|
-
unless atype.tag ==
|
83
|
+
# unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
|
84
|
+
unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name) || param.return_type.generic?
|
74
85
|
match = false
|
75
86
|
break
|
76
87
|
end
|
77
88
|
end
|
78
89
|
if match
|
79
|
-
|
80
|
-
|
81
|
-
|
90
|
+
if ol.block && with_block?
|
91
|
+
block_atypes = ol.block.parameters.map(&:return_type)
|
92
|
+
blocktype = block_call_type(api_map, context, block_atypes, locals)
|
93
|
+
end
|
94
|
+
new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
|
95
|
+
new_return_type = new_signature_pin.return_type
|
96
|
+
type = with_params(new_return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if new_return_type.defined?
|
82
97
|
type ||= ComplexType::UNDEFINED
|
83
98
|
end
|
84
99
|
break if type.defined?
|
85
100
|
end
|
101
|
+
p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
|
86
102
|
next p.proxy(type) if type.defined?
|
87
|
-
|
88
|
-
if type
|
89
|
-
next Solargraph::Pin::Method.new(
|
90
|
-
location: p.location,
|
91
|
-
closure: p.closure,
|
92
|
-
name: p.name,
|
93
|
-
comments: "@return [#{context.subtypes.first.to_s}]",
|
94
|
-
scope: p.scope,
|
95
|
-
visibility: p.visibility,
|
96
|
-
parameters: p.parameters,
|
97
|
-
node: p.node
|
98
|
-
)
|
99
|
-
end
|
100
|
-
if p.is_a?(Pin::Method) && !p.macros.empty?
|
103
|
+
if !p.macros.empty?
|
101
104
|
result = process_macro(p, api_map, context, locals)
|
102
105
|
next result unless result.return_type.undefined?
|
103
106
|
elsif !p.directives.empty?
|
@@ -107,19 +110,29 @@ module Solargraph
|
|
107
110
|
p
|
108
111
|
end
|
109
112
|
result.map do |pin|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
if pin.path == 'Class#new' && context.tag != 'Class'
|
114
|
+
pin.proxy(ComplexType.try_parse(context.namespace))
|
115
|
+
else
|
116
|
+
next pin if pin.return_type.undefined?
|
117
|
+
selfy = pin.return_type.self_to(context.tag)
|
118
|
+
selfy == pin.return_type ? pin : pin.proxy(selfy)
|
119
|
+
end
|
113
120
|
end
|
114
121
|
end
|
115
122
|
|
116
|
-
# @param pin [Pin::
|
123
|
+
# @param pin [Pin::Base]
|
117
124
|
# @param api_map [ApiMap]
|
118
125
|
# @param context [ComplexType]
|
119
|
-
# @param locals [Pin::Base]
|
126
|
+
# @param locals [Enumerable<Pin::Base>]
|
120
127
|
# @return [Pin::Base]
|
121
128
|
def process_macro pin, api_map, context, locals
|
122
129
|
pin.macros.each do |macro|
|
130
|
+
# @todo 'Wrong argument type for
|
131
|
+
# Solargraph::Source::Chain::Call#inner_process_macro:
|
132
|
+
# macro expected YARD::Tags::MacroDirective, received
|
133
|
+
# generic<Elem>' is because we lose 'rooted' information
|
134
|
+
# in the 'Chain::Array' class internally, leaving
|
135
|
+
# ::Array#each shadowed when it shouldn't be.
|
123
136
|
result = inner_process_macro(pin, macro, api_map, context, locals)
|
124
137
|
return result unless result.return_type.undefined?
|
125
138
|
end
|
@@ -129,7 +142,7 @@ module Solargraph
|
|
129
142
|
# @param pin [Pin::Method]
|
130
143
|
# @param api_map [ApiMap]
|
131
144
|
# @param context [ComplexType]
|
132
|
-
# @param locals [Pin::Base]
|
145
|
+
# @param locals [Enumerable<Pin::Base>]
|
133
146
|
# @return [Pin::ProxyType]
|
134
147
|
def process_directive pin, api_map, context, locals
|
135
148
|
pin.directives.each do |dir|
|
@@ -141,11 +154,11 @@ module Solargraph
|
|
141
154
|
Pin::ProxyType.anonymous ComplexType::UNDEFINED
|
142
155
|
end
|
143
156
|
|
144
|
-
# @param pin [Pin]
|
157
|
+
# @param pin [Pin::Base]
|
145
158
|
# @param macro [YARD::Tags::MacroDirective]
|
146
159
|
# @param api_map [ApiMap]
|
147
160
|
# @param context [ComplexType]
|
148
|
-
# @param locals [
|
161
|
+
# @param locals [Enumerable<Pin::Base>]
|
149
162
|
# @return [Pin::ProxyType]
|
150
163
|
def inner_process_macro pin, macro, api_map, context, locals
|
151
164
|
vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
|
@@ -169,35 +182,86 @@ module Solargraph
|
|
169
182
|
|
170
183
|
# @param docstring [YARD::Docstring]
|
171
184
|
# @param context [ComplexType]
|
172
|
-
# @return [ComplexType]
|
185
|
+
# @return [ComplexType, nil]
|
173
186
|
def extra_return_type docstring, context
|
174
|
-
if docstring.has_tag?(
|
187
|
+
if docstring.has_tag?('return_single_parameter') #&& context.subtypes.one?
|
175
188
|
return context.subtypes.first || ComplexType::UNDEFINED
|
176
|
-
elsif docstring.has_tag?(
|
189
|
+
elsif docstring.has_tag?('return_value_parameter') && context.value_types.one?
|
177
190
|
return context.value_types.first
|
178
191
|
end
|
179
192
|
nil
|
180
193
|
end
|
181
194
|
|
182
|
-
# @param arguments [Array<Chain>]
|
183
|
-
# @param
|
195
|
+
# @param arguments [::Array<Chain>]
|
196
|
+
# @param signature [Pin::Signature]
|
184
197
|
# @return [Boolean]
|
185
|
-
def
|
198
|
+
def arity_matches? arguments, signature
|
199
|
+
parameters = signature.parameters
|
186
200
|
argcount = arguments.length
|
187
|
-
# argcount -= 1 if !arguments.empty? && arguments.last.links.first.word.start_with?('&')
|
188
201
|
parcount = parameters.length
|
189
|
-
parcount -= 1 if !parameters.empty? && parameters.last.
|
190
|
-
return false if
|
202
|
+
parcount -= 1 if !parameters.empty? && parameters.last.block?
|
203
|
+
return false if signature.block? && !with_block?
|
204
|
+
return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
|
191
205
|
true
|
192
206
|
end
|
193
207
|
|
194
208
|
# @param api_map [ApiMap]
|
195
209
|
# @param name_pin [Pin::Base]
|
196
|
-
# @return [Array<Pin::Base>]
|
210
|
+
# @return [::Array<Pin::Base>]
|
197
211
|
def super_pins api_map, name_pin
|
198
|
-
pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
|
212
|
+
pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
|
199
213
|
pins.reject{|p| p.path == name_pin.path}
|
200
214
|
end
|
215
|
+
|
216
|
+
# @param api_map [ApiMap]
|
217
|
+
# @param name_pin [Pin::Base]
|
218
|
+
# @return [::Array<Pin::Base>]
|
219
|
+
def yield_pins api_map, name_pin
|
220
|
+
method_pin = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope).first
|
221
|
+
return [] if method_pin.nil?
|
222
|
+
|
223
|
+
method_pin.signatures.map(&:block).compact
|
224
|
+
end
|
225
|
+
|
226
|
+
# @param type [ComplexType]
|
227
|
+
# @param context [ComplexType]
|
228
|
+
# @return [ComplexType]
|
229
|
+
def with_params type, context
|
230
|
+
return type unless type.to_s.include?('$')
|
231
|
+
ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
|
232
|
+
end
|
233
|
+
|
234
|
+
# @return [void]
|
235
|
+
def fix_block_pass
|
236
|
+
argument = @arguments.last&.links&.first
|
237
|
+
@block = @arguments.pop if argument.is_a?(BlockSymbol) || argument.is_a?(BlockVariable)
|
238
|
+
end
|
239
|
+
|
240
|
+
# @param api_map [ApiMap]
|
241
|
+
# @param context [ComplexType]
|
242
|
+
# @param block_parameter_types [::Array<ComplexType>]
|
243
|
+
# @param locals [::Array<Pin::LocalVariable>]
|
244
|
+
# @return [ComplexType, nil]
|
245
|
+
def block_call_type(api_map, context, block_parameter_types, locals)
|
246
|
+
return nil unless with_block?
|
247
|
+
|
248
|
+
# @todo Handle BlockVariable
|
249
|
+
if block.links.map(&:class) == [BlockSymbol]
|
250
|
+
# Ruby's shorthand for sending the passed in method name
|
251
|
+
# to the first yield parameter with no arguments
|
252
|
+
block_symbol_name = block.links.first.word
|
253
|
+
block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
|
254
|
+
callee = api_map.get_path_pins(block_symbol_call_path).first
|
255
|
+
return_type = callee&.return_type
|
256
|
+
# @todo: Figure out why we get unresolved generics at
|
257
|
+
# this point and need to assume method return types
|
258
|
+
# based on the generic type
|
259
|
+
return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
|
260
|
+
return_type || ComplexType::UNDEFINED
|
261
|
+
else
|
262
|
+
block.infer(api_map, Pin::ProxyType.anonymous(context), locals)
|
263
|
+
end
|
264
|
+
end
|
201
265
|
end
|
202
266
|
end
|
203
267
|
end
|
@@ -19,8 +19,14 @@ module Solargraph
|
|
19
19
|
end
|
20
20
|
parts = base.split('::')
|
21
21
|
gates.each do |gate|
|
22
|
+
# @todo 'Wrong argument type for
|
23
|
+
# Solargraph::Source::Chain::Constant#deep_constant_type:
|
24
|
+
# gate expected String, received generic<Elem>' is because
|
25
|
+
# we lose 'rooted' information in the 'Chain::Array' class
|
26
|
+
# internally, leaving ::Array#each shadowed when it
|
27
|
+
# shouldn't be.
|
22
28
|
type = deep_constant_type(gate, api_map)
|
23
|
-
# Use deep inference to resolve root
|
29
|
+
# Use deep inference to resolve root
|
24
30
|
parts[0..-2].each do |sym|
|
25
31
|
pins = api_map.get_constants('', type.namespace).select{ |pin| pin.name == sym }
|
26
32
|
type = first_pin_type(pins, api_map)
|
@@ -35,6 +41,8 @@ module Solargraph
|
|
35
41
|
|
36
42
|
private
|
37
43
|
|
44
|
+
# @param pin [Pin::Base]
|
45
|
+
# @return [::Array<String>]
|
38
46
|
def crawl_gates pin
|
39
47
|
clos = pin
|
40
48
|
until clos.nil?
|
@@ -48,6 +56,9 @@ module Solargraph
|
|
48
56
|
['']
|
49
57
|
end
|
50
58
|
|
59
|
+
# @param pins [::Array<Pin::Base>]
|
60
|
+
# @param api_map [ApiMap]
|
61
|
+
# @return [ComplexType]
|
51
62
|
def first_pin_type(pins, api_map)
|
52
63
|
type = ComplexType::UNDEFINED
|
53
64
|
pins.each do |pin|
|
@@ -59,6 +70,9 @@ module Solargraph
|
|
59
70
|
type
|
60
71
|
end
|
61
72
|
|
73
|
+
# @param gate [String]
|
74
|
+
# @param api_map [ApiMap]
|
75
|
+
# @return [ComplexType]
|
62
76
|
def deep_constant_type(gate, api_map)
|
63
77
|
type = ComplexType::ROOT
|
64
78
|
return type if gate == ''
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solargraph
|
4
|
+
class Source
|
5
|
+
class Chain
|
6
|
+
class If < Link
|
7
|
+
def word
|
8
|
+
'<if>'
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param links [::Array<Link>]
|
12
|
+
def initialize links
|
13
|
+
@links = links
|
14
|
+
end
|
15
|
+
|
16
|
+
def resolve api_map, name_pin, locals
|
17
|
+
types = @links.map { |link| link.infer(api_map, name_pin, locals) }
|
18
|
+
[Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -7,8 +7,10 @@ module Solargraph
|
|
7
7
|
# @return [String]
|
8
8
|
attr_reader :word
|
9
9
|
|
10
|
+
# @return [Pin::Base]
|
10
11
|
attr_accessor :last_context
|
11
12
|
|
13
|
+
# @param word [String]
|
12
14
|
def initialize word = '<undefined>'
|
13
15
|
@word = word
|
14
16
|
end
|
@@ -23,12 +25,16 @@ module Solargraph
|
|
23
25
|
|
24
26
|
# @param api_map [ApiMap]
|
25
27
|
# @param name_pin [Pin::Base]
|
26
|
-
# @param locals [
|
27
|
-
# @return [Array<Pin::Base>]
|
28
|
+
# @param locals [::Enumerable<Pin::Base>]
|
29
|
+
# @return [::Array<Pin::Base>]
|
28
30
|
def resolve api_map, name_pin, locals
|
29
31
|
[]
|
30
32
|
end
|
31
33
|
|
34
|
+
def inspect
|
35
|
+
"#{self.class} #{word}"
|
36
|
+
end
|
37
|
+
|
32
38
|
def head?
|
33
39
|
@head ||= false
|
34
40
|
end
|
@@ -7,11 +7,11 @@ module Solargraph
|
|
7
7
|
# @return [String]
|
8
8
|
attr_reader :word
|
9
9
|
|
10
|
-
# @return [Array<Chain>]
|
10
|
+
# @return [::Array<Chain>]
|
11
11
|
attr_reader :arguments
|
12
12
|
|
13
13
|
# @param word [String]
|
14
|
-
# @param arguments [Array<Chain>]
|
14
|
+
# @param arguments [::Array<Chain>]
|
15
15
|
# @param with_block [Boolean] True if the chain is inside a block
|
16
16
|
# @param head [Boolean] True if the call is the start of its chain
|
17
17
|
def initialize word, with_block = false
|
@@ -20,7 +20,7 @@ module Solargraph
|
|
20
20
|
|
21
21
|
# @param api_map [ApiMap]
|
22
22
|
# @param name_pin [Pin::Base]
|
23
|
-
# @param locals [Array<Pin::Base>]
|
23
|
+
# @param locals [::Array<Pin::Base>]
|
24
24
|
def resolve api_map, name_pin, locals
|
25
25
|
return super_pins(api_map, name_pin)
|
26
26
|
end
|
@@ -19,23 +19,30 @@ module Solargraph
|
|
19
19
|
autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
|
20
20
|
autoload :Literal, 'solargraph/source/chain/literal'
|
21
21
|
autoload :Head, 'solargraph/source/chain/head'
|
22
|
+
autoload :If, 'solargraph/source/chain/if'
|
22
23
|
autoload :Or, 'solargraph/source/chain/or'
|
23
24
|
autoload :BlockVariable, 'solargraph/source/chain/block_variable'
|
25
|
+
autoload :BlockSymbol, 'solargraph/source/chain/block_symbol'
|
24
26
|
autoload :ZSuper, 'solargraph/source/chain/z_super'
|
25
27
|
autoload :Hash, 'solargraph/source/chain/hash'
|
28
|
+
autoload :Array, 'solargraph/source/chain/array'
|
26
29
|
|
27
30
|
@@inference_stack = []
|
28
31
|
@@inference_depth = 0
|
32
|
+
@@inference_invalidation_key = nil
|
33
|
+
@@inference_cache = {}
|
29
34
|
|
30
35
|
UNDEFINED_CALL = Chain::Call.new('<undefined>')
|
31
36
|
UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
|
32
37
|
|
33
|
-
# @return [Array<Source::Chain::Link>]
|
38
|
+
# @return [::Array<Source::Chain::Link>]
|
34
39
|
attr_reader :links
|
35
40
|
|
36
41
|
attr_reader :node
|
37
42
|
|
38
|
-
# @param
|
43
|
+
# @param node [Parser::AST::Node, nil]
|
44
|
+
# @param links [::Array<Chain::Link>]
|
45
|
+
# @param splat [Boolean]
|
39
46
|
def initialize links, node = nil, splat = false
|
40
47
|
@links = links.clone
|
41
48
|
@links.push UNDEFINED_CALL if @links.empty?
|
@@ -56,28 +63,51 @@ module Solargraph
|
|
56
63
|
|
57
64
|
# @param api_map [ApiMap]
|
58
65
|
# @param name_pin [Pin::Base]
|
59
|
-
# @param locals [
|
60
|
-
#
|
66
|
+
# @param locals [::Enumerable<Pin::LocalVariable>]
|
67
|
+
#
|
68
|
+
# @return [::Array<Pin::Base>]
|
61
69
|
def define api_map, name_pin, locals
|
62
70
|
return [] if undefined?
|
63
71
|
working_pin = name_pin
|
64
72
|
links[0..-2].each do |link|
|
65
73
|
pins = link.resolve(api_map, working_pin, locals)
|
66
|
-
type = infer_first_defined(pins, working_pin, api_map)
|
74
|
+
type = infer_first_defined(pins, working_pin, api_map, locals)
|
67
75
|
return [] if type.undefined?
|
68
76
|
working_pin = Pin::ProxyType.anonymous(type)
|
69
77
|
end
|
70
|
-
links.last.last_context =
|
78
|
+
links.last.last_context = name_pin
|
71
79
|
links.last.resolve(api_map, working_pin, locals)
|
72
80
|
end
|
73
81
|
|
74
82
|
# @param api_map [ApiMap]
|
75
83
|
# @param name_pin [Pin::Base]
|
76
|
-
# @param locals [
|
84
|
+
# @param locals [::Enumerable<Pin::LocalVariable>]
|
77
85
|
# @return [ComplexType]
|
86
|
+
# @sg-ignore
|
78
87
|
def infer api_map, name_pin, locals
|
88
|
+
out = nil
|
89
|
+
cached = @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] unless node.nil?
|
90
|
+
return cached if cached && @@inference_invalidation_key == api_map.hash
|
91
|
+
out = infer_uncached api_map, name_pin, locals
|
92
|
+
if @@inference_invalidation_key != api_map.hash
|
93
|
+
@@inference_cache = {}
|
94
|
+
@@inference_invalidation_key = api_map.hash
|
95
|
+
end
|
96
|
+
@@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] = out unless node.nil?
|
97
|
+
out
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param api_map [ApiMap]
|
101
|
+
# @param name_pin [Pin::Base]
|
102
|
+
# @param locals [::Enumerable<Pin::LocalVariable>]
|
103
|
+
# @return [ComplexType]
|
104
|
+
def infer_uncached api_map, name_pin, locals
|
105
|
+
from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
|
106
|
+
if from_here
|
107
|
+
name_pin = name_pin.proxy(from_here)
|
108
|
+
end
|
79
109
|
pins = define(api_map, name_pin, locals)
|
80
|
-
type = infer_first_defined(pins, links.last.last_context, api_map)
|
110
|
+
type = infer_first_defined(pins, links.last.last_context, api_map, locals)
|
81
111
|
maybe_nil(type)
|
82
112
|
end
|
83
113
|
|
@@ -109,29 +139,46 @@ module Solargraph
|
|
109
139
|
|
110
140
|
private
|
111
141
|
|
112
|
-
# @param pins [Array<Pin::Base>]
|
142
|
+
# @param pins [::Array<Pin::Base>]
|
143
|
+
# @param context [Pin::Base]
|
113
144
|
# @param api_map [ApiMap]
|
145
|
+
# @param locals [::Enumerable<Pin::LocalVariable>]
|
114
146
|
# @return [ComplexType]
|
115
|
-
def infer_first_defined pins, context, api_map
|
147
|
+
def infer_first_defined pins, context, api_map, locals
|
116
148
|
possibles = []
|
149
|
+
# @todo this param tag shouldn't be needed to probe the type
|
150
|
+
# @todo ...but given it is needed, typecheck should complain that it is needed
|
151
|
+
# @param pin [Pin::Base]
|
117
152
|
pins.each do |pin|
|
118
153
|
# Avoid infinite recursion
|
119
154
|
next if @@inference_stack.include?(pin.identity)
|
155
|
+
|
120
156
|
@@inference_stack.push pin.identity
|
121
157
|
type = pin.typify(api_map)
|
122
158
|
@@inference_stack.pop
|
123
159
|
if type.defined?
|
124
|
-
|
125
|
-
|
160
|
+
if type.generic?
|
161
|
+
# @todo even at strong, no typechecking complaint
|
162
|
+
# happens when a [Pin::Base,nil] is passed into a method
|
163
|
+
# that accepts only [Pin::Namespace] as an argument
|
164
|
+
type = type.resolve_generics(pin.closure, context.return_type)
|
165
|
+
end
|
166
|
+
if type.defined?
|
167
|
+
possibles.push type
|
168
|
+
break if pin.is_a?(Pin::Method)
|
169
|
+
end
|
126
170
|
end
|
127
171
|
end
|
128
172
|
if possibles.empty?
|
129
173
|
# Limit method inference recursion
|
130
174
|
return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
|
175
|
+
|
131
176
|
@@inference_depth += 1
|
177
|
+
# @param pin [Pin::Base]
|
132
178
|
pins.each do |pin|
|
133
179
|
# Avoid infinite recursion
|
134
180
|
next if @@inference_stack.include?(pin.identity)
|
181
|
+
|
135
182
|
@@inference_stack.push pin.identity
|
136
183
|
type = pin.probe(api_map)
|
137
184
|
@@inference_stack.pop
|
@@ -143,17 +190,20 @@ module Solargraph
|
|
143
190
|
@@inference_depth -= 1
|
144
191
|
end
|
145
192
|
return ComplexType::UNDEFINED if possibles.empty?
|
193
|
+
|
146
194
|
type = if possibles.length > 1
|
147
195
|
sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
|
148
196
|
ComplexType.parse(*sorted)
|
149
197
|
else
|
150
|
-
possibles.
|
198
|
+
ComplexType.parse(possibles.map(&:to_s).join(', '))
|
151
199
|
end
|
152
200
|
return type if context.nil? || context.return_type.undefined?
|
153
|
-
|
201
|
+
|
202
|
+
type.self_to(context.return_type.tag)
|
154
203
|
end
|
155
204
|
|
156
205
|
# @param type [ComplexType]
|
206
|
+
# @return [ComplexType]
|
157
207
|
def maybe_nil type
|
158
208
|
return type if type.undefined? || type.void? || type.nullable?
|
159
209
|
return type unless nullable?
|
@@ -115,6 +115,7 @@ module Solargraph
|
|
115
115
|
end
|
116
116
|
alias receiver recipient
|
117
117
|
|
118
|
+
# @return [AST::Node]
|
118
119
|
def node
|
119
120
|
@node ||= source.node_at(position.line, position.column)
|
120
121
|
end
|
@@ -135,6 +136,7 @@ module Solargraph
|
|
135
136
|
end
|
136
137
|
end
|
137
138
|
|
139
|
+
# @return [Parser::AST::Node, nil]
|
138
140
|
def recipient_node
|
139
141
|
@recipient_node ||= Solargraph::Parser::NodeMethods.find_recipient_node(self)
|
140
142
|
end
|
@@ -14,10 +14,10 @@ module Solargraph
|
|
14
14
|
|
15
15
|
class << self
|
16
16
|
# @param source [Source]
|
17
|
-
# @param position [Position]
|
17
|
+
# @param position [Position, Array(Integer, Integer)]
|
18
18
|
# @return [Source::Chain]
|
19
19
|
def chain source, position
|
20
|
-
new(source, position).chain
|
20
|
+
new(source, Solargraph::Position.normalize(position)).chain
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -41,12 +41,12 @@ module Solargraph
|
|
41
41
|
parent = nil
|
42
42
|
if !source.repaired? && source.parsed? && source.synchronized?
|
43
43
|
tree = source.tree_at(position.line, position.column)
|
44
|
-
# node, parent = source.tree_at(position.line, position.column)[0..2]
|
45
|
-
tree.shift while tree.length > 1 && tree.first.type == :SCOPE
|
46
44
|
node, parent = tree[0..2]
|
47
45
|
elsif source.parsed? && source.repaired? && end_of_phrase == '.'
|
48
46
|
node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
|
49
47
|
node = Parser.parse(fixed_phrase) if node.nil?
|
48
|
+
elsif source.repaired?
|
49
|
+
node = Parser.parse(fixed_phrase)
|
50
50
|
else
|
51
51
|
node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2] unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
|
52
52
|
# Exception for positions that chain literal nodes in unsynchronized sources
|
@@ -58,7 +58,7 @@ module Solargraph
|
|
58
58
|
end
|
59
59
|
return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
|
60
60
|
# chain = NodeChainer.chain(node, source.filename, parent && parent.type == :block)
|
61
|
-
chain = Parser.chain(node, source.filename, parent
|
61
|
+
chain = Parser.chain(node, source.filename, parent)
|
62
62
|
if source.repaired? || !source.parsed? || !source.synchronized?
|
63
63
|
if end_of_phrase.strip == '.'
|
64
64
|
chain.links.push Chain::UNDEFINED_CALL
|
@@ -126,10 +126,13 @@ module Solargraph
|
|
126
126
|
Position.line_char_to_offset(@source.code, line, column)
|
127
127
|
end
|
128
128
|
|
129
|
+
# @return [Integer]
|
129
130
|
def signature_data
|
130
131
|
@signature_data ||= get_signature_data_at(offset)
|
131
132
|
end
|
132
133
|
|
134
|
+
# @param index [Integer]
|
135
|
+
# @return [Integer]
|
133
136
|
def get_signature_data_at index
|
134
137
|
brackets = 0
|
135
138
|
squares = 0
|