solargraph 0.25.1 → 0.26.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/lib/solargraph.rb +18 -16
- data/lib/solargraph/api_map.rb +100 -161
- data/lib/solargraph/api_map/source_to_yard.rb +9 -9
- data/lib/solargraph/api_map/store.rb +50 -13
- data/lib/solargraph/basic_type.rb +33 -0
- data/lib/solargraph/basic_type_methods.rb +111 -0
- data/lib/solargraph/complex_type.rb +51 -89
- data/lib/solargraph/core_fills.rb +12 -8
- data/lib/solargraph/diagnostics/type_not_defined.rb +2 -2
- data/lib/solargraph/language_server.rb +3 -0
- data/lib/solargraph/language_server/completion_item_kinds.rb +2 -0
- data/lib/solargraph/language_server/error_codes.rb +2 -0
- data/lib/solargraph/language_server/host.rb +53 -6
- data/lib/solargraph/language_server/message.rb +13 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +4 -6
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -1
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -1
- data/lib/solargraph/language_server/message_types.rb +2 -0
- data/lib/solargraph/language_server/request.rb +4 -0
- data/lib/solargraph/language_server/symbol_kinds.rb +28 -26
- data/lib/solargraph/language_server/transport.rb +3 -0
- data/lib/solargraph/language_server/uri_helpers.rb +2 -0
- data/lib/solargraph/library.rb +12 -7
- data/lib/solargraph/pin.rb +1 -1
- data/lib/solargraph/pin/attribute.rb +5 -5
- data/lib/solargraph/pin/base.rb +51 -16
- data/lib/solargraph/pin/base_variable.rb +25 -7
- data/lib/solargraph/pin/block.rb +18 -1
- data/lib/solargraph/pin/block_parameter.rb +42 -5
- data/lib/solargraph/pin/conversions.rb +4 -2
- data/lib/solargraph/pin/method.rb +6 -6
- data/lib/solargraph/pin/method_parameter.rb +6 -6
- data/lib/solargraph/pin/namespace.rb +7 -2
- data/lib/solargraph/pin/proxy_type.rb +39 -0
- data/lib/solargraph/pin/symbol.rb +20 -12
- data/lib/solargraph/pin/yard_pin/method.rb +2 -2
- data/lib/solargraph/source.rb +89 -38
- data/lib/solargraph/source/call_chainer.rb +273 -0
- data/lib/solargraph/source/chain.rb +104 -0
- data/lib/solargraph/source/chain/call.rb +72 -0
- data/lib/solargraph/source/chain/class_variable.rb +11 -0
- data/lib/solargraph/source/chain/constant.rb +17 -0
- data/lib/solargraph/source/chain/definition.rb +16 -0
- data/lib/solargraph/source/chain/global_variable.rb +11 -0
- data/lib/solargraph/source/chain/head.rb +20 -0
- data/lib/solargraph/source/chain/instance_variable.rb +11 -0
- data/lib/solargraph/source/chain/link.rb +33 -0
- data/lib/solargraph/source/chain/literal.rb +21 -0
- data/lib/solargraph/source/chain/variable.rb +11 -0
- data/lib/solargraph/source/change.rb +3 -1
- data/lib/solargraph/{api_map → source}/completion.rb +3 -1
- data/lib/solargraph/source/encoding_fixes.rb +21 -0
- data/lib/solargraph/source/fragment.rb +139 -284
- data/lib/solargraph/source/mapper.rb +27 -16
- data/lib/solargraph/source/node_chainer.rb +94 -0
- data/lib/solargraph/source/node_methods.rb +2 -2
- data/lib/solargraph/source/position.rb +4 -0
- data/lib/solargraph/source/range.rb +10 -2
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map.rb +13 -2
- metadata +20 -6
- data/lib/solargraph/api_map/probe.rb +0 -251
- data/lib/solargraph/api_map/type_methods.rb +0 -40
- data/lib/solargraph/pin/proxy_method.rb +0 -30
@@ -20,11 +20,15 @@ module Solargraph
|
|
20
20
|
@node = node
|
21
21
|
@node_stack = []
|
22
22
|
@directives = {}
|
23
|
+
@comment_ranges = comments.map do |c|
|
24
|
+
Source::Range.from_to(c.loc.expression.line, c.loc.expression.column, c.loc.expression.last_line, c.loc.expression.last_column)
|
25
|
+
end
|
23
26
|
@node_comments = associate_comments(node, comments)
|
24
27
|
@pins = []
|
25
28
|
@requires = []
|
26
29
|
@symbols = []
|
27
30
|
@locals = []
|
31
|
+
@strings = []
|
28
32
|
|
29
33
|
@used_comment_locs = []
|
30
34
|
|
@@ -37,7 +41,8 @@ module Solargraph
|
|
37
41
|
@node_comments.reject{|k, v| @used_comment_locs.include?(k)}.each do |k, v|
|
38
42
|
@pins.first.comments.concat v
|
39
43
|
end
|
40
|
-
|
44
|
+
|
45
|
+
[@pins, @locals, @requires, @symbols, @strings, @comment_ranges]
|
41
46
|
end
|
42
47
|
|
43
48
|
class << self
|
@@ -70,7 +75,13 @@ module Solargraph
|
|
70
75
|
@pins ||= []
|
71
76
|
end
|
72
77
|
|
78
|
+
# @param node [Parser::AST::Node]
|
73
79
|
def process node, tree = [], visibility = :public, scope = :instance, fqn = '', stack = []
|
80
|
+
return unless node.is_a?(AST::Node)
|
81
|
+
if node.type == :str
|
82
|
+
@strings.push Source::Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
|
83
|
+
return
|
84
|
+
end
|
74
85
|
stack.push node
|
75
86
|
if node.kind_of?(AST::Node)
|
76
87
|
@node_stack.unshift node
|
@@ -98,17 +109,17 @@ module Solargraph
|
|
98
109
|
ora = find_parent(stack, :or_asgn)
|
99
110
|
unless ora.nil?
|
100
111
|
u = c.updated(:ivasgn, c.children + ora.children[1..-1], nil)
|
101
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u),
|
112
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), context)
|
102
113
|
if visibility == :module_function and context.kind == Pin::METHOD
|
103
114
|
other = pins.select{|pin| pin.path == "#{context.namespace}.#{context.name}"}.first
|
104
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u),
|
115
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), other) unless other.nil?
|
105
116
|
end
|
106
117
|
end
|
107
118
|
else
|
108
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c),
|
119
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context)
|
109
120
|
if visibility == :module_function and context.kind == Pin::METHOD
|
110
121
|
other = pins.select{|pin| pin.path == "#{context.namespace}.#{context.name}"}.first
|
111
|
-
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c),
|
122
|
+
pins.push Solargraph::Pin::InstanceVariable.new(get_node_location(c), fqn || '',c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), other)
|
112
123
|
end
|
113
124
|
end
|
114
125
|
elsif c.type == :cvasgn
|
@@ -118,10 +129,10 @@ module Solargraph
|
|
118
129
|
ora = find_parent(stack, :or_asgn)
|
119
130
|
unless ora.nil?
|
120
131
|
u = c.updated(:cvasgn, c.children + ora.children[1..-1], nil)
|
121
|
-
pins.push Solargraph::Pin::ClassVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u),
|
132
|
+
pins.push Solargraph::Pin::ClassVariable.new(get_node_location(u), fqn || '', c.children[0].to_s, comments_for(u), u.children[1], infer_literal_node_type(u.children[1]), context)
|
122
133
|
end
|
123
134
|
else
|
124
|
-
pins.push Solargraph::Pin::ClassVariable.new(get_node_location(c), fqn || '', c.children[0].to_s, comments_for(c),
|
135
|
+
pins.push Solargraph::Pin::ClassVariable.new(get_node_location(c), fqn || '', c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context)
|
125
136
|
end
|
126
137
|
elsif c.type == :lvasgn
|
127
138
|
here = get_node_start_position(c)
|
@@ -132,25 +143,25 @@ module Solargraph
|
|
132
143
|
ora = find_parent(stack, :or_asgn)
|
133
144
|
unless ora.nil?
|
134
145
|
u = c.updated(:lvasgn, c.children + ora.children[1..-1], nil)
|
135
|
-
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora),
|
146
|
+
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(u), fqn, u.children[0].to_s, comments_for(ora), c.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
|
136
147
|
end
|
137
148
|
else
|
138
|
-
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c),
|
149
|
+
@locals.push Solargraph::Pin::LocalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), context, block, presence)
|
139
150
|
end
|
140
151
|
elsif c.type == :gvasgn
|
141
|
-
pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c),
|
152
|
+
pins.push Solargraph::Pin::GlobalVariable.new(get_node_location(c), fqn, c.children[0].to_s, comments_for(c), c.children[1], infer_literal_node_type(c.children[1]), @pins.first)
|
142
153
|
elsif c.type == :sym
|
143
154
|
@symbols.push Solargraph::Pin::Symbol.new(get_node_location(c), ":#{c.children[0]}")
|
144
155
|
elsif c.type == :casgn
|
145
156
|
here = get_node_start_position(c)
|
146
157
|
block = get_block_pin(here)
|
147
|
-
pins.push Solargraph::Pin::Constant.new(get_node_location(c), fqn, c.children[1].to_s, comments_for(c),
|
158
|
+
pins.push Solargraph::Pin::Constant.new(get_node_location(c), fqn, c.children[1].to_s, comments_for(c), c.children[2], infer_literal_node_type(c.children[2]), block, :public)
|
148
159
|
elsif c.type == :def
|
149
160
|
methpin = Solargraph::Pin::Method.new(get_node_location(c), fqn || '', c.children[(c.type == :def ? 0 : 1)].to_s, comments_for(c), scope, visibility, get_method_args(c))
|
150
161
|
if methpin.name == 'initialize' and methpin.scope == :instance
|
151
162
|
pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, 'new', methpin.comments, :class, :public, methpin.parameters)
|
152
163
|
# @todo Smelly instance variable access.
|
153
|
-
pins.last.instance_variable_set(:@
|
164
|
+
pins.last.instance_variable_set(:@return_complex_type, ComplexType.parse(methpin.namespace))
|
154
165
|
pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, methpin.name, methpin.comments, methpin.scope, :private, methpin.parameters)
|
155
166
|
elsif visibility == :module_function
|
156
167
|
pins.push Solargraph::Pin::Method.new(methpin.location, methpin.namespace, methpin.name, methpin.comments, :class, :public, methpin.parameters)
|
@@ -290,7 +301,7 @@ module Solargraph
|
|
290
301
|
end
|
291
302
|
end
|
292
303
|
elsif c.type == :block
|
293
|
-
@pins.push Solargraph::Pin::Block.new(get_node_location(c), fqn || '', '', comments_for(c),
|
304
|
+
@pins.push Solargraph::Pin::Block.new(get_node_location(c), fqn || '', '', comments_for(c), c.children[0], scope)
|
294
305
|
end
|
295
306
|
process c, tree, visibility, scope, fqn, stack
|
296
307
|
end
|
@@ -333,8 +344,8 @@ module Solargraph
|
|
333
344
|
st = Position.new(0, 0)
|
334
345
|
en = Position.from_offset(@code, @code.length)
|
335
346
|
else
|
336
|
-
st = Position.new(node.loc.line
|
337
|
-
en = Position.new(node.loc.last_line
|
347
|
+
st = Position.new(node.loc.line, node.loc.column)
|
348
|
+
en = Position.new(node.loc.last_line, node.loc.last_column)
|
338
349
|
end
|
339
350
|
range = Range.new(st, en)
|
340
351
|
Location.new(filename, range)
|
@@ -371,7 +382,7 @@ module Solargraph
|
|
371
382
|
# @param node [Parser::AST::Node]
|
372
383
|
# @return [Solargraph::Pin::Namespace]
|
373
384
|
def namespace_for(node)
|
374
|
-
position = Source::Position.new(node.loc.line
|
385
|
+
position = Source::Position.new(node.loc.line, node.loc.column)
|
375
386
|
@pins.select{|pin| pin.kind == Pin::NAMESPACE and pin.location.range.contain?(position)}.last
|
376
387
|
end
|
377
388
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class Source
|
3
|
+
class NodeChainer
|
4
|
+
include NodeMethods
|
5
|
+
|
6
|
+
def initialize filename, node
|
7
|
+
@filename = filename
|
8
|
+
@node = node
|
9
|
+
# @source = source
|
10
|
+
# @line = line
|
11
|
+
# @column = column
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Source::Chain]
|
15
|
+
def chain
|
16
|
+
links = generate_links(@node)
|
17
|
+
Chain.new(@filename, links)
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# @param source [Source]
|
22
|
+
# @param line [Integer]
|
23
|
+
# @param column [Integer]
|
24
|
+
# @return [Source::Chain]
|
25
|
+
def chain filename, node
|
26
|
+
NodeChainer.new(filename, node).chain
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param code [String]
|
30
|
+
# @return [Chain]
|
31
|
+
def load_string(filename, code)
|
32
|
+
node = Source.parse_node(code.sub(/\.$/, ''), filename)
|
33
|
+
chain = Chain.new(filename, node)
|
34
|
+
chain.links.push(Chain::Link.new) if code.end_with?('.')
|
35
|
+
chain
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @param n [Parser::AST::Node]
|
42
|
+
# @return [Array<Chain::Link>]
|
43
|
+
def generate_links n
|
44
|
+
return [] if n.nil?
|
45
|
+
return generate_links(n.children[0]) if n.type == :begin
|
46
|
+
# @todo This might not be right. It's weird either way.
|
47
|
+
# return generate_links(n.children[2] || n.children[0]) if n.type == :block
|
48
|
+
result = []
|
49
|
+
if n.type == :block
|
50
|
+
# result.concat generate_links(n.children[2])
|
51
|
+
result.concat generate_links(n.children[0])
|
52
|
+
elsif n.type == :send
|
53
|
+
if n.children[0].is_a?(Parser::AST::Node)
|
54
|
+
result.concat generate_links(n.children[0])
|
55
|
+
args = []
|
56
|
+
n.children[2..-1].each do |c|
|
57
|
+
# @todo Handle link parameters
|
58
|
+
# args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
|
59
|
+
end
|
60
|
+
result.push Chain::Call.new(n.children[1].to_s, args)
|
61
|
+
elsif n.children[0].nil?
|
62
|
+
args = []
|
63
|
+
n.children[2..-1].each do |c|
|
64
|
+
# @todo Handle link parameters
|
65
|
+
# args.push Chain.new(source, c.loc.last_line - 1, c.loc.column)
|
66
|
+
end
|
67
|
+
result.push Chain::Call.new(n.children[1].to_s, args)
|
68
|
+
else
|
69
|
+
raise "No idea what to do with #{n}"
|
70
|
+
end
|
71
|
+
elsif n.type == :self
|
72
|
+
result.push Chain::Call.new('self')
|
73
|
+
elsif n.type == :const
|
74
|
+
result.push Chain::Constant.new(unpack_name(n))
|
75
|
+
elsif [:lvar, :lvasgn].include?(n.type)
|
76
|
+
result.push Chain::Call.new(n.children[0].to_s)
|
77
|
+
elsif [:ivar, :ivasgn].include?(n.type)
|
78
|
+
result.push Chain::InstanceVariable.new(n.children[0].to_s)
|
79
|
+
elsif [:cvar, :cvasgn].include?(n.type)
|
80
|
+
result.push Chain::ClassVariable.new(n.children[0].to_s)
|
81
|
+
elsif [:gvar, :gvasgn].include?(n.type)
|
82
|
+
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
83
|
+
elsif [:class, :module, :def, :defs].include?(n.type)
|
84
|
+
location = Solargraph::Source::Location.new(@filename, Source::Range.from_to(n.loc.expression.line - 1, n.loc.expression.column, n.loc.expression.last_line - 1, n.loc.expression.last_column))
|
85
|
+
result.push Chain::Definition.new(location)
|
86
|
+
else
|
87
|
+
lit = infer_literal_node_type(n)
|
88
|
+
result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
|
89
|
+
end
|
90
|
+
result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -79,11 +79,11 @@ module Solargraph
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def get_node_start_position(node)
|
82
|
-
Position.new(node.loc.line
|
82
|
+
Position.new(node.loc.line, node.loc.column)
|
83
83
|
end
|
84
84
|
|
85
85
|
def get_node_end_position(node)
|
86
|
-
Position.new(node.loc.last_line
|
86
|
+
Position.new(node.loc.last_line, node.loc.last_column)
|
87
87
|
end
|
88
88
|
|
89
89
|
def drill_signature node, signature
|
@@ -27,15 +27,23 @@ module Solargraph
|
|
27
27
|
|
28
28
|
# True if the specified position is inside the range.
|
29
29
|
#
|
30
|
+
# @param position [Solargraph::Source::Position]
|
30
31
|
# @return [Boolean]
|
31
32
|
def contain? position
|
32
|
-
return false if position.line < start.line
|
33
|
+
return false if position.line < start.line or position.line > ending.line
|
33
34
|
return false if position.line == start.line and position.character < start.character
|
34
|
-
return false if position.line > ending.line
|
35
35
|
return false if position.line == ending.line and position.character > ending.character
|
36
36
|
true
|
37
37
|
end
|
38
38
|
|
39
|
+
# True if the range contains the specified position and the position does not precede it.
|
40
|
+
#
|
41
|
+
# @param position [Source::Position]
|
42
|
+
# @return [Boolean]
|
43
|
+
def include? position
|
44
|
+
contain?(position) and !(position.line == start.line and position.character == start.character)
|
45
|
+
end
|
46
|
+
|
39
47
|
# Create a range from a pair of lines and characters.
|
40
48
|
#
|
41
49
|
# @param l1 [Integer] Starting line
|
data/lib/solargraph/version.rb
CHANGED
data/lib/solargraph/yard_map.rb
CHANGED
@@ -26,6 +26,8 @@ module Solargraph
|
|
26
26
|
# @return [Array<String>]
|
27
27
|
attr_reader :required
|
28
28
|
|
29
|
+
# @param required [Array<String>]
|
30
|
+
# @param workspace [Solargraph::Workspace, nil]
|
29
31
|
def initialize(required: [], workspace: nil)
|
30
32
|
@workspace = workspace
|
31
33
|
# HACK: YardMap needs its own copy of this array
|
@@ -69,7 +71,7 @@ module Solargraph
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
|
-
# @param
|
74
|
+
# @param new_requires [Array<String>]
|
73
75
|
# @return [Boolean]
|
74
76
|
def change new_requires
|
75
77
|
if new_requires.uniq.sort == required.uniq.sort
|
@@ -82,6 +84,7 @@ module Solargraph
|
|
82
84
|
end
|
83
85
|
end
|
84
86
|
|
87
|
+
# @return [Array<Solargraph::Pin::Base>]
|
85
88
|
def core_pins
|
86
89
|
@@core_pins ||= begin
|
87
90
|
result = []
|
@@ -100,6 +103,8 @@ module Solargraph
|
|
100
103
|
@cache ||= YardMap::Cache.new
|
101
104
|
end
|
102
105
|
|
106
|
+
# @param ns [YARD::CodeObjects::Namespace]
|
107
|
+
# @return [Array<Solargraph::Pin::Base>]
|
103
108
|
def recurse_namespace_object ns
|
104
109
|
result = []
|
105
110
|
ns.children.each do |c|
|
@@ -109,6 +114,8 @@ module Solargraph
|
|
109
114
|
result
|
110
115
|
end
|
111
116
|
|
117
|
+
# @param code_object [YARD::CodeObjects::Base]
|
118
|
+
# @return [Solargraph::Pin::Base]
|
112
119
|
def generate_pin code_object
|
113
120
|
location = object_location(code_object)
|
114
121
|
if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
|
@@ -122,6 +129,7 @@ module Solargraph
|
|
122
129
|
end
|
123
130
|
end
|
124
131
|
|
132
|
+
# @return [void]
|
125
133
|
def process_requires
|
126
134
|
pins.clear
|
127
135
|
unresolved_requires.clear
|
@@ -177,6 +185,8 @@ module Solargraph
|
|
177
185
|
pins.concat core_pins
|
178
186
|
end
|
179
187
|
|
188
|
+
# @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
|
189
|
+
# @return [Array<Solargraph::Pin::Base>]
|
180
190
|
def process_stdlib required_namespaces
|
181
191
|
pins = []
|
182
192
|
unless required_namespaces.empty?
|
@@ -199,6 +209,7 @@ module Solargraph
|
|
199
209
|
end
|
200
210
|
|
201
211
|
# @param spec [Gem::Specification]
|
212
|
+
# @return [void]
|
202
213
|
def add_gem_dependencies spec
|
203
214
|
(spec.dependencies - spec.development_dependencies).each do |dep|
|
204
215
|
depspec = Gem::Specification.find_by_name(dep.name)
|
@@ -218,7 +229,7 @@ module Solargraph
|
|
218
229
|
return nil if obj.file.nil? or obj.line.nil?
|
219
230
|
@gem_paths.values.each do |path|
|
220
231
|
file = File.join(path, obj.file)
|
221
|
-
return Solargraph::Source::Location.new(file, Solargraph::Source::Range.from_to(obj.line
|
232
|
+
return Solargraph::Source::Location.new(file, Solargraph::Source::Range.from_to(obj.line, 0, obj.line, 0)) if File.exist?(file)
|
222
233
|
end
|
223
234
|
nil
|
224
235
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solargraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.26.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fred Snyder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -236,11 +236,10 @@ files:
|
|
236
236
|
- lib/solargraph.rb
|
237
237
|
- lib/solargraph/api_map.rb
|
238
238
|
- lib/solargraph/api_map/cache.rb
|
239
|
-
- lib/solargraph/api_map/completion.rb
|
240
|
-
- lib/solargraph/api_map/probe.rb
|
241
239
|
- lib/solargraph/api_map/source_to_yard.rb
|
242
240
|
- lib/solargraph/api_map/store.rb
|
243
|
-
- lib/solargraph/
|
241
|
+
- lib/solargraph/basic_type.rb
|
242
|
+
- lib/solargraph/basic_type_methods.rb
|
244
243
|
- lib/solargraph/complex_type.rb
|
245
244
|
- lib/solargraph/core_fills.rb
|
246
245
|
- lib/solargraph/diagnostics.rb
|
@@ -324,7 +323,7 @@ files:
|
|
324
323
|
- lib/solargraph/pin/method_parameter.rb
|
325
324
|
- lib/solargraph/pin/namespace.rb
|
326
325
|
- lib/solargraph/pin/plugin/method.rb
|
327
|
-
- lib/solargraph/pin/
|
326
|
+
- lib/solargraph/pin/proxy_type.rb
|
328
327
|
- lib/solargraph/pin/reference.rb
|
329
328
|
- lib/solargraph/pin/symbol.rb
|
330
329
|
- lib/solargraph/pin/yard_pin.rb
|
@@ -340,11 +339,26 @@ files:
|
|
340
339
|
- lib/solargraph/server_methods.rb
|
341
340
|
- lib/solargraph/shell.rb
|
342
341
|
- lib/solargraph/source.rb
|
342
|
+
- lib/solargraph/source/call_chainer.rb
|
343
|
+
- lib/solargraph/source/chain.rb
|
344
|
+
- lib/solargraph/source/chain/call.rb
|
345
|
+
- lib/solargraph/source/chain/class_variable.rb
|
346
|
+
- lib/solargraph/source/chain/constant.rb
|
347
|
+
- lib/solargraph/source/chain/definition.rb
|
348
|
+
- lib/solargraph/source/chain/global_variable.rb
|
349
|
+
- lib/solargraph/source/chain/head.rb
|
350
|
+
- lib/solargraph/source/chain/instance_variable.rb
|
351
|
+
- lib/solargraph/source/chain/link.rb
|
352
|
+
- lib/solargraph/source/chain/literal.rb
|
353
|
+
- lib/solargraph/source/chain/variable.rb
|
343
354
|
- lib/solargraph/source/change.rb
|
355
|
+
- lib/solargraph/source/completion.rb
|
356
|
+
- lib/solargraph/source/encoding_fixes.rb
|
344
357
|
- lib/solargraph/source/flawed_builder.rb
|
345
358
|
- lib/solargraph/source/fragment.rb
|
346
359
|
- lib/solargraph/source/location.rb
|
347
360
|
- lib/solargraph/source/mapper.rb
|
361
|
+
- lib/solargraph/source/node_chainer.rb
|
348
362
|
- lib/solargraph/source/node_methods.rb
|
349
363
|
- lib/solargraph/source/position.rb
|
350
364
|
- lib/solargraph/source/range.rb
|
@@ -1,251 +0,0 @@
|
|
1
|
-
module Solargraph
|
2
|
-
class ApiMap
|
3
|
-
# A deep analysis provider for ApiMaps.
|
4
|
-
#
|
5
|
-
class Probe
|
6
|
-
include TypeMethods
|
7
|
-
|
8
|
-
# @return [Solargraph::ApiMap]
|
9
|
-
attr_reader :api_map
|
10
|
-
|
11
|
-
# @param api_map [ApiMap]
|
12
|
-
def initialize api_map
|
13
|
-
@api_map = api_map
|
14
|
-
end
|
15
|
-
|
16
|
-
# Get all matching pins for the signature.
|
17
|
-
#
|
18
|
-
# @param signature [String]
|
19
|
-
# @param context_pin [Pin::Base]
|
20
|
-
# @param locals [Array<Pin::Base>]
|
21
|
-
# @return [Array<Pin::Base>]
|
22
|
-
def infer_signature_pins signature, context_pin, locals
|
23
|
-
return [] if signature.nil? or signature.empty?
|
24
|
-
base, rest = signature.split('.', 2)
|
25
|
-
return infer_word_pins(base, context_pin, locals) if rest.nil?
|
26
|
-
pins = infer_word_pins(base, context_pin, locals).map do |pin|
|
27
|
-
next pin unless pin.return_type.nil?
|
28
|
-
type = resolve_pin_type(pin, locals - [pin])
|
29
|
-
Pin::ProxyMethod.new(type)
|
30
|
-
end
|
31
|
-
return [] if pins.empty?
|
32
|
-
rest = rest.split('.')
|
33
|
-
last = rest.pop
|
34
|
-
rest.each do |meth|
|
35
|
-
found = nil
|
36
|
-
pins.each do |pin|
|
37
|
-
found = infer_method_name_pins(meth, pin)
|
38
|
-
next if found.empty?
|
39
|
-
pins = found
|
40
|
-
break
|
41
|
-
end
|
42
|
-
return [] if found.nil?
|
43
|
-
end
|
44
|
-
pins.each do |pin|
|
45
|
-
found = infer_method_name_pins(last, pin)
|
46
|
-
return found unless found.empty?
|
47
|
-
end
|
48
|
-
[]
|
49
|
-
end
|
50
|
-
|
51
|
-
# Get the return type for the signature.
|
52
|
-
#
|
53
|
-
# @param signature [String]
|
54
|
-
# @param context_pin [Pin::Base]
|
55
|
-
# @param locals [Array<Pin::Base>]
|
56
|
-
# @return [String]
|
57
|
-
def infer_signature_type signature, context_pin, locals
|
58
|
-
pins = infer_signature_pins(signature, context_pin, locals)
|
59
|
-
pins.each do |pin|
|
60
|
-
return qualify(pin.return_type, pin.named_context) unless pin.return_type.nil?
|
61
|
-
type = resolve_pin_type(pin, locals - [pin])
|
62
|
-
return qualify(type, pin.named_context) unless type.nil?
|
63
|
-
end
|
64
|
-
nil
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
# Word search is ALWAYS internal
|
70
|
-
def infer_word_pins word, context_pin, locals
|
71
|
-
return [] if word.empty?
|
72
|
-
return infer_self(context_pin) if word == 'self'
|
73
|
-
lvars = locals.select{|pin| pin.name == word}
|
74
|
-
return resolve_word_types(lvars, locals) unless lvars.empty?
|
75
|
-
return api_map.get_global_variable_pins.select{|pin| pin.name == word} if word.start_with?('$')
|
76
|
-
namespace, scope = extract_namespace_and_scope_from_pin(context_pin)
|
77
|
-
return api_map.get_class_variable_pins(namespace).select{|pin| pin.name == word} if word.start_with?('@@')
|
78
|
-
return api_map.get_instance_variable_pins(namespace, scope).select{|pin| pin.name == word} if word.start_with?('@')
|
79
|
-
return api_map.pins.select{|pin| word_matches_context?(word, namespace, scope, pin)} if variable_name?(word)
|
80
|
-
result = []
|
81
|
-
cparts = namespace.split('::')
|
82
|
-
until cparts.empty?
|
83
|
-
break unless result.empty?
|
84
|
-
cur = cparts.join('::')
|
85
|
-
result.concat api_map.get_path_suggestions("#{cur}::#{word}")
|
86
|
-
cparts.pop
|
87
|
-
end
|
88
|
-
result.concat api_map.get_path_suggestions(word) if result.empty?
|
89
|
-
# result.concat api_map.get_methods(namespace, scope: scope, visibility: [:public, :private, :protected]).select{|pin| pin.name == word} unless word.include?('::')
|
90
|
-
result.concat api_map.get_method_stack(namespace, word, scope: scope) unless word.include?('::')
|
91
|
-
result.concat api_map.get_constants('', namespace).select{|pin| pin.name == word} if result.empty?
|
92
|
-
resolve_word_types(result, locals)
|
93
|
-
end
|
94
|
-
|
95
|
-
def resolve_word_types(pins, locals)
|
96
|
-
pins.each do |p|
|
97
|
-
next unless p.return_type.nil?
|
98
|
-
type = resolve_pin_type(p, locals)
|
99
|
-
# @todo Smelly instance variable access
|
100
|
-
p.instance_variable_set(:@return_complex_types, ComplexType.parse(type)) unless type.nil?
|
101
|
-
end
|
102
|
-
pins
|
103
|
-
end
|
104
|
-
|
105
|
-
def infer_self context_pin
|
106
|
-
if context_pin.kind == Pin::METHOD
|
107
|
-
if context_pin.scope == :instance
|
108
|
-
return [Pin::ProxyMethod.new(context_pin.namespace)]
|
109
|
-
else
|
110
|
-
return api_map.get_path_suggestions(context_pin.namespace)
|
111
|
-
end
|
112
|
-
else
|
113
|
-
return api_map.get_path_suggestions(context_pin.path)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Method name search is external by default
|
118
|
-
# @param method_name [String]
|
119
|
-
# @param context_pin [Solargraph::Pin::Base]
|
120
|
-
def infer_method_name_pins method_name, context_pin, internal = false
|
121
|
-
relname, scope = extract_namespace_and_scope(context_pin.return_type)
|
122
|
-
namespace = api_map.qualify(relname, context_pin.namespace)
|
123
|
-
visibility = [:public]
|
124
|
-
visibility.push :protected, :private if internal
|
125
|
-
# result = api_map.get_methods(namespace, scope: scope, visibility: visibility).select{|pin| pin.name == method_name}
|
126
|
-
result = api_map.get_method_stack(namespace, method_name, scope: scope).select{|pin| visibility.include?(pin.visibility)}
|
127
|
-
# @todo This needs more rules. Probably need to update YardObject for it.
|
128
|
-
return result if result.empty?
|
129
|
-
return result unless method_name == 'new' and result.first.path == 'Class#new'
|
130
|
-
result.unshift virtual_new_pin(result.first, context_pin)
|
131
|
-
result
|
132
|
-
end
|
133
|
-
|
134
|
-
# Word and context matching rules for ApiMap source pins.
|
135
|
-
#
|
136
|
-
# @return [Boolean]
|
137
|
-
def word_matches_context? word, namespace, scope, pin
|
138
|
-
return false unless word == pin.name
|
139
|
-
return true if pin.kind == Pin::NAMESPACE and pin.path == namespace and scope == :class
|
140
|
-
return true if pin.kind == Pin::METHOD and pin.namespace == namespace and pin.scope == scope
|
141
|
-
# @todo Handle instance variables, class variables, etc. in various ways
|
142
|
-
pin.namespace == namespace and pin.scope == scope
|
143
|
-
end
|
144
|
-
|
145
|
-
# Fully qualify the namespace in a type.
|
146
|
-
#
|
147
|
-
# @return [String]
|
148
|
-
def qualify type, context
|
149
|
-
rns, rsc = extract_namespace_and_scope(type)
|
150
|
-
res = api_map.qualify(rns, context)
|
151
|
-
return res if rsc == :instance
|
152
|
-
type.sub(/<#{rns}>/, "<#{res}>")
|
153
|
-
end
|
154
|
-
|
155
|
-
# Extract a namespace and a scope from a pin. For now, the pin must
|
156
|
-
# be either a namespace, a method, or a block.
|
157
|
-
#
|
158
|
-
# @return [Array] The namespace (String) and scope (Symbol).
|
159
|
-
def extract_namespace_and_scope_from_pin pin
|
160
|
-
return [pin.namespace, pin.scope] if pin.kind == Pin::METHOD
|
161
|
-
return [pin.path, :class] if pin.kind == Pin::NAMESPACE
|
162
|
-
# @todo Is :class appropriate for blocks?
|
163
|
-
return [pin.namespace, :class] if pin.kind == Pin::BLOCK
|
164
|
-
raise "Unable to extract namespace and scope from #{pin.path}"
|
165
|
-
end
|
166
|
-
|
167
|
-
# Determine whether or not the word represents a variable. This method
|
168
|
-
# is used to keep the probe from performing unnecessary constant and
|
169
|
-
# method searches.
|
170
|
-
#
|
171
|
-
# @return [Boolean]
|
172
|
-
def variable_name? word
|
173
|
-
word.start_with?('@') or word.start_with?('$')
|
174
|
-
end
|
175
|
-
|
176
|
-
# Create a `new` pin to facilitate type inference. This is necessary for
|
177
|
-
# classes from YARD and classes in the namespace that do not have an
|
178
|
-
# `initialize` method.
|
179
|
-
#
|
180
|
-
# @return [Pin::Method]
|
181
|
-
def virtual_new_pin new_pin, context_pin
|
182
|
-
pin = Pin::Method.new(new_pin.location, context_pin.path, new_pin.name, '', :class, new_pin.visibility, new_pin.parameters)
|
183
|
-
# @todo Smelly instance variable access.
|
184
|
-
pin.instance_variable_set(:@return_complex_types, ComplexType.parse(context_pin.path))
|
185
|
-
pin
|
186
|
-
end
|
187
|
-
|
188
|
-
# @param pin [Solargraph::Pin::Base]
|
189
|
-
# @param locals [Array<Solargraph::Pin::Base>]
|
190
|
-
# @return [String]
|
191
|
-
def resolve_pin_type pin, locals
|
192
|
-
return pin.return_type unless pin.return_type.nil?
|
193
|
-
return pin.namespace if pin.kind == Pin::METHOD and pin.name == 'new' and pin.scope == :class
|
194
|
-
return resolve_block_parameter(pin, locals) if pin.kind == Pin::BLOCK_PARAMETER
|
195
|
-
return resolve_method_parameter(pin) if pin.is_a?(Pin::MethodParameter)
|
196
|
-
return resolve_variable(pin, locals) if pin.variable?
|
197
|
-
nil
|
198
|
-
end
|
199
|
-
|
200
|
-
def resolve_block_parameter pin, locals
|
201
|
-
return pin.return_type unless pin.return_type.nil?
|
202
|
-
signature = pin.block.receiver
|
203
|
-
# @todo Not sure if assuming the first pin is good here
|
204
|
-
meth = infer_signature_pins(signature, pin.block, locals).first
|
205
|
-
return nil if meth.nil?
|
206
|
-
if (Solargraph::CoreFills::METHODS_WITH_YIELDPARAM_SUBTYPES.include?(meth.path))
|
207
|
-
base = signature.split('.')[0..-2].join('.')
|
208
|
-
return nil if base.nil? or base.empty?
|
209
|
-
# @todo Not sure if assuming the first pin is good here
|
210
|
-
bmeth = infer_signature_pins(base, pin.block, locals).first
|
211
|
-
return nil if bmeth.nil?
|
212
|
-
btype = bmeth.return_type
|
213
|
-
btype = infer_signature_type(bmeth.signature, pin.block, locals) if btype.nil? and bmeth.variable?
|
214
|
-
subtypes = get_subtypes(btype)
|
215
|
-
return nil if subtypes.nil?
|
216
|
-
return subtypes[0]
|
217
|
-
else
|
218
|
-
yps = meth.docstring.tags(:yieldparam)
|
219
|
-
unless yps[pin.index].nil? or yps[pin.index].types.nil? or yps[pin.index].types.empty?
|
220
|
-
return yps[pin.index].types[0]
|
221
|
-
end
|
222
|
-
end
|
223
|
-
nil
|
224
|
-
end
|
225
|
-
|
226
|
-
def resolve_method_parameter pin
|
227
|
-
matches = api_map.get_method_stack(pin.namespace, pin.context.name, scope: pin.scope)
|
228
|
-
matches.each do |m|
|
229
|
-
next unless pin.context.parameters == m.parameters
|
230
|
-
tag = m.docstring.tags(:param).select{|t| t.name == pin.name}.first
|
231
|
-
next if tag.nil? or tag.types.nil?
|
232
|
-
return tag.types[0]
|
233
|
-
end
|
234
|
-
nil
|
235
|
-
end
|
236
|
-
|
237
|
-
def resolve_variable(pin, locals)
|
238
|
-
return nil if pin.nil_assignment?
|
239
|
-
# @todo Do we need the locals here?
|
240
|
-
return infer_signature_type(pin.signature, pin.context, locals)
|
241
|
-
end
|
242
|
-
|
243
|
-
def get_subtypes type
|
244
|
-
return nil if type.nil?
|
245
|
-
match = type.match(/<([a-z0-9_:, ]*)>/i)
|
246
|
-
return [] if match.nil?
|
247
|
-
match[1].split(',').map(&:strip)
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|