solargraph 0.28.2 → 0.28.3
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 +12 -11
- data/lib/solargraph/bundle.rb +13 -14
- data/lib/solargraph/diagnostics.rb +1 -0
- data/lib/solargraph/diagnostics/base.rb +2 -0
- data/lib/solargraph/diagnostics/rubocop.rb +12 -20
- data/lib/solargraph/language_server/host.rb +5 -9
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +2 -1
- data/lib/solargraph/language_server/message/text_document/formatting.rb +20 -1
- data/lib/solargraph/library.rb +5 -25
- data/lib/solargraph/location.rb +3 -0
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin/base.rb +6 -4
- data/lib/solargraph/pin/method_parameter.rb +11 -0
- data/lib/solargraph/range.rb +16 -5
- data/lib/solargraph/source/chain.rb +44 -13
- data/lib/solargraph/source/chain/head.rb +1 -1
- data/lib/solargraph/source/node_chainer.rb +4 -10
- data/lib/solargraph/source/source_chainer.rb +1 -22
- data/lib/solargraph/source_map/clip.rb +1 -1
- data/lib/solargraph/source_map/mapper.rb +9 -0
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +21 -15
- data/lib/solargraph/workspace/config.rb +9 -9
- data/lib/solargraph/yard_map.rb +10 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5263886b3711a2cc3a6ff8b93c6162002feae2162055999a42d0e571473e47c
|
4
|
+
data.tar.gz: e936cac7abedde1efab2c97618c15a0290937211016cb7ae0a71d607b6483e23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8dd13d206f759022ab35d9721672b2a0c1c517a18f9e58cfeec7143eacdd6e8d20ad726cb5539bb2e010b9ec82593a4b164dd5bed4ddcb48e4adde17e226689
|
7
|
+
data.tar.gz: b4e88b5cd5f6c5d4495d4562edfd2510651410fe17e6e6b4db33dcee85afbe0ba7110fba5dabd143c76fd04a94e359ad07adae0588ca67ca2a1e445dd421ce67
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -46,7 +46,7 @@ module Solargraph
|
|
46
46
|
# @param source [Source]
|
47
47
|
# @return [self]
|
48
48
|
def map source
|
49
|
-
catalog Bundle.new(
|
49
|
+
catalog Bundle.new(opened: [source])
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
@@ -56,9 +56,6 @@ module Solargraph
|
|
56
56
|
# @param bundle [Bundle]
|
57
57
|
# @return [self]
|
58
58
|
def catalog bundle
|
59
|
-
# @todo This can be more efficient. We don't need to remap sources that
|
60
|
-
# are already here.
|
61
|
-
# all_sources = (workspace.sources + others).uniq
|
62
59
|
new_map_hash = {}
|
63
60
|
unmerged = false
|
64
61
|
bundle.sources.each do |source|
|
@@ -88,11 +85,11 @@ module Solargraph
|
|
88
85
|
pins.concat map.pins
|
89
86
|
reqs.concat map.requires.map(&:name)
|
90
87
|
end
|
91
|
-
reqs.concat bundle.required
|
92
|
-
unless bundle.
|
88
|
+
reqs.concat bundle.workspace.config.required
|
89
|
+
unless bundle.workspace.require_paths.empty?
|
93
90
|
reqs.delete_if do |r|
|
94
91
|
result = false
|
95
|
-
bundle.
|
92
|
+
bundle.workspace.require_paths.each do |l|
|
96
93
|
if new_map_hash.keys.include?(File.join(l, "#{r}.rb"))
|
97
94
|
result = true
|
98
95
|
break
|
@@ -101,13 +98,13 @@ module Solargraph
|
|
101
98
|
result
|
102
99
|
end
|
103
100
|
end
|
104
|
-
|
105
|
-
new_store = Store.new(pins +
|
101
|
+
yard_map.change(reqs)
|
102
|
+
new_store = Store.new(pins + yard_map.pins)
|
106
103
|
@mutex.synchronize {
|
107
104
|
@cache.clear
|
108
105
|
@source_map_hash = new_map_hash
|
109
106
|
@store = new_store
|
110
|
-
@unresolved_requires =
|
107
|
+
@unresolved_requires = yard_map.unresolved_requires
|
111
108
|
}
|
112
109
|
self
|
113
110
|
end
|
@@ -137,7 +134,7 @@ module Solargraph
|
|
137
134
|
# @todo How should this work?
|
138
135
|
api_map = self.new #(Solargraph::Workspace.new(directory))
|
139
136
|
workspace = Solargraph::Workspace.new(directory)
|
140
|
-
api_map.catalog Bundle.new(
|
137
|
+
api_map.catalog Bundle.new(workspace: workspace)
|
141
138
|
api_map
|
142
139
|
end
|
143
140
|
|
@@ -445,6 +442,10 @@ module Solargraph
|
|
445
442
|
|
446
443
|
private
|
447
444
|
|
445
|
+
def yard_map
|
446
|
+
@yard_map ||= YardMap.new
|
447
|
+
end
|
448
|
+
|
448
449
|
# A hash of source maps with filename keys.
|
449
450
|
#
|
450
451
|
# @return [Hash{String => SourceMap}]
|
data/lib/solargraph/bundle.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
module Solargraph
|
2
2
|
class Bundle
|
3
|
-
# @return [
|
4
|
-
attr_reader :
|
5
|
-
|
6
|
-
# @return [Array<String>]
|
7
|
-
attr_reader :required
|
3
|
+
# @return [Workspace]
|
4
|
+
attr_reader :workspace
|
8
5
|
|
9
|
-
# @return [Array<
|
10
|
-
attr_reader :
|
6
|
+
# @return [Array<Source>]
|
7
|
+
attr_reader :opened
|
11
8
|
|
12
|
-
# @
|
13
|
-
|
9
|
+
# @param workspace [Workspace]
|
10
|
+
# @param opened [Array<Source>]
|
11
|
+
def initialize workspace: Workspace.new, opened: []
|
12
|
+
@workspace = workspace
|
13
|
+
@opened = opened
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
@
|
18
|
-
@load_paths = load_paths
|
19
|
-
@yard_map = yard_map
|
16
|
+
# @return [Array<Source>]
|
17
|
+
def sources
|
18
|
+
@sources ||= (opened + workspace.sources).uniq(&:filename)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -19,23 +19,19 @@ module Solargraph
|
|
19
19
|
# @param api_map [Solargraph::ApiMap]
|
20
20
|
# @return [Array<Hash>]
|
21
21
|
def diagnose source, api_map
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
raise DiagnosticsError, 'RuboCop returned invalid data'
|
29
|
-
end
|
22
|
+
options, paths = generate_options(source.filename, source.code)
|
23
|
+
runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
|
24
|
+
result = redirect_stdout{ runner.run(paths) }
|
25
|
+
make_array JSON.parse(result)
|
26
|
+
rescue JSON::ParserError
|
27
|
+
raise DiagnosticsError, 'RuboCop returned invalid data'
|
30
28
|
end
|
31
29
|
|
32
30
|
private
|
33
31
|
|
34
|
-
# @param workspace [Solargraph::Workspace]
|
35
32
|
# @param filename [String]
|
36
33
|
# @param code [String]
|
37
34
|
# @return [Array]
|
38
|
-
# def generate_options workspace, filename, code
|
39
35
|
def generate_options filename, code
|
40
36
|
args = ['-f', 'j']
|
41
37
|
rubocop_file = find_rubocop_file(filename)
|
@@ -46,20 +42,16 @@ module Solargraph
|
|
46
42
|
[options, paths]
|
47
43
|
end
|
48
44
|
|
45
|
+
# @param filename [String]
|
46
|
+
# @return [String, nil]
|
49
47
|
def find_rubocop_file filename
|
50
|
-
rcfile = nil
|
51
48
|
dir = File.dirname(filename)
|
52
|
-
|
49
|
+
until File.dirname(dir) == dir
|
53
50
|
here = File.join(dir, '.rubocop.yml')
|
54
|
-
if File.exist?(here)
|
55
|
-
|
56
|
-
break
|
57
|
-
else
|
58
|
-
break if File.dirname(dir) == dir
|
59
|
-
dir = File.dirname(dir)
|
60
|
-
end
|
51
|
+
return here if File.exist?(here)
|
52
|
+
dir = File.dirname(dir)
|
61
53
|
end
|
62
|
-
|
54
|
+
nil
|
63
55
|
end
|
64
56
|
|
65
57
|
# @todo This is a smelly way to redirect output, but the RuboCop specs do the
|
@@ -136,13 +136,6 @@ module Solargraph
|
|
136
136
|
diagnoser.schedule uri
|
137
137
|
end
|
138
138
|
|
139
|
-
def save params
|
140
|
-
uri = params['textDocument']['uri']
|
141
|
-
filename = uri_to_file(uri)
|
142
|
-
version = params['textDocument']['version']
|
143
|
-
library.overwrite filename, version
|
144
|
-
end
|
145
|
-
|
146
139
|
# @param uri [String]
|
147
140
|
def diagnose uri
|
148
141
|
begin
|
@@ -193,7 +186,7 @@ module Solargraph
|
|
193
186
|
#
|
194
187
|
# @param directory [String]
|
195
188
|
def prepare directory
|
196
|
-
path =
|
189
|
+
path = ''
|
197
190
|
path = normalize_separators(directory) unless directory.nil?
|
198
191
|
begin
|
199
192
|
@library = Solargraph::Library.load(path)
|
@@ -202,7 +195,7 @@ module Solargraph
|
|
202
195
|
'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
|
203
196
|
'message' => e.message
|
204
197
|
}
|
205
|
-
@library = Solargraph::Library.load
|
198
|
+
@library = Solargraph::Library.load
|
206
199
|
end
|
207
200
|
diagnoser.start
|
208
201
|
cataloger.start
|
@@ -565,6 +558,9 @@ module Solargraph
|
|
565
558
|
},
|
566
559
|
'workspace/symbol' => {
|
567
560
|
workspaceSymbolProvider: true
|
561
|
+
},
|
562
|
+
'textDocument/formatting' => {
|
563
|
+
formattingProvider: true
|
568
564
|
}
|
569
565
|
}
|
570
566
|
end
|
@@ -5,11 +5,12 @@ module Solargraph
|
|
5
5
|
module LanguageServer
|
6
6
|
module Message
|
7
7
|
module CompletionItem
|
8
|
+
# completionItem/resolve message handler
|
9
|
+
#
|
8
10
|
class Resolve < Base
|
9
11
|
def process
|
10
12
|
pin = host.locate_pin params
|
11
13
|
if pin.nil?
|
12
|
-
# set_error(Solargraph::LanguageServer::ErrorCodes::INVALID_REQUEST, "Completion item could not be resolved")
|
13
14
|
set_result params
|
14
15
|
else
|
15
16
|
set_result(
|
@@ -14,10 +14,29 @@ module Solargraph
|
|
14
14
|
lines = o.lines
|
15
15
|
index = lines.index{|l| l.start_with?('====================')}
|
16
16
|
formatted = lines[index+1..-1].join
|
17
|
+
# The response is required to send an explicit range. Text edits
|
18
|
+
# with null ranges get ignored. See castwide/vscode-solargraph#83
|
19
|
+
if original.end_with?("\n")
|
20
|
+
ending = {
|
21
|
+
line: original.lines.length,
|
22
|
+
character: 0
|
23
|
+
}
|
24
|
+
else
|
25
|
+
ending = {
|
26
|
+
line: original.lines.length - 1,
|
27
|
+
character: original.lines.last.length
|
28
|
+
}
|
29
|
+
end
|
17
30
|
set_result(
|
18
31
|
[
|
19
32
|
{
|
20
|
-
range:
|
33
|
+
range: {
|
34
|
+
start: {
|
35
|
+
line: 0,
|
36
|
+
character: 0
|
37
|
+
},
|
38
|
+
end: ending
|
39
|
+
},
|
21
40
|
newText: formatted
|
22
41
|
}
|
23
42
|
]
|
data/lib/solargraph/library.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module Solargraph
|
4
|
-
# A
|
2
|
+
# A Library handles coordination between a Workspace and an ApiMap.
|
5
3
|
#
|
6
4
|
class Library
|
7
5
|
# @param workspace [Solargraph::Workspace]
|
8
|
-
def initialize workspace = Solargraph::Workspace.new
|
6
|
+
def initialize workspace = Solargraph::Workspace.new
|
9
7
|
@mutex = Mutex.new
|
10
8
|
@workspace = workspace
|
11
9
|
api_map.catalog bundle
|
@@ -115,22 +113,6 @@ module Solargraph
|
|
115
113
|
end
|
116
114
|
end
|
117
115
|
|
118
|
-
# @param filename [String]
|
119
|
-
# @param version [Integer]
|
120
|
-
# @return [void]
|
121
|
-
def overwrite filename, version
|
122
|
-
mutex.synchronize do
|
123
|
-
source = source_hash[filename]
|
124
|
-
return if source.nil?
|
125
|
-
if source.version > version
|
126
|
-
STDERR.puts "Save out of sync for #{filename} (current #{source.version}, overwrite #{version})" if source.version > version
|
127
|
-
else
|
128
|
-
open filename, File.read(filename), version
|
129
|
-
end
|
130
|
-
catalog
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
116
|
# Get completion suggestions at the specified file and location.
|
135
117
|
#
|
136
118
|
# @param filename [String] The file to analyze
|
@@ -336,7 +318,7 @@ module Solargraph
|
|
336
318
|
#
|
337
319
|
# @param directory [String] The path to be used for the workspace
|
338
320
|
# @return [Solargraph::Library]
|
339
|
-
def self.load directory
|
321
|
+
def self.load directory = ''
|
340
322
|
Solargraph::Library.new(Solargraph::Workspace.new(directory))
|
341
323
|
end
|
342
324
|
|
@@ -358,10 +340,8 @@ module Solargraph
|
|
358
340
|
# @return [Bundle]
|
359
341
|
def bundle
|
360
342
|
Bundle.new(
|
361
|
-
|
362
|
-
|
363
|
-
load_paths: workspace.require_paths,
|
364
|
-
yard_map: yard_map
|
343
|
+
workspace: workspace,
|
344
|
+
opened: open_file_hash.values
|
365
345
|
)
|
366
346
|
end
|
367
347
|
|
data/lib/solargraph/location.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Solargraph
|
2
|
+
# A section of text identified by its filename and range.
|
3
|
+
#
|
2
4
|
class Location
|
3
5
|
# @return [String]
|
4
6
|
attr_reader :filename
|
@@ -13,6 +15,7 @@ module Solargraph
|
|
13
15
|
@range = range
|
14
16
|
end
|
15
17
|
|
18
|
+
# @return [Hash]
|
16
19
|
def to_hash
|
17
20
|
{
|
18
21
|
filename: filename,
|
data/lib/solargraph/pin.rb
CHANGED
data/lib/solargraph/pin/base.rb
CHANGED
@@ -2,6 +2,8 @@ require 'reverse_markdown'
|
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
module Pin
|
5
|
+
# The base class for map pins.
|
6
|
+
#
|
5
7
|
class Base
|
6
8
|
include Conversions
|
7
9
|
include Documenting
|
@@ -214,10 +216,10 @@ module Solargraph
|
|
214
216
|
# @param t2 [YARD::Tags::Tag]
|
215
217
|
# @return [Boolean]
|
216
218
|
def compare_tags t1, t2
|
217
|
-
t1.class == t2.class
|
218
|
-
t1.tag_name == t2.tag_name
|
219
|
-
t1.text == t2.text
|
220
|
-
t1.name == t2.name
|
219
|
+
t1.class == t2.class &&
|
220
|
+
t1.tag_name == t2.tag_name &&
|
221
|
+
t1.text == t2.text &&
|
222
|
+
t1.name == t2.name &&
|
221
223
|
t1.types == t2.types
|
222
224
|
end
|
223
225
|
end
|
@@ -9,6 +9,10 @@ module Solargraph
|
|
9
9
|
params.each do |p|
|
10
10
|
next unless p.name == name
|
11
11
|
found = p
|
12
|
+
break
|
13
|
+
end
|
14
|
+
if found.nil? and !index.nil?
|
15
|
+
found = params[index] if params[index] && (params[index].name.nil? || params[index].name.empty?)
|
12
16
|
end
|
13
17
|
@return_complex_type = ComplexType.parse(*found.types) unless found.nil? or found.types.nil?
|
14
18
|
end
|
@@ -16,6 +20,13 @@ module Solargraph
|
|
16
20
|
@return_complex_type
|
17
21
|
end
|
18
22
|
|
23
|
+
# The parameter's zero-based location in the block's signature.
|
24
|
+
#
|
25
|
+
# @return [Integer]
|
26
|
+
def index
|
27
|
+
block.parameter_names.index(name)
|
28
|
+
end
|
29
|
+
|
19
30
|
def try_merge! pin
|
20
31
|
return false unless super
|
21
32
|
# @todo This is a little expensive, but it's necessary because
|
data/lib/solargraph/range.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Solargraph
|
2
|
+
# A pair of positions that compose a section of text.
|
3
|
+
#
|
2
4
|
class Range
|
3
5
|
# @return [Position]
|
4
6
|
attr_reader :start
|
@@ -29,9 +31,9 @@ module Solargraph
|
|
29
31
|
# @param position [Solargraph::Position]
|
30
32
|
# @return [Boolean]
|
31
33
|
def contain? position
|
32
|
-
return false if position.line < start.line
|
33
|
-
return false if position.line == start.line
|
34
|
-
return false if position.line == ending.line
|
34
|
+
return false if position.line < start.line || position.line > ending.line
|
35
|
+
return false if position.line == start.line && position.character < start.character
|
36
|
+
return false if position.line == ending.line && position.character > ending.character
|
35
37
|
true
|
36
38
|
end
|
37
39
|
|
@@ -40,7 +42,7 @@ module Solargraph
|
|
40
42
|
# @param position [Position]
|
41
43
|
# @return [Boolean]
|
42
44
|
def include? position
|
43
|
-
contain?(position)
|
45
|
+
contain?(position) && !(position.line == start.line && position.character == start.character)
|
44
46
|
end
|
45
47
|
|
46
48
|
# Create a range from a pair of lines and characters.
|
@@ -54,17 +56,26 @@ module Solargraph
|
|
54
56
|
Range.new(Position.new(l1, c1), Position.new(l2, c2))
|
55
57
|
end
|
56
58
|
|
59
|
+
# Get a range from a node.
|
60
|
+
#
|
61
|
+
# @param node [Parser::AST::Node]
|
62
|
+
# @return [Range]
|
57
63
|
def self.from_node node
|
58
64
|
from_expr(node.loc.expression)
|
59
65
|
end
|
60
66
|
|
67
|
+
# Get a range from a Parser range, usually found in
|
68
|
+
# Parser::AST::Node#location#expression.
|
69
|
+
#
|
70
|
+
# @param expr [Parser::Source::Range]
|
71
|
+
# @return [Range]
|
61
72
|
def self.from_expr expr
|
62
73
|
from_to(expr.line, expr.column, expr.last_line, expr.last_column)
|
63
74
|
end
|
64
75
|
|
65
76
|
def == other
|
66
77
|
return false unless other.is_a?(Range)
|
67
|
-
start == other.start
|
78
|
+
start == other.start && ending == other.ending
|
68
79
|
end
|
69
80
|
end
|
70
81
|
end
|
@@ -1,8 +1,11 @@
|
|
1
|
-
# HACK Fix autoload issue
|
1
|
+
# HACK: Fix autoload issue
|
2
2
|
require 'solargraph/source/chain/link'
|
3
3
|
|
4
4
|
module Solargraph
|
5
5
|
class Source
|
6
|
+
# A chain of constants, variables, and method calls for inferring types of
|
7
|
+
# values.
|
8
|
+
#
|
6
9
|
class Chain
|
7
10
|
autoload :Link, 'solargraph/source/chain/link'
|
8
11
|
autoload :Call, 'solargraph/source/chain/call'
|
@@ -14,6 +17,10 @@ module Solargraph
|
|
14
17
|
autoload :Literal, 'solargraph/source/chain/literal'
|
15
18
|
autoload :Head, 'solargraph/source/chain/head'
|
16
19
|
|
20
|
+
# Chain#infer uses the inference stack to avoid recursing into itself.
|
21
|
+
# See Chain#active_signature for more information.
|
22
|
+
@@inference_stack = []
|
23
|
+
|
17
24
|
UNDEFINED_CALL = Chain::Call.new('<undefined>')
|
18
25
|
UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
|
19
26
|
|
@@ -37,22 +44,16 @@ module Solargraph
|
|
37
44
|
# @return [Array<Pin::Base>]
|
38
45
|
def define api_map, name_pin, locals
|
39
46
|
return [] if undefined?
|
40
|
-
type = ComplexType::UNDEFINED
|
41
|
-
head = true
|
42
47
|
working_pin = name_pin
|
43
48
|
links[0..-2].each do |link|
|
44
|
-
pins = link.resolve(api_map, working_pin,
|
45
|
-
|
46
|
-
|
47
|
-
type =
|
48
|
-
pins.each do |pin|
|
49
|
-
type = pin.infer(api_map)
|
50
|
-
break unless type.undefined?
|
51
|
-
end
|
49
|
+
pins = link.resolve(api_map, working_pin, locals)
|
50
|
+
# Locals are only used when resolving the first link
|
51
|
+
locals = []
|
52
|
+
type = infer_first_defined(pins, api_map)
|
52
53
|
return [] if type.undefined?
|
53
54
|
working_pin = Pin::ProxyType.anonymous(type)
|
54
55
|
end
|
55
|
-
links.last.resolve(api_map, working_pin,
|
56
|
+
links.last.resolve(api_map, working_pin, locals)
|
56
57
|
end
|
57
58
|
|
58
59
|
# @param api_map [ApiMap]
|
@@ -60,27 +61,57 @@ module Solargraph
|
|
60
61
|
# @param locals [Array<Pin::Base>]
|
61
62
|
# @return [ComplexType]
|
62
63
|
def infer api_map, name_pin, locals
|
63
|
-
return ComplexType::UNDEFINED if undefined?
|
64
|
+
return ComplexType::UNDEFINED if undefined? || @@inference_stack.include?(active_signature(name_pin))
|
65
|
+
@@inference_stack.push active_signature(name_pin)
|
64
66
|
type = ComplexType::UNDEFINED
|
65
67
|
pins = define(api_map, name_pin, locals)
|
66
68
|
pins.each do |pin|
|
67
69
|
type = pin.infer(api_map)
|
68
70
|
break unless type.undefined?
|
69
71
|
end
|
72
|
+
@@inference_stack.pop
|
70
73
|
type
|
71
74
|
end
|
72
75
|
|
76
|
+
# @return [Boolean]
|
73
77
|
def literal?
|
74
78
|
links.last.is_a?(Chain::Literal)
|
75
79
|
end
|
76
80
|
|
81
|
+
# @return [Boolean]
|
77
82
|
def undefined?
|
78
83
|
links.any?(&:undefined?)
|
79
84
|
end
|
80
85
|
|
86
|
+
# @return [Boolean]
|
81
87
|
def constant?
|
82
88
|
links.last.is_a?(Chain::Constant)
|
83
89
|
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Get a signature for this chain that includes the current context
|
94
|
+
# where it's being analyzed. Chain#infer uses this value to detect
|
95
|
+
# recursive inference into the same chain, e.g., when two variables
|
96
|
+
# reference each other in their assignments.
|
97
|
+
#
|
98
|
+
# @param pin [Pin::Base] The named pin context
|
99
|
+
# @return [String]
|
100
|
+
def active_signature(pin)
|
101
|
+
"#{pin.path}|#{links.map(&:word).join('.')}"
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param pins [Array<Pin::Base>]
|
105
|
+
# @param api_map [ApiMap]
|
106
|
+
# @return [ComplexType]
|
107
|
+
def infer_first_defined pins, api_map
|
108
|
+
type = ComplexType::UNDEFINED
|
109
|
+
pins.each do |pin|
|
110
|
+
type = pin.infer(api_map)
|
111
|
+
break unless type.undefined?
|
112
|
+
end
|
113
|
+
type
|
114
|
+
end
|
84
115
|
end
|
85
116
|
end
|
86
117
|
end
|
@@ -24,7 +24,7 @@ module Solargraph
|
|
24
24
|
# @param name_pin [Pin::Base]
|
25
25
|
# @return [Array<Pin::Base>]
|
26
26
|
def super_pins api_map, name_pin
|
27
|
-
pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
|
27
|
+
pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
|
28
28
|
pins.reject{|p| p.path == name_pin.path}
|
29
29
|
end
|
30
30
|
end
|
@@ -1,14 +1,15 @@
|
|
1
1
|
module Solargraph
|
2
2
|
class Source
|
3
|
+
# A factory for generating chains from nodes.
|
4
|
+
#
|
3
5
|
class NodeChainer
|
4
6
|
include Source::NodeMethods
|
5
7
|
|
8
|
+
# @param node [Parser::AST::Node]
|
9
|
+
# @param filename [String]
|
6
10
|
def initialize node, filename = nil
|
7
11
|
@node = node
|
8
12
|
@filename = filename
|
9
|
-
# @source = source
|
10
|
-
# @line = line
|
11
|
-
# @column = column
|
12
13
|
end
|
13
14
|
|
14
15
|
# @return [Source::Chain]
|
@@ -26,7 +27,6 @@ module Solargraph
|
|
26
27
|
end
|
27
28
|
|
28
29
|
# @param code [String]
|
29
|
-
# @param filename [String, nil]
|
30
30
|
# @return [Chain]
|
31
31
|
def load_string(code)
|
32
32
|
node = Source.parse(code.sub(/\.$/, ''))
|
@@ -47,7 +47,6 @@ module Solargraph
|
|
47
47
|
# return generate_links(n.children[2] || n.children[0]) if n.type == :block
|
48
48
|
result = []
|
49
49
|
if n.type == :block
|
50
|
-
# result.concat generate_links(n.children[2])
|
51
50
|
result.concat generate_links(n.children[0])
|
52
51
|
elsif n.type == :send
|
53
52
|
if n.children[0].is_a?(Parser::AST::Node)
|
@@ -71,12 +70,7 @@ module Solargraph
|
|
71
70
|
elsif n.type == :zsuper
|
72
71
|
result.push Chain::Head.new('super')
|
73
72
|
elsif n.type == :const
|
74
|
-
# result.push Chain::Constant.new(unpack_name(n))
|
75
73
|
const = unpack_name(n)
|
76
|
-
# parts = const.split('::')
|
77
|
-
# last = parts.pop
|
78
|
-
# result.push Chain::Constant.new(parts.join('::')) unless parts.empty?
|
79
|
-
# result.push Chain::Constant.new(last)
|
80
74
|
result.push Chain::Constant.new(const)
|
81
75
|
elsif [:lvar, :lvasgn].include?(n.type)
|
82
76
|
result.push Chain::Call.new(n.children[0].to_s)
|
@@ -24,11 +24,7 @@ module Solargraph
|
|
24
24
|
# @param position [Position]
|
25
25
|
def initialize source, position
|
26
26
|
@source = source
|
27
|
-
# @source.code = source.code
|
28
27
|
@position = position
|
29
|
-
# @todo Get rid of line/column
|
30
|
-
@line = position.line
|
31
|
-
@column = position.column
|
32
28
|
@calculated_literal = false
|
33
29
|
end
|
34
30
|
|
@@ -65,16 +61,6 @@ module Solargraph
|
|
65
61
|
# @return [Position]
|
66
62
|
attr_reader :position
|
67
63
|
|
68
|
-
# The zero-based line number of the fragment's location.
|
69
|
-
#
|
70
|
-
# @return [Integer]
|
71
|
-
attr_reader :line
|
72
|
-
|
73
|
-
# The zero-based column number of the fragment's location.
|
74
|
-
#
|
75
|
-
# @return [Integer]
|
76
|
-
attr_reader :column
|
77
|
-
|
78
64
|
# @return [Solargraph::Source]
|
79
65
|
attr_reader :source
|
80
66
|
|
@@ -105,13 +91,6 @@ module Solargraph
|
|
105
91
|
end
|
106
92
|
end
|
107
93
|
|
108
|
-
# An alias for #column.
|
109
|
-
#
|
110
|
-
# @return [Integer]
|
111
|
-
def character
|
112
|
-
@column
|
113
|
-
end
|
114
|
-
|
115
94
|
# True if the current offset is inside a string.
|
116
95
|
#
|
117
96
|
# @return [Boolean]
|
@@ -122,7 +101,7 @@ module Solargraph
|
|
122
101
|
|
123
102
|
# @return [Integer]
|
124
103
|
def offset
|
125
|
-
@offset ||= get_offset(line, column)
|
104
|
+
@offset ||= get_offset(position.line, position.column)
|
126
105
|
end
|
127
106
|
|
128
107
|
# @param line [Integer]
|
@@ -13,7 +13,7 @@ module Solargraph
|
|
13
13
|
|
14
14
|
# @return [Array<Pin::Base>]
|
15
15
|
def define
|
16
|
-
return [] if cursor.chain.literal?
|
16
|
+
return [] if cursor.comment? || cursor.chain.literal?
|
17
17
|
result = cursor.chain.define(api_map, context_pin, locals)
|
18
18
|
result.concat(source_map.pins.select{ |p| p.location.range.start.line == cursor.position.line }) if result.empty?
|
19
19
|
result
|
@@ -297,6 +297,15 @@ module Solargraph
|
|
297
297
|
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), pin.namespace, c.children[0].children[0].to_s, comments_for(c) || pin.comments, pin.access, pin.scope, pin.visibility)
|
298
298
|
end
|
299
299
|
end
|
300
|
+
elsif c.type == :send && c.children[1] == :alias_method && c.children[2] && c.children[2] && c.children[2].type == :sym && c.children[3] && c.children[3].type == :sym
|
301
|
+
pin = pins.select{|p| p.name == c.children[3].children[0].to_s && p.namespace == fqn && p.scope == scope}.first
|
302
|
+
unless pin.nil?
|
303
|
+
if pin.is_a?(Solargraph::Pin::Method)
|
304
|
+
pins.push Solargraph::Pin::Method.new(get_node_location(c), pin.namespace, c.children[2].children[0].to_s, comments_for(c) || pin.comments, pin.scope, pin.visibility, pin.parameters)
|
305
|
+
elsif pin.is_a?(Solargraph::Pin::Attribute)
|
306
|
+
pins.push Solargraph::Pin::Attribute.new(get_node_location(c), pin.namespace, c.children[2].children[0].to_s, comments_for(c) || pin.comments, pin.access, pin.scope, pin.visibility)
|
307
|
+
end
|
308
|
+
end
|
300
309
|
elsif c.type == :sclass && c.children[0].type == :self
|
301
310
|
process c, tree, :public, :class, fqn || '', stack
|
302
311
|
next
|
data/lib/solargraph/version.rb
CHANGED
data/lib/solargraph/workspace.rb
CHANGED
@@ -10,19 +10,15 @@ module Solargraph
|
|
10
10
|
attr_reader :directory
|
11
11
|
|
12
12
|
# @param directory [String]
|
13
|
-
def initialize directory =
|
14
|
-
# @todo Convert to an absolute path?
|
13
|
+
def initialize directory = '', config = nil
|
15
14
|
@directory = directory
|
16
|
-
@directory = nil if @directory == ''
|
17
15
|
@config = config
|
18
16
|
load_sources
|
19
17
|
end
|
20
18
|
|
21
|
-
# @param reload [Boolean] Force a reload of the config file
|
22
19
|
# @return [Solargraph::Workspace::Config]
|
23
|
-
def config
|
24
|
-
@config
|
25
|
-
@config
|
20
|
+
def config
|
21
|
+
@config ||= Solargraph::Workspace::Config.new(directory)
|
26
22
|
end
|
27
23
|
|
28
24
|
# Merge the source. A merge will update the existing source for the file
|
@@ -32,7 +28,11 @@ module Solargraph
|
|
32
28
|
# @param source [Solargraph::Source]
|
33
29
|
# @return [Boolean] True if the source was added to the workspace
|
34
30
|
def merge source
|
35
|
-
|
31
|
+
unless source_hash.has_key?(source.filename)
|
32
|
+
# Reload the config to determine if a new source should be included
|
33
|
+
@config = Solargraph::Workspace::Config.new(directory)
|
34
|
+
return false unless config.calculated.include?(source.filename)
|
35
|
+
end
|
36
36
|
source_hash[source.filename] = source
|
37
37
|
true
|
38
38
|
end
|
@@ -42,7 +42,9 @@ module Solargraph
|
|
42
42
|
# @param filename [String]
|
43
43
|
# @return [Boolean]
|
44
44
|
def would_merge? filename
|
45
|
-
|
45
|
+
return true if source_hash.include?(filename)
|
46
|
+
@config = Solargraph::Workspace::Config.new(directory)
|
47
|
+
config.calculated.include?(filename)
|
46
48
|
end
|
47
49
|
|
48
50
|
# Remove a source from the workspace. The source will not be removed if
|
@@ -51,7 +53,7 @@ module Solargraph
|
|
51
53
|
# @param filename [String]
|
52
54
|
# @return [Boolean] True if the source was removed from the workspace
|
53
55
|
def remove filename
|
54
|
-
return false
|
56
|
+
return false unless source_hash.has_key?(filename)
|
55
57
|
source_hash.delete filename
|
56
58
|
true
|
57
59
|
end
|
@@ -107,7 +109,7 @@ module Solargraph
|
|
107
109
|
#
|
108
110
|
# @return [Array<String>]
|
109
111
|
def gemspecs
|
110
|
-
return [] if directory.
|
112
|
+
return [] if directory.empty?
|
111
113
|
@gemspecs ||= Dir[File.join(directory, '**/*.gemspec')]
|
112
114
|
end
|
113
115
|
|
@@ -128,7 +130,7 @@ module Solargraph
|
|
128
130
|
|
129
131
|
def load_sources
|
130
132
|
source_hash.clear
|
131
|
-
unless directory.
|
133
|
+
unless directory.empty?
|
132
134
|
size = config.calculated.length
|
133
135
|
raise WorkspaceTooLargeError, "The workspace is too large to index (#{size} files, #{config.max_files} max)" if config.max_files > 0 and size > config.max_files
|
134
136
|
config.calculated.each do |filename|
|
@@ -138,11 +140,14 @@ module Solargraph
|
|
138
140
|
end
|
139
141
|
|
140
142
|
def generate_require_paths
|
141
|
-
return
|
142
|
-
return configured_require_paths unless gemspec?
|
143
|
+
return configured_require_paths if directory.empty? || !gemspec?
|
143
144
|
result = []
|
144
145
|
gemspecs.each do |file|
|
145
|
-
|
146
|
+
# @todo Evaluating gemspec files violates the goal of not running
|
147
|
+
# workspace code, but this is how Gem::Specification.load does it
|
148
|
+
# anyway.
|
149
|
+
spec = eval(File.read(file), binding, file)
|
150
|
+
next unless Gem::Specification === spec
|
146
151
|
base = File.dirname(file)
|
147
152
|
result.concat spec.require_paths.map{ |path| File.join(base, path) } unless spec.nil?
|
148
153
|
end
|
@@ -152,6 +157,7 @@ module Solargraph
|
|
152
157
|
end
|
153
158
|
|
154
159
|
def configured_require_paths
|
160
|
+
return ['lib'] if directory.empty?
|
155
161
|
return [File.join(directory, 'lib')] if config.require_paths.empty?
|
156
162
|
config.require_paths.map{|p| File.join(directory, p)}
|
157
163
|
end
|
@@ -10,18 +10,18 @@ module Solargraph
|
|
10
10
|
MAX_FILES = 5000
|
11
11
|
|
12
12
|
# @return [String]
|
13
|
-
attr_reader :
|
13
|
+
attr_reader :directory
|
14
14
|
|
15
15
|
# @return [Hash]
|
16
16
|
attr_reader :raw_data
|
17
17
|
|
18
18
|
# @param workspace [String]
|
19
|
-
def initialize
|
20
|
-
@
|
19
|
+
def initialize directory = ''
|
20
|
+
@directory = directory
|
21
21
|
include_globs = ['**/*.rb']
|
22
22
|
exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
|
23
|
-
unless @
|
24
|
-
sfile = File.join(@
|
23
|
+
unless @directory.empty?
|
24
|
+
sfile = File.join(@directory, '.solargraph.yml')
|
25
25
|
if File.file?(sfile)
|
26
26
|
@raw_data = YAML.safe_load(File.read(sfile))
|
27
27
|
include_globs = @raw_data['include'] || include_globs
|
@@ -45,7 +45,7 @@ module Solargraph
|
|
45
45
|
#
|
46
46
|
# @return [Array<String>]
|
47
47
|
def included
|
48
|
-
return [] if
|
48
|
+
return [] if directory.empty?
|
49
49
|
@included ||= process_globs(@raw_data['include'])
|
50
50
|
end
|
51
51
|
|
@@ -53,7 +53,7 @@ module Solargraph
|
|
53
53
|
#
|
54
54
|
# @return [Array<String>]
|
55
55
|
def excluded
|
56
|
-
return [] if
|
56
|
+
return [] if directory.empty?
|
57
57
|
@excluded ||= process_exclusions(@raw_data['exclude'])
|
58
58
|
end
|
59
59
|
|
@@ -117,7 +117,7 @@ module Solargraph
|
|
117
117
|
def process_globs globs
|
118
118
|
result = []
|
119
119
|
globs.each do |glob|
|
120
|
-
result.concat Dir[File.join
|
120
|
+
result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
|
121
121
|
end
|
122
122
|
result
|
123
123
|
end
|
@@ -130,7 +130,7 @@ module Solargraph
|
|
130
130
|
def process_exclusions globs
|
131
131
|
remainder = globs.select do |glob|
|
132
132
|
if glob_is_directory?(glob)
|
133
|
-
exdir = File.join(
|
133
|
+
exdir = File.join(directory, glob_to_directory(glob))
|
134
134
|
included.delete_if { |file| file.start_with?(exdir) }
|
135
135
|
false
|
136
136
|
else
|
data/lib/solargraph/yard_map.rb
CHANGED
@@ -24,7 +24,6 @@ module Solargraph
|
|
24
24
|
attr_reader :required
|
25
25
|
|
26
26
|
# @param required [Array<String>]
|
27
|
-
# @param workspace [Solargraph::Workspace, nil]
|
28
27
|
def initialize(required: [])
|
29
28
|
# HACK: YardMap needs its own copy of this array
|
30
29
|
@required = required.clone
|
@@ -65,17 +64,15 @@ module Solargraph
|
|
65
64
|
# @param y [String]
|
66
65
|
# @return [YARD::Registry]
|
67
66
|
def load_yardoc y
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
YARD::Registry.load! y
|
73
|
-
end
|
74
|
-
rescue Exception => e
|
75
|
-
STDERR.puts "Error loading yardoc '#{y}' #{e.class} #{e.message}"
|
76
|
-
yardocs.delete y
|
77
|
-
nil
|
67
|
+
if y.kind_of?(Array)
|
68
|
+
YARD::Registry.load y, true
|
69
|
+
else
|
70
|
+
YARD::Registry.load! y
|
78
71
|
end
|
72
|
+
rescue Exception => e
|
73
|
+
STDERR.puts "Error loading yardoc '#{y}' #{e.class} #{e.message}"
|
74
|
+
yardocs.delete y
|
75
|
+
nil
|
79
76
|
end
|
80
77
|
|
81
78
|
# @return [Array<Solargraph::Pin::Base>]
|
@@ -254,6 +251,8 @@ module Solargraph
|
|
254
251
|
result
|
255
252
|
end
|
256
253
|
|
254
|
+
# @param y [String, nil]
|
255
|
+
# @return [Array<Pin::Base>]
|
257
256
|
def process_yardoc y
|
258
257
|
return [] if y.nil?
|
259
258
|
size = Dir.glob(File.join(y, '**', '*'))
|
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.28.
|
4
|
+
version: 0.28.3
|
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-10-
|
11
|
+
date: 2018-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|