ruby-lsp 0.12.5 → 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp-check +20 -4
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +36 -2
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +132 -13
- data/lib/ruby_indexer/test/configuration_test.rb +10 -0
- data/lib/ruby_indexer/test/index_test.rb +11 -0
- data/lib/ruby_indexer/test/method_test.rb +202 -0
- data/lib/ruby_lsp/addon.rb +9 -13
- data/lib/ruby_lsp/document.rb +3 -0
- data/lib/ruby_lsp/executor.rb +33 -28
- data/lib/ruby_lsp/listener.rb +4 -5
- data/lib/ruby_lsp/requests/code_actions.rb +2 -16
- data/lib/ruby_lsp/requests/code_lens.rb +29 -7
- data/lib/ruby_lsp/requests/completion.rb +11 -8
- data/lib/ruby_lsp/requests/definition.rb +3 -4
- data/lib/ruby_lsp/requests/diagnostics.rb +0 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +2 -3
- data/lib/ruby_lsp/requests/document_link.rb +2 -3
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/folding_ranges.rb +12 -15
- data/lib/ruby_lsp/requests/formatting.rb +0 -5
- data/lib/ruby_lsp/requests/hover.rb +3 -4
- data/lib/ruby_lsp/requests/inlay_hints.rb +20 -3
- data/lib/ruby_lsp/requests/on_type_formatting.rb +31 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +28 -11
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +92 -21
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +1 -1
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +3 -8
- data/lib/ruby_lsp/requests/workspace_symbol.rb +2 -0
- data/lib/ruby_lsp/store.rb +21 -0
- data/lib/ruby_lsp/utils.rb +18 -4
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78df9c8d35fc18cea6fc06a0f679b48b69e3daaaf504d762d2f5ae4df9d99ad0
|
4
|
+
data.tar.gz: 3c251eed7939e81c5aa115d303b2876d3769c509ef0487b0faa26d1a2de79c50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af33b81309429318e7fe61dc4a2bd989328b8e9127097ab621eab162e61e1b2d93f1be1b192307d3b48f47659489343e093d92125e9c68895c40517803dba5ed
|
7
|
+
data.tar.gz: 6373eb77209eb865e29026fba603f4db8d3249949bcff7c0aee3f550569a7225c84b76d5872fd61a8798c0ef04da2d538b50b4d3045697ef40cc85336a2c715b
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.13.1
|
data/exe/ruby-lsp-check
CHANGED
@@ -17,8 +17,6 @@ end
|
|
17
17
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
18
18
|
require "ruby_lsp/internal"
|
19
19
|
|
20
|
-
RubyLsp::Addon.load_addons
|
21
|
-
|
22
20
|
T::Utils.run_all_sig_blocks
|
23
21
|
|
24
22
|
files = Dir.glob("#{Dir.pwd}/**/*.rb")
|
@@ -28,6 +26,7 @@ puts "Verifying that all automatic LSP requests execute successfully. This may t
|
|
28
26
|
errors = {}
|
29
27
|
store = RubyLsp::Store.new
|
30
28
|
message_queue = Thread::Queue.new
|
29
|
+
RubyLsp::Addon.load_addons(message_queue)
|
31
30
|
executor = RubyLsp::Executor.new(store, message_queue)
|
32
31
|
|
33
32
|
files.each_with_index do |file, index|
|
@@ -50,13 +49,30 @@ end
|
|
50
49
|
puts "\n"
|
51
50
|
message_queue.close
|
52
51
|
|
52
|
+
# Indexing
|
53
|
+
puts "Verifying that indexing executes successfully. This may take a while..."
|
54
|
+
|
55
|
+
index = RubyIndexer::Index.new
|
56
|
+
indexables = RubyIndexer.configuration.indexables
|
57
|
+
|
58
|
+
indexables.each_with_index do |indexable, i|
|
59
|
+
result = Prism.parse(File.read(indexable.full_path))
|
60
|
+
collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
|
61
|
+
collector.collect(result.value)
|
62
|
+
rescue => e
|
63
|
+
errors[indexable.full_path] = e
|
64
|
+
ensure
|
65
|
+
print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
|
66
|
+
end
|
67
|
+
puts "\n"
|
68
|
+
|
53
69
|
if errors.empty?
|
54
|
-
puts "All
|
70
|
+
puts "All operations completed successfully!"
|
55
71
|
exit
|
56
72
|
end
|
57
73
|
|
58
74
|
puts <<~ERRORS
|
59
|
-
Errors while executing
|
75
|
+
Errors while executing:
|
60
76
|
|
61
77
|
#{errors.map { |file, error| "#{file}: #{error.message}" }.join("\n")}
|
62
78
|
ERRORS
|
@@ -141,8 +141,18 @@ module RubyIndexer
|
|
141
141
|
|
142
142
|
sig { params(node: Prism::CallNode).void }
|
143
143
|
def handle_call_node(node)
|
144
|
-
message = node.
|
145
|
-
|
144
|
+
message = node.name
|
145
|
+
|
146
|
+
case message
|
147
|
+
when :private_constant
|
148
|
+
handle_private_constant(node)
|
149
|
+
when :attr_reader
|
150
|
+
handle_attribute(node, reader: true, writer: false)
|
151
|
+
when :attr_writer
|
152
|
+
handle_attribute(node, reader: false, writer: true)
|
153
|
+
when :attr_accessor
|
154
|
+
handle_attribute(node, reader: true, writer: true)
|
155
|
+
end
|
146
156
|
end
|
147
157
|
|
148
158
|
sig { params(node: Prism::DefNode).void }
|
@@ -312,5 +322,29 @@ module RubyIndexer
|
|
312
322
|
"#{@stack.join("::")}::#{name}"
|
313
323
|
end.delete_prefix("::")
|
314
324
|
end
|
325
|
+
|
326
|
+
sig { params(node: Prism::CallNode, reader: T::Boolean, writer: T::Boolean).void }
|
327
|
+
def handle_attribute(node, reader:, writer:)
|
328
|
+
arguments = node.arguments&.arguments
|
329
|
+
return unless arguments
|
330
|
+
|
331
|
+
receiver = node.receiver
|
332
|
+
return unless receiver.nil? || receiver.is_a?(Prism::SelfNode)
|
333
|
+
|
334
|
+
comments = collect_comments(node)
|
335
|
+
arguments.each do |argument|
|
336
|
+
name, loc = case argument
|
337
|
+
when Prism::SymbolNode
|
338
|
+
[argument.value, argument.value_loc]
|
339
|
+
when Prism::StringNode
|
340
|
+
[argument.content, argument.content_loc]
|
341
|
+
end
|
342
|
+
|
343
|
+
next unless name && loc
|
344
|
+
|
345
|
+
@index << Entry::Accessor.new(name, @file_path, loc, comments, @current_owner) if reader
|
346
|
+
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @current_owner) if writer
|
347
|
+
end
|
348
|
+
end
|
315
349
|
end
|
316
350
|
end
|
@@ -120,7 +120,7 @@ module RubyIndexer
|
|
120
120
|
IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
|
121
121
|
end,
|
122
122
|
)
|
123
|
-
|
123
|
+
elsif pathname.extname == ".rb"
|
124
124
|
# If the default_path is a Ruby file, we index it
|
125
125
|
indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
|
126
126
|
end
|
@@ -90,20 +90,84 @@ module RubyIndexer
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
+
# A required method parameter, e.g. `def foo(a)`
|
93
94
|
class RequiredParameter < Parameter
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
|
+
# An optional method parameter, e.g. `def foo(a = 123)`
|
98
|
+
class OptionalParameter < Parameter
|
99
|
+
end
|
100
|
+
|
101
|
+
# An required keyword method parameter, e.g. `def foo(a:)`
|
102
|
+
class KeywordParameter < Parameter
|
103
|
+
end
|
104
|
+
|
105
|
+
# An optional keyword method parameter, e.g. `def foo(a: 123)`
|
106
|
+
class OptionalKeywordParameter < Parameter
|
107
|
+
end
|
108
|
+
|
109
|
+
# A rest method parameter, e.g. `def foo(*a)`
|
110
|
+
class RestParameter < Parameter
|
111
|
+
DEFAULT_NAME = T.let(:"<anonymous splat>", Symbol)
|
112
|
+
end
|
113
|
+
|
114
|
+
# A keyword rest method parameter, e.g. `def foo(**a)`
|
115
|
+
class KeywordRestParameter < Parameter
|
116
|
+
DEFAULT_NAME = T.let(:"<anonymous keyword splat>", Symbol)
|
117
|
+
end
|
118
|
+
|
119
|
+
# A block method parameter, e.g. `def foo(&block)`
|
120
|
+
class BlockParameter < Parameter
|
121
|
+
DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
|
122
|
+
end
|
123
|
+
|
124
|
+
class Member < Entry
|
97
125
|
extend T::Sig
|
98
126
|
extend T::Helpers
|
99
|
-
abstract!
|
100
127
|
|
101
|
-
|
102
|
-
attr_reader :parameters
|
128
|
+
abstract!
|
103
129
|
|
104
130
|
sig { returns(T.nilable(Entry::Namespace)) }
|
105
131
|
attr_reader :owner
|
106
132
|
|
133
|
+
sig do
|
134
|
+
params(
|
135
|
+
name: String,
|
136
|
+
file_path: String,
|
137
|
+
location: Prism::Location,
|
138
|
+
comments: T::Array[String],
|
139
|
+
owner: T.nilable(Entry::Namespace),
|
140
|
+
).void
|
141
|
+
end
|
142
|
+
def initialize(name, file_path, location, comments, owner)
|
143
|
+
super(name, file_path, location, comments)
|
144
|
+
@owner = owner
|
145
|
+
end
|
146
|
+
|
147
|
+
sig { abstract.returns(T::Array[Parameter]) }
|
148
|
+
def parameters; end
|
149
|
+
end
|
150
|
+
|
151
|
+
class Accessor < Member
|
152
|
+
extend T::Sig
|
153
|
+
|
154
|
+
sig { override.returns(T::Array[Parameter]) }
|
155
|
+
def parameters
|
156
|
+
params = []
|
157
|
+
params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
|
158
|
+
params
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class Method < Member
|
163
|
+
extend T::Sig
|
164
|
+
extend T::Helpers
|
165
|
+
|
166
|
+
abstract!
|
167
|
+
|
168
|
+
sig { override.returns(T::Array[Parameter]) }
|
169
|
+
attr_reader :parameters
|
170
|
+
|
107
171
|
sig do
|
108
172
|
params(
|
109
173
|
name: String,
|
@@ -115,9 +179,9 @@ module RubyIndexer
|
|
115
179
|
).void
|
116
180
|
end
|
117
181
|
def initialize(name, file_path, location, comments, parameters_node, owner) # rubocop:disable Metrics/ParameterLists
|
118
|
-
super(name, file_path, location, comments)
|
182
|
+
super(name, file_path, location, comments, owner)
|
183
|
+
|
119
184
|
@parameters = T.let(list_params(parameters_node), T::Array[Parameter])
|
120
|
-
@owner = owner
|
121
185
|
end
|
122
186
|
|
123
187
|
private
|
@@ -126,23 +190,78 @@ module RubyIndexer
|
|
126
190
|
def list_params(parameters_node)
|
127
191
|
return [] unless parameters_node
|
128
192
|
|
129
|
-
|
193
|
+
parameters = []
|
194
|
+
|
195
|
+
parameters_node.requireds.each do |required|
|
130
196
|
name = parameter_name(required)
|
131
197
|
next unless name
|
132
198
|
|
133
|
-
RequiredParameter.new(name: name)
|
199
|
+
parameters << RequiredParameter.new(name: name)
|
134
200
|
end
|
135
|
-
end
|
136
201
|
|
137
|
-
|
138
|
-
|
202
|
+
parameters_node.optionals.each do |optional|
|
203
|
+
name = parameter_name(optional)
|
204
|
+
next unless name
|
205
|
+
|
206
|
+
parameters << OptionalParameter.new(name: name)
|
207
|
+
end
|
208
|
+
|
209
|
+
parameters_node.keywords.each do |keyword|
|
210
|
+
name = parameter_name(keyword)
|
211
|
+
next unless name
|
212
|
+
|
213
|
+
case keyword
|
214
|
+
when Prism::RequiredKeywordParameterNode
|
215
|
+
parameters << KeywordParameter.new(name: name)
|
216
|
+
when Prism::OptionalKeywordParameterNode
|
217
|
+
parameters << OptionalKeywordParameter.new(name: name)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
rest = parameters_node.rest
|
222
|
+
|
223
|
+
if rest
|
224
|
+
rest_name = rest.name || RestParameter::DEFAULT_NAME
|
225
|
+
parameters << RestParameter.new(name: rest_name)
|
226
|
+
end
|
227
|
+
|
228
|
+
keyword_rest = parameters_node.keyword_rest
|
229
|
+
|
230
|
+
if keyword_rest.is_a?(Prism::KeywordRestParameterNode)
|
231
|
+
keyword_rest_name = parameter_name(keyword_rest) || KeywordRestParameter::DEFAULT_NAME
|
232
|
+
parameters << KeywordRestParameter.new(name: keyword_rest_name)
|
233
|
+
end
|
234
|
+
|
235
|
+
parameters_node.posts.each do |post|
|
236
|
+
name = parameter_name(post)
|
237
|
+
next unless name
|
238
|
+
|
239
|
+
parameters << RequiredParameter.new(name: name)
|
240
|
+
end
|
241
|
+
|
242
|
+
block = parameters_node.block
|
243
|
+
parameters << BlockParameter.new(name: block.name || BlockParameter::DEFAULT_NAME) if block
|
244
|
+
|
245
|
+
parameters
|
139
246
|
end
|
247
|
+
|
248
|
+
sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(Symbol)) }
|
140
249
|
def parameter_name(node)
|
141
250
|
case node
|
142
|
-
when Prism::RequiredParameterNode
|
251
|
+
when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
|
252
|
+
Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode,
|
253
|
+
Prism::RestParameterNode, Prism::KeywordRestParameterNode
|
143
254
|
node.name
|
144
255
|
when Prism::MultiTargetNode
|
145
|
-
names =
|
256
|
+
names = node.lefts.map { |parameter_node| parameter_name(parameter_node) }
|
257
|
+
|
258
|
+
rest = node.rest
|
259
|
+
if rest.is_a?(Prism::SplatNode)
|
260
|
+
name = rest.expression&.slice
|
261
|
+
names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
|
262
|
+
end
|
263
|
+
|
264
|
+
names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
|
146
265
|
|
147
266
|
names_with_commas = names.join(", ")
|
148
267
|
:"(#{names_with_commas})"
|
@@ -84,6 +84,16 @@ module RubyIndexer
|
|
84
84
|
)
|
85
85
|
end
|
86
86
|
|
87
|
+
def test_indexables_does_not_include_non_ruby_files_inside_rubylibdir
|
88
|
+
path = Pathname.new(RbConfig::CONFIG["rubylibdir"]).join("extra_file.txt").to_s
|
89
|
+
FileUtils.touch(path)
|
90
|
+
indexables = @config.indexables
|
91
|
+
|
92
|
+
assert(indexables.none? { |indexable| indexable.full_path == path })
|
93
|
+
ensure
|
94
|
+
FileUtils.rm(T.must(path))
|
95
|
+
end
|
96
|
+
|
87
97
|
def test_paths_are_unique
|
88
98
|
@config.load_config
|
89
99
|
indexables = @config.indexables
|
@@ -246,5 +246,16 @@ module RubyIndexer
|
|
246
246
|
entry = T.must(entries.first).first
|
247
247
|
assert_equal("baz", entry.name)
|
248
248
|
end
|
249
|
+
|
250
|
+
def test_indexing_prism_fixtures_succeeds
|
251
|
+
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
252
|
+
|
253
|
+
fixtures.each do |fixture|
|
254
|
+
indexable_path = IndexablePath.new("", fixture)
|
255
|
+
@index.index_single(indexable_path)
|
256
|
+
end
|
257
|
+
|
258
|
+
refute_empty(@index.instance_variable_get(:@entries))
|
259
|
+
end
|
249
260
|
end
|
250
261
|
end
|
@@ -70,6 +70,178 @@ module RubyIndexer
|
|
70
70
|
assert_instance_of(Entry::RequiredParameter, parameter)
|
71
71
|
end
|
72
72
|
|
73
|
+
def test_method_with_optional_parameters
|
74
|
+
index(<<~RUBY)
|
75
|
+
class Foo
|
76
|
+
def bar(a = 123)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
82
|
+
entry = T.must(@index["bar"].first)
|
83
|
+
assert_equal(1, entry.parameters.length)
|
84
|
+
parameter = entry.parameters.first
|
85
|
+
assert_equal(:a, parameter.name)
|
86
|
+
assert_instance_of(Entry::OptionalParameter, parameter)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_method_with_keyword_parameters
|
90
|
+
index(<<~RUBY)
|
91
|
+
class Foo
|
92
|
+
def bar(a:, b: 123)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
RUBY
|
96
|
+
|
97
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
98
|
+
entry = T.must(@index["bar"].first)
|
99
|
+
assert_equal(2, entry.parameters.length)
|
100
|
+
a, b = entry.parameters
|
101
|
+
|
102
|
+
assert_equal(:a, a.name)
|
103
|
+
assert_instance_of(Entry::KeywordParameter, a)
|
104
|
+
|
105
|
+
assert_equal(:b, b.name)
|
106
|
+
assert_instance_of(Entry::OptionalKeywordParameter, b)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_method_with_rest_and_keyword_rest_parameters
|
110
|
+
index(<<~RUBY)
|
111
|
+
class Foo
|
112
|
+
def bar(*a, **b)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
116
|
+
|
117
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
118
|
+
entry = T.must(@index["bar"].first)
|
119
|
+
assert_equal(2, entry.parameters.length)
|
120
|
+
a, b = entry.parameters
|
121
|
+
|
122
|
+
assert_equal(:a, a.name)
|
123
|
+
assert_instance_of(Entry::RestParameter, a)
|
124
|
+
|
125
|
+
assert_equal(:b, b.name)
|
126
|
+
assert_instance_of(Entry::KeywordRestParameter, b)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_method_with_post_parameters
|
130
|
+
index(<<~RUBY)
|
131
|
+
class Foo
|
132
|
+
def bar(*a, b)
|
133
|
+
end
|
134
|
+
|
135
|
+
def baz(**a, b)
|
136
|
+
end
|
137
|
+
|
138
|
+
def qux(*a, (b, c))
|
139
|
+
end
|
140
|
+
RUBY
|
141
|
+
|
142
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
143
|
+
entry = T.must(@index["bar"].first)
|
144
|
+
assert_equal(2, entry.parameters.length)
|
145
|
+
a, b = entry.parameters
|
146
|
+
|
147
|
+
assert_equal(:a, a.name)
|
148
|
+
assert_instance_of(Entry::RestParameter, a)
|
149
|
+
|
150
|
+
assert_equal(:b, b.name)
|
151
|
+
assert_instance_of(Entry::RequiredParameter, b)
|
152
|
+
|
153
|
+
entry = T.must(@index["baz"].first)
|
154
|
+
assert_equal(2, entry.parameters.length)
|
155
|
+
a, b = entry.parameters
|
156
|
+
|
157
|
+
assert_equal(:a, a.name)
|
158
|
+
assert_instance_of(Entry::KeywordRestParameter, a)
|
159
|
+
|
160
|
+
assert_equal(:b, b.name)
|
161
|
+
assert_instance_of(Entry::RequiredParameter, b)
|
162
|
+
|
163
|
+
entry = T.must(@index["qux"].first)
|
164
|
+
assert_equal(2, entry.parameters.length)
|
165
|
+
_a, second = entry.parameters
|
166
|
+
|
167
|
+
assert_equal(:"(b, c)", second.name)
|
168
|
+
assert_instance_of(Entry::RequiredParameter, second)
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_method_with_destructured_rest_parameters
|
172
|
+
index(<<~RUBY)
|
173
|
+
class Foo
|
174
|
+
def bar((a, *b))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
RUBY
|
178
|
+
|
179
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
180
|
+
entry = T.must(@index["bar"].first)
|
181
|
+
assert_equal(1, entry.parameters.length)
|
182
|
+
param = entry.parameters.first
|
183
|
+
|
184
|
+
assert_equal(:"(a, *b)", param.name)
|
185
|
+
assert_instance_of(Entry::RequiredParameter, param)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_method_with_block_parameters
|
189
|
+
index(<<~RUBY)
|
190
|
+
class Foo
|
191
|
+
def bar(&block)
|
192
|
+
end
|
193
|
+
|
194
|
+
def baz(&)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
RUBY
|
198
|
+
|
199
|
+
entry = T.must(@index["bar"].first)
|
200
|
+
param = entry.parameters.first
|
201
|
+
assert_equal(:block, param.name)
|
202
|
+
assert_instance_of(Entry::BlockParameter, param)
|
203
|
+
|
204
|
+
entry = T.must(@index["baz"].first)
|
205
|
+
assert_equal(1, entry.parameters.length)
|
206
|
+
|
207
|
+
param = entry.parameters.first
|
208
|
+
assert_equal(Entry::BlockParameter::DEFAULT_NAME, param.name)
|
209
|
+
assert_instance_of(Entry::BlockParameter, param)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_method_with_anonymous_rest_parameters
|
213
|
+
index(<<~RUBY)
|
214
|
+
class Foo
|
215
|
+
def bar(*, **)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
RUBY
|
219
|
+
|
220
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
221
|
+
entry = T.must(@index["bar"].first)
|
222
|
+
assert_equal(2, entry.parameters.length)
|
223
|
+
first, second = entry.parameters
|
224
|
+
|
225
|
+
assert_equal(Entry::RestParameter::DEFAULT_NAME, first.name)
|
226
|
+
assert_instance_of(Entry::RestParameter, first)
|
227
|
+
|
228
|
+
assert_equal(Entry::KeywordRestParameter::DEFAULT_NAME, second.name)
|
229
|
+
assert_instance_of(Entry::KeywordRestParameter, second)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_method_with_forbidden_keyword_splat_parameter
|
233
|
+
index(<<~RUBY)
|
234
|
+
class Foo
|
235
|
+
def bar(**nil)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
RUBY
|
239
|
+
|
240
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
241
|
+
entry = T.must(@index["bar"].first)
|
242
|
+
assert_empty(entry.parameters)
|
243
|
+
end
|
244
|
+
|
73
245
|
def test_keeps_track_of_method_owner
|
74
246
|
index(<<~RUBY)
|
75
247
|
class Foo
|
@@ -83,5 +255,35 @@ module RubyIndexer
|
|
83
255
|
|
84
256
|
assert_equal("Foo", owner_name)
|
85
257
|
end
|
258
|
+
|
259
|
+
def test_keeps_track_of_attributes
|
260
|
+
index(<<~RUBY)
|
261
|
+
class Foo
|
262
|
+
# Hello there
|
263
|
+
attr_reader :bar, :other
|
264
|
+
attr_writer :baz
|
265
|
+
attr_accessor :qux
|
266
|
+
end
|
267
|
+
RUBY
|
268
|
+
|
269
|
+
assert_entry("bar", Entry::Accessor, "/fake/path/foo.rb:2-15:2-18")
|
270
|
+
assert_equal("Hello there", @index["bar"].first.comments.join("\n"))
|
271
|
+
assert_entry("other", Entry::Accessor, "/fake/path/foo.rb:2-21:2-26")
|
272
|
+
assert_equal("Hello there", @index["other"].first.comments.join("\n"))
|
273
|
+
assert_entry("baz=", Entry::Accessor, "/fake/path/foo.rb:3-15:3-18")
|
274
|
+
assert_entry("qux", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
275
|
+
assert_entry("qux=", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_ignores_attributes_invoked_on_constant
|
279
|
+
index(<<~RUBY)
|
280
|
+
class Foo
|
281
|
+
end
|
282
|
+
|
283
|
+
Foo.attr_reader :bar
|
284
|
+
RUBY
|
285
|
+
|
286
|
+
assert_no_entry("bar")
|
287
|
+
end
|
86
288
|
end
|
87
289
|
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -41,8 +41,8 @@ module RubyLsp
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Discovers and loads all addons. Returns the list of activated addons
|
44
|
-
sig { returns(T::Array[Addon]) }
|
45
|
-
def load_addons
|
44
|
+
sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
|
45
|
+
def load_addons(message_queue)
|
46
46
|
# Require all addons entry points, which should be placed under
|
47
47
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
|
48
48
|
Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
|
@@ -55,7 +55,7 @@ module RubyLsp
|
|
55
55
|
# Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
|
56
56
|
# fail to boot the server
|
57
57
|
addons.each do |addon|
|
58
|
-
addon.activate
|
58
|
+
addon.activate(message_queue)
|
59
59
|
nil
|
60
60
|
rescue => e
|
61
61
|
addon.add_error(e)
|
@@ -94,8 +94,8 @@ module RubyLsp
|
|
94
94
|
|
95
95
|
# Each addon should implement `MyAddon#activate` and use to perform any sort of initialization, such as
|
96
96
|
# reading information into memory or even spawning a separate process
|
97
|
-
sig { abstract.void }
|
98
|
-
def activate; end
|
97
|
+
sig { abstract.params(message_queue: Thread::Queue).void }
|
98
|
+
def activate(message_queue); end
|
99
99
|
|
100
100
|
# Each addon should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
|
101
101
|
# child process
|
@@ -111,10 +111,9 @@ module RubyLsp
|
|
111
111
|
overridable.params(
|
112
112
|
uri: URI::Generic,
|
113
113
|
dispatcher: Prism::Dispatcher,
|
114
|
-
message_queue: Thread::Queue,
|
115
114
|
).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
|
116
115
|
end
|
117
|
-
def create_code_lens_listener(uri, dispatcher
|
116
|
+
def create_code_lens_listener(uri, dispatcher); end
|
118
117
|
|
119
118
|
# Creates a new Hover listener. This method is invoked on every Hover request
|
120
119
|
sig do
|
@@ -122,19 +121,17 @@ module RubyLsp
|
|
122
121
|
nesting: T::Array[String],
|
123
122
|
index: RubyIndexer::Index,
|
124
123
|
dispatcher: Prism::Dispatcher,
|
125
|
-
message_queue: Thread::Queue,
|
126
124
|
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
|
127
125
|
end
|
128
|
-
def create_hover_listener(nesting, index, dispatcher
|
126
|
+
def create_hover_listener(nesting, index, dispatcher); end
|
129
127
|
|
130
128
|
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
|
131
129
|
sig do
|
132
130
|
overridable.params(
|
133
131
|
dispatcher: Prism::Dispatcher,
|
134
|
-
message_queue: Thread::Queue,
|
135
132
|
).returns(T.nilable(Listener[T::Array[Interface::DocumentSymbol]]))
|
136
133
|
end
|
137
|
-
def create_document_symbol_listener(dispatcher
|
134
|
+
def create_document_symbol_listener(dispatcher); end
|
138
135
|
|
139
136
|
# Creates a new Definition listener. This method is invoked on every Definition request
|
140
137
|
sig do
|
@@ -143,9 +140,8 @@ module RubyLsp
|
|
143
140
|
nesting: T::Array[String],
|
144
141
|
index: RubyIndexer::Index,
|
145
142
|
dispatcher: Prism::Dispatcher,
|
146
|
-
message_queue: Thread::Queue,
|
147
143
|
).returns(T.nilable(Listener[T.nilable(T.any(T::Array[Interface::Location], Interface::Location))]))
|
148
144
|
end
|
149
|
-
def create_definition_listener(uri, nesting, index, dispatcher
|
145
|
+
def create_definition_listener(uri, nesting, index, dispatcher); end
|
150
146
|
end
|
151
147
|
end
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -24,6 +24,9 @@ module RubyLsp
|
|
24
24
|
sig { returns(URI::Generic) }
|
25
25
|
attr_reader :uri
|
26
26
|
|
27
|
+
sig { returns(String) }
|
28
|
+
attr_reader :encoding
|
29
|
+
|
27
30
|
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: String).void }
|
28
31
|
def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)
|
29
32
|
@cache = T.let({}, T::Hash[String, T.untyped])
|