ruby-lsp 0.26.4 → 0.26.6

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp-launcher +4 -3
  4. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +3 -2
  5. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +19 -0
  6. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +33 -27
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +1 -0
  8. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +6 -2
  9. data/lib/ruby_lsp/global_state.rb +65 -33
  10. data/lib/ruby_lsp/listeners/definition.rb +34 -14
  11. data/lib/ruby_lsp/listeners/document_link.rb +1 -6
  12. data/lib/ruby_lsp/listeners/hover.rb +2 -2
  13. data/lib/ruby_lsp/requests/code_action_resolve.rb +33 -11
  14. data/lib/ruby_lsp/requests/code_actions.rb +20 -5
  15. data/lib/ruby_lsp/requests/completion_resolve.rb +8 -6
  16. data/lib/ruby_lsp/requests/support/source_uri.rb +7 -6
  17. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  18. data/lib/ruby_lsp/setup_bundler.rb +39 -25
  19. metadata +2 -16
  20. data/lib/ruby_indexer/test/class_variables_test.rb +0 -140
  21. data/lib/ruby_indexer/test/classes_and_modules_test.rb +0 -770
  22. data/lib/ruby_indexer/test/configuration_test.rb +0 -279
  23. data/lib/ruby_indexer/test/constant_test.rb +0 -402
  24. data/lib/ruby_indexer/test/enhancements_test.rb +0 -325
  25. data/lib/ruby_indexer/test/global_variable_test.rb +0 -49
  26. data/lib/ruby_indexer/test/index_test.rb +0 -2276
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +0 -264
  28. data/lib/ruby_indexer/test/method_test.rb +0 -990
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +0 -150
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +0 -381
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +0 -395
  32. data/lib/ruby_indexer/test/test_case.rb +0 -57
  33. data/lib/ruby_indexer/test/uri_test.rb +0 -85
