ruby-lsp 0.17.4 → 0.17.13

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +26 -1
  5. data/exe/ruby-lsp-check +1 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +74 -43
  7. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +26 -0
  8. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +147 -29
  9. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +383 -79
  10. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +195 -61
  11. data/lib/ruby_indexer/ruby_indexer.rb +1 -8
  12. data/lib/ruby_indexer/test/classes_and_modules_test.rb +71 -3
  13. data/lib/ruby_indexer/test/configuration_test.rb +1 -1
  14. data/lib/ruby_indexer/test/constant_test.rb +17 -17
  15. data/lib/ruby_indexer/test/enhancements_test.rb +197 -0
  16. data/lib/ruby_indexer/test/index_test.rb +367 -17
  17. data/lib/ruby_indexer/test/method_test.rb +58 -25
  18. data/lib/ruby_indexer/test/rbs_indexer_test.rb +297 -0
  19. data/lib/ruby_indexer/test/test_case.rb +1 -5
  20. data/lib/ruby_lsp/addon.rb +22 -5
  21. data/lib/ruby_lsp/base_server.rb +8 -3
  22. data/lib/ruby_lsp/document.rb +27 -46
  23. data/lib/ruby_lsp/erb_document.rb +125 -0
  24. data/lib/ruby_lsp/global_state.rb +47 -19
  25. data/lib/ruby_lsp/internal.rb +2 -0
  26. data/lib/ruby_lsp/listeners/completion.rb +161 -57
  27. data/lib/ruby_lsp/listeners/definition.rb +91 -27
  28. data/lib/ruby_lsp/listeners/document_highlight.rb +5 -1
  29. data/lib/ruby_lsp/listeners/hover.rb +61 -19
  30. data/lib/ruby_lsp/listeners/signature_help.rb +13 -6
  31. data/lib/ruby_lsp/node_context.rb +65 -5
  32. data/lib/ruby_lsp/requests/code_action_resolve.rb +107 -9
  33. data/lib/ruby_lsp/requests/code_actions.rb +11 -2
  34. data/lib/ruby_lsp/requests/completion.rb +4 -4
  35. data/lib/ruby_lsp/requests/completion_resolve.rb +14 -9
  36. data/lib/ruby_lsp/requests/definition.rb +18 -8
  37. data/lib/ruby_lsp/requests/diagnostics.rb +6 -5
  38. data/lib/ruby_lsp/requests/document_symbol.rb +2 -7
  39. data/lib/ruby_lsp/requests/folding_ranges.rb +6 -2
  40. data/lib/ruby_lsp/requests/formatting.rb +15 -0
  41. data/lib/ruby_lsp/requests/hover.rb +5 -5
  42. data/lib/ruby_lsp/requests/on_type_formatting.rb +6 -4
  43. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
  44. data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -2
  45. data/lib/ruby_lsp/requests/signature_help.rb +3 -3
  46. data/lib/ruby_lsp/requests/support/common.rb +11 -2
  47. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +2 -6
  48. data/lib/ruby_lsp/ruby_document.rb +74 -0
  49. data/lib/ruby_lsp/server.rb +129 -54
  50. data/lib/ruby_lsp/store.rb +33 -9
  51. data/lib/ruby_lsp/test_helper.rb +3 -1
  52. data/lib/ruby_lsp/type_inferrer.rb +61 -25
  53. data/lib/ruby_lsp/utils.rb +13 -0
  54. metadata +9 -8
  55. data/exe/ruby-lsp-doctor +0 -23
@@ -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,12 +176,13 @@ 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)
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)
155
186
  @parent_class = parent_class
156
187
  end
157
188
 
@@ -164,8 +195,8 @@ module RubyIndexer
164
195
  class SingletonClass < Class
165
196
  extend T::Sig
166
197
 
167
- sig { params(location: Prism::Location, comments: T::Array[String]).void }
168
- def update_singleton_information(location, comments)
198
+ sig { params(location: Prism::Location, name_location: Prism::Location, comments: T::Array[String]).void }
199
+ def update_singleton_information(location, name_location, comments)
169
200
  # Create a new RubyIndexer::Location object from the Prism location
