solargraph 0.29.4 → 0.29.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/solargraph/api_map.rb +5 -2
- data/lib/solargraph/api_map/source_to_yard.rb +32 -29
- data/lib/solargraph/api_map/store.rb +4 -6
- data/lib/solargraph/complex_type/type_methods.rb +5 -1
- data/lib/solargraph/diagnostics/type_not_defined.rb +1 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +64 -32
- data/lib/solargraph/library.rb +28 -28
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/pin/attribute.rb +1 -31
- data/lib/solargraph/pin/base.rb +38 -17
- data/lib/solargraph/pin/base_method.rb +64 -0
- data/lib/solargraph/pin/base_variable.rb +2 -4
- data/lib/solargraph/pin/block.rb +1 -3
- data/lib/solargraph/pin/block_parameter.rb +4 -3
- data/lib/solargraph/pin/keyword.rb +0 -4
- data/lib/solargraph/pin/localized.rb +2 -1
- data/lib/solargraph/pin/method.rb +24 -59
- data/lib/solargraph/pin/namespace.rb +1 -2
- data/lib/solargraph/range.rb +4 -2
- data/lib/solargraph/source.rb +18 -0
- data/lib/solargraph/source/chain.rb +5 -2
- data/lib/solargraph/source/chain/call.rb +3 -1
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/node_chainer.rb +2 -0
- data/lib/solargraph/source/node_methods.rb +15 -0
- data/lib/solargraph/source/source_chainer.rb +0 -22
- data/lib/solargraph/source_map.rb +11 -3
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +3 -3
- metadata +10 -9
data/lib/solargraph/pin.rb
CHANGED
@@ -4,6 +4,7 @@ module Solargraph
|
|
4
4
|
module Pin
|
5
5
|
autoload :Conversions, 'solargraph/pin/conversions'
|
6
6
|
autoload :Base, 'solargraph/pin/base'
|
7
|
+
autoload :BaseMethod, 'solargraph/pin/base_method'
|
7
8
|
autoload :Method, 'solargraph/pin/method'
|
8
9
|
autoload :MethodAlias, 'solargraph/pin/method_alias'
|
9
10
|
autoload :Attribute, 'solargraph/pin/attribute'
|
@@ -1,15 +1,9 @@
|
|
1
1
|
module Solargraph
|
2
2
|
module Pin
|
3
|
-
class Attribute <
|
3
|
+
class Attribute < BaseMethod
|
4
4
|
# @return [Symbol] :reader or :writer
|
5
5
|
attr_reader :access
|
6
6
|
|
7
|
-
# @return [Symbol] :class or :instance
|
8
|
-
attr_reader :scope
|
9
|
-
|
10
|
-
# @return [Symbol] :public, :protected, or :private
|
11
|
-
attr_reader :visibility
|
12
|
-
|
13
7
|
def initialize location, namespace, name, comments, access, scope, visibility
|
14
8
|
super(location, namespace, name, comments)
|
15
9
|
@access = access
|
@@ -33,10 +27,6 @@ module Solargraph
|
|
33
27
|
@path ||= namespace + (scope == :instance ? '#' : '.') + name
|
34
28
|
end
|
35
29
|
|
36
|
-
def return_complex_type
|
37
|
-
@return_complex_type ||= generate_complex_type
|
38
|
-
end
|
39
|
-
|
40
30
|
def parameters
|
41
31
|
# Since attributes are generally equivalent to methods, treat
|
42
32
|
# them as methods without parameters
|
@@ -46,26 +36,6 @@ module Solargraph
|
|
46
36
|
def parameter_names
|
47
37
|
[]
|
48
38
|
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# @todo DRY this method. It also exists in Pin::Method.
|
53
|
-
#
|
54
|
-
# @return [ComplexType]
|
55
|
-
def generate_complex_type
|
56
|
-
tag = docstring.tag(:return)
|
57
|
-
if tag.nil?
|
58
|
-
ol = docstring.tag(:overload)
|
59
|
-
tag = ol.tag(:return) unless ol.nil?
|
60
|
-
end
|
61
|
-
return ComplexType::UNDEFINED if tag.nil? or tag.types.nil? or tag.types.empty?
|
62
|
-
begin
|
63
|
-
ComplexType.parse *tag.types
|
64
|
-
rescue Solargraph::ComplexTypeError => e
|
65
|
-
STDERR.puts e.message
|
66
|
-
ComplexType::UNDEFINED
|
67
|
-
end
|
68
|
-
end
|
69
39
|
end
|
70
40
|
end
|
71
41
|
end
|
data/lib/solargraph/pin/base.rb
CHANGED
@@ -85,14 +85,12 @@ module Solargraph
|
|
85
85
|
# @param other [Solargraph::Pin::Base, Object]
|
86
86
|
# @return [Boolean]
|
87
87
|
def nearly? other
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
( ((maybe_directives? == false and other.maybe_directives? == false) or compare_directives(directives, other.directives)) and
|
95
|
-
compare_docstring_tags(docstring, other.docstring) )
|
88
|
+
self.class == other.class &&
|
89
|
+
namespace == other.namespace &&
|
90
|
+
name == other.name &&
|
91
|
+
(comments == other.comments ||
|
92
|
+
(((maybe_directives? == false && other.maybe_directives? == false) || compare_directives(directives, other.directives)) &&
|
93
|
+
compare_docstring_tags(docstring, other.docstring))
|
96
94
|
)
|
97
95
|
end
|
98
96
|
|
@@ -145,12 +143,36 @@ module Solargraph
|
|
145
143
|
@deprecated ||= docstring.has_tag?('deprecated')
|
146
144
|
end
|
147
145
|
|
146
|
+
# Get a fully qualified type from the pin's return type.
|
147
|
+
#
|
148
|
+
# The relative type is determined from YARD documentation (@return,
|
149
|
+
# @param, @type, etc.) and its namespaces are fully qualified using the
|
150
|
+
# provided ApiMap.
|
151
|
+
#
|
148
152
|
# @param api_map [ApiMap]
|
149
153
|
# @return [ComplexType]
|
150
|
-
def
|
154
|
+
def typify api_map
|
151
155
|
return_complex_type.qualify(api_map, namespace)
|
152
156
|
end
|
153
157
|
|
158
|
+
# Infer the pin's return type via static code analysis.
|
159
|
+
#
|
160
|
+
# @param api_map [ApiMap]
|
161
|
+
# @return [ComplexType]
|
162
|
+
def probe api_map
|
163
|
+
typify api_map
|
164
|
+
end
|
165
|
+
|
166
|
+
# @deprecated Use #typify and/or #probe instead
|
167
|
+
# @param api_map [ApiMap]
|
168
|
+
# @return [ComplexType]
|
169
|
+
def infer api_map
|
170
|
+
STDERR.puts "WARNING: Pin #infer methods are deprecated. Use #typify or #probe instead."
|
171
|
+
type = typify(api_map)
|
172
|
+
return type unless type.undefined?
|
173
|
+
probe api_map
|
174
|
+
end
|
175
|
+
|
154
176
|
# Try to merge data from another pin. Merges are only possible if the
|
155
177
|
# pins are near matches (see the #nearly? method). The changes should
|
156
178
|
# not have any side effects on the API surface.
|
@@ -160,14 +182,13 @@ module Solargraph
|
|
160
182
|
def try_merge! pin
|
161
183
|
return false unless nearly?(pin)
|
162
184
|
@location = pin.location
|
163
|
-
if comments
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
185
|
+
return true if comments == pin.comments
|
186
|
+
@comments = pin.comments
|
187
|
+
@docstring = pin.docstring
|
188
|
+
@return_complex_type = pin.return_complex_type
|
189
|
+
@documentation = nil
|
190
|
+
@deprecated = nil
|
191
|
+
reset_conversions
|
171
192
|
true
|
172
193
|
end
|
173
194
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Pin
|
3
|
+
# The base class for method and attribute pins.
|
4
|
+
#
|
5
|
+
class BaseMethod < Base
|
6
|
+
# @return [Symbol] :instance or :class
|
7
|
+
attr_reader :scope
|
8
|
+
|
9
|
+
# @return [Symbol] :public, :private, or :protected
|
10
|
+
attr_reader :visibility
|
11
|
+
|
12
|
+
def return_complex_type
|
13
|
+
@return_complex_type ||= generate_complex_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def typify api_map
|
17
|
+
decl = super
|
18
|
+
return decl unless decl.undefined?
|
19
|
+
type = see_reference(api_map)
|
20
|
+
return type unless type.nil?
|
21
|
+
ComplexType::UNDEFINED
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# @return [ComplexType]
|
27
|
+
def generate_complex_type
|
28
|
+
tag = docstring.tag(:return)
|
29
|
+
if tag.nil?
|
30
|
+
ol = docstring.tag(:overload)
|
31
|
+
tag = ol.tag(:return) unless ol.nil?
|
32
|
+
end
|
33
|
+
return ComplexType::UNDEFINED if tag.nil? or tag.types.nil? or tag.types.empty?
|
34
|
+
begin
|
35
|
+
ComplexType.parse *tag.types
|
36
|
+
rescue Solargraph::ComplexTypeError => e
|
37
|
+
STDERR.puts e.message
|
38
|
+
ComplexType::UNDEFINED
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [ApiMap]
|
43
|
+
def see_reference api_map
|
44
|
+
docstring.ref_tags.each do |ref|
|
45
|
+
next unless ref.tag_name == 'return' && ref.owner
|
46
|
+
parts = ref.owner.to_s.split(/[\.#]/)
|
47
|
+
if parts.first.empty?
|
48
|
+
path = "#{namespace}#{ref.owner.to_s}"
|
49
|
+
else
|
50
|
+
fqns = api_map.qualify(parts.first, namespace)
|
51
|
+
return ComplexType::UNDEFINED if fqns.nil?
|
52
|
+
path = fqns + ref.owner.to_s[parts.first.length] + parts.last
|
53
|
+
end
|
54
|
+
pins = api_map.get_path_pins(path)
|
55
|
+
pins.each do |pin|
|
56
|
+
type = pin.typify(api_map)
|
57
|
+
return type unless type.undefined?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -39,10 +39,8 @@ module Solargraph
|
|
39
39
|
true
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
result = super
|
45
|
-
return result if result.defined? or @assignment.nil?
|
42
|
+
def probe api_map
|
43
|
+
return ComplexType::UNDEFINED if @assignment.nil?
|
46
44
|
chain = Source::NodeChainer.chain(@assignment, filename)
|
47
45
|
clip = api_map.clip_at(location.filename, location.range.start)
|
48
46
|
locals = clip.locals - [self]
|
data/lib/solargraph/pin/block.rb
CHANGED
@@ -6,9 +6,6 @@ module Solargraph
|
|
6
6
|
# @return [Parser::AST::Node]
|
7
7
|
attr_reader :receiver
|
8
8
|
|
9
|
-
# @return [Array<String>]
|
10
|
-
attr_reader :parameters
|
11
|
-
|
12
9
|
def initialize location, namespace, name, comments, receiver, context
|
13
10
|
super(location, namespace, name, comments)
|
14
11
|
@receiver = receiver
|
@@ -19,6 +16,7 @@ module Solargraph
|
|
19
16
|
Pin::BLOCK
|
20
17
|
end
|
21
18
|
|
19
|
+
# @return [Array<String>]
|
22
20
|
def parameters
|
23
21
|
@parameters ||= []
|
24
22
|
end
|
@@ -71,9 +71,10 @@ module Solargraph
|
|
71
71
|
block
|
72
72
|
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
def typify api_map
|
75
|
+
# @todo Does anything need to be eliminated because it's more accurately a probe?
|
76
|
+
type = super
|
77
|
+
return type unless type.undefined?
|
77
78
|
chain = Source::NodeChainer.chain(block.receiver, filename)
|
78
79
|
clip = api_map.clip_at(location.filename, location.range.start)
|
79
80
|
locals = clip.locals - [self]
|
@@ -7,9 +7,10 @@ module Solargraph
|
|
7
7
|
attr_reader :presence
|
8
8
|
|
9
9
|
# @param other [Pin::Base] The caller's block
|
10
|
-
# @param position [Position] The caller's position
|
10
|
+
# @param position [Position, Array(Integer, Integer)] The caller's position
|
11
11
|
# @return [Boolean]
|
12
12
|
def visible_from?(other, position)
|
13
|
+
position = Position.normalize(position)
|
13
14
|
other.filename == filename and
|
14
15
|
( other == block or
|
15
16
|
(block.location.range.contain?(other.location.range.start) and block.location.range.contain?(other.location.range.ending))
|
@@ -1,14 +1,8 @@
|
|
1
1
|
module Solargraph
|
2
2
|
module Pin
|
3
|
-
class Method <
|
3
|
+
class Method < BaseMethod
|
4
4
|
include Source::NodeMethods
|
5
5
|
|
6
|
-
# @return [Symbol] :instance or :class
|
7
|
-
attr_reader :scope
|
8
|
-
|
9
|
-
# @return [Symbol] :public, :private, or :protected
|
10
|
-
attr_reader :visibility
|
11
|
-
|
12
6
|
# @return [Array<String>]
|
13
7
|
attr_reader :parameters
|
14
8
|
|
@@ -51,15 +45,10 @@ module Solargraph
|
|
51
45
|
Solargraph::LanguageServer::CompletionItemKinds::METHOD
|
52
46
|
end
|
53
47
|
|
54
|
-
# @return [Integer]
|
55
48
|
def symbol_kind
|
56
49
|
LanguageServer::SymbolKinds::METHOD
|
57
50
|
end
|
58
51
|
|
59
|
-
def return_complex_type
|
60
|
-
@return_complex_type ||= generate_complex_type
|
61
|
-
end
|
62
|
-
|
63
52
|
def documentation
|
64
53
|
if @documentation.nil?
|
65
54
|
@documentation ||= super || ''
|
@@ -87,14 +76,18 @@ module Solargraph
|
|
87
76
|
visibility == other.visibility
|
88
77
|
end
|
89
78
|
|
90
|
-
def
|
91
|
-
decl = super
|
92
|
-
return decl unless decl.undefined?
|
93
|
-
type = see_reference(api_map)
|
94
|
-
return type unless type.nil?
|
79
|
+
def probe api_map
|
95
80
|
infer_from_return_nodes(api_map)
|
96
81
|
end
|
97
82
|
|
83
|
+
# @deprecated Use #typify and/or #probe instead
|
84
|
+
def infer api_map
|
85
|
+
STDERR.puts 'WARNING: Pin #infer methods are deprecated. Use #typify or #probe instead.'
|
86
|
+
type = typify(api_map)
|
87
|
+
return type unless type.undefined?
|
88
|
+
probe api_map
|
89
|
+
end
|
90
|
+
|
98
91
|
def try_merge! pin
|
99
92
|
return false unless super
|
100
93
|
@node = pin.node
|
@@ -103,59 +96,31 @@ module Solargraph
|
|
103
96
|
|
104
97
|
private
|
105
98
|
|
106
|
-
# @return [
|
107
|
-
def
|
108
|
-
|
109
|
-
if
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
return ComplexType::UNDEFINED if tag.nil? or tag.types.nil? or tag.types.empty?
|
114
|
-
begin
|
115
|
-
ComplexType.parse *tag.types
|
116
|
-
rescue Solargraph::ComplexTypeError => e
|
117
|
-
STDERR.puts e.message
|
118
|
-
ComplexType::UNDEFINED
|
119
|
-
end
|
99
|
+
# @return [Parser::AST:Node, nil]
|
100
|
+
def method_body_node
|
101
|
+
return nil if node.nil?
|
102
|
+
return node.children[2] if node.type == :def
|
103
|
+
return node.children[3] if node.type == :defs
|
104
|
+
nil
|
120
105
|
end
|
121
106
|
|
122
107
|
# @param api_map [ApiMap]
|
108
|
+
# @return [ComplexType]
|
123
109
|
def infer_from_return_nodes api_map
|
124
|
-
return ComplexType::UNDEFINED if node.nil? ||
|
125
|
-
(node.type == :def && node.children[2].nil?) ||
|
126
|
-
(node.type == :defs && node.children[3].nil?)
|
127
110
|
result = []
|
128
|
-
|
129
|
-
nodes.each do |n|
|
111
|
+
returns_from(method_body_node).each do |n|
|
130
112
|
next if n.loc.nil?
|
131
|
-
clip = api_map.clip_at(
|
132
|
-
|
113
|
+
clip = api_map.clip_at(
|
114
|
+
location.filename,
|
115
|
+
[n.loc.expression.last_line, n.loc.expression.last_column]
|
116
|
+
)
|
117
|
+
chain = Solargraph::Source::NodeChainer.chain(n, location.filename)
|
118
|
+
type = chain.infer(api_map, self, clip.locals)
|
133
119
|
result.push type unless type.undefined?
|
134
120
|
end
|
135
121
|
return ComplexType::UNDEFINED if result.empty?
|
136
122
|
ComplexType.parse(*result.map(&:tag))
|
137
123
|
end
|
138
|
-
|
139
|
-
# @param [ApiMap]
|
140
|
-
def see_reference api_map
|
141
|
-
docstring.ref_tags.each do |ref|
|
142
|
-
next unless ref.tag_name == 'return' && ref.owner
|
143
|
-
parts = ref.owner.to_s.split(/[\.#]/)
|
144
|
-
if parts.first.empty?
|
145
|
-
path = "#{namespace}#{ref.owner.to_s}"
|
146
|
-
else
|
147
|
-
fqns = api_map.qualify(parts.first, namespace)
|
148
|
-
return ComplexType::UNDEFINED if fqns.nil?
|
149
|
-
path = fqns + ref.owner.to_s[parts.first.length] + parts.last
|
150
|
-
end
|
151
|
-
pins = api_map.get_path_pins(path)
|
152
|
-
pins.each do |pin|
|
153
|
-
type = pin.infer(api_map)
|
154
|
-
return type unless type.undefined?
|
155
|
-
end
|
156
|
-
end
|
157
|
-
nil
|
158
|
-
end
|
159
124
|
end
|
160
125
|
end
|
161
126
|
end
|
data/lib/solargraph/range.rb
CHANGED
@@ -28,9 +28,10 @@ module Solargraph
|
|
28
28
|
|
29
29
|
# True if the specified position is inside the range.
|
30
30
|
#
|
31
|
-
# @param position [
|
31
|
+
# @param position [Position, Array(Integer, Integer)]
|
32
32
|
# @return [Boolean]
|
33
33
|
def contain? position
|
34
|
+
position = Position.normalize(position)
|
34
35
|
return false if position.line < start.line || position.line > ending.line
|
35
36
|
return false if position.line == start.line && position.character < start.character
|
36
37
|
return false if position.line == ending.line && position.character > ending.character
|
@@ -39,9 +40,10 @@ module Solargraph
|
|
39
40
|
|
40
41
|
# True if the range contains the specified position and the position does not precede it.
|
41
42
|
#
|
42
|
-
# @param position [Position]
|
43
|
+
# @param position [Position, Array(Integer, Integer)]
|
43
44
|
# @return [Boolean]
|
44
45
|
def include? position
|
46
|
+
position = Position.normalize(position)
|
45
47
|
contain?(position) && !(position.line == start.line && position.character == start.character)
|
46
48
|
end
|
47
49
|
|
data/lib/solargraph/source.rb
CHANGED
@@ -24,6 +24,7 @@ module Solargraph
|
|
24
24
|
# @return [Parser::AST::Node]
|
25
25
|
attr_reader :node
|
26
26
|
|
27
|
+
# @return [Array<Parser::Source::Comment>]
|
27
28
|
attr_reader :comments
|
28
29
|
|
29
30
|
# @return [String]
|
@@ -194,6 +195,9 @@ module Solargraph
|
|
194
195
|
arr ? stringify_comment_array(arr) : nil
|
195
196
|
end
|
196
197
|
|
198
|
+
# A location representing the file in its entirety.
|
199
|
+
#
|
200
|
+
# @return [Location]
|
197
201
|
def location
|
198
202
|
st = Position.new(0, 0)
|
199
203
|
en = Position.from_offset(code, code.length)
|
@@ -203,6 +207,9 @@ module Solargraph
|
|
203
207
|
|
204
208
|
private
|
205
209
|
|
210
|
+
# Get a hash of comments grouped by the line numbers of the associated code.
|
211
|
+
#
|
212
|
+
# @return [Hash{Integer => Array<Parser::Source::Comment>}]
|
206
213
|
def associated_comments
|
207
214
|
@associated_comments ||= begin
|
208
215
|
result = {}
|
@@ -216,6 +223,10 @@ module Solargraph
|
|
216
223
|
end
|
217
224
|
end
|
218
225
|
|
226
|
+
# Get a string representation of an array of comments.
|
227
|
+
#
|
228
|
+
# @param comments [Array<Parser::Source::Comment>]
|
229
|
+
# @return [String]
|
219
230
|
def stringify_comment_array comments
|
220
231
|
ctxt = ''
|
221
232
|
num = nil
|
@@ -309,17 +320,24 @@ module Solargraph
|
|
309
320
|
|
310
321
|
# @param code [String]
|
311
322
|
# @param filename [String]
|
323
|
+
# @param version [Integer]
|
312
324
|
# @return [Solargraph::Source]
|
313
325
|
def load_string code, filename = nil, version = 0
|
314
326
|
Source.new code, filename, version
|
315
327
|
end
|
316
328
|
|
329
|
+
# @param code [String]
|
330
|
+
# @param filename [String]
|
331
|
+
# @return [Array(Parser::AST::Node, Array<Parser::Source::Comment>)]
|
317
332
|
def parse_with_comments code, filename = nil
|
318
333
|
buffer = Parser::Source::Buffer.new(filename, 0)
|
319
334
|
buffer.source = code.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '_')
|
320
335
|
parser.parse_with_comments(buffer)
|
321
336
|
end
|
322
337
|
|
338
|
+
# @param code [String]
|
339
|
+
# @param filename [String]
|
340
|
+
# @return [Parser::AST::Node]
|
323
341
|
def parse code, filename = nil
|
324
342
|
buffer = Parser::Source::Buffer.new(filename, 0)
|
325
343
|
buffer.source = code.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '_')
|