ruby-lsp 0.17.3 → 0.17.5
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/README.md +4 -0
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +251 -100
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +173 -114
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +337 -77
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +43 -14
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +79 -3
- data/lib/ruby_indexer/test/index_test.rb +563 -29
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +75 -25
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +38 -2
- data/lib/ruby_indexer/test/test_case.rb +1 -5
- data/lib/ruby_lsp/addon.rb +13 -1
- data/lib/ruby_lsp/document.rb +50 -23
- data/lib/ruby_lsp/erb_document.rb +125 -0
- data/lib/ruby_lsp/global_state.rb +11 -4
- data/lib/ruby_lsp/internal.rb +3 -0
- data/lib/ruby_lsp/listeners/completion.rb +69 -34
- data/lib/ruby_lsp/listeners/definition.rb +34 -23
- data/lib/ruby_lsp/listeners/hover.rb +14 -7
- data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
- data/lib/ruby_lsp/node_context.rb +6 -1
- data/lib/ruby_lsp/requests/code_action_resolve.rb +2 -2
- data/lib/ruby_lsp/requests/completion.rb +6 -5
- data/lib/ruby_lsp/requests/completion_resolve.rb +7 -4
- data/lib/ruby_lsp/requests/definition.rb +4 -3
- data/lib/ruby_lsp/requests/formatting.rb +2 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -2
- data/lib/ruby_lsp/requests/support/common.rb +19 -1
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +87 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/ruby_document.rb +10 -0
- data/lib/ruby_lsp/server.rb +95 -26
- data/lib/ruby_lsp/store.rb +23 -8
- data/lib/ruby_lsp/test_helper.rb +3 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- metadata +10 -6
@@ -22,6 +22,8 @@ module RubyIndexer
|
|
22
22
|
sig { returns(RubyIndexer::Location) }
|
23
23
|
attr_reader :location
|
24
24
|
|
25
|
+
alias_method :name_location, :location
|
26
|
+
|
25
27
|
sig { returns(T::Array[String]) }
|
26
28
|
attr_reader :comments
|
27
29
|
|
@@ -57,6 +59,16 @@ module RubyIndexer
|
|
57
59
|
)
|
58
60
|
end
|
59
61
|
|
62
|
+
sig { returns(T::Boolean) }
|
63
|
+
def public?
|
64
|
+
visibility == Visibility::PUBLIC
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { returns(T::Boolean) }
|
68
|
+
def protected?
|
69
|
+
visibility == Visibility::PROTECTED
|
70
|
+
end
|
71
|
+
|
60
72
|
sig { returns(T::Boolean) }
|
61
73
|
def private?
|
62
74
|
visibility == Visibility::PRIVATE
|
@@ -84,7 +96,6 @@ module RubyIndexer
|
|
84
96
|
|
85
97
|
class Include < ModuleOperation; end
|
86
98
|
class Prepend < ModuleOperation; end
|
87
|
-
class Extend < ModuleOperation; end
|
88
99
|
|
89
100
|
class Namespace < Entry
|
90
101
|
extend T::Sig
|
@@ -95,20 +106,39 @@ module RubyIndexer
|
|
95
106
|
sig { returns(T::Array[String]) }
|
96
107
|
attr_reader :nesting
|
97
108
|
|
109
|
+
# Returns the location of the constant name, excluding the parent class or the body
|
110
|
+
sig { returns(Location) }
|
111
|
+
attr_reader :name_location
|
112
|
+
|
98
113
|
sig do
|
99
114
|
params(
|
100
115
|
nesting: T::Array[String],
|
101
116
|
file_path: String,
|
102
117
|
location: T.any(Prism::Location, RubyIndexer::Location),
|
118
|
+
name_location: T.any(Prism::Location, Location),
|
103
119
|
comments: T::Array[String],
|
104
120
|
).void
|
105
121
|
end
|
106
|
-
def initialize(nesting, file_path, location, comments)
|
122
|
+
def initialize(nesting, file_path, location, name_location, comments)
|
107
123
|
@name = T.let(nesting.join("::"), String)
|
108
124
|
# The original nesting where this namespace was discovered
|
109
125
|
@nesting = nesting
|
110
126
|
|
111
127
|
super(@name, file_path, location, comments)
|
128
|
+
|
129
|
+
@name_location = T.let(
|
130
|
+
if name_location.is_a?(Prism::Location)
|
131
|
+
Location.new(
|
132
|
+
name_location.start_line,
|
133
|
+
name_location.end_line,
|
134
|
+
name_location.start_column,
|
135
|
+
name_location.end_column,
|
136
|
+
)
|
137
|
+
else
|
138
|
+
name_location
|
139
|
+
end,
|
140
|
+
RubyIndexer::Location,
|
141
|
+
)
|
112
142
|
end
|
113
143
|
|
114
144
|
sig { returns(T::Array[String]) }
|
@@ -146,14 +176,14 @@ module RubyIndexer
|
|
146
176
|
nesting: T::Array[String],
|
147
177
|
file_path: String,
|
148
178
|
location: T.any(Prism::Location, RubyIndexer::Location),
|
179
|
+
name_location: T.any(Prism::Location, Location),
|
149
180
|
comments: T::Array[String],
|
150
181
|
parent_class: T.nilable(String),
|
151
182
|
).void
|
152
183
|
end
|
153
|
-
def initialize(nesting, file_path, location, comments, parent_class)
|
154
|
-
super(nesting, file_path, location, comments)
|
155
|
-
|
156
|
-
@parent_class = T.let(parent_class, T.nilable(String))
|
184
|
+
def initialize(nesting, file_path, location, name_location, comments, parent_class) # rubocop:disable Metrics/ParameterLists
|
185
|
+
super(nesting, file_path, location, name_location, comments)
|
186
|
+
@parent_class = parent_class
|
157
187
|
end
|
158
188
|
|
159
189
|
sig { override.returns(Integer) }
|
@@ -162,6 +192,28 @@ module RubyIndexer
|
|
162
192
|
end
|
163
193
|
end
|
164
194
|
|
195
|
+
class SingletonClass < Class
|
196
|
+
extend T::Sig
|
197
|
+
|
198
|
+
sig { params(location: Prism::Location, name_location: Prism::Location, comments: T::Array[String]).void }
|
199
|
+
def update_singleton_information(location, name_location, comments)
|
200
|
+
# Create a new RubyIndexer::Location object from the Prism location
|
201
|
+
@location = Location.new(
|
202
|
+
location.start_line,
|
203
|
+
location.end_line,
|
204
|
+
location.start_column,
|
205
|
+
location.end_column,
|
206
|
+
)
|
207
|
+
@name_location = Location.new(
|
208
|
+
name_location.start_line,
|
209
|
+
name_location.end_line,
|
210
|
+
name_location.start_column,
|
211
|
+
name_location.end_column,
|
212
|
+
)
|
213
|
+
@comments.concat(comments)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
165
217
|
class Constant < Entry
|
166
218
|
end
|
167
219
|
|
@@ -190,6 +242,10 @@ module RubyIndexer
|
|
190
242
|
|
191
243
|
# An optional method parameter, e.g. `def foo(a = 123)`
|
192
244
|
class OptionalParameter < Parameter
|
245
|
+
sig { override.returns(Symbol) }
|
246
|
+
def decorated_name
|
247
|
+
:"#{@name} = <default>"
|
248
|
+
end
|
193
249
|
end
|
194
250
|
|
195
251
|
# An required keyword method parameter, e.g. `def foo(a:)`
|
@@ -204,7 +260,7 @@ module RubyIndexer
|
|
204
260
|
class OptionalKeywordParameter < Parameter
|
205
261
|
sig { override.returns(Symbol) }
|
206
262
|
def decorated_name
|
207
|
-
:"#{@name}:"
|
263
|
+
:"#{@name}: <default>"
|
208
264
|
end
|
209
265
|
end
|
210
266
|
|
@@ -247,6 +303,11 @@ module RubyIndexer
|
|
247
303
|
sig { returns(T.nilable(Entry::Namespace)) }
|
248
304
|
attr_reader :owner
|
249
305
|
|
306
|
+
sig { returns(T::Array[RubyIndexer::Entry::Parameter]) }
|
307
|
+
def parameters
|
308
|
+
T.must(signatures.first).parameters
|
309
|
+
end
|
310
|
+
|
250
311
|
sig do
|
251
312
|
params(
|
252
313
|
name: String,
|
@@ -263,140 +324,75 @@ module RubyIndexer
|
|
263
324
|
@owner = owner
|
264
325
|
end
|
265
326
|
|
266
|
-
sig { abstract.returns(T::Array[
|
267
|
-
def
|
327
|
+
sig { abstract.returns(T::Array[Entry::Signature]) }
|
328
|
+
def signatures; end
|
329
|
+
|
330
|
+
sig { returns(String) }
|
331
|
+
def decorated_parameters
|
332
|
+
first_signature = signatures.first
|
333
|
+
return "()" unless first_signature
|
334
|
+
|
335
|
+
"(#{first_signature.format})"
|
336
|
+
end
|
268
337
|
end
|
269
338
|
|
270
339
|
class Accessor < Member
|
271
340
|
extend T::Sig
|
272
341
|
|
273
|
-
sig { override.returns(T::Array[
|
274
|
-
def
|
275
|
-
|
276
|
-
|
277
|
-
|
342
|
+
sig { override.returns(T::Array[Signature]) }
|
343
|
+
def signatures
|
344
|
+
@signatures ||= T.let(
|
345
|
+
begin
|
346
|
+
params = []
|
347
|
+
params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
|
348
|
+
[Entry::Signature.new(params)]
|
349
|
+
end,
|
350
|
+
T.nilable(T::Array[Signature]),
|
351
|
+
)
|
278
352
|
end
|
279
353
|
end
|
280
354
|
|
281
355
|
class Method < Member
|
282
356
|
extend T::Sig
|
283
|
-
extend T::Helpers
|
284
357
|
|
285
|
-
|
358
|
+
sig { override.returns(T::Array[Signature]) }
|
359
|
+
attr_reader :signatures
|
286
360
|
|
287
|
-
|
288
|
-
|
361
|
+
# Returns the location of the method name, excluding parameters or the body
|
362
|
+
sig { returns(Location) }
|
363
|
+
attr_reader :name_location
|
289
364
|
|
290
365
|
sig do
|
291
366
|
params(
|
292
367
|
name: String,
|
293
368
|
file_path: String,
|
294
369
|
location: T.any(Prism::Location, RubyIndexer::Location),
|
370
|
+
name_location: T.any(Prism::Location, Location),
|
295
371
|
comments: T::Array[String],
|
296
|
-
|
372
|
+
signatures: T::Array[Signature],
|
297
373
|
visibility: Visibility,
|
298
374
|
owner: T.nilable(Entry::Namespace),
|
299
375
|
).void
|
300
376
|
end
|
301
|
-
def initialize(name, file_path, location, comments,
|
377
|
+
def initialize(name, file_path, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
|
302
378
|
super(name, file_path, location, comments, visibility, owner)
|
303
|
-
|
304
|
-
@
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
next unless name
|
318
|
-
|
319
|
-
parameters << RequiredParameter.new(name: name)
|
320
|
-
end
|
321
|
-
|
322
|
-
parameters_node.optionals.each do |optional|
|
323
|
-
name = parameter_name(optional)
|
324
|
-
next unless name
|
325
|
-
|
326
|
-
parameters << OptionalParameter.new(name: name)
|
327
|
-
end
|
328
|
-
|
329
|
-
parameters_node.keywords.each do |keyword|
|
330
|
-
name = parameter_name(keyword)
|
331
|
-
next unless name
|
332
|
-
|
333
|
-
case keyword
|
334
|
-
when Prism::RequiredKeywordParameterNode
|
335
|
-
parameters << KeywordParameter.new(name: name)
|
336
|
-
when Prism::OptionalKeywordParameterNode
|
337
|
-
parameters << OptionalKeywordParameter.new(name: name)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
rest = parameters_node.rest
|
342
|
-
|
343
|
-
if rest.is_a?(Prism::RestParameterNode)
|
344
|
-
rest_name = rest.name || RestParameter::DEFAULT_NAME
|
345
|
-
parameters << RestParameter.new(name: rest_name)
|
346
|
-
end
|
347
|
-
|
348
|
-
keyword_rest = parameters_node.keyword_rest
|
349
|
-
|
350
|
-
if keyword_rest.is_a?(Prism::KeywordRestParameterNode)
|
351
|
-
keyword_rest_name = parameter_name(keyword_rest) || KeywordRestParameter::DEFAULT_NAME
|
352
|
-
parameters << KeywordRestParameter.new(name: keyword_rest_name)
|
353
|
-
end
|
354
|
-
|
355
|
-
parameters_node.posts.each do |post|
|
356
|
-
name = parameter_name(post)
|
357
|
-
next unless name
|
358
|
-
|
359
|
-
parameters << RequiredParameter.new(name: name)
|
360
|
-
end
|
361
|
-
|
362
|
-
block = parameters_node.block
|
363
|
-
parameters << BlockParameter.new(name: block.name || BlockParameter::DEFAULT_NAME) if block
|
364
|
-
|
365
|
-
parameters
|
366
|
-
end
|
367
|
-
|
368
|
-
sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(Symbol)) }
|
369
|
-
def parameter_name(node)
|
370
|
-
case node
|
371
|
-
when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
|
372
|
-
Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode,
|
373
|
-
Prism::RestParameterNode, Prism::KeywordRestParameterNode
|
374
|
-
node.name
|
375
|
-
when Prism::MultiTargetNode
|
376
|
-
names = node.lefts.map { |parameter_node| parameter_name(parameter_node) }
|
377
|
-
|
378
|
-
rest = node.rest
|
379
|
-
if rest.is_a?(Prism::SplatNode)
|
380
|
-
name = rest.expression&.slice
|
381
|
-
names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
|
382
|
-
end
|
383
|
-
|
384
|
-
names << nil if rest.is_a?(Prism::ImplicitRestNode)
|
385
|
-
|
386
|
-
names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
|
387
|
-
|
388
|
-
names_with_commas = names.join(", ")
|
389
|
-
:"(#{names_with_commas})"
|
390
|
-
end
|
379
|
+
@signatures = signatures
|
380
|
+
@name_location = T.let(
|
381
|
+
if name_location.is_a?(Prism::Location)
|
382
|
+
Location.new(
|
383
|
+
name_location.start_line,
|
384
|
+
name_location.end_line,
|
385
|
+
name_location.start_column,
|
386
|
+
name_location.end_column,
|
387
|
+
)
|
388
|
+
else
|
389
|
+
name_location
|
390
|
+
end,
|
391
|
+
RubyIndexer::Location,
|
392
|
+
)
|
391
393
|
end
|
392
394
|
end
|
393
395
|
|
394
|
-
class SingletonMethod < Method
|
395
|
-
end
|
396
|
-
|
397
|
-
class InstanceMethod < Method
|
398
|
-
end
|
399
|
-
|
400
396
|
# An UnresolvedAlias points to a constant alias with a right hand side that has not yet been resolved. For
|
401
397
|
# example, if we find
|
402
398
|
#
|
@@ -470,6 +466,9 @@ module RubyIndexer
|
|
470
466
|
end
|
471
467
|
end
|
472
468
|
|
469
|
+
# An unresolved method alias is an alias entry for which we aren't sure what the right hand side points to yet. For
|
470
|
+
# example, if we have `alias a b`, we create an unresolved alias for `a` because we aren't sure immediate what `b`
|
471
|
+
# is referring to
|
473
472
|
class UnresolvedMethodAlias < Entry
|
474
473
|
extend T::Sig
|
475
474
|
|
@@ -497,5 +496,65 @@ module RubyIndexer
|
|
497
496
|
@owner = owner
|
498
497
|
end
|
499
498
|
end
|
499
|
+
|
500
|
+
# A method alias is a resolved alias entry that points to the exact method target it refers to
|
501
|
+
class MethodAlias < Entry
|
502
|
+
extend T::Sig
|
503
|
+
|
504
|
+
sig { returns(T.any(Member, MethodAlias)) }
|
505
|
+
attr_reader :target
|
506
|
+
|
507
|
+
sig { returns(T.nilable(Entry::Namespace)) }
|
508
|
+
attr_reader :owner
|
509
|
+
|
510
|
+
sig { params(target: T.any(Member, MethodAlias), unresolved_alias: UnresolvedMethodAlias).void }
|
511
|
+
def initialize(target, unresolved_alias)
|
512
|
+
full_comments = ["Alias for #{target.name}\n"]
|
513
|
+
full_comments.concat(unresolved_alias.comments)
|
514
|
+
full_comments << "\n"
|
515
|
+
full_comments.concat(target.comments)
|
516
|
+
|
517
|
+
super(
|
518
|
+
unresolved_alias.new_name,
|
519
|
+
unresolved_alias.file_path,
|
520
|
+
unresolved_alias.location,
|
521
|
+
full_comments,
|
522
|
+
)
|
523
|
+
|
524
|
+
@target = target
|
525
|
+
@owner = T.let(unresolved_alias.owner, T.nilable(Entry::Namespace))
|
526
|
+
end
|
527
|
+
|
528
|
+
sig { returns(T::Array[Parameter]) }
|
529
|
+
def parameters
|
530
|
+
@target.parameters
|
531
|
+
end
|
532
|
+
|
533
|
+
sig { returns(String) }
|
534
|
+
def decorated_parameters
|
535
|
+
@target.decorated_parameters
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
# Ruby doesn't support method overloading, so a method will have only one signature.
|
540
|
+
# However RBS can represent the concept of method overloading, with different return types based on the arguments
|
541
|
+
# passed, so we need to store all the signatures.
|
542
|
+
class Signature
|
543
|
+
extend T::Sig
|
544
|
+
|
545
|
+
sig { returns(T::Array[Parameter]) }
|
546
|
+
attr_reader :parameters
|
547
|
+
|
548
|
+
sig { params(parameters: T::Array[Parameter]).void }
|
549
|
+
def initialize(parameters)
|
550
|
+
@parameters = parameters
|
551
|
+
end
|
552
|
+
|
553
|
+
# Returns a string with the decorated names of the parameters of this member. E.g.: `(a, b = 1, c: 2)`
|
554
|
+
sig { returns(String) }
|
555
|
+
def format
|
556
|
+
@parameters.map(&:decorated_name).join(", ")
|
557
|
+
end
|
558
|
+
end
|
500
559
|
end
|
501
560
|
end
|