solargraph 0.28.2 → 0.28.3
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/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
|