ruby-lsp 0.19.1 → 0.20.1

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +7 -1
  4. data/lib/core_ext/uri.rb +2 -2
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +63 -12
  6. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +85 -36
  7. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +5 -1
  8. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +39 -98
  9. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +12 -19
  10. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
  11. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -7
  12. data/lib/ruby_indexer/test/enhancements_test.rb +5 -7
  13. data/lib/ruby_indexer/test/global_variable_test.rb +49 -0
  14. data/lib/ruby_indexer/test/index_test.rb +89 -0
  15. data/lib/ruby_lsp/erb_document.rb +15 -2
  16. data/lib/ruby_lsp/listeners/definition.rb +20 -0
  17. data/lib/ruby_lsp/listeners/folding_ranges.rb +3 -3
  18. data/lib/ruby_lsp/requests/code_action_resolve.rb +8 -2
  19. data/lib/ruby_lsp/requests/completion.rb +1 -1
  20. data/lib/ruby_lsp/requests/definition.rb +2 -1
  21. data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
  22. data/lib/ruby_lsp/requests/hover.rb +1 -1
  23. data/lib/ruby_lsp/requests/range_formatting.rb +4 -2
  24. data/lib/ruby_lsp/requests/references.rb +3 -1
  25. data/lib/ruby_lsp/requests/rename.rb +3 -1
  26. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  27. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  28. data/lib/ruby_lsp/requests/support/common.rb +1 -1
  29. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
  30. data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -2
  31. data/lib/ruby_lsp/response_builders/hover.rb +2 -2
  32. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +14 -8
  33. data/lib/ruby_lsp/response_builders/signature_help.rb +2 -2
  34. data/lib/ruby_lsp/ruby_document.rb +33 -12
  35. data/lib/ruby_lsp/setup_bundler.rb +30 -8
  36. data/lib/ruby_lsp/type_inferrer.rb +1 -1
  37. metadata +6 -5
@@ -31,30 +31,16 @@ module RubyIndexer
31
31
  params(
32
32
  name: String,
33
33
  file_path: String,
34
- location: T.any(Prism::Location, RubyIndexer::Location),
34
+ location: Location,
35
35
  comments: T.nilable(String),
36
- encoding: Encoding,
37
36
  ).void
38
37
  end
39
- def initialize(name, file_path, location, comments, encoding)
38
+ def initialize(name, file_path, location, comments)
40
39
  @name = name
41
40
  @file_path = file_path
42
41
  @comments = comments
43
42
  @visibility = T.let(Visibility::PUBLIC, Visibility)
44
-
45
- @location = T.let(
46
- if location.is_a?(Prism::Location)
47
- Location.new(
48
- location.start_line,
49
- location.end_line,
50
- location.start_code_units_column(encoding),
51
- location.end_code_units_column(encoding),
52
- )
53
- else
54
- location
55
- end,
56
- RubyIndexer::Location,
57
- )
43
+ @location = location
58
44
  end
59
45
 
60
46
  sig { returns(T::Boolean) }
@@ -152,32 +138,19 @@ module RubyIndexer
152
138
  params(
153
139
  nesting: T::Array[String],
154
140
  file_path: String,
155
- location: T.any(Prism::Location, RubyIndexer::Location),
156
- name_location: T.any(Prism::Location, Location),
141
+ location: Location,
142
+ name_location: Location,
157
143
  comments: T.nilable(String),
158
- encoding: Encoding,
159
144
  ).void
160
145
  end
161
- def initialize(nesting, file_path, location, name_location, comments, encoding) # rubocop:disable Metrics/ParameterLists
146
+ def initialize(nesting, file_path, location, name_location, comments)
162
147
  @name = T.let(nesting.join("::"), String)
163
148
  # The original nesting where this namespace was discovered
164
149
  @nesting = nesting
165
150
 