170
201
  @location = Location.new(
171
202
  location.start_line,
@@ -173,6 +204,12 @@ module RubyIndexer
173
204
  location.start_column,
174
205
  location.end_column,
175
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
+ )
176
213
  @comments.concat(comments)
177
214
  end
178
215
  end
@@ -251,6 +288,14 @@ module RubyIndexer
251
288
  class BlockParameter < Parameter
252
289
  DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
253
290
 
291
+ class << self
292
+ extend T::Sig
293
+ sig { returns(BlockParameter) }
294
+ def anonymous
295
+ new(name: DEFAULT_NAME)
296
+ end
297
+ end
298
+
254
299
  sig { override.returns(Symbol) }
255
300
  def decorated_name
256
301
  :"&#{@name}"
@@ -266,6 +311,11 @@ module RubyIndexer
266
311
  sig { returns(T.nilable(Entry::Namespace)) }
267
312
  attr_reader :owner
268
313
 
314
+ sig { returns(T::Array[RubyIndexer::Entry::Parameter]) }
315
+ def parameters
316
+ T.must(signatures.first).parameters
317
+ end
318
+
269
319
  sig do
270
320
  params(
271
321
  name: String,
@@ -282,47 +332,85 @@ module RubyIndexer
282
332
  @owner = owner
283
333
  end
284
334
 
285
- sig { abstract.returns(T::Array[Parameter]) }
286
- def parameters; end
335
+ sig { abstract.returns(T::Array[Entry::Signature]) }
336
+ def signatures; end
287
337
 
288
- # Returns a string with the decorated names of the parameters of this member. E.g.: `(a, b = 1, c: 2)`
289
338
  sig { returns(String) }
290
339
  def decorated_parameters
291
- "(#{parameters.map(&:decorated_name).join(", ")})"
340
+ first_signature = signatures.first
341
+ return "()" unless first_signature
342
+
343
+ "(#{first_signature.format})"
344
+ end
345
+
346
+ sig { returns(String) }
347
+ def formatted_signatures
348
+ overloads_count = signatures.size
349
+ case overloads_count
350
+ when 1
351
+ ""
352
+ when 2
353
+ "\n(+1 overload)"
354
+ else
355
+ "\n(+#{overloads_count - 1} overloads)"
356
+ end
292
357
  end
293
358
  end
294
359
 
295
360
  class Accessor < Member
296
361
  extend T::Sig
297
362
 
298
- sig { override.returns(T::Array[Parameter]) }
299
- def parameters
300
- params = []
301
- params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
302
- params
363
+ sig { override.returns(T::Array[Signature]) }
364
+ def signatures
365
+ @signatures ||= T.let(
366
+ begin
367
+ params = []
368
+ params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
369
+ [Entry::Signature.new(params)]
370
+ end,
371
+ T.nilable(T::Array[Signature]),
372
+ )
303
373
  end
304
374
  end
305
375
 
306
376
  class Method < Member
307
377
  extend T::Sig
308
378
 
309
- sig { override.returns(T::Array[Parameter]) }
310
- attr_reader :parameters
379
+ sig { override.returns(T::Array[Signature]) }
380
+ attr_reader :signatures
381
+
382
+ # Returns the location of the method name, excluding parameters or the body
383
+ sig { returns(Location) }
384
+ attr_reader :name_location
311
385
 
312
386
  sig do
313
387
  params(
314
388
  name: String,
315
389
  file_path: String,
316
390
  location: T.any(Prism::Location, RubyIndexer::Location),
391
+ name_location: T.any(Prism::Location, Location),
317
392
  comments: T::Array[String],
318
- parameters: T::Array[Parameter],
393
+ signatures: T::Array[Signature],
319
394
  visibility: Visibility,
320
395
  owner: T.nilable(Entry::Namespace),
321
396
  ).void
322
397
  end
323
- def initialize(name, file_path, location, comments, parameters, visibility, owner) # rubocop:disable Metrics/ParameterLists
398
+ def initialize(name, file_path, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
324
399
  super(name, file_path, location, comments, visibility, owner)
325
- @parameters = parameters
400
+ @signatures = signatures
401
+ @name_location = T.let(
402
+ if name_location.is_a?(Prism::Location)
403
+ Location.new(
404
+ name_location.start_line,
405
+ name_location.end_line,
406
+ name_location.start_column,
407
+ name_location.end_column,
408
+ )
409
+ else
410
+ name_location
411
+ end,
412
+ RubyIndexer::Location,
413
+ )
326
414
  end
327
415
  end
328
416
 
@@ -336,7 +424,7 @@ module RubyIndexer
336
424
  # All aliases are inserted as UnresolvedAlias in the index first and then we lazily resolve them to the correct
337
425
  # target in [rdoc-ref:Index#resolve]. If the right hand side contains a constant that doesn't exist, then it's not
338
426
  # possible to resolve the alias and it will remain an UnresolvedAlias until the right hand side constant exists
339
- class UnresolvedAlias < Entry
427
+ class UnresolvedConstantAlias < Entry
340
428
  extend T::Sig
341
429
 
342
430
  sig { returns(String) }
@@ -364,13 +452,13 @@ module RubyIndexer
364
452
  end
365
453
 
366
454
  # Alias represents a resolved alias, which points to an existing constant target
367
- class Alias < Entry
455
+ class ConstantAlias < Entry
368
456
  extend T::Sig
369
457
 
370
458
  sig { returns(String) }
371
459
  attr_reader :target
372
460
 
373
- sig { params(target: String, unresolved_alias: UnresolvedAlias).void }
461
+ sig { params(target: String, unresolved_alias: UnresolvedConstantAlias).void }
374
462
  def initialize(target, unresolved_alias)
375
463
  super(unresolved_alias.name, unresolved_alias.file_path, unresolved_alias.location, unresolved_alias.comments)
376
464
 
@@ -417,7 +505,7 @@ module RubyIndexer
417
505
  old_name: String,
418
506
  owner: T.nilable(Entry::Namespace),
419
507
  file_path: String,
420
- location: Prism::Location,
508
+ location: T.any(Prism::Location, RubyIndexer::Location),
421
509
  comments: T::Array[String],
422
510
  ).void
423
511
  end
@@ -437,6 +525,9 @@ module RubyIndexer
437
525
  sig { returns(T.any(Member, MethodAlias)) }
438
526
  attr_reader :target
439
527
 
528
+ sig { returns(T.nilable(Entry::Namespace)) }
529
+ attr_reader :owner
530
+
440
531
  sig { params(target: T.any(Member, MethodAlias), unresolved_alias: UnresolvedMethodAlias).void }
441
532
  def initialize(target, unresolved_alias)
442
533
  full_comments = ["Alias for #{target.name}\n"]
@@ -452,11 +543,7 @@ module RubyIndexer
452
543
  )
