ruby-lsp 0.19.1 → 0.20.1

Sign up to get free protection for your applications and to get access to all the features.
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