166
- super(@name, file_path, location, comments, encoding)
167
-
168
- @name_location = T.let(
169
- if name_location.is_a?(Prism::Location)
170
- Location.new(
171
- name_location.start_line,
172
- name_location.end_line,
173
- name_location.start_code_units_column(encoding),
174
- name_location.end_code_units_column(encoding),
175
- )
176
- else
177
- name_location
178
- end,
179
- RubyIndexer::Location,
180
- )
151
+ super(@name, file_path, location, comments)
152
+
153
+ @name_location = name_location
181
154
  end
182
155
 
183
156
  sig { returns(T::Array[String]) }
@@ -214,15 +187,14 @@ module RubyIndexer
214
187
  params(
215
188
  nesting: T::Array[String],
216
189
  file_path: String,
217
- location: T.any(Prism::Location, RubyIndexer::Location),
218
- name_location: T.any(Prism::Location, Location),
190
+ location: Location,
191
+ name_location: Location,
219
192
  comments: T.nilable(String),
220
- encoding: Encoding,
221
193
  parent_class: T.nilable(String),
222
194
  ).void
223
195
  end
224
- def initialize(nesting, file_path, location, name_location, comments, encoding, parent_class) # rubocop:disable Metrics/ParameterLists
225
- super(nesting, file_path, location, name_location, comments, encoding)
196
+ def initialize(nesting, file_path, location, name_location, comments, parent_class) # rubocop:disable Metrics/ParameterLists
197
+ super(nesting, file_path, location, name_location, comments)
226
198
  @parent_class = parent_class
227
199
  end
228
200
 
@@ -237,26 +209,14 @@ module RubyIndexer
237
209
 
238
210
  sig do
239
211
  params(
240
- location: Prism::Location,
241
- name_location: Prism::Location,
212
+ location: Location,
213
+ name_location: Location,
242
214
  comments: T.nilable(String),
243
- encoding: Encoding,
244
215
  ).void
245
216
  end
246
- def update_singleton_information(location, name_location, comments, encoding)
247
- # Create a new RubyIndexer::Location object from the Prism location
248
- @location = Location.new(
249
- location.start_line,
250
- location.end_line,
251
- location.start_code_units_column(encoding),
252
- location.end_code_units_column(encoding),
253
- )
254
- @name_location = Location.new(
255
- name_location.start_line,
256
- name_location.end_line,
257
- name_location.start_code_units_column(encoding),
258
- name_location.end_code_units_column(encoding),
259
- )
217
+ def update_singleton_information(location, name_location, comments)
218
+ @location = location
219
+ @name_location = name_location
260
220
  (@comments ||= +"") << comments if comments
261
221
  end
262
222
  end
@@ -373,15 +333,14 @@ module RubyIndexer
373
333
  params(
374
334
  name: String,
375
335
  file_path: String,
376
- location: T.any(Prism::Location, RubyIndexer::Location),
336
+ location: Location,
377
337
  comments: T.nilable(String),
378
- encoding: Encoding,
379
338
  visibility: Visibility,
380
339
  owner: T.nilable(Entry::Namespace),
381
340
  ).void
382
341
  end
383
- def initialize(name, file_path, location, comments, encoding, visibility, owner) # rubocop:disable Metrics/ParameterLists
384
- super(name, file_path, location, comments, encoding)
342
+ def initialize(name, file_path, location, comments, visibility, owner) # rubocop:disable Metrics/ParameterLists
343
+ super(name, file_path, location, comments)
385
344
  @visibility = visibility
386
345
  @owner = owner
387
346
  end
@@ -441,31 +400,18 @@ module RubyIndexer
441
400
  params(
442
401
  name: String,
443
402
  file_path: String,
444
- location: T.any(Prism::Location, RubyIndexer::Location),
445
- name_location: T.any(Prism::Location, Location),
403
+ location: Location,
404
+ name_location: Location,
446
405
  comments: T.nilable(String),
447
- encoding: Encoding,
448
406
  signatures: T::Array[Signature],
449
407
  visibility: Visibility,
450
408
  owner: T.nilable(Entry::Namespace),
451
409
  ).void
452
410
  end
