ruby-lsp 0.16.7 → 0.17.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +195 -18
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +129 -12
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +333 -44
  7. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +99 -0
  8. data/lib/ruby_indexer/ruby_indexer.rb +1 -0
  9. data/lib/ruby_indexer/test/classes_and_modules_test.rb +58 -11
  10. data/lib/ruby_indexer/test/configuration_test.rb +5 -6
  11. data/lib/ruby_indexer/test/constant_test.rb +9 -9
  12. data/lib/ruby_indexer/test/index_test.rb +867 -7
  13. data/lib/ruby_indexer/test/instance_variables_test.rb +131 -0
  14. data/lib/ruby_indexer/test/method_test.rb +57 -0
  15. data/lib/ruby_indexer/test/rbs_indexer_test.rb +42 -0
  16. data/lib/ruby_indexer/test/test_case.rb +10 -1
  17. data/lib/ruby_lsp/addon.rb +8 -8
  18. data/lib/ruby_lsp/document.rb +26 -3
  19. data/lib/ruby_lsp/global_state.rb +37 -16
  20. data/lib/ruby_lsp/internal.rb +2 -0
  21. data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
  22. data/lib/ruby_lsp/listeners/completion.rb +74 -17
  23. data/lib/ruby_lsp/listeners/definition.rb +82 -24
  24. data/lib/ruby_lsp/listeners/hover.rb +62 -6
  25. data/lib/ruby_lsp/listeners/signature_help.rb +4 -4
  26. data/lib/ruby_lsp/node_context.rb +39 -0
  27. data/lib/ruby_lsp/requests/code_action_resolve.rb +73 -2
  28. data/lib/ruby_lsp/requests/code_actions.rb +16 -15
  29. data/lib/ruby_lsp/requests/completion.rb +21 -13
  30. data/lib/ruby_lsp/requests/completion_resolve.rb +9 -0
  31. data/lib/ruby_lsp/requests/definition.rb +25 -5
  32. data/lib/ruby_lsp/requests/document_highlight.rb +2 -2
  33. data/lib/ruby_lsp/requests/hover.rb +5 -6
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +8 -4
  35. data/lib/ruby_lsp/requests/signature_help.rb +3 -3
  36. data/lib/ruby_lsp/requests/support/common.rb +4 -3
  37. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +23 -6
  38. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +5 -1
  39. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
  40. data/lib/ruby_lsp/requests/workspace_symbol.rb +7 -4
  41. data/lib/ruby_lsp/server.rb +22 -5
  42. data/lib/ruby_lsp/test_helper.rb +1 -0
  43. metadata +29 -5
@@ -107,16 +107,16 @@ module RubyIndexer
107
107
  RUBY
108
108
 
109
109
  result = @index.fuzzy_search("Bar")
110
- assert_equal(1, result.length)
111
- assert_equal(@index["Bar"].first, result.first)
110
+ assert_equal(3, result.length)
111
+ assert_equal(["Bar", "Backtrace", "Base"], result.map(&:name))
112
112
 
113
113
  result = @index.fuzzy_search("foobarsomeking")
114
- assert_equal(5, result.length)
115
- assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Bar"], result.map(&:name))
114
+ assert_equal(6, result.length)
115
+ assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Base", "Bar"], result.map(&:name))
116
116
 
117
117
  result = @index.fuzzy_search("FooBaz")
118
- assert_equal(4, result.length)
119
- assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something"], result.map(&:name))
118
+ assert_equal(5, result.length)
119
+ assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something", "Float"], result.map(&:name))
120
120
  end
121
121
 
122
122
  def test_index_single_ignores_directories
@@ -140,6 +140,8 @@ module RubyIndexer
140
140
  end
141
141
 
142
142
  def test_searching_for_entries_based_on_prefix
143
+ # For this test, it's easier if we don't include core classes and modules
144
+ @index = Index.new
143
145
  @index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
144
146
  class Foo::Bar
145
147
  end
@@ -181,6 +183,9 @@ module RubyIndexer
181
183
 