@@ -1,2276 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require_relative "test_case"
5
-
6
- module RubyIndexer
7
- class IndexTest < TestCase
8
- def test_deleting_one_entry_for_a_class
9
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
10
- class Foo
11
- end
12
- RUBY
13
- @index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb"), <<~RUBY)
14
- class Foo
15
- end
16
- RUBY
17
-
18
- entries = @index["Foo"] #: as !nil
19
- assert_equal(2, entries.length)
20
-
21
- @index.delete(URI::Generic.from_path(path: "/fake/path/other_foo.rb"))
22
- entries = @index["Foo"] #: as !nil
23
- assert_equal(1, entries.length)
24
- end
25
-
26
- def test_deleting_all_entries_for_a_class
27
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
28
- class Foo
29
- end
30
- RUBY
31
-
32
- entries = @index["Foo"] #: as !nil
33
- assert_equal(1, entries.length)
34
-
35
- @index.delete(URI::Generic.from_path(path: "/fake/path/foo.rb"))
36
- entries = @index["Foo"]
37
- assert_nil(entries)
38
- end
39
-
40
- def test_index_resolve
41
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
42
- class Bar; end
43
-
44
- module Foo
45
- class Bar
46
- end
47
-
48
- class Baz
49
- class Something
50
- end
51
- end
52
- end
53
- RUBY
54
-
55
- entries = @index.resolve("Something", ["Foo", "Baz"]) #: as !nil
56
- refute_empty(entries)
57
- assert_equal("Foo::Baz::Something", entries.first&.name)
58
-
59
- entries = @index.resolve("Bar", ["Foo"]) #: as !nil
60
- refute_empty(entries)
61
- assert_equal("Foo::Bar", entries.first&.name)
62
-
63
- entries = @index.resolve("Bar", ["Foo", "Baz"]) #: as !nil
64
- refute_empty(entries)
65
- assert_equal("Foo::Bar", entries.first&.name)
66
-
67
- entries = @index.resolve("Foo::Bar", ["Foo", "Baz"]) #: as !nil
68
- refute_empty(entries)
69
- assert_equal("Foo::Bar", entries.first&.name)
70
-
71
- assert_nil(@index.resolve("DoesNotExist", ["Foo"]))
72
- end
73
-
74
- def test_accessing_with_colon_colon_prefix
75
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
76
- class Bar; end
77
-
78
- module Foo
79
- class Bar
80
- end
81
-
82
- class Baz
83
- class Something
84
- end
85
- end
86
- end
87
- RUBY
88
-
89
- entries = @index["::Foo::Baz::Something"] #: as !nil
90
- refute_empty(entries)
91
- assert_equal("Foo::Baz::Something", entries.first&.name)
92
- end
93
-
94
- def test_fuzzy_search
95
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
96
- class Zws; end
97
-
98
- module Qtl
99
- class Zws
100
- end
101
-
102
- class Zwo
103
- class Something
104
- end
105
- end
106
- end
107
- RUBY
108
-
109
- result = @index.fuzzy_search("Zws")
110
- assert_equal(2, result.length)
111
- assert_equal(["Zws", "Qtl::Zwo::Something"], result.map(&:name))
112
-
113
- result = @index.fuzzy_search("qtlzwssomeking")
114
- assert_equal(5, result.length)
115
- assert_equal(["Qtl::Zwo::Something", "Qtl::Zws", "Qtl::Zwo", "Qtl", "Zws"], result.map(&:name))
116
-
117
- result = @index.fuzzy_search("QltZwo")
118
- assert_equal(4, result.length)
119
- assert_equal(["Qtl::Zwo", "Qtl::Zws", "Qtl::Zwo::Something", "Qtl"], result.map(&:name))
120
- end
121
-
122
- def test_index_single_ignores_directories
123
- path = "#{Dir.pwd}/lib/this_is_a_dir.rb"
124
- FileUtils.mkdir(path)
125
-
126
- begin
127
- @index.index_file(URI::Generic.from_path(path: path))
128
- ensure
129
- FileUtils.rm_r(path)
130
- end
131
- end
132
-
133
- def test_searching_for_require_paths
134
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
135
- class Foo
136
- end
137
- RUBY
138
- @index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
139
- class Foo
140
- end
141
- RUBY
142
-
143
- assert_equal(["path/other_foo", "path/foo"], @index.search_require_paths("path").map(&:require_path))
144
- end
145
-
146
- def test_searching_for_entries_based_on_prefix
147
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
148
- class Foo::Bizw
149
- end
150
- RUBY
151
- @index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
152
- class Foo::Bizw
153
- end
154
-
155
- class Foo::Bizt
156
- end
157
- RUBY
158
-
159
- results = @index.prefix_search("Foo", []).map { |entries| entries.map(&:name) }
160
- assert_equal([["Foo::Bizt"], ["Foo::Bizw", "Foo::Bizw"]], results)
161
-
162
- results = @index.prefix_search("Biz", ["Foo"]).map { |entries| entries.map(&:name) }
163
- assert_equal([["Foo::Bizt"], ["Foo::Bizw", "Foo::Bizw"]], results)
164
- end
165
-
166
- def test_resolve_normalizes_top_level_names
167
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
168
- class Bar; end
169
-
170
- module Foo
171
- class Bar; end
172
- end
173
- RUBY
174
-
175
- entries = @index.resolve("::Foo::Bar", []) #: as !nil
176
- refute_nil(entries)
177
-
178
- assert_equal("Foo::Bar", entries.first&.name)
179
-
180
- entries = @index.resolve("::Bar", ["Foo"]) #: as !nil
181
- refute_nil(entries)
182
-
183
- assert_equal("Bar", entries.first&.name)
184
- end
185
-
186
- def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
187
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
188
- class Bar
189
- end
190
-
191
- module Foo
192
- class Bar < self
193
- BAZ = ::Bar::BAZ
194
- end
195
- end
196
- RUBY
197
-
198
- entry = @index.resolve("BAZ", ["Foo", "Bar"])&.first
199
- refute_nil(entry)
200
-
201
- assert_instance_of(Entry::UnresolvedConstantAlias, entry)
202
- end
203
-
204
- def test_visitor_does_not_visit_unnecessary_nodes
205
- concats = (0...10_000).map do |i|
206
- <<~STRING
207
- "string#{i}" \\
208
- STRING
209
- end.join
210
-
211
- index(<<~RUBY)
212
- module Foo
213
- local_var = #{concats}
214
- "final"
215
- @class_instance_var = #{concats}
216
- "final"
217
- @@class_var = #{concats}
218
- "final"
219
- $global_var = #{concats}
220
- "final"
221
- CONST = #{concats}
222
- "final"
223
- end
224
- RUBY
225
- end
226
-
227
- def test_resolve_method_with_known_receiver
228
- index(<<~RUBY)
229
- module Foo
230
- module Bar
231
- def baz; end
232
- end
233
- end
234
- RUBY
235
-
236
- entries = @index.resolve_method("baz", "Foo::Bar") #: as !nil
237
- assert_equal("baz", entries.first&.name)
238
- owner = entries.first&.owner #: as !nil
239
- assert_equal("Foo::Bar", owner.name)
240
- end
241
-
242
- def test_resolve_method_with_class_name_conflict
243
- index(<<~RUBY)
244
- class Array
245
- end
246
-
247
- class Foo
248
- def Array(*args); end
249
- end
250
- RUBY
251
-
252
- entries = @index.resolve_method("Array", "Foo") #: as !nil
253
- assert_equal("Array", entries.first&.name)
254
- owner = entries.first&.owner #: as !nil
255
- assert_equal("Foo", owner.name)
256
- end
257
-
258
- def test_resolve_method_attribute
259
- index(<<~RUBY)
260
- class Foo
261
- attr_reader :bar
262
- end
263
- RUBY
264
-
265
- entries = @index.resolve_method("bar", "Foo") #: as !nil
266
- assert_equal("bar", entries.first&.name)
267
- owner = entries.first&.owner #: as !nil
268
- assert_equal("Foo", owner.name)
269
- end
270
-
271
- def test_resolve_method_with_two_definitions
272
- index(<<~RUBY)
273
- class Foo
274
- # Hello from first `bar`
275
- def bar; end
276
- end
277
-
278
- class Foo
279
- # Hello from second `bar`
280
- def bar; end
281
- end
282
- RUBY
283
-
284
- first_entry, second_entry = @index.resolve_method("bar", "Foo") #: as !nil
285
-
286
- assert_equal("bar", first_entry&.name)
287
- owner = first_entry&.owner #: as !nil
288
- assert_equal("Foo", owner.name)
289
- assert_includes(first_entry&.comments, "Hello from first `bar`")
290
-
291
- assert_equal("bar", second_entry&.name)
292
- owner = second_entry&.owner #: as !nil
293
- assert_equal("Foo", owner.name)
294
- assert_includes(second_entry&.comments, "Hello from second `bar`")
295
- end
296
-
297
- def test_resolve_method_inherited_only
298
- index(<<~RUBY)
299
- class Bar
300
- def baz; end
301
- end
302
-
303
- class Foo < Bar
304
- def baz; end
305
- end
306
- RUBY
307
-
308
- entry = @index.resolve_method("baz", "Foo", inherited_only: true)&.first #: as !nil
309
- assert_equal("Bar", entry.owner&.name)
310
- end
311
-
312
- def test_resolve_method_inherited_only_for_prepended_module
313
- index(<<~RUBY)
314
- module Bar
315
- def baz
316
- super
317
- end
318
- end
319
-
320
- class Foo
321
- prepend Bar
322
-
323
- def baz; end
324
- end
325
- RUBY
326
-
327
- # This test is just to document the fact that we don't yet support resolving inherited methods for modules that
328
- # are prepended. The only way to support this is to find all namespaces that have the module a subtype, so that we
329
- # can show the results for everywhere the module has been prepended.
330
- assert_nil(@index.resolve_method("baz", "Bar", inherited_only: true))
331
- end
332
-
333
- def test_prefix_search_for_methods
334
- index(<<~RUBY)
335
- module Foo
336
- module Bar
337
- def qzx; end
338
- end
339
- end
340
- RUBY
341
-
342
- entries = @index.prefix_search("qz")
343
- refute_empty(entries)
344
-
345
- entry = entries.first&.first #: as !nil
346
- assert_equal("qzx", entry.name)
347
- end
348
-
349
- def test_indexing_prism_fixtures_succeeds
350
- unless Dir.exist?("test/fixtures/prism/test/prism/fixtures")
351
- raise "Prism fixtures not found. Run `git submodule update --init` to fetch them."
352
- end
353
-
354
- fixtures = Dir.glob("#{Dir.pwd}/test/fixtures/prism/test/prism/fixtures/**/*.txt")
355
-
356
- fixtures.each do |fixture|
357
- uri = URI::Generic.from_path(path: fixture)
358
- @index.index_file(uri)
359
- end
360
-
361
- refute_empty(@index)
362
- end
363
-
364
- def test_index_single_does_not_fail_for_non_existing_file
365
- @index.index_file(URI::Generic.from_path(path: "/fake/path/foo.rb"))
366
- entries_after_indexing = @index.names
367
- assert_equal(@default_indexed_entries.keys, entries_after_indexing)
368
- end
369
-
370
- def test_linearized_ancestors_basic_ordering
371
- index(<<~RUBY)
372
- module A; end
373
- module B; end
374
-
375
- class Foo
376
- prepend A
377
- prepend B
378
- end
379
-
380
- class Bar
381
- include A
382
- include B
383
- end
384
- RUBY
385
-
386
- assert_equal(
387
- [
388
- "B",
389
- "A",
390
- "Foo",
391
- "Object",
392
- "Kernel",
393
- "BasicObject",
394
- ],
395
- @index.linearized_ancestors_of("Foo"),
396
- )
397
-
398
- assert_equal(
399
- [
400
- "Bar",
401
- "B",
402
- "A",
403
- "Object",
404
- "Kernel",
405
- "BasicObject",
406
- ],
407
- @index.linearized_ancestors_of("Bar"),
408
- )
409
- end
410
-
411
- def test_linearized_ancestors
412
- index(<<~RUBY)
413
- module A; end
414
- module B; end
415
- module C; end
416
-
417
- module D
418
- include A
419
- end
420
-
421
- module E
422
- prepend B
423
- end
424
-
425
- module F
426
- include C
427
- include A
428
- end
429
-
430
- class Bar
431
- prepend F
432
- end
433
-
434
- class Foo < Bar
435
- include E
436
- prepend D
437
- end
438
- RUBY
439
-
440
- # Object, Kernel and BasicObject are intentionally commented out for now until we develop a strategy for indexing
441
- # declarations made in C code
442
- assert_equal(
443
- [
444
- "D",
445
- "A",
446
- "Foo",
447
- "B",
448
- "E",
449
- "F",
450
- "A",
451
- "C",
452
- "Bar",
453
- "Object",
454
- "Kernel",
455
- "BasicObject",
456
- ],
457
- @index.linearized_ancestors_of("Foo"),
458
- )
459
- end
460
-
461
- def test_linearized_ancestors_duplicates
462
- index(<<~RUBY)
463
- module A; end
464
- module B
465
- include A
466
- end
467
-
468
- class Foo
469
- include B
470
- include A
471
- end
472
-
473
- class Bar
474
- prepend B
475
- prepend A
476
- end
477
- RUBY
478
-
479
- assert_equal(
480
- [
481
- "Foo",
482
- "B",
483
- "A",
484
- "Object",
485
- "Kernel",
486
- "BasicObject",
487
- ],
488
- @index.linearized_ancestors_of("Foo"),
489
- )
490
-
491
- assert_equal(
492
- [
493
- "B",
494
- "A",
495
- "Bar",
496
- "Object",
497
- "Kernel",
498
- "BasicObject",
499
- ],
500
- @index.linearized_ancestors_of("Bar"),
501
- )
502
- end
503
-
504
- def test_linearizing_ancestors_is_cached
505
- index(<<~RUBY)
506
- module C; end
507
- module A; end
508
- module B
509
- include A
510
- end
511
-
512
- class Foo
513
- include B
514
- include A
515
- end
516
- RUBY
517
-
518
- @index.linearized_ancestors_of("Foo")
519
- ancestors = @index.instance_variable_get(:@ancestors)
520
- assert(ancestors.key?("Foo"))
521
- assert(ancestors.key?("A"))
522
- assert(ancestors.key?("B"))
523
- refute(ancestors.key?("C"))
524
- end
525
-
526
- def test_duplicate_prepend_include
527
- index(<<~RUBY)
528
- module A; end
529
-
530
- class Foo
531
- prepend A
532
- include A
533
- end
534
-
535
- class Bar
536
- include A
537
- prepend A
538
- end
539
- RUBY
540
-
541
- assert_equal(
542
- [
543
- "A",
544
- "Foo",
545
- "Object",
546
- "Kernel",
547
- "BasicObject",
548
- ],
549
- @index.linearized_ancestors_of("Foo"),
550
- )
551
-
552
- assert_equal(
553
- [
554
- "A",
555
- "Bar",
556
- "A",
557
- "Object",
558
- "Kernel",
559
- "BasicObject",
560
- ],
561
- @index.linearized_ancestors_of("Bar"),
562
- )
563
- end
564
-
565
- def test_linearizing_ancestors_handles_circular_parent_class
566
- index(<<~RUBY)
567
- class Foo < Foo
568
- end
569
- RUBY
570
-
571
- assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
572
- end
573
-
574
- def test_ancestors_linearization_complex_prepend_duplication
575
- index(<<~RUBY)
576
- module A; end
577
- module B
578
- prepend A
579
- end
580
- module C
581
- prepend B
582
- end
583
-
584
- class Foo
585
- prepend A
586
- prepend C
587
- end
588
- RUBY
589
-
590
- assert_equal(
591
- [
592
- "A",
593
- "B",
594
- "C",
595
- "Foo",
596
- "Object",
597
- "Kernel",
598
- "BasicObject",
599
- ],
600
- @index.linearized_ancestors_of("Foo"),
601
- )
602
- end
603
-
604
- def test_ancestors_linearization_complex_include_duplication
605
- index(<<~RUBY)
606
- module A; end
607
- module B
608
- include A
609
- end
610
- module C
611
- include B
612
- end
613
-
614
- class Foo
615
- include A
616
- include C
617
- end
618
- RUBY
619
-
620
- assert_equal(
621
- [
622
- "Foo",
623
- "C",
624
- "B",
625
- "A",
626
- "Object",
627
- "Kernel",
628
- "BasicObject",
629
- ],
630
- @index.linearized_ancestors_of("Foo"),
631
- )
632
- end
633
-
634
- def test_linearizing_ancestors_that_need_to_be_resolved
635
- index(<<~RUBY)
636
- module Foo
637
- module Baz
638
- end
639
- module Qux
640
- end
641
-
642
- class Something; end
643
-
644
- class Bar < Something
645
- include Baz
646
- prepend Qux
647
- end
648
- end
649
- RUBY
650
-
651
- assert_equal(
652
- [
653
- "Foo::Qux",
654
- "Foo::Bar",
655
- "Foo::Baz",
656
- "Foo::Something",
657
- "Object",
658
- "Kernel",
659
- "BasicObject",
660
- ],
661
- @index.linearized_ancestors_of("Foo::Bar"),
662
- )
663
- end
664
-
665
- def test_linearizing_ancestors_for_non_existing_namespaces
666
- index(<<~RUBY)
667
- def Bar(a); end
668
- RUBY
669
-
670
- assert_raises(Index::NonExistingNamespaceError) do
671
- @index.linearized_ancestors_of("Foo")
672
- end
673
-
674
- assert_raises(Index::NonExistingNamespaceError) do
675
- @index.linearized_ancestors_of("Bar")
676
- end
677
- end
678
-
679
- def test_linearizing_circular_ancestors
680
- index(<<~RUBY)
681
- module M1
682
- include M2
683
- end
684
-
685
- module M2
686
- include M1
687
- end
688
-
689
- module A1
690
- include A2
691
- end
692
-
693
- module A2
694
- include A3
695
- end
696
-
697
- module A3
698
- include A1
699
- end
700
-
701
- class Foo < Foo
702
- include Foo
703
- end
704
-
705
- module Bar
706
- include Bar
707
- end
708
- RUBY
709
-
710
- assert_equal(["M2", "M1"], @index.linearized_ancestors_of("M2"))
711
- assert_equal(["A3", "A1", "A2"], @index.linearized_ancestors_of("A3"))
712
- assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
713
- assert_equal(["Bar"], @index.linearized_ancestors_of("Bar"))
714
- end
715
-
716
- def test_linearizing_circular_aliased_dependency
717
- index(<<~RUBY)
718
- module A
719
- end
720
-
721
- ALIAS = A
722
-
723
- module A
724
- include ALIAS
725
- end
726
- RUBY
727
-
728
- assert_equal(["A", "ALIAS"], @index.linearized_ancestors_of("A"))
729
- end
730
-
731
- def test_linearizing_ancestors_for_classes_with_overridden_parents
732
- index(<<~RUBY)
733
- # Find the re-open of a class first, without specifying a parent
734
- class Child
735
- end
736
-
737
- # Now, find the actual definition of the class, which includes a parent
738
- class Parent; end
739
- class Child < Parent
740
- end
741
- RUBY
742
-
743
- assert_equal(
744
- [
745
- "Child",
746
- "Parent",
747
- "Object",
748
- "Kernel",
749
- "BasicObject",
750
- ],
751
- @index.linearized_ancestors_of("Child"),
752
- )
753
- end
754
-
755
- def test_resolving_an_inherited_method
756
- index(<<~RUBY)
757
- module Foo
758
- def baz; end
759
- end
760
-
761
- class Bar
762
- def qux; end
763
- end
764
-
765
- class Wow < Bar
766
- include Foo
767
- end
768
- RUBY
769
-
770
- entry = @index.resolve_method("baz", "Wow")&.first #: as !nil
771
- assert_equal("baz", entry.name)
772
- assert_equal("Foo", entry.owner&.name)
773
-
774
- entry = @index.resolve_method("qux", "Wow")&.first #: as !nil
775
- assert_equal("qux", entry.name)
776
- assert_equal("Bar", entry.owner&.name)
777
- end
778
-
779
- def test_resolving_an_inherited_method_lands_on_first_match
780
- index(<<~RUBY)
781
- module Foo
782
- def qux; end
783
- end
784
-
785
- class Bar
786
- def qux; end
787
- end
788
-
789
- class Wow < Bar
790
- prepend Foo
791
-
792
- def qux; end
793
- end
794
- RUBY
795
-
796
- entries = @index.resolve_method("qux", "Wow") #: as !nil
797
- assert_equal(1, entries.length)
798
-
799
- entry = entries.first #: as !nil
800
- assert_equal("qux", entry.name)
801
- assert_equal("Foo", entry.owner&.name)
802
- end
803
-
804
- def test_handle_change_clears_ancestor_cache_if_tree_changed
805
- Dir.mktmpdir do |dir|
806
- Dir.chdir(dir) do
807
- # Write the original file
808
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
809
- module Foo
810
- end
811
-
812
- class Bar
813
- include Foo
814
- end
815
- RUBY
816
-
817
- uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
818
- @index.index_file(uri)
819
-
820
- assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
821
-
822
- # Remove include to invalidate the ancestor tree
823
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
824
- module Foo
825
- end
826
-
827
- class Bar
828
- end
829
- RUBY
830
-
831
- path = uri.full_path #: as !nil
832
- @index.handle_change(uri, File.read(path))
833
- assert_empty(@index.instance_variable_get(:@ancestors))
834
- assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
835
- end
836
- end
837
- end
838
-
839
- def test_handle_change_does_not_clear_ancestor_cache_if_tree_not_changed
840
- Dir.mktmpdir do |dir|
841
- Dir.chdir(dir) do
842
- # Write the original file
843
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
844
- module Foo
845
- end
846
-
847
- class Bar
848
- include Foo
849
- end
850
- RUBY
851
-
852
- uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
853
- @index.index_file(uri)
854
-
855
- assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
856
-
857
- # Remove include to invalidate the ancestor tree
858
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
859
- module Foo
860
- end
861
-
862
- class Bar
863
- include Foo
864
-
865
- def baz; end
866
- end
867
- RUBY
868
-
869
- path = uri.full_path #: as !nil
870
- @index.handle_change(uri, File.read(path))
871
- refute_empty(@index.instance_variable_get(:@ancestors))
872
- assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
873
- end
874
- end
875
- end
876
-
877
- def test_handle_change_clears_ancestor_cache_if_parent_class_changed
878
- Dir.mktmpdir do |dir|
879
- Dir.chdir(dir) do
880
- # Write the original file
881
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
882
- class Foo
883
- end
884
-
885
- class Bar < Foo
886
- end
887
- RUBY
888
-
889
- uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
890
- @index.index_file(uri)
891
-
892
- assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
893
-
894
- # Remove include to invalidate the ancestor tree
895
- File.write(File.join(dir, "foo.rb"), <<~RUBY)
896
- class Foo
897
- end
898
-
899
- class Bar
900
- end
901
- RUBY
902
-
903
- path = uri.full_path #: as !nil
904
- @index.handle_change(uri, File.read(path))
905
- assert_empty(@index.instance_variable_get(:@ancestors))
906
- assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
907
- end
908
- end
909
- end
910
-
911
- def test_resolving_inherited_constants
912
- index(<<~RUBY)
913
- module Foo
914
- CONST = 1
915
- end
916
-
917
- module Baz
918
- CONST = 2
919
- end
920
-
921
- module Qux
922
- include Foo
923
- end
924
-
925
- module Namespace
926
- CONST = 3
927
-
928
- include Baz
929
-
930
- class Bar
931
- include Qux
932
- end
933
- end
934
-
935
- CONST = 4
936
- RUBY
937
-
938
- entry = @index.resolve("CONST", ["Namespace", "Bar"])&.first #: as !nil
939
- assert_equal(14, entry.location.start_line)
940
- end
941
-
942
- def test_resolving_inherited_aliased_namespace
943
- index(<<~RUBY)
944
- module Bar
945
- TARGET = 123
946
- end
947
-
948
- module Foo
949
- CONST = Bar
950
- end
951
-
952
- module Namespace
953
- class Bar
954
- include Foo
955
- end
956
- end
957
- RUBY
958
-
959
- entry = @index.resolve("Foo::CONST::TARGET", [])&.first #: as !nil
960
- assert_equal(2, entry.location.start_line)
961
-
962
- entry = @index.resolve("Namespace::Bar::CONST::TARGET", [])&.first #: as !nil
963
- assert_equal(2, entry.location.start_line)
964
- end
965
-
966
- def test_resolving_same_constant_from_different_scopes
967
- index(<<~RUBY)
968
- module Namespace
969
- CONST = 123
970
-
971
- class Parent
972
- CONST = 321
973
- end
974
-
975
- class Child < Parent
976
- end
977
- end
978
- RUBY
979
-
980
- entry = @index.resolve("CONST", ["Namespace", "Child"])&.first #: as !nil
981
- assert_equal(2, entry.location.start_line)
982
-
983
- entry = @index.resolve("Namespace::Child::CONST", [])&.first #: as !nil
984
- assert_equal(5, entry.location.start_line)
985
- end
986
-
987
- def test_resolving_prepended_constants
988
- index(<<~RUBY)
989
- module Included
990
- CONST = 123
991
- end
992
-
993
- module Prepended
994
- CONST = 321
995
- end
996
-
997
- class Foo
998
- include Included
999
- prepend Prepended
1000
- end
1001
-
1002
- class Bar
1003
- CONST = 456
1004
- include Included
1005
- prepend Prepended
1006
- end
1007
- RUBY
1008
-
1009
- entry = @index.resolve("CONST", ["Foo"])&.first #: as !nil
1010
- assert_equal(6, entry.location.start_line)
1011
-
1012
- entry = @index.resolve("Foo::CONST", [])&.first #: as !nil
1013
- assert_equal(6, entry.location.start_line)
1014
-
1015
- entry = @index.resolve("Bar::CONST", [])&.first #: as !nil
1016
- assert_equal(15, entry.location.start_line)
1017
- end
1018
-
1019
- def test_resolving_constants_favors_ancestors_over_top_level
1020
- index(<<~RUBY)
1021
- module Value1
1022
- CONST = 1
1023
- end
1024
-
1025
- module Value2
1026
- CONST = 2
1027
- end
1028
-
1029
- CONST = 3
1030
- module First
1031
- include Value1
1032
-
1033
- module Second
1034
- include Value2
1035
- end
1036
- end
1037
- RUBY
1038
-
1039
- entry = @index.resolve("CONST", ["First", "Second"])&.first #: as !nil
1040
- assert_equal(6, entry.location.start_line)
1041
- end
1042
-
1043
- def test_resolving_circular_alias
1044
- index(<<~RUBY)
1045
- module Namespace
1046
- FOO = BAR
1047
- BAR = FOO
1048
- end
1049
- RUBY
1050
-
1051
- foo_entry = @index.resolve("FOO", ["Namespace"])&.first #: as !nil
1052
- assert_equal(2, foo_entry.location.start_line)
1053
- assert_instance_of(Entry::ConstantAlias, foo_entry)
1054
-
1055
- bar_entry = @index.resolve("BAR", ["Namespace"])&.first #: as !nil
1056
- assert_equal(3, bar_entry.location.start_line)
1057
- assert_instance_of(Entry::ConstantAlias, bar_entry)
1058
- end
1059
-
1060
- def test_resolving_circular_alias_three_levels
1061
- index(<<~RUBY)
1062
- module Namespace
1063
- FOO = BAR
1064
- BAR = BAZ
1065
- BAZ = FOO
1066
- end
1067
- RUBY
1068
-
1069
- foo_entry = @index.resolve("FOO", ["Namespace"])&.first #: as !nil
1070
- assert_equal(2, foo_entry.location.start_line)
1071
- assert_instance_of(Entry::ConstantAlias, foo_entry)
1072
-
1073
- bar_entry = @index.resolve("BAR", ["Namespace"])&.first #: as !nil
1074
- assert_equal(3, bar_entry.location.start_line)
1075
- assert_instance_of(Entry::ConstantAlias, bar_entry)
1076
-
1077
- baz_entry = @index.resolve("BAZ", ["Namespace"])&.first #: as !nil
1078
- assert_equal(4, baz_entry.location.start_line)
1079
- assert_instance_of(Entry::ConstantAlias, baz_entry)
1080
- end
1081
-
1082
- def test_resolving_constants_in_aliased_namespace
1083
- index(<<~RUBY)
1084
- module Original
1085
- module Something
1086
- CONST = 123
1087
- end
1088
- end
1089
-
1090
- module Other
1091
- ALIAS = Original::Something
1092
- end
1093
-
1094
- module Third
1095
- Other::ALIAS::CONST
1096
- end
1097
- RUBY
1098
-
1099
- entry = @index.resolve("Other::ALIAS::CONST", ["Third"])&.first #: as !nil
1100
- assert_kind_of(Entry::Constant, entry)
1101
- assert_equal("Original::Something::CONST", entry.name)
1102
- end
1103
-
1104
- def test_resolving_top_level_aliases
1105
- index(<<~RUBY)
1106
- class Foo
1107
- CONST = 123
1108
- end
1109
-
1110
- FOO = Foo
1111
- FOO::CONST
1112
- RUBY
1113
-
1114
- entry = @index.resolve("FOO::CONST", [])&.first #: as !nil
1115
- assert_kind_of(Entry::Constant, entry)
1116
- assert_equal("Foo::CONST", entry.name)
1117
- end
1118
-
1119
- def test_resolving_top_level_compact_reference
1120
- index(<<~RUBY)
1121
- class Foo::Bar
1122
- end
1123
- RUBY
1124
-
1125
- foo_entry = @index.resolve("Foo::Bar", [])&.first #: as !nil
1126
- assert_equal(1, foo_entry.location.start_line)
1127
- assert_instance_of(Entry::Class, foo_entry)
1128
- end
1129
-
1130
- def test_resolving_references_with_redundant_namespaces
1131
- index(<<~RUBY)
1132
- module Bar
1133
- CONST = 1
1134
- end
1135
-
1136
- module A
1137
- CONST = 2
1138
-
1139
- module B
1140
- CONST = 3
1141
-
1142
- class Foo
1143
- include Bar
1144
- end
1145
-
1146
- A::B::Foo::CONST
1147
- end
1148
- end
1149
- RUBY
1150
-
1151
- foo_entry = @index.resolve("A::B::Foo::CONST", ["A", "B"])&.first #: as !nil
1152
- assert_equal(2, foo_entry.location.start_line)
1153
- end
1154
-
1155
- def test_resolving_self_referential_constant_alias
1156
- index(<<~RUBY)
1157
- module A
1158
- module B
1159
- class C
1160
- end
1161
- end
1162
- end
1163
-
1164
- module A
1165
- module D
1166
- B = B::C
1167
- end
1168
- end
1169
- RUBY
1170
-
1171
- entry = @index.resolve("A::D::B", [])&.first #: as Entry::ConstantAlias
1172
-
1173
- assert_kind_of(RubyIndexer::Entry::ConstantAlias, entry)
1174
- assert_equal(10, entry.location.start_line)
1175
- assert_equal("A::B::C", entry.target)
1176
- end
1177
-
1178
- def test_resolving_non_existing_self_referential_constant_alias
1179
- index(<<~RUBY)
1180
- module Foo
1181
- SomeClass = ::SomeClass
1182
- UNRESOLVED = SomeClass::CONSTANT
1183
- end
1184
- RUBY
1185
-
1186
- entry = @index.resolve("Foo::UNRESOLVED", [])&.first #: as Entry::UnresolvedConstantAlias
1187
- assert_kind_of(Entry::UnresolvedConstantAlias, entry)
1188
- assert_equal(3, entry.location.start_line)
1189
- assert_equal("SomeClass::CONSTANT", entry.target)
1190
-
1191
- entry = @index.resolve("SomeClass::CONSTANT", ["Foo"])
1192
- refute(entry)
1193
- end
1194
-
1195
- def test_resolving_qualified_references
1196
- index(<<~RUBY)
1197
- module Namespace
1198
- class Entry
1199
- CONST = 1
1200
- end
1201
- end
1202
-
1203
- module Namespace
1204
- class Index
1205
- end
1206
- end
1207
- RUBY
1208
-
1209
- foo_entry = @index.resolve("Entry::CONST", ["Namespace", "Index"])&.first #: as !nil
1210
- assert_equal(3, foo_entry.location.start_line)
1211
- end
1212
-
1213
- def test_resolving_unqualified_references
1214
- index(<<~RUBY)
1215
- module Foo
1216
- CONST = 1
1217
- end
1218
-
1219
- module Namespace
1220
- CONST = 2
1221
-
1222
- class Index
1223
- include Foo
1224
- end
1225
- end
1226
- RUBY
1227
-
1228
- foo_entry = @index.resolve("CONST", ["Namespace", "Index"])&.first #: as !nil
1229
- assert_equal(6, foo_entry.location.start_line)
1230
- end
1231
-
1232
- def test_resolving_references_with_only_top_level_declaration
1233
- index(<<~RUBY)
1234
- CONST = 1
1235
-
1236
- module Foo; end
1237
-
1238
- module Namespace
1239
- class Index
1240
- include Foo
1241
- end
1242
- end
1243
- RUBY
1244
-
1245
- foo_entry = @index.resolve("CONST", ["Namespace", "Index"])&.first #: as !nil
1246
- assert_equal(1, foo_entry.location.start_line)
1247
- end
1248
-
1249
- def test_instance_variables_completions_from_different_owners_with_conflicting_names
1250
- index(<<~RUBY)
1251
- class Foo
1252
- def initialize
1253
- @bar = 1
1254
- end
1255
- end
1256
-
1257
- class Bar
1258
- def initialize
1259
- @bar = 2
1260
- end
1261
- end
1262
- RUBY
1263
-
1264
- entry = @index.instance_variable_completion_candidates("@", "Bar").first #: as !nil
1265
- assert_equal("@bar", entry.name)
1266
- assert_equal("Bar", entry.owner&.name)
1267
- end
1268
-
1269
- def test_resolving_a_qualified_reference
1270
- index(<<~RUBY)
1271
- class Base
1272
- module Third
1273
- CONST = 1
1274
- end
1275
- end
1276
-
1277
- class Foo
1278
- module Third
1279
- CONST = 2
1280
- end
1281
-
1282
- class Second < Base
1283
- end
1284
- end
1285
- RUBY
1286
-
1287
- foo_entry = @index.resolve("Third::CONST", ["Foo"])&.first #: as !nil
1288
- assert_equal(9, foo_entry.location.start_line)
1289
- end
1290
-
1291
- def test_resolving_unindexed_constant_with_no_nesting
1292
- assert_nil(@index.resolve("RSpec", []))
1293
- end
1294
-
1295
- def test_object_superclass_indexing_and_resolution_with_reopened_object_class
1296
- index(<<~RUBY)
1297
- class Object; end
1298
- RUBY
1299
-
1300
- entries = @index["Object"] #: as !nil
1301
- assert_equal(2, entries.length)
1302
- reopened_entry = entries.last #: as Entry::Class
1303
- assert_equal("::BasicObject", reopened_entry.parent_class)
1304
- assert_equal(["Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Object"))
1305
- end
1306
-
1307
- def test_object_superclass_indexing_and_resolution_with_reopened_basic_object_class
1308
- index(<<~RUBY)
1309
- class BasicObject; end
1310
- RUBY
1311
-
1312
- entries = @index["BasicObject"] #: as !nil
1313
- assert_equal(2, entries.length)
1314
- reopened_entry = entries.last #: as Entry::Class
1315
- assert_nil(reopened_entry.parent_class)
1316
- assert_equal(["BasicObject"], @index.linearized_ancestors_of("BasicObject"))
1317
- end
1318
-
1319
- def test_object_superclass_resolution
1320
- index(<<~RUBY)
1321
- module Foo
1322
- class Object; end
1323
-
1324
- class Bar; end
1325
- class Baz < Object; end
1326
- end
1327
- RUBY
1328
-
1329
- assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1330
- assert_equal(
1331
- ["Foo::Baz", "Foo::Object", "Object", "Kernel", "BasicObject"],
1332
- @index.linearized_ancestors_of("Foo::Baz"),
1333
- )
1334
- end
1335
-
1336
- def test_basic_object_superclass_resolution
1337
- index(<<~RUBY)
1338
- module Foo
1339
- class BasicObject; end
1340
-
1341
- class Bar; end
1342
- class Baz < BasicObject; end
1343
- end
1344
- RUBY
1345
-
1346
- assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1347
- assert_equal(
1348
- ["Foo::Baz", "Foo::BasicObject", "Object", "Kernel", "BasicObject"],
1349
- @index.linearized_ancestors_of("Foo::Baz"),
1350
- )
1351
- end
1352
-
1353
- def test_top_level_object_superclass_resolution
1354
- index(<<~RUBY)
1355
- module Foo
1356
- class Object; end
1357
-
1358
- class Bar < ::Object; end
1359
- end
1360
- RUBY
1361
-
1362
- assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1363
- end
1364
-
1365
- def test_top_level_basic_object_superclass_resolution
1366
- index(<<~RUBY)
1367
- module Foo
1368
- class BasicObject; end
1369
-
1370
- class Bar < ::BasicObject; end
1371
- end
1372
- RUBY
1373
-
1374
- assert_equal(["Foo::Bar", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1375
- end
1376
-
1377
- def test_resolving_method_inside_singleton_context
1378
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1379
- module Foo
1380
- class Bar
1381
- class << self
1382
- class Baz
1383
- class << self
1384
- def found_me!; end
1385
- end
1386
- end
1387
- end
1388
- end
1389
- end
1390
- RUBY
1391
-
1392
- entry = @index.resolve_method("found_me!", "Foo::Bar::<Class:Bar>::Baz::<Class:Baz>")&.first #: as !nil
1393
- refute_nil(entry)
1394
- assert_equal("found_me!", entry.name)
1395
- end
1396
-
1397
- def test_resolving_constants_in_singleton_contexts
1398
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1399
- module Foo
1400
- class Bar
1401
- CONST = 3
1402
-
1403
- class << self
1404
- CONST = 2
1405
-
1406
- class Baz
1407
- CONST = 1
1408
-
1409
- class << self
1410
- end
1411
- end
1412
- end
1413
- end
1414
- end
1415
- RUBY
1416
-
1417
- entry = @index.resolve("CONST", ["Foo", "Bar", "<Class:Bar>", "Baz", "<Class:Baz>"])&.first #: as !nil
1418
- refute_nil(entry)
1419
- assert_equal(9, entry.location.start_line)
1420
- end
1421
-
1422
- def test_resolving_instance_variables_in_singleton_contexts
1423
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1424
- module Foo
1425
- class Bar
1426
- @a = 123
1427
-
1428
- class << self
1429
- def hello
1430
- @b = 123
1431
- end
1432
-
1433
- @c = 123
1434
- end
1435
- end
1436
- end
1437
- RUBY
1438
-
1439
- entry = @index.resolve_instance_variable("@a", "Foo::Bar::<Class:Bar>")&.first #: as !nil
1440
- refute_nil(entry)
1441
- assert_equal("@a", entry.name)
1442
-
1443
- entry = @index.resolve_instance_variable("@b", "Foo::Bar::<Class:Bar>")&.first #: as !nil
1444
- refute_nil(entry)
1445
- assert_equal("@b", entry.name)
1446
-
1447
- entry = @index.resolve_instance_variable("@c", "Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>")&.first #: as !nil
1448
- refute_nil(entry)
1449
- assert_equal("@c", entry.name)
1450
- end
1451
-
1452
- def test_instance_variable_completion_in_singleton_contexts
1453
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1454
- module Foo
1455
- class Bar
1456
- @a = 123
1457
-
1458
- class << self
1459
- def hello
1460
- @b = 123
1461
- end
1462
-
1463
- @c = 123
1464
- end
1465
- end
1466
- end
1467
- RUBY
1468
-
1469
- entries = @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>").map(&:name)
1470
- assert_includes(entries, "@a")
1471
- assert_includes(entries, "@b")
1472
- end
1473
-
1474
- def test_singletons_are_excluded_from_prefix_search
1475
- index(<<~RUBY)
1476
- class Zwq
1477
- class << self
1478
- end
1479
- end
1480
- RUBY
1481
-
1482
- assert_empty(@index.prefix_search("Zwq::<C"))
1483
- end
1484
-
1485
- def test_singletons_are_excluded_from_fuzzy_search
1486
- index(<<~RUBY)
1487
- class Zwq
1488
- class << self
1489
- end
1490
- end
1491
- RUBY
1492
-
1493
- results = @index.fuzzy_search("Zwq")
1494
- assert_equal(1, results.length)
1495
- assert_equal("Zwq", results.first&.name)
1496
- end
1497
-
1498
- def test_resolving_method_aliases
1499
- index(<<~RUBY)
1500
- class Foo
1501
- def bar(a, b, c)
1502
- end
1503
-
1504
- alias double_alias bar
1505
- end
1506
-
1507
- class Bar < Foo
1508
- def hello(b); end
1509
-
1510
- alias baz bar
1511
- alias_method :qux, :hello
1512
- alias double double_alias
1513
- end
1514
- RUBY
1515
-
1516
- # baz
1517
- methods = @index.resolve_method("baz", "Bar") #: as !nil
1518
- refute_nil(methods)
1519
-
1520
- entry = methods.first #: as Entry::MethodAlias
1521
- assert_kind_of(Entry::MethodAlias, entry)
1522
- assert_equal("bar", entry.target.name)
1523
- assert_equal("Foo", entry.target.owner&.name)
1524
-
1525
- # qux
1526
- methods = @index.resolve_method("qux", "Bar") #: as !nil
1527
- refute_nil(methods)
1528
-
1529
- entry = methods.first #: as Entry::MethodAlias
1530
- assert_kind_of(Entry::MethodAlias, entry)
1531
- assert_equal("hello", entry.target.name)
1532
- assert_equal("Bar", entry.target.owner&.name)
1533
-
1534
- # double
1535
- methods = @index.resolve_method("double", "Bar") #: as !nil
1536
- refute_nil(methods)
1537
-
1538
- entry = methods.first #: as Entry::MethodAlias
1539
- assert_kind_of(Entry::MethodAlias, entry)
1540
-
1541
- target = entry.target #: as Entry::MethodAlias
1542
- assert_equal("double_alias", target.name)
1543
- assert_kind_of(Entry::MethodAlias, target)
1544
- assert_equal("Foo", target.owner&.name)
1545
-
1546
- final_target = target.target
1547
- assert_equal("bar", final_target.name)
1548
- assert_kind_of(Entry::Method, final_target)
1549
- assert_equal("Foo", final_target.owner&.name)
1550
- end
1551
-
1552
- def test_resolving_circular_method_aliases
1553
- index(<<~RUBY)
1554
- class Foo
1555
- alias bar bar
1556
- end
1557
- RUBY
1558
-
1559
- # It's not possible to resolve an alias that points to itself
1560
- methods = @index.resolve_method("bar", "Foo")
1561
- assert_nil(methods)
1562
-
1563
- entry = @index["bar"]&.first
1564
- assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1565
- end
1566
-
1567
- def test_unresolvable_method_aliases
1568
- index(<<~RUBY)
1569
- class Foo
1570
- alias bar baz
1571
- end
1572
- RUBY
1573
-
1574
- # `baz` does not exist, so resolving `bar` is not possible
1575
- methods = @index.resolve_method("bar", "Foo")
1576
- assert_nil(methods)
1577
-
1578
- entry = @index["bar"]&.first
1579
- assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1580
- end
1581
-
1582
- def test_only_aliases_for_the_right_owner_are_resolved
1583
- index(<<~RUBY)
1584
- class Foo
1585
- attr_reader :name
1586
- alias_method :decorated_name, :name
1587
- end
1588
-
1589
- class Bar
1590
- alias_method :decorated_name, :to_s
1591
- end
1592
- RUBY
1593
-
1594
- methods = @index.resolve_method("decorated_name", "Foo") #: as !nil
1595
- refute_nil(methods)
1596
-
1597
- entry = methods.first #: as Entry::MethodAlias
1598
- assert_kind_of(Entry::MethodAlias, entry)
1599
-
1600
- target = entry.target
1601
- assert_equal("name", target.name)
1602
- assert_kind_of(Entry::Accessor, target)
1603
- assert_equal("Foo", target.owner&.name)
1604
-
1605
- other_decorated_name = @index["decorated_name"]&.find { |e| e.is_a?(Entry::UnresolvedMethodAlias) }
1606
- assert_kind_of(Entry::UnresolvedMethodAlias, other_decorated_name)
1607
- end
1608
-
1609
- def test_completion_does_not_include_unresolved_aliases
1610
- index(<<~RUBY)
1611
- class Foo
1612
- alias_method :bar, :missing
1613
- end
1614
- RUBY
1615
-
1616
- assert_empty(@index.method_completion_candidates("bar", "Foo"))
1617
- end
1618
-
1619
- def test_first_unqualified_const
1620
- index(<<~RUBY)
1621
- module Foo
1622
- class Bar; end
1623
- end
1624
-
1625
- module Baz
1626
- class Bar; end
1627
- end
1628
- RUBY
1629
-
1630
- entry = @index.first_unqualified_const("Bar")&.first #: as !nil
1631
- assert_equal("Foo::Bar", entry.name)
1632
- end
1633
-
1634
- def test_first_unqualified_const_prefers_exact_matches
1635
- index(<<~RUBY)
1636
- module Foo
1637
- class ParseResultType
1638
- end
1639
- end
1640
-
1641
- module Namespace
1642
- class Type
1643
- end
1644
- end
1645
- RUBY
1646
-
1647
- entry = @index.first_unqualified_const("Type")&.first #: as !nil
1648
- assert_equal("Namespace::Type", entry.name)
1649
- end
1650
-
1651
- def test_completion_does_not_duplicate_overridden_methods
1652
- index(<<~RUBY)
1653
- class Foo
1654
- def bar; end
1655
- end
1656
-
1657
- class Baz < Foo
1658
- def bar; end
1659
- end
1660
- RUBY
1661
-
1662
- entries = @index.method_completion_candidates("bar", "Baz")
1663
- assert_equal(["bar"], entries.map(&:name))
1664
- assert_equal("Baz", entries.first&.owner&.name)
1665
- end
1666
-
1667
- def test_completion_does_not_duplicate_methods_overridden_by_aliases
1668
- index(<<~RUBY)
1669
- class Foo
1670
- def bar; end
1671
- end
1672
-
1673
- class Baz < Foo
1674
- alias bar to_s
1675
- end
1676
- RUBY
1677
-
1678
- entries = @index.method_completion_candidates("bar", "Baz")
1679
- assert_equal(["bar"], entries.map(&:name))
1680
- assert_equal("Baz", entries.first&.owner&.name)
1681
- end
1682
-
1683
- def test_decorated_parameters
1684
- index(<<~RUBY)
1685
- class Foo
1686
- def bar(a, b = 1, c: 2)
1687
- end
1688
- end
1689
- RUBY
1690
-
1691
- methods = @index.resolve_method("bar", "Foo") #: as !nil
1692
- refute_nil(methods)
1693
-
1694
- entry = methods.first #: as Entry::Method
1695
- assert_equal("(a, b = <default>, c: <default>)", entry.decorated_parameters)
1696
- end
1697
-
1698
- def test_decorated_parameters_when_method_has_no_parameters
1699
- index(<<~RUBY)
1700
- class Foo
1701
- def bar
1702
- end
1703
- end
1704
- RUBY
1705
-
1706
- methods = @index.resolve_method("bar", "Foo") #: as !nil
1707
- refute_nil(methods)
1708
-
1709
- entry = methods.first #: as Entry::Method
1710
- assert_equal("()", entry.decorated_parameters)
1711
- end
1712
-
1713
- def test_linearizing_singleton_ancestors_of_singleton_when_class_has_parent
1714
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1715
- class Foo; end
1716
-
1717
- class Bar < Foo
1718
- end
1719
-
1720
- class Baz < Bar
1721
- class << self
1722
- class << self
1723
- end
1724
- end
1725
- end
1726
- RUBY
1727
-
1728
- assert_equal(
1729
- [
1730
- "Baz::<Class:Baz>::<Class:<Class:Baz>>",
1731
- "Bar::<Class:Bar>::<Class:<Class:Bar>>",
1732
- "Foo::<Class:Foo>::<Class:<Class:Foo>>",
1733
- "Object::<Class:Object>::<Class:<Class:Object>>",
1734
- "BasicObject::<Class:BasicObject>::<Class:<Class:BasicObject>>",
1735
- "Class::<Class:Class>",
1736
- "Module::<Class:Module>",
1737
- "Object::<Class:Object>",
1738
- "BasicObject::<Class:BasicObject>",
1739
- "Class",
1740
- "Module",
1741
- "Object",
1742
- "Kernel",
1743
- "BasicObject",
1744
- ],
1745
- @index.linearized_ancestors_of("Baz::<Class:Baz>::<Class:<Class:Baz>>"),
1746
- )
1747
- end
1748
-
1749
- def test_linearizing_singleton_object
1750
- assert_equal(
1751
- [
1752
- "Object::<Class:Object>",
1753
- "BasicObject::<Class:BasicObject>",
1754
- "Class",
1755
- "Module",
1756
- "Object",
1757
- "Kernel",
1758
- "BasicObject",
1759
- ],
1760
- @index.linearized_ancestors_of("Object::<Class:Object>"),
1761
- )
1762
- end
1763
-
1764
- def test_extend_self
1765
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1766
- module Foo
1767
- def bar
1768
- end
1769
-
1770
- extend self
1771
-
1772
- def baz
1773
- end
1774
- end
1775
- RUBY
1776
-
1777
- ["bar", "baz"].product(["Foo", "Foo::<Class:Foo>"]).each do |method, receiver|
1778
- entry = @index.resolve_method(method, receiver)&.first #: as !nil
1779
- refute_nil(entry)
1780
- assert_equal(method, entry.name)
1781
- end
1782
-
1783
- assert_equal(
1784
- [
1785
- "Foo::<Class:Foo>",
1786
- "Foo",
1787
- "Module",
1788
- "Object",
1789
- "Kernel",
1790
- "BasicObject",
1791
- ],
1792
- @index.linearized_ancestors_of("Foo::<Class:Foo>"),
1793
- )
1794
- end
1795
-
1796
- def test_linearizing_singleton_ancestors
1797
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1798
- module First
1799
- end
1800
-
1801
- module Second
1802
- include First
1803
- end
1804
-
1805
- module Foo
1806
- class Bar
1807
- class << self
1808
- class Baz
1809
- extend Second
1810
-
1811
- class << self
1812
- include First
1813
- end
1814
- end
1815
- end
1816
- end
1817
- end
1818
- RUBY
1819
-
1820
- assert_equal(
1821
- [
1822
- "Foo::Bar::<Class:Bar>::Baz::<Class:Baz>",
1823
- "Second",
1824
- "First",
1825
- "Object::<Class:Object>",
1826
- "BasicObject::<Class:BasicObject>",
1827
- "Class",
1828
- "Module",
1829
- "Object",
1830
- "Kernel",
1831
- "BasicObject",
1832
- ],
1833
- @index.linearized_ancestors_of("Foo::Bar::<Class:Bar>::Baz::<Class:Baz>"),
1834
- )
1835
- end
1836
-
1837
- def test_linearizing_singleton_ancestors_when_class_has_parent
1838
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1839
- class Foo; end
1840
-
1841
- class Bar < Foo
1842
- end
1843
-
1844
- class Baz < Bar
1845
- class << self
1846
- end
1847
- end
1848
- RUBY
1849
-
1850
- assert_equal(
1851
- [
1852
- "Baz::<Class:Baz>",
1853
- "Bar::<Class:Bar>",
1854
- "Foo::<Class:Foo>",
1855
- "Object::<Class:Object>",
1856
- "BasicObject::<Class:BasicObject>",
1857
- "Class",
1858
- "Module",
1859
- "Object",
1860
- "Kernel",
1861
- "BasicObject",
1862
- ],
1863
- @index.linearized_ancestors_of("Baz::<Class:Baz>"),
1864
- )
1865
- end
1866
-
1867
- def test_linearizing_a_module_singleton_class
1868
- @index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
1869
- module A; end
1870
- RUBY
1871
-
1872
- assert_equal(
1873
- [
1874
- "A::<Class:A>",
1875
- "Module",
1876
- "Object",
1877
- "Kernel",
1878
- "BasicObject",
1879
- ],
1880
- @index.linearized_ancestors_of("A::<Class:A>"),
1881
- )
1882
- end
1883
-
1884
- def test_linearizing_a_singleton_class_with_no_attached
1885
- assert_raises(Index::NonExistingNamespaceError) do
1886
- @index.linearized_ancestors_of("A::<Class:A>")
1887
- end
1888
- end
1889
-
1890
- def test_linearizing_singleton_parent_class_with_namespace
1891
- index(<<~RUBY)
1892
- class ActiveRecord::Base; end
1893
-
1894
- class User < ActiveRecord::Base
1895
- end
1896
- RUBY
1897
-
1898
- assert_equal(
1899
- [
1900
- "User::<Class:User>",
1901
- "ActiveRecord::Base::<Class:Base>",
1902
- "Object::<Class:Object>",
1903
- "BasicObject::<Class:BasicObject>",
1904
- "Class",
1905
- "Module",
1906
- "Object",
1907
- "Kernel",
1908
- "BasicObject",
1909
- ],
1910
- @index.linearized_ancestors_of("User::<Class:User>"),
1911
- )
1912
- end
1913
-
1914
- def test_singleton_nesting_is_correctly_split_during_linearization
1915
- index(<<~RUBY)
1916
- module Bar; end
1917
-
1918
- module Foo
1919
- class Namespace::Parent
1920
- extend Bar
1921
- end
1922
- end
1923
-
1924
- module Foo
1925
- class Child < Namespace::Parent
1926
- end
1927
- end
1928
- RUBY
1929
-
1930
- assert_equal(
1931
- [
1932
- "Foo::Child::<Class:Child>",
1933
- "Foo::Namespace::Parent::<Class:Parent>",
1934
- "Bar",
1935
- "Object::<Class:Object>",
1936
- "BasicObject::<Class:BasicObject>",
1937
- "Class",
1938
- "Module",
1939
- "Object",
1940
- "Kernel",
1941
- "BasicObject",
1942
- ],
1943
- @index.linearized_ancestors_of("Foo::Child::<Class:Child>"),
1944
- )
1945
- end
1946
-
1947
- def test_resolving_circular_method_aliases_on_class_reopen
1948
- index(<<~RUBY)
1949
- class Foo
1950
- alias bar ==
1951
- def ==(other) = true
1952
- end
1953
-
1954
- class Foo
1955
- alias == bar
1956
- end
1957
- RUBY
1958
-
1959
- method = @index.resolve_method("==", "Foo")&.first #: as Entry::Method
1960
- assert_kind_of(Entry::Method, method)
1961
- assert_equal("==", method.name)
1962
-
1963
- candidates = @index.method_completion_candidates("=", "Foo")
1964
- assert_equal(["==", "==="], candidates.map(&:name))
1965
- end
1966
-
1967
- def test_entries_for
1968
- index(<<~RUBY)
1969
- class Foo; end
1970
-
1971
- module Bar
1972
- def my_def; end
1973
- def self.my_singleton_def; end
1974
- end
1975
- RUBY
1976
-
1977
- entries = @index.entries_for("file:///fake/path/foo.rb", Entry) #: as !nil
1978
- assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
1979
-
1980
- entries = @index.entries_for("file:///fake/path/foo.rb", RubyIndexer::Entry::Namespace) #: as !nil
1981
- assert_equal(["Foo", "Bar", "Bar::<Class:Bar>"], entries.map(&:name))
1982
-
1983
- entries = @index.entries_for("file:///fake/path/foo.rb") #: as !nil
1984
- assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
1985
- end
1986
-
1987
- def test_entries_for_returns_nil_if_no_matches
1988
- assert_nil(@index.entries_for("non_existing_file.rb", Entry::Namespace))
1989
- end
1990
-
1991
- def test_constant_completion_candidates_all_possible_constants
1992
- index(<<~RUBY)
1993
- XQRK = 3
1994
-
1995
- module Bar
1996
- XQRK = 2
1997
- end
1998
-
1999
- module Foo
2000
- XQRK = 1
2001
- end
2002
-
2003
- module Namespace
2004
- XQRK = 0
2005
-
2006
- class Baz
2007
- include Foo
2008
- include Bar
2009
- end
2010
- end
2011
- RUBY
2012
-
2013
- result = @index.constant_completion_candidates("X", ["Namespace", "Baz"])
2014
-
2015
- result.each do |entries|
2016
- name = entries.first&.name
2017
- assert(entries.all? { |e| e.name == name })
2018
- end
2019
-
2020
- assert_equal(["Namespace::XQRK", "Bar::XQRK", "XQRK"], result.map { |entries| entries.first&.name })
2021
-
2022
- result = @index.constant_completion_candidates("::X", ["Namespace", "Baz"])
2023
- assert_equal(["XQRK"], result.map { |entries| entries.first&.name })
2024
- end
2025
-
2026
- def test_constant_completion_does_not_confuse_uppercase_methods
2027
- index(<<~RUBY)
2028
- class Foo
2029
- def Qux
2030
- end
2031
- end
2032
- RUBY
2033
-
2034
- candidates = @index.constant_completion_candidates("Q", [])
2035
- refute_includes(candidates.flat_map { |entries| entries.map(&:name) }, "Qux")
2036
-
2037
- candidates = @index.constant_completion_candidates("Qux", [])
2038
- assert_equal(0, candidates.length)
2039
- end
2040
-
2041
- def test_constant_completion_candidates_for_empty_name
2042
- index(<<~RUBY)
2043
- module Foo
2044
- Bar = 1
2045
- end
2046
-
2047
- class Baz
2048
- include Foo
2049
- end
2050
- RUBY
2051
-
2052
- result = @index.constant_completion_candidates("Baz::", [])
2053
- assert_includes(result.map { |entries| entries.first&.name }, "Foo::Bar")
2054
- end
2055
-
2056
- def test_follow_alias_namespace
2057
- index(<<~RUBY)
2058
- module First
2059
- module Second
2060
- class Foo
2061
- end
2062
- end
2063
- end
2064
-
2065
- module Namespace
2066
- Second = First::Second
2067
- end
2068
- RUBY
2069
-
2070
- real_namespace = @index.follow_aliased_namespace("Namespace::Second")
2071
- assert_equal("First::Second", real_namespace)
2072
- end
2073
-
2074
- def test_resolving_alias_to_non_existing_namespace
2075
- index(<<~RUBY)
2076
- module Namespace
2077
- class Foo
2078
- module InnerNamespace
2079
- Constants = Namespace::Foo::Constants
2080
- end
2081
- end
2082
- end
2083
- RUBY
2084
-
2085
- entry = @index.resolve("Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
2086
- assert_instance_of(Entry::UnresolvedConstantAlias, entry)
2087
-
2088
- entry = @index.resolve("Namespace::Foo::Constants", ["Namespace", "Foo", "InnerNamespace"])&.first
2089
- assert_nil(entry)
2090
- end
2091
-
2092
- def test_resolving_alias_to_existing_constant_from_inner_namespace
2093
- index(<<~RUBY)
2094
- module Parent
2095
- CONST = 123
2096
- end
2097
-
2098
- module First
2099
- module Namespace
2100
- class Foo
2101
- include Parent
2102
-
2103
- module InnerNamespace
2104
- Constants = Namespace::Foo::CONST
2105
- end
2106
- end
2107
- end
2108
- end
2109
- RUBY
2110
-
2111
- entry = @index.resolve("Namespace::Foo::CONST", ["First", "Namespace", "Foo", "InnerNamespace"])&.first #: as !nil
2112
- assert_equal("Parent::CONST", entry.name)
2113
- assert_instance_of(Entry::Constant, entry)
2114
- end
2115
-
2116
- def test_build_non_redundant_name
2117
- assert_equal(
2118
- "Namespace::Foo::Constants",
2119
- @index.send(
2120
- :build_non_redundant_full_name,
2121
- "Namespace::Foo::Constants",
2122
- ["Namespace", "Foo", "InnerNamespace"],
2123
- ),
2124
- )
2125
-
2126
- assert_equal(
2127
- "Namespace::Foo::Constants",
2128
- @index.send(
2129
- :build_non_redundant_full_name,
2130
- "Namespace::Foo::Constants",
2131
- ["Namespace", "Foo"],
2132
- ),
2133
- )
2134
-
2135
- assert_equal(
2136
- "Namespace::Foo::Constants",
2137
- @index.send(
2138
- :build_non_redundant_full_name,
2139
- "Foo::Constants",
2140
- ["Namespace", "Foo"],
2141
- ),
2142
- )
2143
-
2144
- assert_equal(
2145
- "Bar::Namespace::Foo::Constants",
2146
- @index.send(
2147
- :build_non_redundant_full_name,
2148
- "Namespace::Foo::Constants",
2149
- ["Bar"],
2150
- ),
2151
- )
2152
-
2153
- assert_equal(
2154
- "First::Namespace::Foo::Constants",
2155
- @index.send(
2156
- :build_non_redundant_full_name,
2157
- "Namespace::Foo::Constants",
2158
- ["First", "Namespace", "Foo", "InnerNamespace"],
2159
- ),
2160
- )
2161
- end
2162
-
2163
- def test_prevents_multiple_calls_to_index_all
2164
- @index.index_all
2165
-
2166
- assert_raises(Index::IndexNotEmptyError) do
2167
- @index.index_all
2168
- end
2169
- end
2170
-
2171
- def test_index_can_handle_entries_from_untitled_scheme
2172
- uri = URI("untitled:Untitled-1")
2173
-
2174
- index(<<~RUBY, uri: uri)
2175
- class Foo
2176
- end
2177
- RUBY
2178
-
2179
- entry = @index["Foo"]&.first #: as !nil
2180
- refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
2181
- assert_equal("untitled:Untitled-1", entry.uri.to_s)
2182
- assert_equal("Untitled-1", entry.file_name)
2183
- assert_nil(entry.file_path)
2184
-
2185
- @index.handle_change(uri, <<~RUBY)
2186
- # I added this comment!
2187
- class Foo
2188
- end
2189
- RUBY
2190
-
2191
- entry = @index["Foo"]&.first #: as !nil
2192
- refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
2193
- assert_equal("I added this comment!", entry.comments)
2194
- end
2195
-
2196
- def test_instance_variable_completion_returns_class_variables_too
2197
- index(<<~RUBY)
2198
- class Parent
2199
- @@abc = 123
2200
- end
2201
-
2202
- class Child < Parent
2203
- @@adf = 123
2204
-
2205
- def self.do
2206
- end
2207
- end
2208
- RUBY
2209
-
2210
- adf, abc = @index.instance_variable_completion_candidates("@", "Child::<Class:Child>")
2211
-
2212
- refute_nil(abc)
2213
- refute_nil(adf)
2214
-
2215
- assert_equal("@@abc", abc&.name)
2216
- assert_equal("@@adf", adf&.name)
2217
- end
2218
-
2219
- def test_class_variable_completion_from_singleton_context
2220
- index(<<~RUBY)
2221
- class Foo
2222
- @@hello = 123
2223
-
2224
- def self.do
2225
- end
2226
- end
2227
- RUBY
2228
-
2229
- candidates = @index.class_variable_completion_candidates("@@", "Foo::<Class:Foo>")
2230
- refute_empty(candidates)
2231
-
2232
- assert_equal("@@hello", candidates.first&.name)
2233
- end
2234
-
2235
- def test_resolve_class_variable_in_singleton_context
2236
- index(<<~RUBY)
2237
- class Foo
2238
- @@hello = 123
2239
- end
2240
- RUBY
2241
-
2242
- candidates = @index.resolve_class_variable("@@hello", "Foo::<Class:Foo>") #: as !nil
2243
- refute_empty(candidates)
2244
-
2245
- assert_equal("@@hello", candidates.first&.name)
2246
- end
2247
-
2248
- def test_actual_nesting
2249
- assert_equal(["Foo"], Index.actual_nesting([], "Foo"))
2250
- assert_equal(["TopLevel", "Foo"], Index.actual_nesting(["First", "::TopLevel"], "Foo"))
2251
- assert_equal(["TopLevel", "Another", "Foo"], Index.actual_nesting(["::TopLevel", "Another"], "Foo"))
2252
- assert_equal(["TopLevel"], Index.actual_nesting(["First", "::TopLevel"], nil))
2253
- end
2254
-
2255
- def test_constant_name
2256
- node = Prism.parse("class var::Foo; end").value.statements.body.first.constant_path
2257
- assert_nil(Index.constant_name(node))
2258
-
2259
- node = Prism.parse("class ; end").value.statements.body.first.constant_path
2260
- assert_nil(Index.constant_name(node))
2261
-
2262
- node = Prism.parse("class method_call; end").value.statements.body.first.constant_path
2263
- assert_nil(Index.constant_name(node))
2264
-
2265
- node = Prism.parse("class Foo; end").value.statements.body.first.constant_path
2266
- assert_equal("Foo", Index.constant_name(node))
2267
-
2268
- node = Prism.parse(<<~RUBY).value.statements.body.first.constant_path
2269
- class class Foo
2270
- end
2271
- end
2272
- RUBY
2273
- assert_nil(Index.constant_name(node))
2274
- end
2275
- end
2276
- end