453
- def initialize(name, file_path, location, name_location, comments, encoding, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
454
- super(name, file_path, location, comments, encoding, visibility, owner)
411
+ def initialize(name, file_path, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
412
+ super(name, file_path, location, comments, visibility, owner)
455
413
  @signatures = signatures
456
- @name_location = T.let(
457
- if name_location.is_a?(Prism::Location)
458
- Location.new(
459
- name_location.start_line,
460
- name_location.end_line,
461
- name_location.start_code_units_column(encoding),
462
- name_location.end_code_units_column(encoding),
463
- )
464
- else
465
- name_location
466
- end,
467
- RubyIndexer::Location,
468
- )
414
+ @name_location = name_location
469
415
  end
470
416
  end
471
417
 
@@ -494,13 +440,12 @@ module RubyIndexer
494
440
  nesting: T::Array[String],
495
441
  name: String,
496
442
  file_path: String,
497
- location: T.any(Prism::Location, RubyIndexer::Location),
443
+ location: Location,
498
444
  comments: T.nilable(String),
499
- encoding: Encoding,
500
445
  ).void
501
446
  end
502
- def initialize(target, nesting, name, file_path, location, comments, encoding) # rubocop:disable Metrics/ParameterLists
503
- super(name, file_path, location, comments, encoding)
447
+ def initialize(target, nesting, name, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
448
+ super(name, file_path, location, comments)
504
449
 
505
450
  @target = target
506
451
  @nesting = nesting
@@ -514,14 +459,13 @@ module RubyIndexer
514
459
  sig { returns(String) }
515
460
  attr_reader :target
516
461
 
517
- sig { params(target: String, unresolved_alias: UnresolvedConstantAlias, encoding: Encoding).void }
518
- def initialize(target, unresolved_alias, encoding)
462
+ sig { params(target: String, unresolved_alias: UnresolvedConstantAlias).void }
463
+ def initialize(target, unresolved_alias)
519
464
  super(
520
465
  unresolved_alias.name,
521
466
  unresolved_alias.file_path,
522
467
  unresolved_alias.location,
523
468
  unresolved_alias.comments,
524
- encoding
525
469
  )
526
470
 
527
471
  @visibility = unresolved_alias.visibility
@@ -541,14 +485,13 @@ module RubyIndexer
541
485
  params(
542
486
  name: String,
543
487
  file_path: String,
544
- location: T.any(Prism::Location, RubyIndexer::Location),
488
+ location: Location,
545
489
  comments: T.nilable(String),
546
- encoding: Encoding,
547
490
  owner: T.nilable(Entry::Namespace),
548
491
  ).void
549
492
  end
550
- def initialize(name, file_path, location, comments, encoding, owner) # rubocop:disable Metrics/ParameterLists
551
- super(name, file_path, location, comments, encoding)
493
+ def initialize(name, file_path, location, comments, owner)
494
+ super(name, file_path, location, comments)
552
495
  @owner = owner
553
496
  end
554
497
  end
@@ -571,13 +514,12 @@ module RubyIndexer
571
514
  old_name: String,
572
515
  owner: T.nilable(Entry::Namespace),
573
516
  file_path: String,
574
- location: T.any(Prism::Location, RubyIndexer::Location),
517
+ location: Location,
575
518
  comments: T.nilable(String),
576
- encoding: Encoding,
577
519
  ).void
578
520
  end
579
- def initialize(new_name, old_name, owner, file_path, location, comments, encoding) # rubocop:disable Metrics/ParameterLists
580
- super(new_name, file_path, location, comments, encoding)
521
+ def initialize(new_name, old_name, owner, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
522
+ super(new_name, file_path, location, comments)
581
523
 
582
524
  @new_name = new_name
583
525
  @old_name = old_name
@@ -596,9 +538,9 @@ module RubyIndexer
596
538
  attr_reader :owner
597
539
 
598
540
  sig do
599
- params(target: T.any(Member, MethodAlias), unresolved_alias: UnresolvedMethodAlias, encoding: Encoding).void
541
+ params(target: T.any(Member, MethodAlias), unresolved_alias: UnresolvedMethodAlias).void
600
542
  end
601
- def initialize(target, unresolved_alias, encoding)
543
+ def initialize(target, unresolved_alias)
602
544
  full_comments = +"Alias for #{target.name}\n"
603
545
  full_comments << "#{unresolved_alias.comments}\n"
604
546
  full_comments << target.comments
@@ -608,7 +550,6 @@ module RubyIndexer
608
550
  unresolved_alias.file_path,
609
551
  unresolved_alias.location,
610
552
  full_comments,
611
- encoding
612
553
  )
613
554
 
614
555
  @target = target
@@ -665,7 +665,6 @@ module RubyIndexer
665
665
  attached_ancestor.location,
666
666
  attached_ancestor.name_location,
667
667
  nil,
668
- @configuration.encoding,
669
668
  nil,
670
669
  )
