ruby-lsp 0.17.4 → 0.17.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71204369ec5201376f1af11875a2e1bf16df56a31719ea78932a7f5f6e9c7e5c
4
- data.tar.gz: d83e299ade275415fe4cac25abe78f7ee7ec622c47cc1699d42b3b772816fdba
3
+ metadata.gz: 7299237468ae17d80028a1454903f58b1be4ff34428a6c8a538530b5caad54d1
4
+ data.tar.gz: 26351e5be1671219a9b3624076b2f50fb68c5838303fe1a021eecb39c4e3e9f1
5
5
  SHA512:
6
- metadata.gz: f3ac517cb1c711dc1a5ddf2c4027f705e393e30028b9ae7063b18a5f51362fd4d7277607d19d8ca7a9a3c9146960bd612a02ed4a8933c8223a42daf3dfe5e63b
7
- data.tar.gz: 0c4408865d1894547aeedfc0441fa558a8281f54e7e26c38b619e67fd67bfc3bed49aa27dc06d8b89924c7ee8db4452b5cd2f810c0dfb01157eef127910b2182
6
+ metadata.gz: 54cc76a3506a268398cfc51645a70300e2d14bda5b39c12274863270f70ed666b33bfebdf50dac8e013410e8ddba5645f4f435863af795d268710e0ccf9d8814
7
+ data.tar.gz: 95e52a4aa6f68785495f7435fe54cc395c062809ad3754703f808c68d2599bc34a619578bbb8453cb54de88a8312ac49eff8dd2e72a82bc04554c7b659c477cd
data/README.md CHANGED
@@ -109,6 +109,10 @@ features. This is the mechanism that powers addons like
109
109
  - [Ruby LSP RSpec](https://github.com/st0012/ruby-lsp-rspec)
110
110
  - [Ruby LSP rubyfmt](https://github.com/jscharf/ruby-lsp-rubyfmt)
111
111
 
112
+ Additionally, some tools may include a Ruby LSP addon directly, like
113
+
114
+ - [Standard Ruby (from v1.39.1)](https://github.com/standardrb/standard/wiki/IDE:-vscode#using-ruby-lsp)
115
+
112
116
  Other community driven addons can be found in [rubygems](https://rubygems.org/search?query=name%3A+ruby-lsp) by
113
117
  searching for the `ruby-lsp` prefix.
114
118
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.17.4
1
+ 0.17.6
@@ -64,7 +64,8 @@ module RubyIndexer
64
64
  sig { params(node: Prism::ClassNode).void }
65
65
  def on_class_node_enter(node)
66
66
  @visibility_stack.push(Entry::Visibility::PUBLIC)
67
- name = node.constant_path.location.slice
67
+ constant_path = node.constant_path
68
+ name = constant_path.slice
68
69
 
69
70
  comments = collect_comments(node)
70
71
 
@@ -93,6 +94,7 @@ module RubyIndexer
93
94
  nesting,
94
95
  @file_path,
95
96
  node.location,
97
+ constant_path.location,
96
98
  comments,
97
99
  parent_class,
98
100
  )
@@ -112,12 +114,13 @@ module RubyIndexer
112
114
  sig { params(node: Prism::ModuleNode).void }
113
115
  def on_module_node_enter(node)
114
116
  @visibility_stack.push(Entry::Visibility::PUBLIC)
115
- name = node.constant_path.location.slice
117
+ constant_path = node.constant_path
118
+ name = constant_path.slice
116
119
 
117
120
  comments = collect_comments(node)
118
121
 
119
122
  nesting = name.start_with?("::") ? [name.delete_prefix("::")] : @stack + [name.delete_prefix("::")]
120
- entry = Entry::Module.new(nesting, @file_path, node.location, comments)
123
+ entry = Entry::Module.new(nesting, @file_path, node.location, constant_path.location, comments)
121
124
 
122
125
  @owner_stack << entry
123
126
  @index.add(entry)
@@ -145,9 +148,16 @@ module RubyIndexer
145
148
 
146
149
  if existing_entries
147
150
  entry = T.must(existing_entries.first)
148
- entry.update_singleton_information(node.location, collect_comments(node))
151
+ entry.update_singleton_information(node.location, expression.location, collect_comments(node))
149
152
  else
150
- entry = Entry::SingletonClass.new(@stack, @file_path, node.location, collect_comments(node), nil)
153
+ entry = Entry::SingletonClass.new(
154
+ @stack,
155
+ @file_path,
156
+ node.location,
157
+ expression.location,
158
+ collect_comments(node),
159
+ nil,
160
+ )
151
161
  @index.add(entry, skip_prefix_tree: true)
152
162
  end
153
163
 
@@ -297,25 +307,29 @@ module RubyIndexer
297
307
  method_name,
298
308
  @file_path,
299
309
  node.location,
310
+ node.name_loc,
300
311
  comments,
301
- list_params(node.parameters),
312
+ [Entry::Signature.new(list_params(node.parameters))],
302
313
  current_visibility,
303
314
  @owner_stack.last,
304
315
  ))
305
316
  when Prism::SelfNode
306
- singleton = singleton_klass
317
+ owner = @owner_stack.last
318
+
319
+ if owner
320
+ singleton = @index.existing_or_new_singleton_class(owner.name)
321
+
322
+ @index.add(Entry::Method.new(
323
+ method_name,
324
+ @file_path,
325
+ node.location,
326
+ node.name_loc,
327
+ comments,
328
+ [Entry::Signature.new(list_params(node.parameters))],
329
+ current_visibility,
330
+ singleton,
331
+ ))
307
332
 
308
- @index.add(Entry::Method.new(
309
- method_name,
310
- @file_path,
311
- node.location,
312
- comments,
313
- list_params(node.parameters),
314
- current_visibility,
315
- singleton,
316
- ))
317
-
318
- if singleton
319
333
  @owner_stack << singleton
320
334
  @stack << "<Class:#{@stack.last}>"
321
335
  end
@@ -393,7 +407,12 @@ module RubyIndexer
393
407
 
394
408
  # When instance variables are declared inside the class body, they turn into class instance variables rather than
395
409
  # regular instance variables
396
- owner = @inside_def ? @owner_stack.last : singleton_klass
410
+ owner = @owner_stack.last
411
+
412
+ if owner && !@inside_def
413
+ owner = @index.existing_or_new_singleton_class(owner.name)
414
+ end
415
+
397
416
  @index.add(Entry::InstanceVariable.new(name, @file_path, loc, collect_comments(node), owner))
398
417
  end
399
418
 
@@ -593,7 +612,8 @@ module RubyIndexer
593
612
  when :prepend
594
613
  owner.mixin_operations << Entry::Prepend.new(node.full_name)
595
614
  when :extend
596
- owner.mixin_operations << Entry::Extend.new(node.full_name)
615
+ singleton = @index.existing_or_new_singleton_class(owner.name)
616
+ singleton.mixin_operations << Entry::Include.new(node.full_name)
597
617
  end
598
618
  rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
599
619
  Prism::ConstantPathNode::MissingNodesInConstantPathError
@@ -689,24 +709,5 @@ module RubyIndexer
689
709
  :"(#{names_with_commas})"
690
710
  end
691
711
  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
711
712
  end
712
713
  end
@@ -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,72 @@ 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})"
292
344
  end