453
544
 
454
545
  @target = target
455
- end
456
-
457
- sig { returns(T.nilable(Entry::Namespace)) }
458
- def owner
459
- @target.owner
546
+ @owner = T.let(unresolved_alias.owner, T.nilable(Entry::Namespace))
460
547
  end
461
548
 
462
549
  sig { returns(T::Array[Parameter]) }
@@ -468,6 +555,37 @@ module RubyIndexer
468
555
  def decorated_parameters
469
556
  @target.decorated_parameters
470
557
  end
558
+
559
+ sig { returns(String) }
560
+ def formatted_signatures
561
+ @target.formatted_signatures
562
+ end
563
+
564
+ sig { returns(T::Array[Signature]) }
565
+ def signatures
566
+ @target.signatures
567
+ end
568
+ end
569
+
570
+ # Ruby doesn't support method overloading, so a method will have only one signature.
571
+ # However RBS can represent the concept of method overloading, with different return types based on the arguments
572
+ # passed, so we need to store all the signatures.
573
+ class Signature
574
+ extend T::Sig
575
+
576
+ sig { returns(T::Array[Parameter]) }
577
+ attr_reader :parameters
578
+
579
+ sig { params(parameters: T::Array[Parameter]).void }
580
+ def initialize(parameters)
581
+ @parameters = parameters
582
+ end
583
+
584
+ # Returns a string with the decorated names of the parameters of this member. E.g.: `(a, b = 1, c: 2)`
585
+ sig { returns(String) }
586
+ def format
587
+ @parameters.map(&:decorated_name).join(", ")
588
+ end
471
589
  end
472
590
  end
473
591
  end