671
670
  add(singleton, skip_prefix_tree: true)
@@ -859,7 +858,7 @@ module RubyIndexer
859
858
  return entry unless target
860
859
 
861
860
  target_name = T.must(target.first).name
862
- resolved_alias = Entry::ConstantAlias.new(target_name, entry, @configuration.encoding)
861
+ resolved_alias = Entry::ConstantAlias.new(target_name, entry)
863
862
 
864
863
  # Replace the UnresolvedAlias by a resolved one so that we don't have to do this again later
865
864
  original_entries = T.must(@entries[alias_name])
@@ -981,29 +980,23 @@ module RubyIndexer
981
980
  # nesting
982
981
  sig { params(name: String, nesting: T::Array[String]).returns(String) }
983
982
  def build_non_redundant_full_name(name, nesting)
983
+ # If there's no nesting, then we can just return the name as is
984
984
  return name if nesting.empty?
985
985
 
986
- namespace = nesting.join("::")
987
-
988
986
  # If the name is not qualified, we can just concatenate the nesting and the name
989
- return "#{namespace}::#{name}" unless name.include?("::")
987
+ return "#{nesting.join("::")}::#{name}" unless name.include?("::")
990
988
 
991
989
  name_parts = name.split("::")
990
+ first_redundant_part = nesting.index(name_parts[0])
992
991
 
993
- # Find the first part of the name that is not in the nesting
994
- index = name_parts.index { |part| !nesting.include?(part) }
992
+ # If there are no redundant parts between the name and the nesting, then the full name is both combined
993
+ return "#{nesting.join("::")}::#{name}" unless first_redundant_part
995
994
 
996
- if index.nil?
997
- # All parts of the nesting are redundant because they are already present in the name. We can return the name
998
- # directly
999
- name
1000
- elsif index == 0
1001
- # No parts of the nesting are in the name, we can concatenate the namespace and the name
1002
- "#{namespace}::#{name}"
1003
- else
1004
- # The name includes some parts of the nesting. We need to remove the redundant parts
1005
- "#{namespace}::#{T.must(name_parts[index..-1]).join("::")}"
1006
- end
995
+ # Otherwise, push all of the leading parts of the nesting that aren't redundant into the name. For example, if we
996
+ # have a reference to `Foo::Bar` inside the `[Namespace, Foo]` nesting, then only the `Foo` part is redundant, but
997
+ # we still need to include the `Namespace` part
998
+ T.unsafe(name_parts).unshift(*nesting[0...first_redundant_part])
999
+ name_parts.join("::")
1007
1000
  end
1008
1001
 
1009
1002
  sig do
@@ -1050,7 +1043,7 @@ module RubyIndexer
1050
1043
  target_method_entries = resolve_method(entry.old_name, receiver_name, seen_names)
1051
1044
  return entry unless target_method_entries
1052
1045
 
1053
- resolved_alias = Entry::MethodAlias.new(T.must(target_method_entries.first), entry, @configuration.encoding)
1046
+ resolved_alias = Entry::MethodAlias.new(T.must(target_method_entries.first), entry)
1054
1047
  original_entries = T.must(@entries[new_name])