182
184
  def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
183
185
  @index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
186
+ class Float
187
+ end
188
+
184
189
  module Foo
185
190
  class Float < self
186
191
  INFINITY = ::Float::INFINITY
@@ -299,6 +304,10 @@ module RubyIndexer
299
304
  end
300
305
 
301
306
  def test_indexing_prism_fixtures_succeeds
307
+ unless Dir.exist?("test/fixtures/prism/test/prism/fixtures")
308
+ raise "Prism fixtures not found. Run `git submodule update --init` to fetch them."
309
+ end
310
+
302
311
  fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
303
312
 
304
313
  fixtures.each do |fixture|
@@ -311,7 +320,858 @@ module RubyIndexer
311
320
 
312
321
  def test_index_single_does_not_fail_for_non_existing_file
313
322
  @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"))
314
- assert_empty(@index.instance_variable_get(:@entries))
323
+ entries_after_indexing = @index.instance_variable_get(:@entries).keys
324
+ assert_equal(@default_indexed_entries.keys, entries_after_indexing)
325
+ end
326
+
327
+ def test_linearized_ancestors_basic_ordering
328
+ index(<<~RUBY)
329
+ module A; end
330
+ module B; end
331
+
332
+ class Foo
333
+ prepend A
334
+ prepend B
335
+ end
336
+
337
+ class Bar
338
+ include A
339
+ include B
340
+ end
341
+ RUBY
342
+
343
+ assert_equal(
344
+ [
345
+ "B",
346
+ "A",
347
+ "Foo",
348
+ "Object",
349
+ "Kernel",
350
+ "BasicObject",
351
+ ],
352
+ @index.linearized_ancestors_of("Foo"),
353
+ )
354
+
355
+ assert_equal(
356
+ [
357
+ "Bar",
358
+ "B",
359
+ "A",
360
+ "Object",
361
+ "Kernel",
362
+ "BasicObject",
363
+ ],
364
+ @index.linearized_ancestors_of("Bar"),
365
+ )
366
+ end
367
+
368
+ def test_linearized_ancestors
369
+ index(<<~RUBY)
370
+ module A; end
371
+ module B; end
372
+ module C; end
373
+
374
+ module D
375
+ include A
376
+ end
377
+
378
+ module E
379
+ prepend B
380
+ end
381
+
382
+ module F
383
+ include C
384
+ include A
385
+ end
386
+
387
+ class Bar
388
+ prepend F
389
+ end
390
+
391
+ class Foo < Bar
392
+ include E
393
+ prepend D
394
+ end
395
+ RUBY
396
+
397
+ # Object, Kernel and BasicObject are intentionally commented out for now until we develop a strategy for indexing
398
+ # declarations made in C code
399
+ assert_equal(
400
+ [
401
+ "D",
402
+ "A",
403
+ "Foo",
404
+ "B",
405
+ "E",
406
+ "F",
407
+ "A",
408
+ "C",
409
+ "Bar",
410
+ "Object",
411
+ "Kernel",
412
+ "BasicObject",
413
+ ],
414
+ @index.linearized_ancestors_of("Foo"),
415
+ )
416
+ end
417
+
418
+ def test_linearized_ancestors_duplicates
419
+ index(<<~RUBY)
420
+ module A; end
421
+ module B
422
+ include A
423
+ end
424
+
425
+ class Foo
426
+ include B
427
+ include A
428
+ end
429
+
430
+ class Bar
431
+ prepend B
432
+ prepend A
433
+ end
434
+ RUBY
435
+
436
+ assert_equal(
437
+ [
438
+ "Foo",
439
+ "B",
440
+ "A",
441
+ "Object",
442
+ "Kernel",
443
+ "BasicObject",
444
+ ],
445
+ @index.linearized_ancestors_of("Foo"),
446
+ )
447
+
448
+ assert_equal(
449
+ [
450
+ "B",
451
+ "A",
452
+ "Bar",
453
+ "Object",
454
+ "Kernel",
455
+ "BasicObject",
456
+ ],
457
+ @index.linearized_ancestors_of("Bar"),
458
+ )
459
+ end
460
+
461
+ def test_linearizing_ancestors_is_cached
462
+ index(<<~RUBY)
463
+ module C; end
464
+ module A; end
465
+ module B
466
+ include A
467
+ end
468
+
469
+ class Foo
470
+ include B
471
+ include A
472
+ end
473
+ RUBY
474
+
475
+ @index.linearized_ancestors_of("Foo")
476
+ ancestors = @index.instance_variable_get(:@ancestors)
477
+ assert(ancestors.key?("Foo"))
478
+ assert(ancestors.key?("A"))
479
+ assert(ancestors.key?("B"))
480
+ refute(ancestors.key?("C"))
481
+ end
482
+
483
+ def test_duplicate_prepend_include
484
+ index(<<~RUBY)
485
+ module A; end
486
+
487
+ class Foo
488
+ prepend A
489
+ include A
490
+ end
491
+
492
+ class Bar
493
+ include A
494
+ prepend A
495
+ end
496
+ RUBY
497
+
498
+ assert_equal(
499
+ [
500
+ "A",
501
+ "Foo",
502
+ "Object",
503
+ "Kernel",
504
+ "BasicObject",
505
+ ],
506
+ @index.linearized_ancestors_of("Foo"),
507
+ )
508
+
509
+ assert_equal(
510
+ [
511
+ "A",
512
+ "Bar",
513
+ "A",
514
+ "Object",
515
+ "Kernel",
516
+ "BasicObject",
517
+ ],
518
+ @index.linearized_ancestors_of("Bar"),
519
+ )
520
+ end
521
+
522
+ def test_linearizing_ancestors_handles_circular_parent_class
523
+ index(<<~RUBY)
524
+ class Foo < Foo
525
+ end
526
+ RUBY
527
+
528
+ assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
529
+ end
530
+
531
+ def test_ancestors_linearization_complex_prepend_duplication
532
+ index(<<~RUBY)
533
+ module A; end
534
+ module B
535
+ prepend A
536
+ end
537
+ module C
538
+ prepend B
539
+ end
540
+
541
+ class Foo
542
+ prepend A
543
+ prepend C
544
+ end
545
+ RUBY
546
+
547
+ assert_equal(
548
+ [
549
+ "A",
550
+ "B",
551
+ "C",
552
+ "Foo",
553
+ "Object",
554
+ "Kernel",
555
+ "BasicObject",
556
+ ],
557
+ @index.linearized_ancestors_of("Foo"),
558
+ )
559
+ end
560
+
561
+ def test_ancestors_linearization_complex_include_duplication
562
+ index(<<~RUBY)
563
+ module A; end
564
+ module B
565
+ include A
566
+ end
567
+ module C
568
+ include B
569
+ end
570
+
571
+ class Foo
572
+ include A
573
+ include C
574
+ end
575
+ RUBY
576
+
577
+ assert_equal(
578
+ [
579
+ "Foo",
580
+ "C",
581
+ "B",
582
+ "A",
583
+ "Object",
584
+ "Kernel",
585
+ "BasicObject",
586
+ ],
587
+ @index.linearized_ancestors_of("Foo"),
588
+ )
589
+ end
590
+
591
+ def test_linearizing_ancestors_that_need_to_be_resolved
592
+ index(<<~RUBY)
593
+ module Foo
594
+ module Baz
595
+ end
596
+ module Qux
597
+ end
598
+
599
+ class Something; end
600
+
601
+ class Bar < Something
602
+ include Baz
603
+ prepend Qux
604
+ end
605
+ end
606
+ RUBY
607
+
608
+ assert_equal(
609
+ [
610
+ "Foo::Qux",
611
+ "Foo::Bar",
612
+ "Foo::Baz",
613
+ "Foo::Something",
614
+ "Object",
615
+ "Kernel",
616
+ "BasicObject",
617
+ ],
618
+ @index.linearized_ancestors_of("Foo::Bar"),
619
+ )
620
+ end
621
+
622
+ def test_linearizing_ancestors_for_non_existing_namespaces
623
+ index(<<~RUBY)
624
+ def Bar(a); end
625
+ RUBY
626
+
627
+ assert_raises(Index::NonExistingNamespaceError) do
628
+ @index.linearized_ancestors_of("Foo")
629
+ end
630
+
631
+ assert_raises(Index::NonExistingNamespaceError) do
632
+ @index.linearized_ancestors_of("Bar")
633
+ end
634
+ end
635
+
636
+ def test_linearizing_circular_ancestors
637
+ index(<<~RUBY)
638
+ module M1
639
+ include M2
640
+ end
641
+
642
+ module M2
643
+ include M1
644
+ end
645
+
646
+ module A1
647
+ include A2
648
+ end
649
+
650
+ module A2
651
+ include A3
652
+ end
653
+
654
+ module A3
655
+ include A1
656
+ end
657
+
658
+ class Foo < Foo
659
+ include Foo
660
+ end
661
+
662
+ module Bar
663
+ include Bar
664
+ end
665
+ RUBY
666
+
667
+ assert_equal(["M2", "M1"], @index.linearized_ancestors_of("M2"))
668
+ assert_equal(["A3", "A1", "A2"], @index.linearized_ancestors_of("A3"))
669
+ assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
670
+ assert_equal(["Bar"], @index.linearized_ancestors_of("Bar"))
671
+ end
672
+
673
+ def test_linearizing_circular_aliased_dependency
674
+ index(<<~RUBY)
675
+ module A
676
+ end
677
+
678
+ ALIAS = A
679
+
680
+ module A
681
+ include ALIAS
682
+ end
683
+ RUBY
684
+
685
+ assert_equal(["A", "ALIAS"], @index.linearized_ancestors_of("A"))
686
+ end
687
+
688
+ def test_resolving_an_inherited_method
689
+ index(<<~RUBY)
690
+ module Foo
691
+ def baz; end
692
+ end
693
+
694
+ class Bar
695
+ def qux; end
696
+ end
697
+
698
+ class Wow < Bar
699
+ include Foo
700
+ end
701
+ RUBY
702
+
703
+ entry = T.must(@index.resolve_method("baz", "Wow")&.first)
704
+ assert_equal("baz", entry.name)
705
+ assert_equal("Foo", T.must(entry.owner).name)
706
+
707
+ entry = T.must(@index.resolve_method("qux", "Wow")&.first)
708
+ assert_equal("qux", entry.name)
709
+ assert_equal("Bar", T.must(entry.owner).name)
710
+ end
711
+
712
+ def test_resolving_an_inherited_method_lands_on_first_match
713
+ index(<<~RUBY)
714
+ module Foo
715
+ def qux; end
716
+ end
717
+
718
+ class Bar
719
+ def qux; end
720
+ end
721
+
722
+ class Wow < Bar
723
+ prepend Foo
724
+
725
+ def qux; end
726
+ end
727
+ RUBY
728
+
729
+ entries = T.must(@index.resolve_method("qux", "Wow"))
730
+ assert_equal(1, entries.length)
731
+
732
+ entry = T.must(entries.first)
733
+ assert_equal("qux", entry.name)
734
+ assert_equal("Foo", T.must(entry.owner).name)
735
+ end
736
+
737
+ def test_handle_change_clears_ancestor_cache_if_tree_changed
738
+ Dir.mktmpdir do |dir|
739
+ Dir.chdir(dir) do
740
+ # Write the original file
741
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
742
+ module Foo
743
+ end
744
+
745
+ class Bar
746
+ include Foo
747
+ end
748
+ RUBY
749
+
750
+ indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
751
+ @index.index_single(indexable_path)
752
+
753
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
754
+
755
+ # Remove include to invalidate the ancestor tree
756
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
757
+ module Foo
758
+ end
759
+
760
+ class Bar
761
+ end
762
+ RUBY
763
+
764
+ @index.handle_change(indexable_path)
765
+ assert_empty(@index.instance_variable_get(:@ancestors))
766
+ assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
767
+ end
768
+ end
769
+ end
770
+
771
+ def test_handle_change_does_not_clear_ancestor_cache_if_tree_not_changed
772
+ Dir.mktmpdir do |dir|
773
+ Dir.chdir(dir) do
774
+ # Write the original file
775
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
776
+ module Foo
777
+ end
778
+
779
+ class Bar
780
+ include Foo
781
+ end
782
+ RUBY
783
+
784
+ indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
785
+ @index.index_single(indexable_path)
786
+
787
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
788
+
789
+ # Remove include to invalidate the ancestor tree
790
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
791
+ module Foo
792
+ end
793
+
794
+ class Bar
795
+ include Foo
796
+
797
+ def baz; end
798
+ end
799
+ RUBY
800
+
801
+ @index.handle_change(indexable_path)
802
+ refute_empty(@index.instance_variable_get(:@ancestors))
803
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
804
+ end
805
+ end
806
+ end
807
+
808
+ def test_handle_change_clears_ancestor_cache_if_parent_class_changed
809
+ Dir.mktmpdir do |dir|
810
+ Dir.chdir(dir) do
811
+ # Write the original file
812
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
813
+ class Foo
814
+ end
815
+
816
+ class Bar < Foo
817
+ end
818
+ RUBY
819
+
820
+ indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
821
+ @index.index_single(indexable_path)
822
+
823
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
824
+
825
+ # Remove include to invalidate the ancestor tree
826
+ File.write(File.join(dir, "foo.rb"), <<~RUBY)
827
+ class Foo
828
+ end
829
+
830
+ class Bar
831
+ end
832
+ RUBY
833
+
834
+ @index.handle_change(indexable_path)
835
+ assert_empty(@index.instance_variable_get(:@ancestors))
836
+ assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
837
+ end
838
+ end
839
+ end
840
+
841
+ def test_resolving_inherited_constants
842
+ index(<<~RUBY)
843
+ module Foo
844
+ CONST = 1
845
+ end
846
+
847
+ module Baz
848
+ CONST = 2
849
+ end
850
+
851
+ module Qux
852
+ include Foo
853
+ end
854
+
855
+ module Namespace
856
+ CONST = 3
857
+
858
+ include Baz
859
+
860
+ class Bar
861
+ include Qux
862
+ end
863
+ end
864
+
865
+ CONST = 4
866
+ RUBY
867
+
868
+ entry = T.must(@index.resolve("CONST", ["Namespace", "Bar"])&.first)
869
+ assert_equal(14, entry.location.start_line)
870
+ end
871
+
872
+ def test_resolving_inherited_alised_namespace
873
+ index(<<~RUBY)
874
+ module Bar
875
+ TARGET = 123
876
+ end
877
+
878
+ module Foo
879
+ CONST = Bar
880
+ end
881
+
882
+ module Namespace
883
+ class Bar
884
+ include Foo
885
+ end
886
+ end
887
+ RUBY
888
+
889
+ entry = T.must(@index.resolve("Foo::CONST::TARGET", [])&.first)
890
+ assert_equal(2, entry.location.start_line)
891
+
892
+ entry = T.must(@index.resolve("Namespace::Bar::CONST::TARGET", [])&.first)
893
+ assert_equal(2, entry.location.start_line)
894
+ end
895
+
896
+ def test_resolving_same_constant_from_different_scopes
897
+ index(<<~RUBY)
898
+ module Namespace
899
+ CONST = 123
900
+
901
+ class Parent
902
+ CONST = 321
903
+ end
904
+
905
+ class Child < Parent
906
+ end
907
+ end
908
+ RUBY
909
+
910
+ entry = T.must(@index.resolve("CONST", ["Namespace", "Child"])&.first)
911
+ assert_equal(2, entry.location.start_line)
912
+
913
+ entry = T.must(@index.resolve("Namespace::Child::CONST", [])&.first)
914
+ assert_equal(5, entry.location.start_line)
915
+ end
916
+
917
+ def test_resolving_prepended_constants
918
+ index(<<~RUBY)
919
+ module Included
920
+ CONST = 123
921
+ end
922
+
923
+ module Prepended
924
+ CONST = 321
925
+ end
926
+
927
+ class Foo
928
+ include Included
929
+ prepend Prepended
930
+ end
931
+
932
+ class Bar
933
+ CONST = 456
934
+ include Included
935
+ prepend Prepended
936
+ end
937
+ RUBY
938
+
939
+ entry = T.must(@index.resolve("CONST", ["Foo"])&.first)
940
+ assert_equal(6, entry.location.start_line)
941
+
942
+ entry = T.must(@index.resolve("Foo::CONST", [])&.first)
943
+ assert_equal(6, entry.location.start_line)
944
+
945
+ entry = T.must(@index.resolve("Bar::CONST", [])&.first)
946
+ assert_equal(15, entry.location.start_line)
947
+ end
948
+
949
+ def test_resolving_constants_favors_ancestors_over_top_level
950
+ index(<<~RUBY)
951
+ module Value1
952
+ CONST = 1
953
+ end
954
+
955
+ module Value2
956
+ CONST = 2
957
+ end
958
+
959
+ CONST = 3
960
+ module First
961
+ include Value1
962
+
963
+ module Second
964
+ include Value2
965
+ end
966
+ end
967
+ RUBY
968
+
969
+ entry = T.must(@index.resolve("CONST", ["First", "Second"])&.first)
970
+ assert_equal(6, entry.location.start_line)
971
+ end
972
+
973
+ def test_resolving_circular_alias
974
+ index(<<~RUBY)
975
+ module Namespace
976
+ FOO = BAR
977
+ BAR = FOO
978
+ end
979
+ RUBY
980
+
981
+ foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
982
+ assert_equal(2, foo_entry.location.start_line)
983
+ assert_instance_of(Entry::Alias, foo_entry)
984
+
985
+ bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
986
+ assert_equal(3, bar_entry.location.start_line)
987
+ assert_instance_of(Entry::Alias, bar_entry)
988
+ end
989
+
990
+ def test_resolving_circular_alias_three_levels
991
+ index(<<~RUBY)
992
+ module Namespace
993
+ FOO = BAR
994
+ BAR = BAZ
995
+ BAZ = FOO
996
+ end
997
+ RUBY
998
+
999
+ foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
1000
+ assert_equal(2, foo_entry.location.start_line)
1001
+ assert_instance_of(Entry::Alias, foo_entry)
1002
+
1003
+ bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
1004
+ assert_equal(3, bar_entry.location.start_line)
1005
+ assert_instance_of(Entry::Alias, bar_entry)
1006
+
1007
+ baz_entry = T.must(@index.resolve("BAZ", ["Namespace"])&.first)
1008
+ assert_equal(4, baz_entry.location.start_line)
1009
+ assert_instance_of(Entry::Alias, baz_entry)
1010
+ end
1011
+
1012
+ def test_resolving_top_level_compact_reference
1013
+ index(<<~RUBY)
1014
+ class Foo::Bar
1015
+ end
1016
+ RUBY
1017
+
1018
+ foo_entry = T.must(@index.resolve("Foo::Bar", [])&.first)
1019
+ assert_equal(1, foo_entry.location.start_line)
1020
+ assert_instance_of(Entry::Class, foo_entry)
1021
+ end
1022
+
1023
+ def test_resolving_references_with_redundant_namespaces
1024
+ index(<<~RUBY)
1025
+ module Bar
1026
+ CONST = 1
1027
+ end
1028
+
1029
+ module A
1030
+ CONST = 2
1031
+
1032
+ module B
1033
+ CONST = 3
1034
+
1035
+ class Foo
1036
+ include Bar
1037
+ end
1038
+
1039
+ A::B::Foo::CONST
1040
+ end
1041
+ end
1042
+ RUBY
1043
+
1044
+ foo_entry = T.must(@index.resolve("A::B::Foo::CONST", ["A", "B"])&.first)
1045
+ assert_equal(2, foo_entry.location.start_line)
1046
+ end
1047
+
1048
+ def test_resolving_qualified_references
1049
+ index(<<~RUBY)
1050
+ module Namespace
1051
+ class Entry
1052
+ CONST = 1
1053
+ end
1054
+ end
1055
+
1056
+ module Namespace
1057
+ class Index
1058
+ end
1059
+ end
1060
+ RUBY
1061
+
1062
+ foo_entry = T.must(@index.resolve("Entry::CONST", ["Namespace", "Index"])&.first)
1063
+ assert_equal(3, foo_entry.location.start_line)
1064
+ end
1065
+
1066
+ def test_resolving_unqualified_references
1067
+ index(<<~RUBY)
1068
+ module Foo
1069
+ CONST = 1
1070
+ end
1071
+
1072
+ module Namespace
1073
+ CONST = 2
1074
+
1075
+ class Index
1076
+ include Foo
1077
+ end
1078
+ end
1079
+ RUBY
1080
+
1081
+ foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
1082
+ assert_equal(6, foo_entry.location.start_line)
1083
+ end
1084
+
1085
+ def test_resolving_references_with_only_top_level_declaration
1086
+ index(<<~RUBY)
1087
+ CONST = 1
1088
+
1089
+ module Foo; end
1090
+
1091
+ module Namespace
1092
+ class Index
1093
+ include Foo
1094
+ end
1095
+ end
1096
+ RUBY
1097
+
1098
+ foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
1099
+ assert_equal(1, foo_entry.location.start_line)
1100
+ end
1101
+
1102
+ def test_instance_variables_completions_from_different_owners_with_conflicting_names
1103
+ index(<<~RUBY)
1104
+ class Foo
1105
+ def initialize
1106
+ @bar = 1
1107
+ end
1108
+ end
1109
+
1110
+ class Bar
1111
+ def initialize
1112
+ @bar = 2
1113
+ end
1114
+ end
1115
+ RUBY
1116
+
1117
+ entry = T.must(@index.instance_variable_completion_candidates("@", "Bar")&.first)
1118
+ assert_equal("@bar", entry.name)
1119
+ assert_equal("Bar", T.must(entry.owner).name)
1120
+ end
1121
+
1122
+ def test_resolving_a_qualified_reference
1123
+ index(<<~RUBY)
1124
+ class Base
1125
+ module Third
1126
+ CONST = 1
1127
+ end
1128
+ end
1129
+
1130
+ class Foo
1131
+ module Third
1132
+ CONST = 2
1133
+ end
1134
+
1135
+ class Second < Base
1136
+ end
1137
+ end
1138
+ RUBY
1139
+
1140
+ foo_entry = T.must(@index.resolve("Third::CONST", ["Foo"])&.first)
1141
+ assert_equal(9, foo_entry.location.start_line)
1142
+ end
1143
+
1144
+ def test_resolving_unindexed_constant_with_no_nesting
1145
+ assert_nil(@index.resolve("RSpec", []))
1146
+ end
1147
+
1148
+ def test_object_superclass_resolution
1149
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1150
+ module Foo
1151
+ class Object; end
1152
+
1153
+ class Bar; end
1154
+ class Baz < Object; end
1155
+ end
1156
+ RUBY
1157
+
1158
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1159
+ assert_equal(
1160
+ ["Foo::Baz", "Foo::Object", "Object", "Kernel", "BasicObject"],
1161
+ @index.linearized_ancestors_of("Foo::Baz"),
1162
+ )
1163
+ end
1164
+
1165
+ def test_top_level_object_superclass_resolution
1166
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1167
+ module Foo
1168
+ class Object; end
1169
+
1170
+ class Bar < ::Object; end
1171
+ end
1172
+ RUBY
1173
+
1174
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
315
1175
  end
316
1176
  end
317
1177
  end