ruby-lsp 0.17.2 → 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/README.md +2 -0
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +280 -74
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +102 -102
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +234 -56
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +147 -0
- data/lib/ruby_indexer/ruby_indexer.rb +1 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -2
- data/lib/ruby_indexer/test/configuration_test.rb +1 -1
- data/lib/ruby_indexer/test/constant_test.rb +1 -1
- data/lib/ruby_indexer/test/index_test.rb +702 -71
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +74 -24
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +67 -0
- data/lib/ruby_indexer/test/test_case.rb +7 -0
- data/lib/ruby_lsp/document.rb +37 -8
- data/lib/ruby_lsp/global_state.rb +43 -18
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
- 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 -4
- data/lib/ruby_lsp/test_helper.rb +1 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- metadata +29 -4
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/README.md
CHANGED
@@ -48,6 +48,8 @@ If using VS Code, all you have to do is install the [Ruby LSP
|
|
48
48
|
extension](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp) to get the extra features in the
|
49
49
|
editor. Do not install the `ruby-lsp` gem manually.
|
50
50
|
|
51
|
+
For more information on using and configuring the extension, see [vscode/README.md](vscode/README.md).
|
52
|
+
|
51
53
|
### With other editors
|
52
54
|
|
53
55
|
See [editors](EDITORS.md) for community instructions on setting up the Ruby LSP, which current includes Emacs, Neovim, Sublime Text, and Zed.
|
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,
|
@@ -52,6 +57,7 @@ module RubyIndexer
|
|
52
57
|
:on_instance_variable_operator_write_node_enter,
|
53
58
|
:on_instance_variable_or_write_node_enter,
|
54
59
|
:on_instance_variable_target_node_enter,
|
60
|
+
:on_alias_method_node_enter,
|
55
61
|
)
|
56
62
|
end
|
57
63
|
|
@@ -63,13 +69,26 @@ module RubyIndexer
|
|
63
69
|
comments = collect_comments(node)
|
64
70
|
|
65
71
|
superclass = node.superclass
|
72
|
+
|
73
|
+
nesting = name.start_with?("::") ? [name.delete_prefix("::")] : @stack + [name.delete_prefix("::")]
|
74
|
+
|
66
75
|
parent_class = case superclass
|
67
76
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
68
77
|
superclass.slice
|
78
|
+
else
|
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
|
69
90
|
end
|
70
91
|
|
71
|
-
nesting = name.start_with?("::") ? [name.delete_prefix("::")] : @stack + [name.delete_prefix("::")]
|
72
|
-
|
73
92
|
entry = Entry::Class.new(
|
74
93
|
nesting,
|
75
94
|
@file_path,
|
@@ -79,7 +98,7 @@ module RubyIndexer
|
|
79
98
|
)
|
80
99
|
|
81
100
|
@owner_stack << entry
|
82
|
-
@index
|
101
|
+
@index.add(entry)
|
83
102
|
@stack << name
|
84
103
|
end
|
85
104
|
|
@@ -101,7 +120,7 @@ module RubyIndexer
|
|
101
120
|
entry = Entry::Module.new(nesting, @file_path, node.location, comments)
|
102
121
|
|
103
122
|
@owner_stack << entry
|
104
|
-
@index
|
123
|
+
@index.add(entry)
|
105
124
|
@stack << name
|
106
125
|
end
|
107
126
|
|
@@ -112,6 +131,37 @@ module RubyIndexer
|
|
112
131
|
@visibility_stack.pop
|
113
132
|
end
|
114
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
|
+
|
115
165
|
sig { params(node: Prism::MultiWriteNode).void }
|
116
166
|
def on_multi_write_node_enter(node)
|
117
167
|
value = node.value
|
@@ -209,6 +259,8 @@ module RubyIndexer
|
|
209
259
|
handle_attribute(node, reader: false, writer: true)
|
210
260
|
when :attr_accessor
|
211
261
|
handle_attribute(node, reader: true, writer: true)
|
262
|
+
when :alias_method
|
263
|
+
handle_alias_method(node)
|
212
264
|
when :include, :prepend, :extend
|
213
265
|
handle_module_operation(node, message)
|
214
266
|
when :public
|
@@ -241,105 +293,110 @@ module RubyIndexer
|
|
241
293
|
|
242
294
|
case node.receiver
|
243
295
|
when nil
|
244
|
-
@index
|
296
|
+
@index.add(Entry::Method.new(
|
245
297
|
method_name,
|
246
298
|
@file_path,
|
247
299
|
node.location,
|
248
300
|
comments,
|
249
|
-
node.parameters,
|
301
|
+
list_params(node.parameters),
|
250
302
|
current_visibility,
|
251
303
|
@owner_stack.last,
|
252
|
-
)
|
304
|
+
))
|
253
305
|
when Prism::SelfNode
|
254
|
-
|
306
|
+
singleton = singleton_klass
|
307
|
+
|
308
|
+
@index.add(Entry::Method.new(
|
255
309
|
method_name,
|
256
310
|
@file_path,
|
257
311
|
node.location,
|
258
312
|
comments,
|
259
|
-
node.parameters,
|
313
|
+
list_params(node.parameters),
|
260
314
|
current_visibility,
|
261
|
-
|
262
|
-
)
|
315
|
+
singleton,
|
316
|
+
))
|
317
|
+
|
318
|
+
if singleton
|
319
|
+
@owner_stack << singleton
|
320
|
+
@stack << "<Class:#{@stack.last}>"
|
321
|
+
end
|
263
322
|
end
|
264
323
|
end
|
265
324
|
|
266
325
|
sig { params(node: Prism::DefNode).void }
|
267
326
|
def on_def_node_leave(node)
|
268
327
|
@inside_def = false
|
328
|
+
|
329
|
+
if node.receiver.is_a?(Prism::SelfNode)
|
330
|
+
@owner_stack.pop
|
331
|
+
@stack.pop
|
332
|
+
end
|
269
333
|
end
|
270
334
|
|
271
335
|
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
272
336
|
def on_instance_variable_write_node_enter(node)
|
273
|
-
|
274
|
-
return if name == "@"
|
275
|
-
|
276
|
-
@index << Entry::InstanceVariable.new(
|
277
|
-
name,
|
278
|
-
@file_path,
|
279
|
-
node.name_loc,
|
280
|
-
collect_comments(node),
|
281
|
-
@owner_stack.last,
|
282
|
-
)
|
337
|
+
handle_instance_variable(node, node.name_loc)
|
283
338
|
end
|
284
339
|
|
285
340
|
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
286
341
|
def on_instance_variable_and_write_node_enter(node)
|
287
|
-
|
288
|
-
return if name == "@"
|
289
|
-
|
290
|
-
@index << Entry::InstanceVariable.new(
|
291
|
-
name,
|
292
|
-
@file_path,
|
293
|
-
node.name_loc,
|
294
|
-
collect_comments(node),
|
295
|
-
@owner_stack.last,
|
296
|
-
)
|
342
|
+
handle_instance_variable(node, node.name_loc)
|
297
343
|
end
|
298
344
|
|
299
345
|
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
300
346
|
def on_instance_variable_operator_write_node_enter(node)
|
301
|
-
|
302
|
-
return if name == "@"
|
303
|
-
|
304
|
-
@index << Entry::InstanceVariable.new(
|
305
|
-
name,
|
306
|
-
@file_path,
|
307
|
-
node.name_loc,
|
308
|
-
collect_comments(node),
|
309
|
-
@owner_stack.last,
|
310
|
-
)
|
347
|
+
handle_instance_variable(node, node.name_loc)
|
311
348
|
end
|
312
349
|
|
313
350
|
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
314
351
|
def on_instance_variable_or_write_node_enter(node)
|
315
|
-
|
316
|
-
return if name == "@"
|
317
|
-
|
318
|
-
@index << Entry::InstanceVariable.new(
|
319
|
-
name,
|
320
|
-
@file_path,
|
321
|
-
node.name_loc,
|
322
|
-
collect_comments(node),
|
323
|
-
@owner_stack.last,
|
324
|
-
)
|
352
|
+
handle_instance_variable(node, node.name_loc)
|
325
353
|
end
|
326
354
|
|
327
355
|
sig { params(node: Prism::InstanceVariableTargetNode).void }
|
328
356
|
def on_instance_variable_target_node_enter(node)
|
329
|
-
|
330
|
-
|
357
|
+
handle_instance_variable(node, node.location)
|
358
|
+
end
|
331
359
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
360
|
+
sig { params(node: Prism::AliasMethodNode).void }
|
361
|
+
def on_alias_method_node_enter(node)
|
362
|
+
method_name = node.new_name.slice
|
363
|
+
comments = collect_comments(node)
|
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
|
+
),
|
338
373
|
)
|
339
374
|
end
|
340
375
|
|
341
376
|
private
|
342
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
|
+
|
343
400
|
sig { params(node: Prism::CallNode).void }
|
344
401
|
def handle_private_constant(node)
|
345
402
|
arguments = node.arguments&.arguments
|
@@ -365,6 +422,45 @@ module RubyIndexer
|
|
365
422
|
entries&.each { |entry| entry.visibility = Entry::Visibility::PRIVATE }
|
366
423
|
end
|
367
424
|
|
425
|
+
sig { params(node: Prism::CallNode).void }
|
426
|
+
def handle_alias_method(node)
|
427
|
+
arguments = node.arguments&.arguments
|
428
|
+
return unless arguments
|
429
|
+
|
430
|
+
new_name, old_name = arguments
|
431
|
+
return unless new_name && old_name
|
432
|
+
|
433
|
+
new_name_value = case new_name
|
434
|
+
when Prism::StringNode
|
435
|
+
new_name.content
|
436
|
+
when Prism::SymbolNode
|
437
|
+
new_name.value
|
438
|
+
end
|
439
|
+
|
440
|
+
return unless new_name_value
|
441
|
+
|
442
|
+
old_name_value = case old_name
|
443
|
+
when Prism::StringNode
|
444
|
+
old_name.content
|
445
|
+
when Prism::SymbolNode
|
446
|
+
old_name.value
|
447
|
+
end
|
448
|
+
|
449
|
+
return unless old_name_value
|
450
|
+
|
451
|
+
comments = collect_comments(node)
|
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
|
+
),
|
461
|
+
)
|
462
|
+
end
|
463
|
+
|
368
464
|
sig do
|
369
465
|
params(
|
370
466
|
node: T.any(
|
@@ -387,22 +483,24 @@ module RubyIndexer
|
|
387
483
|
value = node.value unless node.is_a?(Prism::ConstantTargetNode) || node.is_a?(Prism::ConstantPathTargetNode)
|
388
484
|
comments = collect_comments(node)
|
389
485
|
|
390
|
-
@index
|
391
|
-
|
392
|
-
|
393
|
-
|
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,
|
394
491
|
Prism::ConstantOperatorWriteNode
|
395
492
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
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,
|
400
497
|
Prism::ConstantPathAndWriteNode
|
401
498
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
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
|
+
)
|
406
504
|
end
|
407
505
|
|
408
506
|
sig { params(node: Prism::Node).returns(T::Array[String]) }
|
@@ -459,15 +557,20 @@ module RubyIndexer
|
|
459
557
|
|
460
558
|
next unless name && loc
|
461
559
|
|
462
|
-
|
463
|
-
|
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(
|
464
567
|
"#{name}=",
|
465
568
|
@file_path,
|
466
569
|
loc,
|
467
570
|
comments,
|
468
571
|
current_visibility,
|
469
572
|
@owner_stack.last,
|
470
|
-
)
|
573
|
+
))
|
471
574
|
end
|
472
575
|
end
|
473
576
|
|
@@ -502,5 +605,108 @@ module RubyIndexer
|
|
502
605
|
def current_visibility
|
503
606
|
T.must(@visibility_stack.last)
|
504
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
|
505
711
|
end
|
506
712
|
end
|