1055
1048
  original_entries.delete(entry)
1056
1049
  original_entries << resolved_alias
@@ -5,6 +5,28 @@ module RubyIndexer
5
5
  class Location
6
6
  extend T::Sig
7
7
 
8
+ class << self
9
+ extend T::Sig
10
+
11
+ sig do
12
+ params(
13
+ prism_location: Prism::Location,
14
+ code_units_cache: T.any(
15
+ T.proc.params(arg0: Integer).returns(Integer),
16
+ Prism::CodeUnitsCache,
17
+ ),
18
+ ).returns(T.attached_class)
19
+ end
20
+ def from_prism_location(prism_location, code_units_cache)
21
+ new(
22
+ prism_location.start_line,
23
+ prism_location.end_line,
24
+ prism_location.cached_start_code_units_column(code_units_cache),
25
+ prism_location.cached_end_code_units_column(code_units_cache),
26
+ )
27
+ end
28
+ end
29
+
8
30
  sig { returns(Integer) }
9
31
  attr_reader :start_line, :end_line, :start_column, :end_column
10
32
 
@@ -61,9 +61,9 @@ module RubyIndexer
61
61
  comments = comments_to_string(declaration)
62
62
  entry = if declaration.is_a?(RBS::AST::Declarations::Class)
63
63
  parent_class = declaration.super_class&.name&.name&.to_s
64
- Entry::Class.new(nesting, file_path, location, location, comments, @index.configuration.encoding, parent_class)
64
+ Entry::Class.new(nesting, file_path, location, location, comments, parent_class)
65
65
  else
66
- Entry::Module.new(nesting, file_path, location, location, comments, @index.configuration.encoding)
66
+ Entry::Module.new(nesting, file_path, location, location, comments)
67
67
  end
68
68
  add_declaration_mixins_to_entry(declaration, entry)
69
69
  @index.add(entry)
@@ -136,7 +136,6 @@ module RubyIndexer
136
136
  location,
137
137
  location,
138
138
  comments,
139
- @index.configuration.encoding,
140
139
  signatures,
141
140
  visibility,
142
141
  real_owner,
@@ -269,7 +268,6 @@ module RubyIndexer
269
268
  file_path,
270
269
  to_ruby_indexer_location(declaration.location),
271
270
  comments_to_string(declaration),
272
- @index.configuration.encoding,
273
271
  ))
274
272
  end
275
273
 
@@ -279,14 +277,12 @@ module RubyIndexer
279
277
  file_path = pathname.to_s
280
278
  location = to_ruby_indexer_location(declaration.location)
281
279
  comments = comments_to_string(declaration)
282
- encoding = @index.configuration.encoding
283
280
 
284
281
  @index.add(Entry::GlobalVariable.new(
285
282
  name,
286
283
  file_path,
287
284
  location,
288
285
  comments,
289
- encoding,
290
286
  ))
291
287
  end
292
288
 
@@ -302,7 +298,6 @@ module RubyIndexer
302
298
  file_path,
303
299
  to_ruby_indexer_location(member.location),
304
300
  comments,
305
- @index.configuration.encoding,
306
301
  )
307
302
 
308
303
  @index.add(entry)
@@ -9,14 +9,14 @@ module RubyIndexer
9
9
  enhancement_class = Class.new do
10
10
  include Enhancement
11
11
 
12
- def on_call_node(index, owner, node, file_path)
12
+ def on_call_node(index, owner, node, file_path, code_units_cache)
13
13
  return unless owner
14
14
  return unless node.name == :extend
15
15
 
16
16
  arguments = node.arguments&.arguments
17
17
  return unless arguments
18
18
 
19
- location = node.location
19
+ location = Location.from_prism_location(node.location, code_units_cache)
20
20
 
21
21
  arguments.each do |node|
22
22
  next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
@@ -39,7 +39,6 @@ module RubyIndexer
39
39
  location,
40
40
  location,
41
41
  nil,
