solargraph 0.39.17 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -7
- data/CHANGELOG.md +984 -0
- data/SPONSORS.md +1 -0
- data/lib/solargraph.rb +2 -4
- data/lib/solargraph/api_map.rb +61 -64
- data/lib/solargraph/api_map/cache.rb +2 -2
- data/lib/solargraph/api_map/store.rb +3 -7
- data/lib/solargraph/{bundle.rb → bench.rb} +6 -2
- data/lib/solargraph/compat.rb +14 -0
- 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/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/library.rb +5 -5
- data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +1 -1
- data/lib/solargraph/parser/legacy/node_processors/send_node.rb +34 -22
- data/lib/solargraph/parser/node_processor/base.rb +3 -0
- 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 +38 -28
- data/lib/solargraph/pin.rb +0 -3
- data/lib/solargraph/pin/common.rb +1 -1
- data/lib/solargraph/pin/conversions.rb +1 -1
- 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/source.rb +10 -6
- data/lib/solargraph/source/chain.rb +3 -3
- 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 +38 -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 +11 -5
- 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/{pin/yard_pin/method.rb → yard_map/to_method.rb} +29 -30
- data/solargraph.gemspec +4 -4
- metadata +20 -34
- data/lib/solargraph/core_fills.rb +0 -164
- data/lib/solargraph/pin/attribute.rb +0 -49
- data/lib/solargraph/pin/base_method.rb +0 -149
- data/lib/solargraph/pin/yard_pin.rb +0 -12
- 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
data/lib/solargraph/pin.rb
CHANGED
@@ -9,10 +9,8 @@ module Solargraph
|
|
9
9
|
autoload :Common, 'solargraph/pin/common'
|
10
10
|
autoload :Conversions, 'solargraph/pin/conversions'
|
11
11
|
autoload :Base, 'solargraph/pin/base'
|
12
|
-
autoload :BaseMethod, 'solargraph/pin/base_method'
|
13
12
|
autoload :Method, 'solargraph/pin/method'
|
14
13
|
autoload :MethodAlias, 'solargraph/pin/method_alias'
|
15
|
-
autoload :Attribute, 'solargraph/pin/attribute'
|
16
14
|
autoload :BaseVariable, 'solargraph/pin/base_variable'
|
17
15
|
autoload :InstanceVariable, 'solargraph/pin/instance_variable'
|
18
16
|
autoload :ClassVariable, 'solargraph/pin/class_variable'
|
@@ -30,7 +28,6 @@ module Solargraph
|
|
30
28
|
autoload :Localized, 'solargraph/pin/localized'
|
31
29
|
autoload :ProxyType, 'solargraph/pin/proxy_type'
|
32
30
|
autoload :DuckMethod, 'solargraph/pin/duck_method'
|
33
|
-
autoload :YardPin, 'solargraph/pin/yard_pin'
|
34
31
|
autoload :Singleton, 'solargraph/pin/singleton'
|
35
32
|
autoload :KeywordParam, 'solargraph/pin/keyword_param'
|
36
33
|
|
@@ -54,7 +54,7 @@ module Solargraph
|
|
54
54
|
until here.nil?
|
55
55
|
if here.is_a?(Pin::Namespace)
|
56
56
|
return here.return_type
|
57
|
-
elsif here.is_a?(Pin::
|
57
|
+
elsif here.is_a?(Pin::Method)
|
58
58
|
if here.scope == :instance
|
59
59
|
return ComplexType.try_parse(here.context.namespace)
|
60
60
|
else
|
@@ -47,7 +47,7 @@ module Solargraph
|
|
47
47
|
# This property is not cached in an instance variable because it can
|
48
48
|
# change when pins get proxied.
|
49
49
|
detail = String.new
|
50
|
-
detail += "(#{parameters.map(&:full).join(', ')}) " unless !is_a?(Pin::
|
50
|
+
detail += "(#{parameters.map(&:full).join(', ')}) " unless !is_a?(Pin::Method) || parameters.empty?
|
51
51
|
detail += "=#{probed? ? '~' : (proxied? ? '^' : '>')} #{return_type.to_s}" unless return_type.undefined?
|
52
52
|
detail.strip!
|
53
53
|
return nil if detail.empty?
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'kramdown'
|
4
|
+
require 'kramdown-parser-gfm'
|
4
5
|
require 'yard'
|
5
6
|
require 'reverse_markdown'
|
6
7
|
require 'solargraph/converters/dl'
|
@@ -8,9 +9,6 @@ require 'solargraph/converters/dt'
|
|
8
9
|
require 'solargraph/converters/dd'
|
9
10
|
require 'solargraph/converters/misc'
|
10
11
|
|
11
|
-
# HACK: Setting :html_parser through `Maruku.new` does not work
|
12
|
-
MaRuKu::Globals[:html_parser] = 'nokogiri'
|
13
|
-
|
14
12
|
module Solargraph
|
15
13
|
module Pin
|
16
14
|
# A module to add the Pin::Base#documentation method.
|
@@ -41,11 +39,7 @@ module Solargraph
|
|
41
39
|
|
42
40
|
def to_s
|
43
41
|
return "\n```ruby\n#{@plaintext}#{@plaintext.end_with?("\n") ? '' : "\n"}```\n\n" if code?
|
44
|
-
ReverseMarkdown.convert unescape_brackets(
|
45
|
-
rescue MaRuKu::Exception
|
46
|
-
# Maruku exceptions usually indicate that the documentation is in
|
47
|
-
# RDoc syntax.
|
48
|
-
ReverseMarkdown.convert YARD::Templates::Helpers::Markup::RDocMarkup.new(@plaintext).to_html
|
42
|
+
ReverseMarkdown.convert unescape_brackets(Kramdown::Document.new(escape_brackets(@plaintext), input: 'GFM').to_html)
|
49
43
|
end
|
50
44
|
|
51
45
|
private
|
@@ -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/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
|
|
@@ -119,12 +119,12 @@ module Solargraph
|
|
119
119
|
@@inference_stack.pop
|
120
120
|
if type.defined?
|
121
121
|
possibles.push type
|
122
|
-
break if pin.is_a?(Pin::
|
122
|
+
break if pin.is_a?(Pin::Method)
|
123
123
|
end
|
124
124
|
end
|
125
125
|
if possibles.empty?
|
126
126
|
# Limit method inference recursion
|
127
|
-
return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::
|
127
|
+
return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
|
128
128
|
@@inference_depth += 1
|
129
129
|
pins.each do |pin|
|
130
130
|
# Avoid infinite recursion
|
@@ -134,7 +134,7 @@ module Solargraph
|
|
134
134
|
@@inference_stack.pop
|
135
135
|
if type.defined?
|
136
136
|
possibles.push type
|
137
|
-
break if pin.is_a?(Pin::
|
137
|
+
break if pin.is_a?(Pin::Method)
|
138
138
|
end
|
139
139
|
end
|
140
140
|
@@inference_depth -= 1
|
@@ -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|
|