293
345
  end
294
346
 
295
347
  class Accessor < Member
296
348
  extend T::Sig
297
349
 
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
350
+ sig { override.returns(T::Array[Signature]) }
351
+ def signatures
352
+ @signatures ||= T.let(
353
+ begin
354
+ params = []
355
+ params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
356
+ [Entry::Signature.new(params)]
357
+ end,
358
+ T.nilable(T::Array[Signature]),
359
+ )
303
360
  end
304
361
  end
305
362
 
306
363
  class Method < Member
307
364
  extend T::Sig
308
365
 
309
- sig { override.returns(T::Array[Parameter]) }
310
- attr_reader :parameters
366
+ sig { override.returns(T::Array[Signature]) }
367
+ attr_reader :signatures
368
+
369
+ # Returns the location of the method name, excluding parameters or the body
370
+ sig { returns(Location) }
371
+ attr_reader :name_location
311
372
 
312
373
  sig do
313
374
  params(
314
375
  name: String,
315
376
  file_path: String,
316
377
  location: T.any(Prism::Location, RubyIndexer::Location),
378
+ name_location: T.any(Prism::Location, Location),
317
379
  comments: T::Array[String],
318
- parameters: T::Array[Parameter],
380
+ signatures: T::Array[Signature],
319
381
  visibility: Visibility,
320
382
  owner: T.nilable(Entry::Namespace),
321
383
  ).void
322
384
  end
323
- def initialize(name, file_path, location, comments, parameters, visibility, owner) # rubocop:disable Metrics/ParameterLists
385
+ def initialize(name, file_path, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
324
386
  super(name, file_path, location, comments, visibility, owner)
325
- @parameters = parameters
387
+ @signatures = signatures
388
+ @name_location = T.let(
389
+ if name_location.is_a?(Prism::Location)
390
+ Location.new(
391
+ name_location.start_line,
392
+ name_location.end_line,
393
+ name_location.start_column,
394
+ name_location.end_column,
395
+ )
396
+ else
397
+ name_location
398
+ end,
399
+ RubyIndexer::Location,
400
+ )
326
401
  end
327
402
  end
328
403
 
@@ -437,6 +512,9 @@ module RubyIndexer
437
512
  sig { returns(T.any(Member, MethodAlias)) }
438
513
  attr_reader :target
439
514
 
515
+ sig { returns(T.nilable(Entry::Namespace)) }
516
+ attr_reader :owner
517
+
440
518
  sig { params(target: T.any(Member, MethodAlias), unresolved_alias: UnresolvedMethodAlias).void }
441
519
  def initialize(target, unresolved_alias)
442
520
  full_comments = ["Alias for #{target.name}\n"]
@@ -452,11 +530,7 @@ module RubyIndexer
452
530
  )
453
531
 
454
532
  @target = target
455
- end
456
-
457
- sig { returns(T.nilable(Entry::Namespace)) }
458
- def owner
459
- @target.owner
533
+ @owner = T.let(unresolved_alias.owner, T.nilable(Entry::Namespace))
460
534
  end
461
535
 
462
536
  sig { returns(T::Array[Parameter]) }
@@ -469,5 +543,26 @@ module RubyIndexer
469
543
  @target.decorated_parameters
470
544
  end
471
545
  end
546
+
547
+ # Ruby doesn't support method overloading, so a method will have only one signature.
548
+ # However RBS can represent the concept of method overloading, with different return types based on the arguments
549
+ # passed, so we need to store all the signatures.
550
+ class Signature
551
+ extend T::Sig
552
+
553
+ sig { returns(T::Array[Parameter]) }
554
+ attr_reader :parameters
555
+
556
+ sig { params(parameters: T::Array[Parameter]).void }
557
+ def initialize(parameters)
558
+ @parameters = parameters
559
+ end
560
+
561
+ # Returns a string with the decorated names of the parameters of this member. E.g.: `(a, b = 1, c: 2)`
562
+ sig { returns(String) }
563
+ def format
564
+ @parameters.map(&:decorated_name).join(", ")
565
+ end
566
+ end
472
567
  end
473
568
  end