42
- index.configuration.encoding,
43
42
  [Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
44
43
  Entry::Visibility::PUBLIC,
45
44
  owner,
@@ -102,7 +101,7 @@ module RubyIndexer
102
101
  enhancement_class = Class.new do
103
102
  include Enhancement
104
103
 
105
- def on_call_node(index, owner, node, file_path)
104
+ def on_call_node(index, owner, node, file_path, code_units_cache)
106
105
  return unless owner
107
106
 
108
107
  name = node.name
@@ -114,7 +113,7 @@ module RubyIndexer
114
113
  association_name = arguments.first
115
114
  return unless association_name.is_a?(Prism::SymbolNode)
116
115
 
117
- location = association_name.location
116
+ location = Location.from_prism_location(association_name.location, code_units_cache)
118
117
 
119
118
  index.add(Entry::Method.new(
120
119
  T.must(association_name.value),
@@ -122,7 +121,6 @@ module RubyIndexer
122
121
  location,
123
122
  location,
124
123
  nil,
125
- index.configuration.encoding,
126
124
  [],
127
125
  Entry::Visibility::PUBLIC,
128
126
  owner,
@@ -166,7 +164,7 @@ module RubyIndexer
166
164
  enhancement_class = Class.new do
167
165
  include Enhancement
168
166
 
169
- def on_call_node(index, owner, node, file_path)
167
+ def on_call_node(index, owner, node, file_path, code_units_cache)
170
168
  raise "Error"
171
169
  end
172
170
 
@@ -0,0 +1,49 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "test_case"
5
+
6
+ module RubyIndexer
7
+ class GlobalVariableTest < TestCase
8
+ def test_global_variable_and_write
9
+ index(<<~RUBY)
10
+ $foo &&= 1
11
+ RUBY
12
+
13
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
14
+ end
15
+
16
+ def test_global_variable_operator_write
17
+ index(<<~RUBY)
18
+ $foo += 1
19
+ RUBY
20
+
21
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
22
+ end
23
+
24
+ def test_global_variable_or_write
25
+ index(<<~RUBY)
26
+ $foo ||= 1
27
+ RUBY
28
+
29
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
30
+ end
31
+
32
+ def test_global_variable_target_node
33
+ index(<<~RUBY)
34
+ $foo, $bar = 1
35
+ RUBY
36
+
37
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
38
+ assert_entry("$bar", Entry::GlobalVariable, "/fake/path/foo.rb:0-6:0-10")
39
+ end
40
+
41
+ def test_global_variable_write
42
+ index(<<~RUBY)
43
+ $foo = 1
44
+ RUBY
45
+
46
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
47
+ end
48
+ end
49
+ end
@@ -1934,5 +1934,94 @@ module RubyIndexer
1934
1934
  real_namespace = @index.follow_aliased_namespace("Namespace::Second")
1935
1935
  assert_equal("First::Second", real_namespace)
1936
1936
  end
1937
+
1938
+ def test_resolving_alias_to_non_existing_namespace
1939
+ index(<<~RUBY)
1940
+ module Namespace
1941
+ class Foo
1942
+ module InnerNamespace
1943
+ Constants = Namespace::Foo::Constants
1944
+ end
1945
+ end
1946
+ end
1947
+ RUBY
1948
+
1949
+ entry = @index.resolve("Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
1950
+ assert_instance_of(Entry::UnresolvedConstantAlias, entry)
1951
+
1952
+ entry = @index.resolve("Namespace::Foo::Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
1953
+ assert_nil(entry)
1954
+ end
1955
+
1956
+ def test_resolving_alias_to_existing_constant_from_inner_namespace
1957
+ index(<<~RUBY)
1958
+ module Parent
1959
+ CONST = 123
1960
+ end
1961
+
1962
+ module First
1963
+ module Namespace
1964
+ class Foo
1965
+ include Parent
1966
+
1967
+ module InnerNamespace
1968
+ Constants = Namespace::Foo::CONST
1969
+ end
1970
+ end
1971
+ end
1972
+ end
1973
+ RUBY
1974
+
1975
+ entry = @index.resolve("Namespace::Foo::CONST", ["First", "Namespace", "Foo", "InnerNamespace"])&.first
1976
+ assert_equal("Parent::CONST", entry.name)
1977
+ assert_instance_of(Entry::Constant, entry)
1978
+ end
1979
+
1980
+ def test_build_non_redundant_name
1981
+ assert_equal(
1982
+ "Namespace::Foo::Constants",
1983
+ @index.send(
1984
+ :build_non_redundant_full_name,
1985
+ "Namespace::Foo::Constants",
1986
+ ["Namespace", "Foo", "InnerNamespace"],
1987
+ ),
1988
+ )
1989
+
1990
+ assert_equal(
1991
+ "Namespace::Foo::Constants",
1992
+ @index.send(
1993
+ :build_non_redundant_full_name,
1994
+ "Namespace::Foo::Constants",
1995
+ ["Namespace", "Foo"],
1996
+ ),
1997
+ )
1998
+
1999
+ assert_equal(
2000
+ "Namespace::Foo::Constants",
2001
+ @index.send(
2002
+ :build_non_redundant_full_name,
2003
+ "Foo::Constants",
2004
+ ["Namespace", "Foo"],
2005
+ ),
2006
+ )
2007
+
2008
+ assert_equal(
2009
+ "Bar::Namespace::Foo::Constants",
2010
+ @index.send(
2011
+ :build_non_redundant_full_name,
2012
+ "Namespace::Foo::Constants",
2013
+ ["Bar"],
2014
+ ),
2015
+ )
2016
+
2017
+ assert_equal(
2018
+ "First::Namespace::Foo::Constants",
2019
+ @index.send(
2020
+ :build_non_redundant_full_name,
2021
+ "Namespace::Foo::Constants",
2022
+ ["First", "Namespace", "Foo", "InnerNamespace"],
2023
+ ),
2024
+ )
2025
+ end
1937
2026
  end
1938
2027
  end
@@ -6,10 +6,18 @@ module RubyLsp
6
6
  extend T::Sig
7
7
  extend T::Generic
8
8
 
9
+ ParseResultType = type_member { { fixed: Prism::ParseResult } }
10
+
9
11
  sig { returns(String) }
10
12
  attr_reader :host_language_source
11
13
 
12
- ParseResultType = type_member { { fixed: Prism::ParseResult } }
14
+ sig do
15
+ returns(T.any(
16
+ T.proc.params(arg0: Integer).returns(Integer),
17
+ Prism::CodeUnitsCache,
18
+ ))
19
+ end
20
+ attr_reader :code_units_cache
13
21
 
14
22
  sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
15
23
  def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
@@ -17,6 +25,10 @@ module RubyLsp
17
25
  # overrides this with the proper virtual host language source
18
26
  @host_language_source = T.let("", String)
19
27
  super
28
+ @code_units_cache = T.let(@parse_result.code_units_cache(@encoding), T.any(
29
+ T.proc.params(arg0: Integer).returns(Integer),
30
+ Prism::CodeUnitsCache,
31
+ ))
20
32
  end
21
33
 
22
34
  sig { override.returns(T::Boolean) }
@@ -30,6 +42,7 @@ module RubyLsp
30
42
  # Use partial script to avoid syntax errors in ERB files where keywords may be used without the full context in
31
43
  # which they will be evaluated
32
44
  @parse_result = Prism.parse(scanner.ruby, partial_script: true)
45
+ @code_units_cache = @parse_result.code_units_cache(@encoding)
33
46
  true
34
47
  end
35
48
 
@@ -53,8 +66,8 @@ module RubyLsp
53
66
  RubyDocument.locate(
54
67
  @parse_result.value,
55
68
  create_scanner.find_char_position(position),
69
+ code_units_cache: @code_units_cache,
56
70
  node_types: node_types,
57
- encoding: @encoding,
58
71
  )
59
72
  end
60
73