solargraph 0.39.14 → 0.40.1
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/.travis.yml +4 -8
- data/CHANGELOG.md +988 -0
- data/Rakefile +12 -1
- data/SPONSORS.md +1 -0
- data/lib/solargraph.rb +2 -4
- data/lib/solargraph/api_map.rb +75 -74
- data/lib/solargraph/api_map/cache.rb +2 -2
- data/lib/solargraph/api_map/store.rb +4 -8
- data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
- data/lib/solargraph/compat.rb +14 -0
- data/lib/solargraph/complex_type.rb +2 -2
- data/lib/solargraph/convention.rb +13 -4
- data/lib/solargraph/convention/base.rb +16 -8
- data/lib/solargraph/convention/gemfile.rb +2 -5
- data/lib/solargraph/convention/gemspec.rb +3 -6
- data/lib/solargraph/convention/rspec.rb +3 -6
- data/lib/solargraph/documentor.rb +2 -0
- data/lib/solargraph/environ.rb +11 -6
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +6 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/formatting.rb +17 -19
- data/lib/solargraph/library.rb +8 -10
- data/lib/solargraph/parser/legacy/node_chainer.rb +7 -7
- data/lib/solargraph/parser/legacy/node_methods.rb +5 -0
- data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +36 -23
- data/lib/solargraph/parser/node_processor/base.rb +3 -0
- data/lib/solargraph/parser/rubyvm/node_chainer.rb +9 -9
- data/lib/solargraph/parser/rubyvm/node_methods.rb +11 -1
- data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +1 -1
- data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +40 -29
- data/lib/solargraph/pin.rb +0 -3
- data/lib/solargraph/pin/common.rb +1 -1
- data/lib/solargraph/pin/conversions.rb +3 -4
- data/lib/solargraph/pin/documenting.rb +3 -9
- data/lib/solargraph/pin/method.rb +141 -7
- data/lib/solargraph/pin/method_alias.rb +1 -1
- data/lib/solargraph/position.rb +2 -14
- data/lib/solargraph/shell.rb +1 -1
- data/lib/solargraph/source.rb +10 -6
- data/lib/solargraph/source/chain.rb +18 -5
- data/lib/solargraph/source_map.rb +4 -1
- data/lib/solargraph/source_map/clip.rb +3 -2
- data/lib/solargraph/source_map/mapper.rb +10 -6
- data/lib/solargraph/type_checker.rb +35 -39
- data/lib/solargraph/type_checker/param_def.rb +1 -1
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map.rb +40 -47
- data/lib/solargraph/yard_map/core_fills.rb +185 -0
- data/lib/solargraph/yard_map/helpers.rb +16 -0
- data/lib/solargraph/yard_map/mapper.rb +14 -8
- data/lib/solargraph/{pin/yard_pin/constant.rb → yard_map/mapper/to_constant.rb} +6 -6
- data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
- data/lib/solargraph/{pin/yard_pin/namespace.rb → yard_map/mapper/to_namespace.rb} +6 -6
- data/lib/solargraph/yard_map/rdoc_to_yard.rb +1 -1
- data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
- data/lib/solargraph/yard_map/to_method.rb +79 -0
- data/solargraph.gemspec +4 -4
- metadata +20 -34
- data/lib/solargraph/core_fills.rb +0 -160
- data/lib/solargraph/pin/attribute.rb +0 -49
- data/lib/solargraph/pin/base_method.rb +0 -141
- data/lib/solargraph/pin/yard_pin.rb +0 -12
- data/lib/solargraph/pin/yard_pin/method.rb +0 -80
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +0 -20
- data/lib/solargraph/stdlib_fills.rb +0 -40
- data/travis-bundler.rb +0 -11
@@ -2,18 +2,29 @@
|
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
module Pin
|
5
|
-
class
|
5
|
+
# The base class for method and attribute pins.
|
6
|
+
#
|
7
|
+
class Method < Closure
|
6
8
|
include Solargraph::Parser::NodeMethods
|
7
9
|
|
8
10
|
# @return [Array<Pin::Parameter>]
|
9
11
|
attr_reader :parameters
|
10
12
|
|
11
|
-
# @
|
12
|
-
|
13
|
-
|
13
|
+
# @return [::Symbol] :public, :private, or :protected
|
14
|
+
attr_reader :visibility
|
15
|
+
|
16
|
+
# @return [Parser::AST::Node]
|
17
|
+
attr_reader :node
|
18
|
+
|
19
|
+
# @param visibility [::Symbol] :public, :protected, or :private
|
20
|
+
# @param explicit [Boolean]
|
21
|
+
def initialize visibility: :public, explicit: true, parameters: [], node: nil, attribute: false, **splat
|
14
22
|
super(**splat)
|
23
|
+
@visibility = visibility
|
24
|
+
@explicit = explicit
|
15
25
|
@parameters = parameters
|
16
26
|
@node = node
|
27
|
+
@attribute = attribute
|
17
28
|
end
|
18
29
|
|
19
30
|
# @return [Array<String>]
|
@@ -22,11 +33,70 @@ module Solargraph
|
|
22
33
|
end
|
23
34
|
|
24
35
|
def completion_item_kind
|
25
|
-
Solargraph::LanguageServer::CompletionItemKinds::METHOD
|
36
|
+
attribute? ? Solargraph::LanguageServer::CompletionItemKinds::PROPERTY : Solargraph::LanguageServer::CompletionItemKinds::METHOD
|
26
37
|
end
|
27
38
|
|
28
39
|
def symbol_kind
|
29
|
-
LanguageServer::SymbolKinds::METHOD
|
40
|
+
attribute? ? Solargraph::LanguageServer::SymbolKinds::PROPERTY : LanguageServer::SymbolKinds::METHOD
|
41
|
+
end
|
42
|
+
|
43
|
+
def return_type
|
44
|
+
@return_type ||= generate_complex_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def path
|
48
|
+
@path ||= "#{namespace}#{(scope == :instance ? '#' : '.')}#{name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def typify api_map
|
52
|
+
decl = super
|
53
|
+
return decl unless decl.undefined?
|
54
|
+
type = see_reference(api_map) || typify_from_super(api_map)
|
55
|
+
return type.qualify(api_map, namespace) unless type.nil?
|
56
|
+
name.end_with?('?') ? ComplexType::BOOLEAN : ComplexType::UNDEFINED
|
57
|
+
end
|
58
|
+
|
59
|
+
def documentation
|
60
|
+
if @documentation.nil?
|
61
|
+
@documentation ||= super || ''
|
62
|
+
param_tags = docstring.tags(:param)
|
63
|
+
unless param_tags.nil? or param_tags.empty?
|
64
|
+
@documentation += "\n\n" unless @documentation.empty?
|
65
|
+
@documentation += "Params:\n"
|
66
|
+
lines = []
|
67
|
+
param_tags.each do |p|
|
68
|
+
l = "* #{p.name}"
|
69
|
+
l += " [#{escape_brackets(p.types.join(', '))}]" unless p.types.nil? or p.types.empty?
|
70
|
+
l += " #{p.text}"
|
71
|
+
lines.push l
|
72
|
+
end
|
73
|
+
@documentation += lines.join("\n")
|
74
|
+
end
|
75
|
+
return_tags = docstring.tags(:return)
|
76
|
+
unless return_tags.empty?
|
77
|
+
@documentation += "\n\n" unless @documentation.empty?
|
78
|
+
@documentation += "Returns:\n"
|
79
|
+
lines = []
|
80
|
+
return_tags.each do |r|
|
81
|
+
l = "*"
|
82
|
+
l += " [#{escape_brackets(r.types.join(', '))}]" unless r.types.nil? or r.types.empty?
|
83
|
+
l += " #{r.text}"
|
84
|
+
lines.push l
|
85
|
+
end
|
86
|
+
@documentation += lines.join("\n")
|
87
|
+
end
|
88
|
+
@documentation += "\n\n" unless @documentation.empty?
|
89
|
+
@documentation += "Visibility: #{visibility}"
|
90
|
+
end
|
91
|
+
@documentation.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def explicit?
|
95
|
+
@explicit
|
96
|
+
end
|
97
|
+
|
98
|
+
def attribute?
|
99
|
+
@attribute
|
30
100
|
end
|
31
101
|
|
32
102
|
def nearly? other
|
@@ -37,7 +107,7 @@ module Solargraph
|
|
37
107
|
end
|
38
108
|
|
39
109
|
def probe api_map
|
40
|
-
infer_from_return_nodes(api_map)
|
110
|
+
attribute? ? infer_from_iv(api_map) : infer_from_return_nodes(api_map)
|
41
111
|
end
|
42
112
|
|
43
113
|
def try_merge! pin
|
@@ -70,6 +140,57 @@ module Solargraph
|
|
70
140
|
|
71
141
|
private
|
72
142
|
|
143
|
+
# @return [ComplexType]
|
144
|
+
def generate_complex_type
|
145
|
+
tags = docstring.tags(:return).map(&:types).flatten.reject(&:nil?)
|
146
|
+
return ComplexType::UNDEFINED if tags.empty?
|
147
|
+
ComplexType.try_parse *tags
|
148
|
+
end
|
149
|
+
|
150
|
+
# @param api_map [ApiMap]
|
151
|
+
# @return [ComplexType, nil]
|
152
|
+
def see_reference api_map
|
153
|
+
docstring.ref_tags.each do |ref|
|
154
|
+
next unless ref.tag_name == 'return' && ref.owner
|
155
|
+
result = resolve_reference(ref.owner.to_s, api_map)
|
156
|
+
return result unless result.nil?
|
157
|
+
end
|
158
|
+
match = comments.match(/^[ \t]*\(see (.*)\)/m)
|
159
|
+
return nil if match.nil?
|
160
|
+
resolve_reference match[1], api_map
|
161
|
+
end
|
162
|
+
|
163
|
+
# @param api_map [ApiMap]
|
164
|
+
# @return [ComplexType, nil]
|
165
|
+
def typify_from_super api_map
|
166
|
+
stack = api_map.get_method_stack(namespace, name, scope: scope).reject { |pin| pin.path == path }
|
167
|
+
return nil if stack.empty?
|
168
|
+
stack.each do |pin|
|
169
|
+
return pin.return_type unless pin.return_type.undefined?
|
170
|
+
end
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
# @param ref [String]
|
175
|
+
# @param api_map [ApiMap]
|
176
|
+
# @return [ComplexType]
|
177
|
+
def resolve_reference ref, api_map
|
178
|
+
parts = ref.split(/[\.#]/)
|
179
|
+
if parts.first.empty? || parts.one?
|
180
|
+
path = "#{namespace}#{ref}"
|
181
|
+
else
|
182
|
+
fqns = api_map.qualify(parts.first, namespace)
|
183
|
+
return ComplexType::UNDEFINED if fqns.nil?
|
184
|
+
path = fqns + ref[parts.first.length] + parts.last
|
185
|
+
end
|
186
|
+
pins = api_map.get_path_pins(path)
|
187
|
+
pins.each do |pin|
|
188
|
+
type = pin.typify(api_map)
|
189
|
+
return type unless type.undefined?
|
190
|
+
end
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
73
194
|
# @return [Parser::AST::Node, nil]
|
74
195
|
def method_body_node
|
75
196
|
return nil if node.nil?
|
@@ -106,6 +227,19 @@ module Solargraph
|
|
106
227
|
return ComplexType::UNDEFINED if result.empty?
|
107
228
|
ComplexType.try_parse(*result.map(&:tag).uniq)
|
108
229
|
end
|
230
|
+
|
231
|
+
def infer_from_iv api_map
|
232
|
+
types = []
|
233
|
+
varname = "@#{name.gsub(/=$/, '')}"
|
234
|
+
pins = api_map.get_instance_variable_pins(binder.namespace, binder.scope).select { |iv| iv.name == varname }
|
235
|
+
pins.each do |pin|
|
236
|
+
type = pin.typify(api_map)
|
237
|
+
type = pin.probe(api_map) if type.undefined?
|
238
|
+
types.push type if type.defined?
|
239
|
+
end
|
240
|
+
return ComplexType::UNDEFINED if types.empty?
|
241
|
+
ComplexType.try_parse(*types.map(&:tag).uniq)
|
242
|
+
end
|
109
243
|
end
|
110
244
|
end
|
111
245
|
end
|
data/lib/solargraph/position.rb
CHANGED
@@ -40,20 +40,8 @@ module Solargraph
|
|
40
40
|
# @param position [Position]
|
41
41
|
# @return [Integer]
|
42
42
|
def self.to_offset text, position
|
43
|
-
|
44
|
-
|
45
|
-
line = position.line
|
46
|
-
column = position.character
|
47
|
-
text.lines.each do |l|
|
48
|
-
line_length = l.length
|
49
|
-
if feed == line
|
50
|
-
result += column
|
51
|
-
break
|
52
|
-
end
|
53
|
-
result += line_length
|
54
|
-
feed += 1
|
55
|
-
end
|
56
|
-
result
|
43
|
+
return 0 if text.empty?
|
44
|
+
text.lines[0...position.line].sum(&:length) + position.character
|
57
45
|
end
|
58
46
|
|
59
47
|
# Get a numeric offset for the specified text and a position identified
|
data/lib/solargraph/shell.rb
CHANGED
@@ -153,7 +153,7 @@ module Solargraph
|
|
153
153
|
probcount += problems.length
|
154
154
|
end
|
155
155
|
puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
|
156
|
-
exit 1 if probcount
|
156
|
+
exit 1 if probcount > 0
|
157
157
|
end
|
158
158
|
|
159
159
|
desc 'scan', 'Test the workspace for problems'
|
data/lib/solargraph/source.rb
CHANGED
@@ -284,7 +284,7 @@ module Solargraph
|
|
284
284
|
|
285
285
|
FOLDING_NODE_TYPES = if Parser.rubyvm?
|
286
286
|
%i[
|
287
|
-
CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR
|
287
|
+
CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
|
288
288
|
].freeze
|
289
289
|
else
|
290
290
|
%i[
|
@@ -345,18 +345,22 @@ module Solargraph
|
|
345
345
|
|
346
346
|
# @param top [Parser::AST::Node]
|
347
347
|
# @param result [Array<Range>]
|
348
|
+
# @param parent [Symbol]
|
348
349
|
# @return [void]
|
349
|
-
def inner_folding_ranges top, result = []
|
350
|
+
def inner_folding_ranges top, result = [], parent = nil
|
350
351
|
# return unless top.is_a?(::Parser::AST::Node)
|
351
352
|
return unless Parser.is_ast_node?(top)
|
352
353
|
if FOLDING_NODE_TYPES.include?(top.type)
|
353
|
-
|
354
|
-
|
355
|
-
|
354
|
+
# @todo Smelly exception for hash's first-level array in RubyVM
|
355
|
+
unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
|
356
|
+
range = Range.from_node(top)
|
357
|
+
if result.empty? || range.start.line > result.last.start.line
|
358
|
+
result.push range unless range.ending.line - range.start.line < 2
|
359
|
+
end
|
356
360
|
end
|
357
361
|
end
|
358
362
|
top.children.each do |child|
|
359
|
-
inner_folding_ranges(child, result)
|
363
|
+
inner_folding_ranges(child, result, top.type)
|
360
364
|
end
|
361
365
|
end
|
362
366
|
|
@@ -110,18 +110,21 @@ module Solargraph
|
|
110
110
|
# @param api_map [ApiMap]
|
111
111
|
# @return [ComplexType]
|
112
112
|
def infer_first_defined pins, context, api_map
|
113
|
-
|
113
|
+
possibles = []
|
114
114
|
pins.each do |pin|
|
115
115
|
# Avoid infinite recursion
|
116
116
|
next if @@inference_stack.include?(pin.identity)
|
117
117
|
@@inference_stack.push pin.identity
|
118
118
|
type = pin.typify(api_map)
|
119
119
|
@@inference_stack.pop
|
120
|
-
|
120
|
+
if type.defined?
|
121
|
+
possibles.push type
|
122
|
+
break if pin.is_a?(Pin::Method)
|
123
|
+
end
|
121
124
|
end
|
122
|
-
if
|
125
|
+
if possibles.empty?
|
123
126
|
# Limit method inference recursion
|
124
|
-
return
|
127
|
+
return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
|
125
128
|
@@inference_depth += 1
|
126
129
|
pins.each do |pin|
|
127
130
|
# Avoid infinite recursion
|
@@ -129,10 +132,20 @@ module Solargraph
|
|
129
132
|
@@inference_stack.push pin.identity
|
130
133
|
type = pin.probe(api_map)
|
131
134
|
@@inference_stack.pop
|
132
|
-
|
135
|
+
if type.defined?
|
136
|
+
possibles.push type
|
137
|
+
break if pin.is_a?(Pin::Method)
|
138
|
+
end
|
133
139
|
end
|
134
140
|
@@inference_depth -= 1
|
135
141
|
end
|
142
|
+
return ComplexType::UNDEFINED if possibles.empty?
|
143
|
+
type = if possibles.length > 1
|
144
|
+
sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
|
145
|
+
ComplexType.parse(*sorted)
|
146
|
+
else
|
147
|
+
possibles.first
|
148
|
+
end
|
136
149
|
return type if context.nil? || context.return_type.undefined?
|
137
150
|
type.self_to(context.return_type.namespace)
|
138
151
|
end
|
@@ -30,7 +30,7 @@ module Solargraph
|
|
30
30
|
@source = source.dup
|
31
31
|
@pins = pins
|
32
32
|
@locals = locals
|
33
|
-
environ.merge Convention.
|
33
|
+
environ.merge Convention.for_local(self) unless filename.nil?
|
34
34
|
@pin_class_hash = pins.to_set.classify(&:class).transform_values(&:to_a)
|
35
35
|
@pin_select_cache = {}
|
36
36
|
end
|
@@ -168,6 +168,9 @@ module Solargraph
|
|
168
168
|
position = Position.new(line, character)
|
169
169
|
found = nil
|
170
170
|
pins.each do |pin|
|
171
|
+
# @todo Attribute pins should not be treated like closures, but
|
172
|
+
# there's probably a better way to handle it
|
173
|
+
next if pin.is_a?(Pin::Method) && pin.attribute?
|
171
174
|
found = pin if (klasses.empty? || klasses.any? { |kls| pin.is_a?(kls) } ) && pin.location.range.contain?(position)
|
172
175
|
break if pin.location.range.start.line > line
|
173
176
|
end
|
@@ -149,7 +149,7 @@ module Solargraph
|
|
149
149
|
frag_start = cursor.start_of_word.to_s.downcase
|
150
150
|
filtered = result.uniq(&:name).select { |s|
|
151
151
|
s.name.downcase.start_with?(frag_start) &&
|
152
|
-
(!s.is_a?(Pin::
|
152
|
+
(!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
|
153
153
|
}
|
154
154
|
Completion.new(filtered, cursor.range)
|
155
155
|
end
|
@@ -212,7 +212,8 @@ module Solargraph
|
|
212
212
|
result.concat api_map.get_constants(context_pin.context.namespace, *gates)
|
213
213
|
result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
|
214
214
|
result.concat api_map.get_methods('Kernel')
|
215
|
-
result.concat ApiMap.keywords
|
215
|
+
# result.concat ApiMap.keywords
|
216
|
+
result.concat api_map.keyword_pins
|
216
217
|
result.concat yielded_self_pins
|
217
218
|
end
|
218
219
|
end
|
@@ -126,27 +126,31 @@ module Solargraph
|
|
126
126
|
namespace = closure_at(source_position)
|
127
127
|
t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
|
128
128
|
if t.nil? || t.include?('r')
|
129
|
-
pins.push Solargraph::Pin::
|
129
|
+
pins.push Solargraph::Pin::Method.new(
|
130
130
|
location: location,
|
131
131
|
closure: namespace,
|
132
132
|
name: directive.tag.name,
|
133
133
|
comments: docstring.all.to_s,
|
134
|
-
access: :reader,
|
135
134
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
136
135
|
visibility: :public,
|
137
|
-
explicit: false
|
136
|
+
explicit: false,
|
137
|
+
attribute: true
|
138
138
|
)
|
139
139
|
end
|
140
140
|
if t.nil? || t.include?('w')
|
141
|
-
pins.push Solargraph::Pin::
|
141
|
+
pins.push Solargraph::Pin::Method.new(
|
142
142
|
location: location,
|
143
143
|
closure: namespace,
|
144
144
|
name: "#{directive.tag.name}=",
|
145
145
|
comments: docstring.all.to_s,
|
146
|
-
access: :writer,
|
147
146
|
scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
|
148
|
-
visibility: :public
|
147
|
+
visibility: :public,
|
148
|
+
attribute: true
|
149
149
|
)
|
150
|
+
pins.last.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
151
|
+
if pins.last.return_type.defined?
|
152
|
+
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
|
153
|
+
end
|
150
154
|
end
|
151
155
|
when 'parse'
|
152
156
|
begin
|
@@ -73,15 +73,15 @@ module Solargraph
|
|
73
73
|
# @return [Array<Problem>]
|
74
74
|
def method_tag_problems
|
75
75
|
result = []
|
76
|
-
# @param pin [Pin::
|
77
|
-
source_map.pins_by_class(Pin::
|
76
|
+
# @param pin [Pin::Method]
|
77
|
+
source_map.pins_by_class(Pin::Method).each do |pin|
|
78
78
|
result.concat method_return_type_problems_for(pin)
|
79
79
|
result.concat method_param_type_problems_for(pin)
|
80
80
|
end
|
81
81
|
result
|
82
82
|
end
|
83
83
|
|
84
|
-
# @param pin [Pin::
|
84
|
+
# @param pin [Pin::Method]
|
85
85
|
# @return [Array<Problem>]
|
86
86
|
def method_return_type_problems_for pin
|
87
87
|
result = []
|
@@ -115,7 +115,7 @@ module Solargraph
|
|
115
115
|
pin.location && source_map.source.comment_at?(pin.location.range.ending)
|
116
116
|
end
|
117
117
|
|
118
|
-
# @param pin [Pin::
|
118
|
+
# @param pin [Pin::Method]
|
119
119
|
# @return [Array<Problem>]
|
120
120
|
def method_param_type_problems_for pin
|
121
121
|
stack = api_map.get_method_stack(pin.namespace, pin.name, scope: pin.scope)
|
@@ -147,14 +147,12 @@ module Solargraph
|
|
147
147
|
result = []
|
148
148
|
all_variables.each do |pin|
|
149
149
|
if pin.return_type.defined?
|
150
|
-
# @todo Somwhere in here we still need to determine if the variable is defined by an external call
|
151
150
|
declared = pin.typify(api_map)
|
152
151
|
if declared.defined?
|
153
152
|
if rules.validate_tags?
|
154
153
|
inferred = pin.probe(api_map)
|
155
154
|
if inferred.undefined?
|
156
155
|
next if rules.ignore_all_undefined?
|
157
|
-
# next unless internal?(pin) # @todo This might be redundant for variables
|
158
156
|
if declared_externally?(pin)
|
159
157
|
ignored_pins.push pin
|
160
158
|
else
|
@@ -172,7 +170,6 @@ module Solargraph
|
|
172
170
|
result.push Problem.new(pin.location, "Unresolved type #{pin.return_type} for variable #{pin.name}", pin: pin)
|
173
171
|
end
|
174
172
|
else
|
175
|
-
# @todo Check if the variable is defined by an external call
|
176
173
|
inferred = pin.probe(api_map)
|
177
174
|
if inferred.undefined? && declared_externally?(pin)
|
178
175
|
ignored_pins.push pin
|
@@ -227,7 +224,7 @@ module Solargraph
|
|
227
224
|
base = base.base
|
228
225
|
end
|
229
226
|
closest = found.typify(api_map) if found
|
230
|
-
if !found || closest.defined?
|
227
|
+
if !found || (closest.defined? && internal_or_core?(found))
|
231
228
|
unless ignored_pins.include?(found)
|
232
229
|
result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
|
233
230
|
@marked_ranges.push rng
|
@@ -244,8 +241,8 @@ module Solargraph
|
|
244
241
|
base = chain
|
245
242
|
until base.links.length == 1 && base.undefined?
|
246
243
|
pins = base.define(api_map, block_pin, locals)
|
247
|
-
if pins.first.is_a?(Pin::
|
248
|
-
# @type [Pin::
|
244
|
+
if pins.first.is_a?(Pin::Method)
|
245
|
+
# @type [Pin::Method]
|
249
246
|
pin = pins.first
|
250
247
|
ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
|
251
248
|
arity_problems_for(pin, fake_args_for(block_pin), location)
|
@@ -313,7 +310,6 @@ module Solargraph
|
|
313
310
|
end
|
314
311
|
else
|
315
312
|
if par.decl == :kwarg
|
316
|
-
# @todo Problem: missing required keyword argument
|
317
313
|
result.push Problem.new(location, "Call to #{pin.path} is missing keyword argument #{par.name}")
|
318
314
|
end
|
319
315
|
end
|
@@ -360,9 +356,14 @@ module Solargraph
|
|
360
356
|
|
361
357
|
# @param pin [Pin::Base]
|
362
358
|
def internal? pin
|
359
|
+
return false if pin.nil?
|
363
360
|
pin.location && api_map.bundled?(pin.location.filename)
|
364
361
|
end
|
365
362
|
|
363
|
+
def internal_or_core? pin
|
364
|
+
internal?(pin) || api_map.yard_map.core_pins.include?(pin) || api_map.yard_map.stdlib_pins.include?(pin)
|
365
|
+
end
|
366
|
+
|
366
367
|
# @param pin [Pin::Base]
|
367
368
|
def external? pin
|
368
369
|
!internal? pin
|
@@ -395,7 +396,7 @@ module Solargraph
|
|
395
396
|
true
|
396
397
|
end
|
397
398
|
|
398
|
-
# @param pin [Pin::
|
399
|
+
# @param pin [Pin::Method]
|
399
400
|
def arity_problems_for(pin, arguments, location)
|
400
401
|
return [] unless pin.explicit?
|
401
402
|
return [] if pin.parameters.empty? && arguments.empty?
|
@@ -410,29 +411,29 @@ module Solargraph
|
|
410
411
|
if unchecked.empty? && pin.parameters.any? { |param| param.decl == :kwarg }
|
411
412
|
return [Problem.new(location, "Missing keyword arguments to #{pin.path}")]
|
412
413
|
end
|
414
|
+
settled_kwargs = 0
|
413
415
|
unless unchecked.empty?
|
414
416
|
kwargs = convert_hash(unchecked.last.node)
|
415
|
-
|
416
|
-
if
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
end
|
428
|
-
end
|
429
|
-
kwargs.clear if pin.parameters.any?(&:kwrestarg?)
|
430
|
-
unless kwargs.empty?
|
431
|
-
return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
|
417
|
+
if pin.parameters.any? { |param| [:kwarg, :kwoptarg].include?(param.decl) || param.kwrestarg? }
|
418
|
+
if kwargs.empty?
|
419
|
+
add_params += 1
|
420
|
+
else
|
421
|
+
unchecked.pop
|
422
|
+
pin.parameters.each do |param|
|
423
|
+
next unless param.keyword?
|
424
|
+
if kwargs.key?(param.name.to_sym)
|
425
|
+
kwargs.delete param.name.to_sym
|
426
|
+
settled_kwargs += 1
|
427
|
+
elsif param.decl == :kwarg
|
428
|
+
return [Problem.new(location, "Missing keyword argument #{param.name} to #{pin.path}")]
|
432
429
|
end
|
433
430
|
end
|
431
|
+
kwargs.clear if pin.parameters.any?(&:kwrestarg?)
|
432
|
+
unless kwargs.empty?
|
433
|
+
return [Problem.new(location, "Unrecognized keyword argument #{kwargs.keys.first} to #{pin.path}")]
|
434
|
+
end
|
434
435
|
end
|
435
|
-
|
436
|
+
end
|
436
437
|
end
|
437
438
|
req = required_param_count(pin)
|
438
439
|
if req + add_params < unchecked.length
|
@@ -443,23 +444,18 @@ module Solargraph
|
|
443
444
|
return []
|
444
445
|
end
|
445
446
|
return [Problem.new(location, "Too many arguments to #{pin.path}")]
|
446
|
-
elsif unchecked.length < req && (arguments.empty? || !arguments.last.splat?)
|
447
|
+
elsif unchecked.length < req - settled_kwargs && (arguments.empty? || !arguments.last.splat?)
|
447
448
|
return [Problem.new(location, "Not enough arguments to #{pin.path}")]
|
448
449
|
end
|
449
450
|
[]
|
450
451
|
end
|
451
452
|
|
452
|
-
# @param pin [Pin::
|
453
|
+
# @param pin [Pin::Method]
|
453
454
|
def required_param_count(pin)
|
454
|
-
|
455
|
-
pin.parameters.each do |param|
|
456
|
-
break unless param.decl == :arg
|
457
|
-
count += 1
|
458
|
-
end
|
459
|
-
count
|
455
|
+
pin.parameters.sum { |param| %i[arg kwarg].include?(param.decl) ? 1 : 0 }
|
460
456
|
end
|
461
457
|
|
462
|
-
# @param pin [Pin::
|
458
|
+
# @param pin [Pin::Method]
|
463
459
|
def optional_param_count(pin)
|
464
460
|
count = 0
|
465
461
|
pin.parameters.each do |param|
|