solargraph 0.54.0 → 0.58.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/workflows/linting.yml +127 -0
- data/.github/workflows/plugins.yml +184 -6
- data/.github/workflows/rspec.yml +55 -5
- data/.github/workflows/typecheck.yml +8 -3
- data/.gitignore +7 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +1279 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +171 -0
- data/README.md +20 -6
- data/Rakefile +125 -13
- data/bin/solargraph +8 -5
- data/lib/solargraph/api_map/cache.rb +13 -3
- data/lib/solargraph/api_map/constants.rb +279 -0
- data/lib/solargraph/api_map/index.rb +193 -0
- data/lib/solargraph/api_map/source_to_yard.rb +13 -4
- data/lib/solargraph/api_map/store.rb +207 -132
- data/lib/solargraph/api_map.rb +394 -261
- data/lib/solargraph/bench.rb +18 -1
- data/lib/solargraph/complex_type/type_methods.rb +29 -12
- data/lib/solargraph/complex_type/unique_type.rb +205 -26
- data/lib/solargraph/complex_type.rb +126 -26
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +20 -3
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
- data/lib/solargraph/convention/data_definition.rb +105 -0
- data/lib/solargraph/convention/gemspec.rb +3 -2
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
- data/lib/solargraph/convention/struct_definition.rb +164 -0
- data/lib/solargraph/convention.rb +36 -4
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
- data/lib/solargraph/doc_map.rb +316 -64
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/equality.rb +34 -0
- data/lib/solargraph/gem_pins.rb +64 -38
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +54 -5
- data/lib/solargraph/language_server/host.rb +36 -18
- data/lib/solargraph/language_server/message/base.rb +20 -12
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/language_server/message/initialize.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +27 -2
- data/lib/solargraph/language_server/request.rb +4 -1
- data/lib/solargraph/library.rb +83 -73
- data/lib/solargraph/location.rb +45 -1
- data/lib/solargraph/logging.rb +12 -2
- data/lib/solargraph/page.rb +3 -0
- data/lib/solargraph/parser/comment_ripper.rb +20 -7
- data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +26 -8
- data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
- data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
- data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
- data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
- data/lib/solargraph/parser/region.rb +4 -1
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/parser.rb +3 -5
- data/lib/solargraph/pin/base.rb +417 -42
- data/lib/solargraph/pin/base_variable.rb +21 -12
- data/lib/solargraph/pin/block.rb +9 -26
- data/lib/solargraph/pin/breakable.rb +9 -0
- data/lib/solargraph/pin/callable.rb +231 -0
- data/lib/solargraph/pin/closure.rb +30 -10
- data/lib/solargraph/pin/common.rb +12 -7
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/delegated_method.rb +20 -1
- data/lib/solargraph/pin/documenting.rb +16 -0
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/keyword.rb +7 -2
- data/lib/solargraph/pin/local_variable.rb +15 -7
- data/lib/solargraph/pin/method.rb +241 -70
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/namespace.rb +21 -13
- data/lib/solargraph/pin/parameter.rb +94 -32
- data/lib/solargraph/pin/proxy_type.rb +17 -7
- data/lib/solargraph/pin/reference/override.rb +24 -6
- data/lib/solargraph/pin/reference/require.rb +2 -2
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +17 -0
- data/lib/solargraph/pin/search.rb +6 -1
- data/lib/solargraph/pin/signature.rb +39 -121
- data/lib/solargraph/pin/singleton.rb +1 -1
- data/lib/solargraph/pin/symbol.rb +8 -2
- data/lib/solargraph/pin/until.rb +18 -0
- data/lib/solargraph/pin/while.rb +18 -0
- data/lib/solargraph/pin.rb +8 -2
- data/lib/solargraph/pin_cache.rb +245 -0
- data/lib/solargraph/position.rb +19 -0
- data/lib/solargraph/range.rb +23 -4
- data/lib/solargraph/rbs_map/conversions.rb +315 -99
- data/lib/solargraph/rbs_map/core_fills.rb +50 -16
- data/lib/solargraph/rbs_map/core_map.rb +41 -11
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +87 -16
- data/lib/solargraph/shell.rb +117 -17
- data/lib/solargraph/source/chain/array.rb +13 -8
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +135 -66
- data/lib/solargraph/source/chain/constant.rb +3 -66
- data/lib/solargraph/source/chain/hash.rb +9 -3
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/chain/if.rb +7 -2
- data/lib/solargraph/source/chain/link.rb +38 -6
- data/lib/solargraph/source/chain/literal.rb +27 -2
- data/lib/solargraph/source/chain/or.rb +2 -2
- data/lib/solargraph/source/chain/z_super.rb +1 -1
- data/lib/solargraph/source/chain.rb +140 -63
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +4 -4
- data/lib/solargraph/source/source_chainer.rb +3 -3
- data/lib/solargraph/source.rb +110 -89
- data/lib/solargraph/source_map/clip.rb +22 -28
- data/lib/solargraph/source_map/data.rb +34 -0
- data/lib/solargraph/source_map/mapper.rb +11 -7
- data/lib/solargraph/source_map.rb +50 -43
- data/lib/solargraph/type_checker/checks.rb +4 -0
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +35 -8
- data/lib/solargraph/type_checker.rb +331 -189
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +25 -5
- data/lib/solargraph/workspace/require_paths.rb +97 -0
- data/lib/solargraph/workspace.rb +53 -72
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
- data/lib/solargraph/yard_map/mapper.rb +5 -3
- data/lib/solargraph/yard_map/to_method.rb +6 -3
- data/lib/solargraph/yardoc.rb +45 -10
- data/lib/solargraph.rb +35 -1
- data/rbs/fills/bundler/0/bundler.rbs +4271 -0
- data/rbs/fills/open3/0/open3.rbs +172 -0
- data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
- data/rbs/fills/rubygems/0/errors.rbs +364 -0
- data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
- data/rbs/fills/rubygems/0/specification.rbs +1753 -0
- data/rbs/fills/tuple/tuple.rbs +149 -0
- data/rbs_collection.yaml +19 -0
- data/sig/shims/ast/0/node.rbs +5 -0
- data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
- data/sig/shims/ast/2.4/ast.rbs +73 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
- data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
- data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +32 -10
- metadata +237 -37
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/cache.rb +0 -77
- data/lib/solargraph/parser/node_methods.rb +0 -83
|
@@ -21,14 +21,24 @@ module Solargraph
|
|
|
21
21
|
# @return [ApiMap]
|
|
22
22
|
attr_reader :api_map
|
|
23
23
|
|
|
24
|
-
# @param filename [String]
|
|
24
|
+
# @param filename [String, nil]
|
|
25
25
|
# @param api_map [ApiMap, nil]
|
|
26
|
-
# @param level [Symbol]
|
|
27
|
-
|
|
26
|
+
# @param level [Symbol] Don't complain about anything above this level
|
|
27
|
+
# @param workspace [Workspace, nil] Workspace to use for loading
|
|
28
|
+
# type checker rules modified by user config
|
|
29
|
+
# @param type_checker_rules [Hash{Symbol => Symbol}] Overrides for
|
|
30
|
+
# type checker rules - e.g., :report_undefined => :strong
|
|
31
|
+
# @param rules [Rules] Type checker rules object
|
|
32
|
+
def initialize filename,
|
|
33
|
+
api_map: nil,
|
|
34
|
+
level: :normal,
|
|
35
|
+
workspace: filename ? Workspace.new(File.dirname(filename)) : nil,
|
|
36
|
+
rules: workspace ? workspace.rules(level) : Rules.new(level, {})
|
|
28
37
|
@filename = filename
|
|
29
38
|
# @todo Smarter directory resolution
|
|
30
39
|
@api_map = api_map || Solargraph::ApiMap.load(File.dirname(filename))
|
|
31
|
-
@rules =
|
|
40
|
+
@rules = rules
|
|
41
|
+
# @type [Array<Range>]
|
|
32
42
|
@marked_ranges = []
|
|
33
43
|
end
|
|
34
44
|
|
|
@@ -37,15 +47,20 @@ module Solargraph
|
|
|
37
47
|
@source_map ||= api_map.source_map(filename)
|
|
38
48
|
end
|
|
39
49
|
|
|
50
|
+
# @return [Source]
|
|
51
|
+
def source
|
|
52
|
+
@source_map.source
|
|
53
|
+
end
|
|
54
|
+
|
|
40
55
|
# @return [Array<Problem>]
|
|
41
56
|
def problems
|
|
42
57
|
@problems ||= begin
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
all = method_tag_problems
|
|
59
|
+
.concat(variable_type_tag_problems)
|
|
60
|
+
.concat(const_problems)
|
|
61
|
+
.concat(call_problems)
|
|
62
|
+
unignored = without_ignored(all)
|
|
63
|
+
unignored.concat(unneeded_sgignore_problems)
|
|
49
64
|
end
|
|
50
65
|
end
|
|
51
66
|
|
|
@@ -90,11 +105,11 @@ module Solargraph
|
|
|
90
105
|
def method_return_type_problems_for pin
|
|
91
106
|
return [] if pin.is_a?(Pin::MethodAlias)
|
|
92
107
|
result = []
|
|
93
|
-
declared = pin.typify(api_map).
|
|
108
|
+
declared = pin.typify(api_map).self_to_type(pin.full_context).qualify(api_map, *pin.gates)
|
|
94
109
|
if declared.undefined?
|
|
95
110
|
if pin.return_type.undefined? && rules.require_type_tags?
|
|
96
111
|
if pin.attribute?
|
|
97
|
-
inferred = pin.probe(api_map).
|
|
112
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
|
98
113
|
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin) unless inferred.defined?
|
|
99
114
|
else
|
|
100
115
|
result.push Problem.new(pin.location, "Missing @return tag for #{pin.path}", pin: pin)
|
|
@@ -106,14 +121,14 @@ module Solargraph
|
|
|
106
121
|
end
|
|
107
122
|
elsif rules.validate_tags?
|
|
108
123
|
unless pin.node.nil? || declared.void? || virtual_pin?(pin) || abstract?(pin)
|
|
109
|
-
inferred = pin.probe(api_map).
|
|
124
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
|
110
125
|
if inferred.undefined?
|
|
111
126
|
unless rules.ignore_all_undefined? || external?(pin)
|
|
112
127
|
result.push Problem.new(pin.location, "#{pin.path} return type could not be inferred", pin: pin)
|
|
113
128
|
end
|
|
114
129
|
else
|
|
115
|
-
unless (rules.
|
|
116
|
-
result.push Problem.new(pin.location, "Declared return type #{declared} does not match inferred type #{inferred} for #{pin.path}", pin: pin)
|
|
130
|
+
unless (rules.require_all_return_types_match_inferred? ? all_types_match?(api_map, inferred, declared) : any_types_match?(api_map, declared, inferred))
|
|
131
|
+
result.push Problem.new(pin.location, "Declared return type #{declared.rooted_tags} does not match inferred type #{inferred.rooted_tags} for #{pin.path}", pin: pin)
|
|
117
132
|
end
|
|
118
133
|
end
|
|
119
134
|
end
|
|
@@ -139,40 +154,39 @@ module Solargraph
|
|
|
139
154
|
|
|
140
155
|
# @param pin [Pin::Base]
|
|
141
156
|
def virtual_pin? pin
|
|
142
|
-
pin.location &&
|
|
157
|
+
pin.location && source.comment_at?(pin.location.range.ending)
|
|
143
158
|
end
|
|
144
159
|
|
|
145
160
|
# @param pin [Pin::Method]
|
|
146
161
|
# @return [Array<Problem>]
|
|
147
162
|
def method_param_type_problems_for pin
|
|
148
163
|
stack = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
|
|
149
|
-
params = first_param_hash(stack)
|
|
150
164
|
result = []
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
pin.signatures.each do |sig|
|
|
166
|
+
params = param_details_from_stack(sig, stack)
|
|
167
|
+
if rules.require_type_tags?
|
|
168
|
+
sig.parameters.each do |par|
|
|
169
|
+
break if par.decl == :restarg || par.decl == :kwrestarg || par.decl == :blockarg
|
|
170
|
+
unless params[par.name]
|
|
171
|
+
if pin.attribute?
|
|
172
|
+
inferred = pin.probe(api_map).self_to_type(pin.full_context)
|
|
173
|
+
if inferred.undefined?
|
|
174
|
+
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
175
|
+
end
|
|
176
|
+
else
|
|
159
177
|
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
160
178
|
end
|
|
161
|
-
else
|
|
162
|
-
result.push Problem.new(pin.location, "Missing @param tag for #{par.name} on #{pin.path}", pin: pin)
|
|
163
179
|
end
|
|
164
180
|
end
|
|
165
|
-
end
|
|
166
181
|
end
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
|
|
182
|
+
# @param name [String]
|
|
183
|
+
# @param data [Hash{Symbol => BasicObject}]
|
|
184
|
+
params.each_pair do |name, data|
|
|
185
|
+
# @type [ComplexType]
|
|
186
|
+
type = data[:qualified]
|
|
187
|
+
if type.undefined?
|
|
188
|
+
result.push Problem.new(pin.location, "Unresolved type #{data[:tagged]} for #{name} param on #{pin.path}", pin: pin)
|
|
189
|
+
end
|
|
176
190
|
end
|
|
177
191
|
end
|
|
178
192
|
result
|
|
@@ -190,7 +204,7 @@ module Solargraph
|
|
|
190
204
|
if pin.return_type.defined?
|
|
191
205
|
declared = pin.typify(api_map)
|
|
192
206
|
next if declared.duck_type?
|
|
193
|
-
if declared.defined?
|
|
207
|
+
if declared.defined? && pin.assignment
|
|
194
208
|
if rules.validate_tags?
|
|
195
209
|
inferred = pin.probe(api_map)
|
|
196
210
|
if inferred.undefined?
|
|
@@ -211,7 +225,7 @@ module Solargraph
|
|
|
211
225
|
elsif !pin.is_a?(Pin::Parameter) && !resolved_constant?(pin)
|
|
212
226
|
result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
|
|
213
227
|
end
|
|
214
|
-
|
|
228
|
+
elsif pin.assignment
|
|
215
229
|
inferred = pin.probe(api_map)
|
|
216
230
|
if inferred.undefined? && declared_externally?(pin)
|
|
217
231
|
ignored_pins.push pin
|
|
@@ -230,13 +244,14 @@ module Solargraph
|
|
|
230
244
|
def const_problems
|
|
231
245
|
return [] unless rules.validate_consts?
|
|
232
246
|
result = []
|
|
233
|
-
Solargraph::Parser::NodeMethods.const_nodes_from(
|
|
247
|
+
Solargraph::Parser::NodeMethods.const_nodes_from(source.node).each do |const|
|
|
234
248
|
rng = Solargraph::Range.from_node(const)
|
|
235
249
|
chain = Solargraph::Parser.chain(const, filename)
|
|
236
|
-
|
|
250
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
251
|
+
closure_pin.rebind(api_map)
|
|
237
252
|
location = Location.new(filename, rng)
|
|
238
253
|
locals = source_map.locals_at(location)
|
|
239
|
-
pins = chain.define(api_map,
|
|
254
|
+
pins = chain.define(api_map, closure_pin, locals)
|
|
240
255
|
if pins.empty?
|
|
241
256
|
result.push Problem.new(location, "Unresolved constant #{Solargraph::Parser::NodeMethods.unpack_name(const)}")
|
|
242
257
|
@marked_ranges.push location.range
|
|
@@ -248,21 +263,29 @@ module Solargraph
|
|
|
248
263
|
# @return [Array<Problem>]
|
|
249
264
|
def call_problems
|
|
250
265
|
result = []
|
|
251
|
-
Solargraph::Parser::NodeMethods.call_nodes_from(
|
|
266
|
+
Solargraph::Parser::NodeMethods.call_nodes_from(source.node).each do |call|
|
|
252
267
|
rng = Solargraph::Range.from_node(call)
|
|
253
268
|
next if @marked_ranges.any? { |d| d.contain?(rng.start) }
|
|
254
269
|
chain = Solargraph::Parser.chain(call, filename)
|
|
255
|
-
|
|
270
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
271
|
+
namespace_pin = closure_pin
|
|
272
|
+
if call.type == :block
|
|
273
|
+
# blocks in the AST include the method call as well, so the
|
|
274
|
+
# node returned by #call_nodes_from needs to be backed out
|
|
275
|
+
# one closure
|
|
276
|
+
closure_pin = closure_pin.closure
|
|
277
|
+
end
|
|
278
|
+
closure_pin.rebind(api_map)
|
|
256
279
|
location = Location.new(filename, rng)
|
|
257
280
|
locals = source_map.locals_at(location)
|
|
258
|
-
type = chain.infer(api_map,
|
|
281
|
+
type = chain.infer(api_map, closure_pin, locals)
|
|
259
282
|
if type.undefined? && !rules.ignore_all_undefined?
|
|
260
283
|
base = chain
|
|
261
284
|
missing = chain
|
|
262
285
|
found = nil
|
|
263
286
|
closest = ComplexType::UNDEFINED
|
|
264
287
|
until base.links.first.undefined?
|
|
265
|
-
found = base.define(api_map,
|
|
288
|
+
found = base.define(api_map, closure_pin, locals).first
|
|
266
289
|
break if found
|
|
267
290
|
missing = base
|
|
268
291
|
base = base.base
|
|
@@ -271,159 +294,174 @@ module Solargraph
|
|
|
271
294
|
# @todo remove the internal_or_core? check at a higher-than-strict level
|
|
272
295
|
if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
|
|
273
296
|
unless closest.generic? || ignored_pins.include?(found)
|
|
274
|
-
|
|
297
|
+
if closest.defined?
|
|
298
|
+
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word} on #{closest}")
|
|
299
|
+
else
|
|
300
|
+
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
|
|
301
|
+
end
|
|
275
302
|
@marked_ranges.push rng
|
|
276
303
|
end
|
|
277
304
|
end
|
|
278
305
|
end
|
|
279
|
-
result.concat argument_problems_for(chain, api_map,
|
|
306
|
+
result.concat argument_problems_for(chain, api_map, closure_pin, locals, location)
|
|
280
307
|
end
|
|
281
308
|
result
|
|
282
309
|
end
|
|
283
310
|
|
|
284
311
|
# @param chain [Solargraph::Source::Chain]
|
|
285
312
|
# @param api_map [Solargraph::ApiMap]
|
|
286
|
-
# @param
|
|
313
|
+
# @param closure_pin [Solargraph::Pin::Closure]
|
|
287
314
|
# @param locals [Array<Solargraph::Pin::Base>]
|
|
288
315
|
# @param location [Solargraph::Location]
|
|
289
316
|
# @return [Array<Problem>]
|
|
290
|
-
def argument_problems_for chain, api_map,
|
|
317
|
+
def argument_problems_for chain, api_map, closure_pin, locals, location
|
|
291
318
|
result = []
|
|
292
319
|
base = chain
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
# @type last_base_link [Solargraph::Source::Chain::Call]
|
|
321
|
+
last_base_link = base.links.last
|
|
322
|
+
return [] unless last_base_link.is_a?(Solargraph::Source::Chain::Call)
|
|
323
|
+
|
|
324
|
+
arguments = last_base_link.arguments
|
|
325
|
+
|
|
326
|
+
pins = base.define(api_map, closure_pin, locals)
|
|
327
|
+
|
|
328
|
+
first_pin = pins.first
|
|
329
|
+
if first_pin.is_a?(Pin::DelegatedMethod) && !first_pin.resolvable?(api_map)
|
|
330
|
+
# Do nothing, as we can't find the actual method implementation
|
|
331
|
+
elsif first_pin.is_a?(Pin::Method)
|
|
332
|
+
# @type [Pin::Method]
|
|
333
|
+
pin = first_pin
|
|
334
|
+
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
335
|
+
arity_problems_for(pin, fake_args_for(closure_pin), location)
|
|
336
|
+
elsif pin.path == 'Class#new'
|
|
337
|
+
fqns = if base.links.one?
|
|
338
|
+
closure_pin.namespace
|
|
339
|
+
else
|
|
340
|
+
base.base.infer(api_map, closure_pin, locals).namespace
|
|
341
|
+
end
|
|
342
|
+
init = api_map.get_method_stack(fqns, 'initialize').first
|
|
343
|
+
init ? arity_problems_for(init, arguments, location) : []
|
|
344
|
+
else
|
|
345
|
+
arity_problems_for(pin, arguments, location)
|
|
346
|
+
end
|
|
347
|
+
return ap unless ap.empty?
|
|
348
|
+
return [] if !rules.validate_calls? || base.links.first.is_a?(Solargraph::Source::Chain::ZSuper)
|
|
349
|
+
|
|
350
|
+
all_errors = []
|
|
351
|
+
pin.signatures.sort { |sig| sig.parameters.length }.each do |sig|
|
|
352
|
+
params = param_details_from_stack(sig, pins)
|
|
353
|
+
|
|
354
|
+
signature_errors = signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
|
|
355
|
+
|
|
356
|
+
if signature_errors.empty?
|
|
357
|
+
# we found a signature that works - meaning errors from
|
|
358
|
+
# other signatures don't matter.
|
|
359
|
+
return []
|
|
360
|
+
end
|
|
361
|
+
all_errors.concat signature_errors
|
|
362
|
+
end
|
|
363
|
+
result.concat all_errors
|
|
364
|
+
end
|
|
365
|
+
result
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# @param location [Location]
|
|
369
|
+
# @param locals [Array<Pin::LocalVariable>]
|
|
370
|
+
# @param closure_pin [Pin::Closure]
|
|
371
|
+
# @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
|
|
372
|
+
# @param arguments [Array<Source::Chain>]
|
|
373
|
+
# @param sig [Pin::Signature]
|
|
374
|
+
# @param pin [Pin::Method]
|
|
375
|
+
# @param pins [Array<Pin::Method>]
|
|
376
|
+
#
|
|
377
|
+
# @return [Array<Problem>]
|
|
378
|
+
def signature_argument_problems_for location, locals, closure_pin, params, arguments, sig, pin
|
|
379
|
+
errors = []
|
|
380
|
+
# @todo add logic mapping up restarg parameters with
|
|
381
|
+
# arguments (including restarg arguments). Use tuples
|
|
382
|
+
# when possible, and when not, ensure provably
|
|
383
|
+
# incorrect situations are detected.
|
|
384
|
+
sig.parameters.each_with_index do |par, idx|
|
|
385
|
+
return errors if par.decl == :restarg # bail out and assume the rest is valid pending better arg processing
|
|
386
|
+
argchain = arguments[idx]
|
|
387
|
+
if argchain.nil?
|
|
388
|
+
if par.decl == :arg
|
|
389
|
+
final_arg = arguments.last
|
|
390
|
+
if final_arg && final_arg.node.type == :splat
|
|
391
|
+
argchain = final_arg
|
|
392
|
+
return errors
|
|
312
393
|
else
|
|
313
|
-
|
|
394
|
+
errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
|
|
314
395
|
end
|
|
315
|
-
init = api_map.get_method_stack(fqns, 'initialize').first
|
|
316
|
-
init ? arity_problems_for(init, arguments, location) : []
|
|
317
396
|
else
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
unless ap.empty?
|
|
321
|
-
result.concat ap
|
|
322
|
-
break
|
|
397
|
+
final_arg = arguments.last
|
|
398
|
+
argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
|
|
323
399
|
end
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
final_arg = arguments.last
|
|
341
|
-
if final_arg && final_arg.node.type == :splat
|
|
342
|
-
argchain = final_arg
|
|
343
|
-
next # don't try to apply the type of the splat - unlikely to be specific enough
|
|
344
|
-
else
|
|
345
|
-
errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
|
|
346
|
-
next
|
|
347
|
-
end
|
|
348
|
-
else
|
|
349
|
-
final_arg = arguments.last
|
|
350
|
-
argchain = final_arg if final_arg && [:kwsplat, :hash].include?(final_arg.node.type)
|
|
351
|
-
end
|
|
352
|
-
end
|
|
353
|
-
if argchain
|
|
354
|
-
if par.decl != :arg
|
|
355
|
-
errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
|
|
356
|
-
next
|
|
357
|
-
else
|
|
358
|
-
if argchain.node.type == :splat && argchain == arguments.last
|
|
359
|
-
final_arg = argchain
|
|
360
|
-
end
|
|
361
|
-
if (final_arg && final_arg.node.type == :splat)
|
|
362
|
-
# The final argument given has been seen and was a
|
|
363
|
-
# splat, which doesn't give us useful types or
|
|
364
|
-
# arities against positional parameters, so let's
|
|
365
|
-
# continue on in case there are any required
|
|
366
|
-
# kwargs we should warn about
|
|
367
|
-
next
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
if argchain.node.type == :splat && par != sig.parameters.last
|
|
371
|
-
# we have been given a splat and there are more
|
|
372
|
-
# arguments to come.
|
|
373
|
-
|
|
374
|
-
# @todo Improve this so that we can skip past the
|
|
375
|
-
# rest of the positional parameters here but still
|
|
376
|
-
# process the kwargs
|
|
377
|
-
break
|
|
378
|
-
end
|
|
379
|
-
ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
|
|
380
|
-
ptype = ptype.self_to(par.context.namespace)
|
|
381
|
-
if ptype.nil?
|
|
382
|
-
# @todo Some level (strong, I guess) should require the param here
|
|
383
|
-
else
|
|
384
|
-
argtype = argchain.infer(api_map, block_pin, locals)
|
|
385
|
-
if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
|
|
386
|
-
errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
387
|
-
next
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
end
|
|
391
|
-
elsif par.decl == :kwarg
|
|
392
|
-
errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
|
393
|
-
next
|
|
394
|
-
end
|
|
400
|
+
end
|
|
401
|
+
if argchain
|
|
402
|
+
if par.decl != :arg
|
|
403
|
+
errors.concat kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
|
|
404
|
+
next
|
|
405
|
+
else
|
|
406
|
+
if argchain.node.type == :splat && argchain == arguments.last
|
|
407
|
+
final_arg = argchain
|
|
408
|
+
end
|
|
409
|
+
if (final_arg && final_arg.node.type == :splat)
|
|
410
|
+
# The final argument given has been seen and was a
|
|
411
|
+
# splat, which doesn't give us useful types or
|
|
412
|
+
# arities against positional parameters, so let's
|
|
413
|
+
# continue on in case there are any required
|
|
414
|
+
# kwargs we should warn about
|
|
415
|
+
next
|
|
395
416
|
end
|
|
396
|
-
if
|
|
397
|
-
|
|
398
|
-
|
|
417
|
+
if argchain.node.type == :splat && par != sig.parameters.last
|
|
418
|
+
# we have been given a splat and there are more
|
|
419
|
+
# arguments to come.
|
|
420
|
+
|
|
421
|
+
# @todo Improve this so that we can skip past the
|
|
422
|
+
# rest of the positional parameters here but still
|
|
423
|
+
# process the kwargs
|
|
424
|
+
return errors
|
|
425
|
+
end
|
|
426
|
+
ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
|
|
427
|
+
ptype = ptype.self_to_type(par.context)
|
|
428
|
+
if ptype.nil?
|
|
429
|
+
# @todo Some level (strong, I guess) should require the param here
|
|
430
|
+
else
|
|
431
|
+
argtype = argchain.infer(api_map, closure_pin, locals)
|
|
432
|
+
argtype = argtype.self_to_type(closure_pin.context)
|
|
433
|
+
if argtype.defined? && ptype.defined? && !any_types_match?(api_map, ptype, argtype)
|
|
434
|
+
errors.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
435
|
+
return errors
|
|
436
|
+
end
|
|
399
437
|
end
|
|
400
|
-
all_errors.concat errors
|
|
401
438
|
end
|
|
402
|
-
|
|
439
|
+
elsif par.decl == :kwarg
|
|
440
|
+
errors.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
|
441
|
+
next
|
|
403
442
|
end
|
|
404
|
-
base = base.base
|
|
405
443
|
end
|
|
406
|
-
|
|
444
|
+
errors
|
|
407
445
|
end
|
|
408
446
|
|
|
409
447
|
# @param sig [Pin::Signature]
|
|
410
448
|
# @param argchain [Source::Chain]
|
|
411
449
|
# @param api_map [ApiMap]
|
|
412
|
-
# @param
|
|
450
|
+
# @param closure_pin [Pin::Closure]
|
|
413
451
|
# @param locals [Array<Pin::LocalVariable>]
|
|
414
452
|
# @param location [Location]
|
|
415
453
|
# @param pin [Pin::Method]
|
|
416
|
-
# @param params [Hash{String =>
|
|
454
|
+
# @param params [Hash{String => Hash{Symbol => String, Solargraph::ComplexType}}]
|
|
417
455
|
# @param idx [Integer]
|
|
418
456
|
#
|
|
419
457
|
# @return [Array<Problem>]
|
|
420
|
-
def kwarg_problems_for sig, argchain, api_map,
|
|
458
|
+
def kwarg_problems_for sig, argchain, api_map, closure_pin, locals, location, pin, params, idx
|
|
421
459
|
result = []
|
|
422
460
|
kwargs = convert_hash(argchain.node)
|
|
423
461
|
par = sig.parameters[idx]
|
|
424
462
|
argchain = kwargs[par.name.to_sym]
|
|
425
463
|
if par.decl == :kwrestarg || (par.decl == :optarg && idx == pin.parameters.length - 1 && par.asgn_code == '{}')
|
|
426
|
-
result.concat kwrestarg_problems_for(api_map,
|
|
464
|
+
result.concat kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
|
|
427
465
|
else
|
|
428
466
|
if argchain
|
|
429
467
|
data = params[par.name]
|
|
@@ -431,8 +469,11 @@ module Solargraph
|
|
|
431
469
|
# @todo Some level (strong, I guess) should require the param here
|
|
432
470
|
else
|
|
433
471
|
ptype = data[:qualified]
|
|
472
|
+
ptype = ptype.self_to_type(pin.context)
|
|
434
473
|
unless ptype.undefined?
|
|
435
|
-
|
|
474
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1127
|
|
475
|
+
argtype = argchain.infer(api_map, closure_pin, locals).self_to_type(closure_pin.context)
|
|
476
|
+
# @sg-ignore Unresolved call to defined?
|
|
436
477
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
|
437
478
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{par.name} expected #{ptype}, received #{argtype}")
|
|
438
479
|
end
|
|
@@ -446,19 +487,21 @@ module Solargraph
|
|
|
446
487
|
end
|
|
447
488
|
|
|
448
489
|
# @param api_map [ApiMap]
|
|
449
|
-
# @param
|
|
490
|
+
# @param closure_pin [Pin::Closure]
|
|
450
491
|
# @param locals [Array<Pin::LocalVariable>]
|
|
451
492
|
# @param location [Location]
|
|
452
493
|
# @param pin [Pin::Method]
|
|
453
494
|
# @param params [Hash{String => [nil, Hash]}]
|
|
454
495
|
# @param kwargs [Hash{Symbol => Source::Chain}]
|
|
455
496
|
# @return [Array<Problem>]
|
|
456
|
-
def kwrestarg_problems_for(api_map,
|
|
497
|
+
def kwrestarg_problems_for(api_map, closure_pin, locals, location, pin, params, kwargs)
|
|
457
498
|
result = []
|
|
458
499
|
kwargs.each_pair do |pname, argchain|
|
|
459
500
|
next unless params.key?(pname.to_s)
|
|
460
501
|
ptype = params[pname.to_s][:qualified]
|
|
461
|
-
|
|
502
|
+
ptype = ptype.self_to_type(pin.context)
|
|
503
|
+
argtype = argchain.infer(api_map, closure_pin, locals)
|
|
504
|
+
argtype = argtype.self_to_type(closure_pin.context)
|
|
462
505
|
if argtype.defined? && ptype && !any_types_match?(api_map, ptype, argtype)
|
|
463
506
|
result.push Problem.new(location, "Wrong argument type for #{pin.path}: #{pname} expected #{ptype}, received #{argtype}")
|
|
464
507
|
end
|
|
@@ -466,32 +509,94 @@ module Solargraph
|
|
|
466
509
|
result
|
|
467
510
|
end
|
|
468
511
|
|
|
469
|
-
# @param
|
|
470
|
-
# @
|
|
471
|
-
|
|
512
|
+
# @param param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
513
|
+
# @param pin [Pin::Method, Pin::Signature]
|
|
514
|
+
# @param relevant_pin [Pin::Method, Pin::Signature] the pin which is under inspection
|
|
515
|
+
# @return [void]
|
|
516
|
+
def add_restkwarg_param_tag_details(param_details, pin, relevant_pin)
|
|
517
|
+
# see if we have additional tags to pay attention to from YARD -
|
|
518
|
+
# e.g., kwargs in a **restkwargs splat
|
|
472
519
|
tags = pin.docstring.tags(:param)
|
|
473
|
-
|
|
520
|
+
tags.each do |tag|
|
|
521
|
+
next if param_details.key? tag.name.to_s
|
|
522
|
+
next if tag.types.nil?
|
|
523
|
+
details = {
|
|
524
|
+
tagged: tag.types.join(', '),
|
|
525
|
+
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.full_context.namespace)
|
|
526
|
+
}
|
|
527
|
+
# don't complain about a param that didn't come from the pin we're looking at anyway
|
|
528
|
+
if details[:qualified].defined? ||
|
|
529
|
+
relevant_pin.parameter_names.include?(tag.name.to_s)
|
|
530
|
+
param_details[tag.name.to_s] = details
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
# @param pin [Pin::Signature]
|
|
536
|
+
# @return [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
537
|
+
def signature_param_details(pin)
|
|
538
|
+
# @type [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
474
539
|
result = {}
|
|
540
|
+
pin.parameters.each do |param|
|
|
541
|
+
type = param.typify(api_map)
|
|
542
|
+
next if type.nil? || type.undefined?
|
|
543
|
+
result[param.name.to_s] = {
|
|
544
|
+
tagged: type.tags,
|
|
545
|
+
qualified: type
|
|
546
|
+
}
|
|
547
|
+
end
|
|
548
|
+
# see if we have additional tags to pay attention to from YARD -
|
|
549
|
+
# e.g., kwargs in a **restkwargs splat
|
|
550
|
+
tags = pin.docstring.tags(:param)
|
|
475
551
|
tags.each do |tag|
|
|
476
|
-
next if
|
|
552
|
+
next if result.key? tag.name.to_s
|
|
553
|
+
next if tag.types.nil?
|
|
477
554
|
result[tag.name.to_s] = {
|
|
478
555
|
tagged: tag.types.join(', '),
|
|
479
|
-
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, pin.
|
|
556
|
+
qualified: Solargraph::ComplexType.try_parse(*tag.types).qualify(api_map, *pin.closure.gates)
|
|
480
557
|
}
|
|
481
558
|
end
|
|
482
559
|
result
|
|
483
560
|
end
|
|
484
561
|
|
|
485
|
-
#
|
|
486
|
-
#
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
562
|
+
# The original signature defines the parameters, but other
|
|
563
|
+
# signatures and method pins can help by adding type information
|
|
564
|
+
#
|
|
565
|
+
# @param param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
566
|
+
# @param param_names [Array<String>]
|
|
567
|
+
# @param new_param_details [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
568
|
+
#
|
|
569
|
+
# @return [void]
|
|
570
|
+
def add_to_param_details(param_details, param_names, new_param_details)
|
|
571
|
+
new_param_details.each do |param_name, details|
|
|
572
|
+
next unless param_names.include?(param_name)
|
|
573
|
+
|
|
574
|
+
param_details[param_name] ||= {}
|
|
575
|
+
param_details[param_name][:tagged] ||= details[:tagged]
|
|
576
|
+
param_details[param_name][:qualified] ||= details[:qualified]
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# @param signature [Pin::Signature]
|
|
581
|
+
# @param method_pin_stack [Array<Pin::Method>]
|
|
582
|
+
# @return [Hash{String => Hash{Symbol => String, ComplexType}}]
|
|
583
|
+
def param_details_from_stack(signature, method_pin_stack)
|
|
584
|
+
signature_type = signature.typify(api_map)
|
|
585
|
+
signature = signature.proxy signature_type
|
|
586
|
+
param_details = signature_param_details(signature)
|
|
587
|
+
param_names = signature.parameter_names
|
|
588
|
+
|
|
589
|
+
method_pin_stack.each do |method_pin|
|
|
590
|
+
add_restkwarg_param_tag_details(param_details, method_pin, signature)
|
|
591
|
+
|
|
592
|
+
# documentation of types in superclasses should fail back to
|
|
593
|
+
# subclasses if the subclass hasn't documented something
|
|
594
|
+
method_pin.signatures.each do |sig|
|
|
595
|
+
add_restkwarg_param_tag_details(param_details, sig, signature)
|
|
596
|
+
add_to_param_details param_details, param_names, signature_param_details(sig)
|
|
597
|
+
end
|
|
493
598
|
end
|
|
494
|
-
|
|
599
|
+
param_details
|
|
495
600
|
end
|
|
496
601
|
|
|
497
602
|
# @param pin [Pin::Base]
|
|
@@ -512,22 +617,23 @@ module Solargraph
|
|
|
512
617
|
!internal? pin
|
|
513
618
|
end
|
|
514
619
|
|
|
515
|
-
# @param pin [Pin::
|
|
620
|
+
# @param pin [Pin::BaseVariable]
|
|
516
621
|
def declared_externally? pin
|
|
517
|
-
|
|
622
|
+
raise "No assignment found" if pin.assignment.nil?
|
|
623
|
+
|
|
518
624
|
chain = Solargraph::Parser.chain(pin.assignment, filename)
|
|
519
625
|
rng = Solargraph::Range.from_node(pin.assignment)
|
|
520
|
-
|
|
626
|
+
closure_pin = source_map.locate_closure_pin(rng.start.line, rng.start.column)
|
|
521
627
|
location = Location.new(filename, Range.from_node(pin.assignment))
|
|
522
628
|
locals = source_map.locals_at(location)
|
|
523
|
-
type = chain.infer(api_map,
|
|
629
|
+
type = chain.infer(api_map, closure_pin, locals)
|
|
524
630
|
if type.undefined? && !rules.ignore_all_undefined?
|
|
525
631
|
base = chain
|
|
526
632
|
missing = chain
|
|
527
633
|
found = nil
|
|
528
634
|
closest = ComplexType::UNDEFINED
|
|
529
635
|
until base.links.first.undefined?
|
|
530
|
-
found = base.define(api_map,
|
|
636
|
+
found = base.define(api_map, closure_pin, locals).first
|
|
531
637
|
break if found
|
|
532
638
|
missing = base
|
|
533
639
|
base = base.base
|
|
@@ -562,7 +668,7 @@ module Solargraph
|
|
|
562
668
|
return [] unless pin.explicit?
|
|
563
669
|
return [] if parameters.empty? && arguments.empty?
|
|
564
670
|
return [] if pin.anon_splat?
|
|
565
|
-
unchecked = arguments.
|
|
671
|
+
unchecked = arguments.dup # creates copy of and unthaws array
|
|
566
672
|
add_params = 0
|
|
567
673
|
if unchecked.empty? && parameters.any? { |param| param.decl == :kwarg }
|
|
568
674
|
return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
|
|
@@ -584,7 +690,8 @@ module Solargraph
|
|
|
584
690
|
kwargs.delete param.name.to_sym
|
|
585
691
|
settled_kwargs += 1
|
|
586
692
|
elsif param.decl == :kwarg
|
|
587
|
-
|
|
693
|
+
last_arg_last_link = arguments.last.links.last
|
|
694
|
+
return [] if last_arg_last_link.is_a?(Solargraph::Source::Chain::Hash) && last_arg_last_link.splatted?
|
|
588
695
|
return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
|
|
589
696
|
end
|
|
590
697
|
end
|
|
@@ -619,7 +726,6 @@ module Solargraph
|
|
|
619
726
|
# @param parameters [Enumerable<Pin::Parameter>]
|
|
620
727
|
# @todo need to use generic types in method to choose correct
|
|
621
728
|
# signature and generate Integer as return type
|
|
622
|
-
# @sg-ignore
|
|
623
729
|
# @return [Integer]
|
|
624
730
|
def required_param_count(parameters)
|
|
625
731
|
parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
|
|
@@ -638,7 +744,7 @@ module Solargraph
|
|
|
638
744
|
(pin.closure && pin.closure.docstring.has_tag?('abstract'))
|
|
639
745
|
end
|
|
640
746
|
|
|
641
|
-
# @param pin [Pin::
|
|
747
|
+
# @param pin [Pin::Method]
|
|
642
748
|
# @return [Array<Source::Chain>]
|
|
643
749
|
def fake_args_for(pin)
|
|
644
750
|
args = []
|
|
@@ -660,12 +766,48 @@ module Solargraph
|
|
|
660
766
|
args
|
|
661
767
|
end
|
|
662
768
|
|
|
769
|
+
# @return [Set<Integer>]
|
|
770
|
+
def sg_ignore_lines_processed
|
|
771
|
+
@sg_ignore_lines_processed ||= Set.new
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
# @return [Set<Integer>]
|
|
775
|
+
def all_sg_ignore_lines
|
|
776
|
+
source.associated_comments.select do |_line, text|
|
|
777
|
+
text.include?('@sg-ignore')
|
|
778
|
+
end.keys.to_set
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
# @return [Array<Integer>]
|
|
782
|
+
def unprocessed_sg_ignore_lines
|
|
783
|
+
(all_sg_ignore_lines - sg_ignore_lines_processed).to_a.sort
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# @return [Array<Problem>]
|
|
787
|
+
def unneeded_sgignore_problems
|
|
788
|
+
return [] unless rules.validate_sg_ignores?
|
|
789
|
+
|
|
790
|
+
unprocessed_sg_ignore_lines.map do |line|
|
|
791
|
+
Problem.new(
|
|
792
|
+
Location.new(filename, Range.from_to(line, 0, line, 0)),
|
|
793
|
+
'Unneeded @sg-ignore comment'
|
|
794
|
+
)
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
|
|
663
798
|
# @param problems [Array<Problem>]
|
|
664
799
|
# @return [Array<Problem>]
|
|
665
800
|
def without_ignored problems
|
|
666
801
|
problems.reject do |problem|
|
|
667
|
-
node =
|
|
668
|
-
node &&
|
|
802
|
+
node = source.node_at(problem.location.range.start.line, problem.location.range.start.column)
|
|
803
|
+
ignored = node && source.comments_for(node)&.include?('@sg-ignore')
|
|
804
|
+
unless !ignored || all_sg_ignore_lines.include?(problem.location.range.start.line)
|
|
805
|
+
# :nocov:
|
|
806
|
+
Solargraph.assert_or_log(:sg_ignore) { "@sg-ignore accounting issue - node is #{node}" }
|
|
807
|
+
# :nocov:
|
|
808
|
+
end
|
|
809
|
+
sg_ignore_lines_processed.add problem.location.range.start.line if ignored
|
|
810
|
+
ignored
|
|
669
811
|
end
|
|
670
812
|
end
|
|
671
813
|
end
|