ruby-lsp 0.17.3 → 0.17.4
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/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +241 -91
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +74 -102
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +81 -19
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +50 -2
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
- data/lib/ruby_indexer/test/index_test.rb +326 -27
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +54 -24
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +27 -2
- data/lib/ruby_lsp/document.rb +37 -8
- data/lib/ruby_lsp/global_state.rb +7 -3
- data/lib/ruby_lsp/internal.rb +1 -0
- data/lib/ruby_lsp/listeners/completion.rb +53 -14
- data/lib/ruby_lsp/listeners/definition.rb +11 -7
- 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/completion.rb +5 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
- 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 +91 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/server.rb +54 -15
- data/lib/ruby_lsp/test_helper.rb +1 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71204369ec5201376f1af11875a2e1bf16df56a31719ea78932a7f5f6e9c7e5c
|
4
|
+
data.tar.gz: d83e299ade275415fe4cac25abe78f7ee7ec622c47cc1699d42b3b772816fdba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3ac517cb1c711dc1a5ddf2c4027f705e393e30028b9ae7063b18a5f51362fd4d7277607d19d8ca7a9a3c9146960bd612a02ed4a8933c8223a42daf3dfe5e63b
|
7
|
+
data.tar.gz: 0c4408865d1894547aeedfc0441fa558a8281f54e7e26c38b619e67fd67bfc3bed49aa27dc06d8b89924c7ee8db4452b5cd2f810c0dfb01157eef127910b2182
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.17.
|
1
|
+
0.17.4
|
@@ -5,6 +5,9 @@ module RubyIndexer
|
|
5
5
|
class DeclarationListener
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
+
OBJECT_NESTING = T.let(["Object"].freeze, T::Array[String])
|
9
|
+
BASIC_OBJECT_NESTING = T.let(["BasicObject"].freeze, T::Array[String])
|
10
|
+
|
8
11
|
sig do
|
9
12
|
params(index: Index, dispatcher: Prism::Dispatcher, parse_result: Prism::ParseResult, file_path: String).void
|
10
13
|
end
|
@@ -33,6 +36,8 @@ module RubyIndexer
|
|
33
36
|
:on_class_node_leave,
|
34
37
|
:on_module_node_enter,
|
35
38
|
:on_module_node_leave,
|
39
|
+
:on_singleton_class_node_enter,
|
40
|
+
:on_singleton_class_node_leave,
|
36
41
|
:on_def_node_enter,
|
37
42
|
:on_def_node_leave,
|
38
43
|
:on_call_node_enter,
|
@@ -64,15 +69,26 @@ module RubyIndexer
|
|
64
69
|
comments = collect_comments(node)
|
65
70
|
|
66
71
|
superclass = node.superclass
|
72
|
+
|
73
|
+
nesting = name.start_with?("::") ? [name.delete_prefix("::")] : @stack + [name.delete_prefix("::")]
|
74
|
+
|
67
75
|
parent_class = case superclass
|
68
76
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
69
77
|
superclass.slice
|
70
78
|
else
|
71
|
-
|
79
|
+
case nesting
|
80
|
+
when OBJECT_NESTING
|
81
|
+
# When Object is reopened, its parent class should still be the top-level BasicObject
|
82
|
+
"::BasicObject"
|
83
|
+
when BASIC_OBJECT_NESTING
|
84
|
+
# When BasicObject is reopened, its parent class should still be nil
|
85
|
+
nil
|
86
|
+
else
|
87
|
+
# Otherwise, the parent class should be the top-level Object
|
88
|
+
"::Object"
|
89
|
+
end
|
72
90
|
end
|
73
91
|
|
74
|
-
nesting = name.start_with?("::") ? [name.delete_prefix("::")] : @stack + [name.delete_prefix("::")]
|
75
|
-
|
76
92
|
entry = Entry::Class.new(
|
77
93
|
nesting,
|
78
94
|
@file_path,
|
@@ -82,7 +98,7 @@ module RubyIndexer
|
|
82
98
|
)
|
83
99
|
|
84
100
|
@owner_stack << entry
|
85
|
-
@index
|
101
|
+
@index.add(entry)
|
86
102
|
@stack << name
|
87
103
|
end
|
88
104
|
|
@@ -104,7 +120,7 @@ module RubyIndexer
|
|
104
120
|
entry = Entry::Module.new(nesting, @file_path, node.location, comments)
|
105
121
|
|
106
122
|
@owner_stack << entry
|
107
|
-
@index
|
123
|
+
@index.add(entry)
|
108
124
|
@stack << name
|
109
125
|
end
|
110
126
|
|
@@ -115,6 +131,37 @@ module RubyIndexer
|
|
115
131
|
@visibility_stack.pop
|
116
132
|
end
|
117
133
|
|
134
|
+
sig { params(node: Prism::SingletonClassNode).void }
|
135
|
+
def on_singleton_class_node_enter(node)
|
136
|
+
@visibility_stack.push(Entry::Visibility::PUBLIC)
|
137
|
+
|
138
|
+
current_owner = @owner_stack.last
|
139
|
+
|
140
|
+
if current_owner
|
141
|
+
expression = node.expression
|
142
|
+
@stack << (expression.is_a?(Prism::SelfNode) ? "<Class:#{@stack.last}>" : "<Class:#{expression.slice}>")
|
143
|
+
|
144
|
+
existing_entries = T.cast(@index[@stack.join("::")], T.nilable(T::Array[Entry::SingletonClass]))
|
145
|
+
|
146
|
+
if existing_entries
|
147
|
+
entry = T.must(existing_entries.first)
|
148
|
+
entry.update_singleton_information(node.location, collect_comments(node))
|
149
|
+
else
|
150
|
+
entry = Entry::SingletonClass.new(@stack, @file_path, node.location, collect_comments(node), nil)
|
151
|
+
@index.add(entry, skip_prefix_tree: true)
|
152
|
+
end
|
153
|
+
|
154
|
+
@owner_stack << entry
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
sig { params(node: Prism::SingletonClassNode).void }
|
159
|
+
def on_singleton_class_node_leave(node)
|
160
|
+
@stack.pop
|
161
|
+
@owner_stack.pop
|
162
|
+
@visibility_stack.pop
|
163
|
+
end
|
164
|
+
|
118
165
|
sig { params(node: Prism::MultiWriteNode).void }
|
119
166
|
def on_multi_write_node_enter(node)
|
120
167
|
value = node.value
|
@@ -246,119 +293,110 @@ module RubyIndexer
|
|
246
293
|
|
247
294
|
case node.receiver
|
248
295
|
when nil
|
249
|
-
@index
|
296
|
+
@index.add(Entry::Method.new(
|
250
297
|
method_name,
|
251
298
|
@file_path,
|
252
299
|
node.location,
|
253
300
|
comments,
|
254
|
-
node.parameters,
|
301
|
+
list_params(node.parameters),
|
255
302
|
current_visibility,
|
256
303
|
@owner_stack.last,
|
257
|
-
)
|
304
|
+
))
|
258
305
|
when Prism::SelfNode
|
259
|
-
|
306
|
+
singleton = singleton_klass
|
307
|
+
|
308
|
+
@index.add(Entry::Method.new(
|
260
309
|
method_name,
|
261
310
|
@file_path,
|
262
311
|
node.location,
|
263
312
|
comments,
|
264
|
-
node.parameters,
|
313
|
+
list_params(node.parameters),
|
265
314
|
current_visibility,
|
266
|
-
|
267
|
-
)
|
315
|
+
singleton,
|
316
|
+
))
|
317
|
+
|
318
|
+
if singleton
|
319
|
+
@owner_stack << singleton
|
320
|
+
@stack << "<Class:#{@stack.last}>"
|
321
|
+
end
|
268
322
|
end
|
269
323
|
end
|
270
324
|
|
271
325
|
sig { params(node: Prism::DefNode).void }
|
272
326
|
def on_def_node_leave(node)
|
273
327
|
@inside_def = false
|
328
|
+
|
329
|
+
if node.receiver.is_a?(Prism::SelfNode)
|
330
|
+
@owner_stack.pop
|
331
|
+
@stack.pop
|
332
|
+
end
|
274
333
|
end
|
275
334
|
|
276
335
|
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
277
336
|
def on_instance_variable_write_node_enter(node)
|
278
|
-
|
279
|
-
return if name == "@"
|
280
|
-
|
281
|
-
@index << Entry::InstanceVariable.new(
|
282
|
-
name,
|
283
|
-
@file_path,
|
284
|
-
node.name_loc,
|
285
|
-
collect_comments(node),
|
286
|
-
@owner_stack.last,
|
287
|
-
)
|
337
|
+
handle_instance_variable(node, node.name_loc)
|
288
338
|
end
|
289
339
|
|
290
340
|
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
291
341
|
def on_instance_variable_and_write_node_enter(node)
|
292
|
-
|
293
|
-
return if name == "@"
|
294
|
-
|
295
|
-
@index << Entry::InstanceVariable.new(
|
296
|
-
name,
|
297
|
-
@file_path,
|
298
|
-
node.name_loc,
|
299
|
-
collect_comments(node),
|
300
|
-
@owner_stack.last,
|
301
|
-
)
|
342
|
+
handle_instance_variable(node, node.name_loc)
|
302
343
|
end
|
303
344
|
|
304
345
|
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
305
346
|
def on_instance_variable_operator_write_node_enter(node)
|
306
|
-
|
307
|
-
return if name == "@"
|
308
|
-
|
309
|
-
@index << Entry::InstanceVariable.new(
|
310
|
-
name,
|
311
|
-
@file_path,
|
312
|
-
node.name_loc,
|
313
|
-
collect_comments(node),
|
314
|
-
@owner_stack.last,
|
315
|
-
)
|
347
|
+
handle_instance_variable(node, node.name_loc)
|
316
348
|
end
|
317
349
|
|
318
350
|
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
319
351
|
def on_instance_variable_or_write_node_enter(node)
|
320
|
-
|
321
|
-
return if name == "@"
|
322
|
-
|
323
|
-
@index << Entry::InstanceVariable.new(
|
324
|
-
name,
|
325
|
-
@file_path,
|
326
|
-
node.name_loc,
|
327
|
-
collect_comments(node),
|
328
|
-
@owner_stack.last,
|
329
|
-
)
|
352
|
+
handle_instance_variable(node, node.name_loc)
|
330
353
|
end
|
331
354
|
|
332
355
|
sig { params(node: Prism::InstanceVariableTargetNode).void }
|
333
356
|
def on_instance_variable_target_node_enter(node)
|
334
|
-
|
335
|
-
return if name == "@"
|
336
|
-
|
337
|
-
@index << Entry::InstanceVariable.new(
|
338
|
-
name,
|
339
|
-
@file_path,
|
340
|
-
node.location,
|
341
|
-
collect_comments(node),
|
342
|
-
@owner_stack.last,
|
343
|
-
)
|
357
|
+
handle_instance_variable(node, node.location)
|
344
358
|
end
|
345
359
|
|
346
360
|
sig { params(node: Prism::AliasMethodNode).void }
|
347
361
|
def on_alias_method_node_enter(node)
|
348
362
|
method_name = node.new_name.slice
|
349
363
|
comments = collect_comments(node)
|
350
|
-
@index
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
364
|
+
@index.add(
|
365
|
+
Entry::UnresolvedMethodAlias.new(
|
366
|
+
method_name,
|
367
|
+
node.old_name.slice,
|
368
|
+
@owner_stack.last,
|
369
|
+
@file_path,
|
370
|
+
node.new_name.location,
|
371
|
+
comments,
|
372
|
+
),
|
357
373
|
)
|
358
374
|
end
|
359
375
|
|
360
376
|
private
|
361
377
|
|
378
|
+
sig do
|
379
|
+
params(
|
380
|
+
node: T.any(
|
381
|
+
Prism::InstanceVariableAndWriteNode,
|
382
|
+
Prism::InstanceVariableOperatorWriteNode,
|
383
|
+
Prism::InstanceVariableOrWriteNode,
|
384
|
+
Prism::InstanceVariableTargetNode,
|
385
|
+
Prism::InstanceVariableWriteNode,
|
386
|
+
),
|
387
|
+
loc: Prism::Location,
|
388
|
+
).void
|
389
|
+
end
|
390
|
+
def handle_instance_variable(node, loc)
|
391
|
+
name = node.name.to_s
|
392
|
+
return if name == "@"
|
393
|
+
|
394
|
+
# When instance variables are declared inside the class body, they turn into class instance variables rather than
|
395
|
+
# regular instance variables
|
396
|
+
owner = @inside_def ? @owner_stack.last : singleton_klass
|
397
|
+
@index.add(Entry::InstanceVariable.new(name, @file_path, loc, collect_comments(node), owner))
|
398
|
+
end
|
399
|
+
|
362
400
|
sig { params(node: Prism::CallNode).void }
|
363
401
|
def handle_private_constant(node)
|
364
402
|
arguments = node.arguments&.arguments
|
@@ -411,13 +449,15 @@ module RubyIndexer
|
|
411
449
|
return unless old_name_value
|
412
450
|
|
413
451
|
comments = collect_comments(node)
|
414
|
-
@index
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
452
|
+
@index.add(
|
453
|
+
Entry::UnresolvedMethodAlias.new(
|
454
|
+
new_name_value,
|
455
|
+
old_name_value,
|
456
|
+
@owner_stack.last,
|
457
|
+
@file_path,
|
458
|
+
new_name.location,
|
459
|
+
comments,
|
460
|
+
),
|
421
461
|
)
|
422
462
|
end
|
423
463
|
|
@@ -443,22 +483,24 @@ module RubyIndexer
|
|
443
483
|
value = node.value unless node.is_a?(Prism::ConstantTargetNode) || node.is_a?(Prism::ConstantPathTargetNode)
|
444
484
|
comments = collect_comments(node)
|
445
485
|
|
446
|
-
@index
|
447
|
-
|
448
|
-
|
449
|
-
|
486
|
+
@index.add(
|
487
|
+
case value
|
488
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
489
|
+
Entry::UnresolvedAlias.new(value.slice, @stack.dup, name, @file_path, node.location, comments)
|
490
|
+
when Prism::ConstantWriteNode, Prism::ConstantAndWriteNode, Prism::ConstantOrWriteNode,
|
450
491
|
Prism::ConstantOperatorWriteNode
|
451
492
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
493
|
+
# If the right hand side is another constant assignment, we need to visit it because that constant has to be
|
494
|
+
# indexed too
|
495
|
+
Entry::UnresolvedAlias.new(value.name.to_s, @stack.dup, name, @file_path, node.location, comments)
|
496
|
+
when Prism::ConstantPathWriteNode, Prism::ConstantPathOrWriteNode, Prism::ConstantPathOperatorWriteNode,
|
456
497
|
Prism::ConstantPathAndWriteNode
|
457
498
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
499
|
+
Entry::UnresolvedAlias.new(value.target.slice, @stack.dup, name, @file_path, node.location, comments)
|
500
|
+
else
|
501
|
+
Entry::Constant.new(name, @file_path, node.location, comments)
|
502
|
+
end,
|
503
|
+
)
|
462
504
|
end
|
463
505
|
|
464
506
|
sig { params(node: Prism::Node).returns(T::Array[String]) }
|
@@ -515,15 +557,20 @@ module RubyIndexer
|
|
515
557
|
|
516
558
|
next unless name && loc
|
517
559
|
|
518
|
-
|
519
|
-
|
560
|
+
if reader
|
561
|
+
@index.add(Entry::Accessor.new(name, @file_path, loc, comments, current_visibility, @owner_stack.last))
|
562
|
+
end
|
563
|
+
|
564
|
+
next unless writer
|
565
|
+
|
566
|
+
@index.add(Entry::Accessor.new(
|
520
567
|
"#{name}=",
|
521
568
|
@file_path,
|
522
569
|
loc,
|
523
570
|
comments,
|
524
571
|
current_visibility,
|
525
572
|
@owner_stack.last,
|
526
|
-
)
|
573
|
+
))
|
527
574
|
end
|
528
575
|
end
|
529
576
|
|
@@ -558,5 +605,108 @@ module RubyIndexer
|
|
558
605
|
def current_visibility
|
559
606
|
T.must(@visibility_stack.last)
|
560
607
|
end
|
608
|
+
|
609
|
+
sig { params(parameters_node: T.nilable(Prism::ParametersNode)).returns(T::Array[Entry::Parameter]) }
|
610
|
+
def list_params(parameters_node)
|
611
|
+
return [] unless parameters_node
|
612
|
+
|
613
|
+
parameters = []
|
614
|
+
|
615
|
+
parameters_node.requireds.each do |required|
|
616
|
+
name = parameter_name(required)
|
617
|
+
next unless name
|
618
|
+
|
619
|
+
parameters << Entry::RequiredParameter.new(name: name)
|
620
|
+
end
|
621
|
+
|
622
|
+
parameters_node.optionals.each do |optional|
|
623
|
+
name = parameter_name(optional)
|
624
|
+
next unless name
|
625
|
+
|
626
|
+
parameters << Entry::OptionalParameter.new(name: name)
|
627
|
+
end
|
628
|
+
|
629
|
+
rest = parameters_node.rest
|
630
|
+
|
631
|
+
if rest.is_a?(Prism::RestParameterNode)
|
632
|
+
rest_name = rest.name || Entry::RestParameter::DEFAULT_NAME
|
633
|
+
parameters << Entry::RestParameter.new(name: rest_name)
|
634
|
+
end
|
635
|
+
|
636
|
+
parameters_node.keywords.each do |keyword|
|
637
|
+
name = parameter_name(keyword)
|
638
|
+
next unless name
|
639
|
+
|
640
|
+
case keyword
|
641
|
+
when Prism::RequiredKeywordParameterNode
|
642
|
+
parameters << Entry::KeywordParameter.new(name: name)
|
643
|
+
when Prism::OptionalKeywordParameterNode
|
644
|
+
parameters << Entry::OptionalKeywordParameter.new(name: name)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
keyword_rest = parameters_node.keyword_rest
|
649
|
+
|
650
|
+
if keyword_rest.is_a?(Prism::KeywordRestParameterNode)
|
651
|
+
keyword_rest_name = parameter_name(keyword_rest) || Entry::KeywordRestParameter::DEFAULT_NAME
|
652
|
+
parameters << Entry::KeywordRestParameter.new(name: keyword_rest_name)
|
653
|
+
end
|
654
|
+
|
655
|
+
parameters_node.posts.each do |post|
|
656
|
+
name = parameter_name(post)
|
657
|
+
next unless name
|
658
|
+
|
659
|
+
parameters << Entry::RequiredParameter.new(name: name)
|
660
|
+
end
|
661
|
+
|
662
|
+
block = parameters_node.block
|
663
|
+
parameters << Entry::BlockParameter.new(name: block.name || Entry::BlockParameter::DEFAULT_NAME) if block
|
664
|
+
|
665
|
+
parameters
|
666
|
+
end
|
667
|
+
|
668
|
+
sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(Symbol)) }
|
669
|
+
def parameter_name(node)
|
670
|
+
case node
|
671
|
+
when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
|
672
|
+
Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode,
|
673
|
+
Prism::RestParameterNode, Prism::KeywordRestParameterNode
|
674
|
+
node.name
|
675
|
+
when Prism::MultiTargetNode
|
676
|
+
names = node.lefts.map { |parameter_node| parameter_name(parameter_node) }
|
677
|
+
|
678
|
+
rest = node.rest
|
679
|
+
if rest.is_a?(Prism::SplatNode)
|
680
|
+
name = rest.expression&.slice
|
681
|
+
names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
|
682
|
+
end
|
683
|
+
|
684
|
+
names << nil if rest.is_a?(Prism::ImplicitRestNode)
|
685
|
+
|
686
|
+
names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
|
687
|
+
|
688
|
+
names_with_commas = names.join(", ")
|
689
|
+
:"(#{names_with_commas})"
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
sig { returns(T.nilable(Entry::Class)) }
|
694
|
+
def singleton_klass
|
695
|
+
attached_class = @owner_stack.last
|
696
|
+
return unless attached_class
|
697
|
+
|
698
|
+
# Return the existing singleton class if available
|
699
|
+
owner = T.cast(
|
700
|
+
@index["#{attached_class.name}::<Class:#{attached_class.name}>"],
|
701
|
+
T.nilable(T::Array[Entry::SingletonClass]),
|
702
|
+
)
|
703
|
+
return owner.first if owner
|
704
|
+
|
705
|
+
# If not available, create the singleton class lazily
|
706
|
+
nesting = @stack + ["<Class:#{@stack.last}>"]
|
707
|
+
entry = Entry::SingletonClass.new(nesting, @file_path, attached_class.location, [], nil)
|
708
|
+
@index.add(entry, skip_prefix_tree: true)
|
709
|
+
entry
|
710
|
+
end
|
561
711
|
end
|
562
712
|
end
|