ruby-lsp 0.17.2 → 0.17.4

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/README.md +2 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +280 -74
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +102 -102
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +234 -56
  7. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +147 -0
  8. data/lib/ruby_indexer/ruby_indexer.rb +1 -0
  9. data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -2
  10. data/lib/ruby_indexer/test/configuration_test.rb +1 -1
  11. data/lib/ruby_indexer/test/constant_test.rb +1 -1
  12. data/lib/ruby_indexer/test/index_test.rb +702 -71
  13. data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
  14. data/lib/ruby_indexer/test/method_test.rb +74 -24
  15. data/lib/ruby_indexer/test/rbs_indexer_test.rb +67 -0
  16. data/lib/ruby_indexer/test/test_case.rb +7 -0
  17. data/lib/ruby_lsp/document.rb +37 -8
  18. data/lib/ruby_lsp/global_state.rb +43 -18
  19. data/lib/ruby_lsp/internal.rb +2 -0
  20. data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
  21. data/lib/ruby_lsp/listeners/completion.rb +53 -14
  22. data/lib/ruby_lsp/listeners/definition.rb +11 -7
  23. data/lib/ruby_lsp/listeners/hover.rb +14 -7
  24. data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
  25. data/lib/ruby_lsp/node_context.rb +6 -1
  26. data/lib/ruby_lsp/requests/completion.rb +5 -4
  27. data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
  28. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
  29. data/lib/ruby_lsp/requests/support/common.rb +19 -1
  30. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
  31. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +91 -0
  32. data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
  33. data/lib/ruby_lsp/requests.rb +2 -0
  34. data/lib/ruby_lsp/server.rb +54 -4
  35. data/lib/ruby_lsp/test_helper.rb +1 -1
  36. data/lib/ruby_lsp/type_inferrer.rb +86 -0
  37. metadata +29 -4
@@ -93,30 +93,30 @@ module RubyIndexer
93
93
 
94
94
  def test_fuzzy_search
95
95
  @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
96
- class Bar; end
96
+ class Zws; end
97
97
 
98
- module Foo
99
- class Bar
98
+ module Qtl
99
+ class Zws
100
100
  end
101
101
 
102
- class Baz
102
+ class Zwo
103
103
  class Something
104
104
  end
105
105
  end
106
106
  end
107
107
  RUBY
108
108
 
109
- result = @index.fuzzy_search("Bar")
110
- assert_equal(1, result.length)
111
- assert_equal(@index["Bar"].first, result.first)
109
+ result = @index.fuzzy_search("Zws")
110
+ assert_equal(2, result.length)
111
+ assert_equal(["Zws", "Qtl::Zwo::Something"], result.map(&:name))
112
112
 
113
- result = @index.fuzzy_search("foobarsomeking")
113
+ result = @index.fuzzy_search("qtlzwssomeking")
114
114
  assert_equal(5, result.length)
115
- assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Bar"], result.map(&:name))
115
+ assert_equal(["Qtl::Zwo::Something", "Qtl::Zws", "Qtl::Zwo", "Qtl", "Zws"], result.map(&:name))
116
116
 
117
- result = @index.fuzzy_search("FooBaz")
117
+ result = @index.fuzzy_search("QltZwo")
118
118
  assert_equal(4, result.length)
119
- assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something"], result.map(&:name))
119
+ assert_equal(["Qtl::Zwo", "Qtl::Zws", "Qtl::Zwo::Something", "Qtl"], result.map(&:name))
120
120
  end
121
121
 
122
122
  def test_index_single_ignores_directories
@@ -141,22 +141,22 @@ module RubyIndexer
141
141
 
142
142
  def test_searching_for_entries_based_on_prefix
143
143
  @index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
144
- class Foo::Bar
144
+ class Foo::Bizw
145
145
  end
146
146
  RUBY
147
147
  @index.index_single(IndexablePath.new("/fake", "/fake/path/other_foo.rb"), <<~RUBY)
148
- class Foo::Bar
148
+ class Foo::Bizw
149
149
  end
150
150
 
151
- class Foo::Baz
151
+ class Foo::Bizt
152
152
  end
153
153
  RUBY
154
154
 
155
155
  results = @index.prefix_search("Foo", []).map { |entries| entries.map(&:name) }
156
- assert_equal([["Foo::Bar", "Foo::Bar"], ["Foo::Baz"]], results)
156
+ assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
157
157
 
158
- results = @index.prefix_search("Ba", ["Foo"]).map { |entries| entries.map(&:name) }
159
- assert_equal([["Foo::Bar", "Foo::Bar"], ["Foo::Baz"]], results)
158
+ results = @index.prefix_search("Biz", ["Foo"]).map { |entries| entries.map(&:name) }
159
+ assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
160
160
  end
161
161
 
162
162
  def test_resolve_normalizes_top_level_names
@@ -181,6 +181,9 @@ module RubyIndexer
181
181
 
182
182
  def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
183
183
  @index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
184
+ class Float
185
+ end
186
+
184
187
  module Foo
185
188
  class Float < self
186
189
  INFINITY = ::Float::INFINITY
@@ -286,16 +289,16 @@ module RubyIndexer
286
289
  index(<<~RUBY)
287
290
  module Foo
288
291
  module Bar
289
- def baz; end
292
+ def qzx; end
290
293
  end
291
294
  end
292
295
  RUBY
293
296
 
294
- entries = @index.prefix_search("ba")
297
+ entries = @index.prefix_search("qz")
295
298
  refute_empty(entries)
296
299
 
297
- entry = T.must(entries.first).first
298
- assert_equal("baz", entry.name)
300
+ entry = T.must(T.must(entries.first).first)
301
+ assert_equal("qzx", entry.name)
299
302
  end
300
303
 
301
304
  def test_indexing_prism_fixtures_succeeds
@@ -315,7 +318,8 @@ module RubyIndexer
315
318
 
316
319
  def test_index_single_does_not_fail_for_non_existing_file
317
320
  @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"))
318
- assert_empty(@index.instance_variable_get(:@entries))
321
+ entries_after_indexing = @index.instance_variable_get(:@entries).keys
322
+ assert_equal(@default_indexed_entries.keys, entries_after_indexing)
319
323
  end
320
324
 
321
325
  def test_linearized_ancestors_basic_ordering
@@ -339,9 +343,9 @@ module RubyIndexer
339
343
  "B",
340
344
  "A",
341
345
  "Foo",
342
- # "Object",
343
- # "Kernel",
344
- # "BasicObject",
346
+ "Object",
347
+ "Kernel",
348
+ "BasicObject",
345
349
  ],
346
350
  @index.linearized_ancestors_of("Foo"),
347
351
  )
@@ -351,9 +355,9 @@ module RubyIndexer
351
355
  "Bar",
352
356
  "B",
353
357
  "A",
354
- # "Object",
355
- # "Kernel",
356
- # "BasicObject",
358
+ "Object",
359
+ "Kernel",
360
+ "BasicObject",
357
361
  ],
358
362
  @index.linearized_ancestors_of("Bar"),
359
363
  )
@@ -401,9 +405,9 @@ module RubyIndexer
401
405
  "A",
402
406
  "C",
403
407
  "Bar",
404
- # "Object",
405
- # "Kernel",
406
- # "BasicObject",
408
+ "Object",
409
+ "Kernel",
410
+ "BasicObject",
407
411
  ],
408
412
  @index.linearized_ancestors_of("Foo"),
409
413
  )
@@ -432,9 +436,9 @@ module RubyIndexer
432
436
  "Foo",
433
437
  "B",
434
438
  "A",
435
- # "Object",
436
- # "Kernel",
437
- # "BasicObject",
439
+ "Object",
440
+ "Kernel",
441
+ "BasicObject",
438
442
  ],
439
443
  @index.linearized_ancestors_of("Foo"),
440
444
  )
@@ -444,9 +448,9 @@ module RubyIndexer
444
448
  "B",
445
449
  "A",
446
450
  "Bar",
447
- # "Object",
448
- # "Kernel",
449
- # "BasicObject",
451
+ "Object",
452
+ "Kernel",
453
+ "BasicObject",
450
454
  ],
451
455
  @index.linearized_ancestors_of("Bar"),
452
456
  )
@@ -493,9 +497,9 @@ module RubyIndexer
493
497
  [
494
498
  "A",
495
499
  "Foo",
496
- # "Object",
497
- # "Kernel",
498
- # "BasicObject",
500
+ "Object",
501
+ "Kernel",
502
+ "BasicObject",
499
503
  ],
500
504
  @index.linearized_ancestors_of("Foo"),
501
505
  )
@@ -505,9 +509,9 @@ module RubyIndexer
505
509
  "A",
506
510
  "Bar",
507
511
  "A",
508
- # "Object",
509
- # "Kernel",
510
- # "BasicObject",
512
+ "Object",
513
+ "Kernel",
514
+ "BasicObject",
511
515
  ],
512
516
  @index.linearized_ancestors_of("Bar"),
513
517
  )
@@ -519,15 +523,7 @@ module RubyIndexer
519
523
  end
520
524
  RUBY
521
525
 
522
- assert_equal(
523
- [
524
- "Foo",
525
- # "Object",
526
- # "Kernel",
527
- # "BasicObject",
528
- ],
529
- @index.linearized_ancestors_of("Foo"),
530
- )
526
+ assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
531
527
  end
532
528
 
533
529
  def test_ancestors_linearization_complex_prepend_duplication
@@ -552,9 +548,9 @@ module RubyIndexer
552
548
  "B",
553
549
  "C",
554
550
  "Foo",
555
- # "Object",
556
- # "Kernel",
557
- # "BasicObject",
551
+ "Object",
552
+ "Kernel",
553
+ "BasicObject",
558
554
  ],
559
555
  @index.linearized_ancestors_of("Foo"),
560
556
  )
@@ -582,9 +578,9 @@ module RubyIndexer
582
578
  "C",
583
579
  "B",
584
580
  "A",
585
- # "Object",
586
- # "Kernel",
587
- # "BasicObject",
581
+ "Object",
582
+ "Kernel",
583
+ "BasicObject",
588
584
  ],
589
585
  @index.linearized_ancestors_of("Foo"),
590
586
  )
@@ -613,9 +609,9 @@ module RubyIndexer
613
609
  "Foo::Bar",
614
610
  "Foo::Baz",
615
611
  "Foo::Something",
616
- # "Object",
617
- # "Kernel",
618
- # "BasicObject",
612
+ "Object",
613
+ "Kernel",
614
+ "BasicObject",
619
615
  ],
620
616
  @index.linearized_ancestors_of("Foo::Bar"),
621
617
  )
@@ -623,9 +619,7 @@ module RubyIndexer
623
619
 
624
620
  def test_linearizing_ancestors_for_non_existing_namespaces
625
621
  index(<<~RUBY)
626
- module Kernel
627
- def Array(a); end
628
- end
622
+ def Bar(a); end
629
623
  RUBY
630
624
 
631
625
  assert_raises(Index::NonExistingNamespaceError) do
@@ -633,7 +627,7 @@ module RubyIndexer
633
627
  end
634
628
 
635
629
  assert_raises(Index::NonExistingNamespaceError) do
636
- @index.linearized_ancestors_of("Array")
630
+ @index.linearized_ancestors_of("Bar")
637
631
  end
638
632
  end
639
633
 
@@ -754,7 +748,7 @@ module RubyIndexer
754
748
  indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
755
749
  @index.index_single(indexable_path)
756
750
 
757
- assert_equal(["Bar", "Foo"], @index.linearized_ancestors_of("Bar"))
751
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
758
752
 
759
753
  # Remove include to invalidate the ancestor tree
760
754
  File.write(File.join(dir, "foo.rb"), <<~RUBY)
@@ -767,7 +761,7 @@ module RubyIndexer
767
761
 
768
762
  @index.handle_change(indexable_path)
769
763
  assert_empty(@index.instance_variable_get(:@ancestors))
770
- assert_equal(["Bar"], @index.linearized_ancestors_of("Bar"))
764
+ assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
771
765
  end
772
766
  end
773
767
  end
@@ -788,7 +782,7 @@ module RubyIndexer
788
782
  indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
789
783
  @index.index_single(indexable_path)
790
784
 
791
- assert_equal(["Bar", "Foo"], @index.linearized_ancestors_of("Bar"))
785
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
792
786
 
793
787
  # Remove include to invalidate the ancestor tree
794
788
  File.write(File.join(dir, "foo.rb"), <<~RUBY)
@@ -804,7 +798,7 @@ module RubyIndexer
804
798
 
805
799
  @index.handle_change(indexable_path)
806
800
  refute_empty(@index.instance_variable_get(:@ancestors))
807
- assert_equal(["Bar", "Foo"], @index.linearized_ancestors_of("Bar"))
801
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
808
802
  end
809
803
  end
810
804
  end
@@ -824,7 +818,7 @@ module RubyIndexer
824
818
  indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
825
819
  @index.index_single(indexable_path)
826
820
 
827
- assert_equal(["Bar", "Foo"], @index.linearized_ancestors_of("Bar"))
821
+ assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
828
822
 
829
823
  # Remove include to invalidate the ancestor tree
830
824
  File.write(File.join(dir, "foo.rb"), <<~RUBY)
@@ -837,9 +831,646 @@ module RubyIndexer
837
831
 
838
832
  @index.handle_change(indexable_path)
839
833
  assert_empty(@index.instance_variable_get(:@ancestors))
840
- assert_equal(["Bar"], @index.linearized_ancestors_of("Bar"))
834
+ assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
841
835
  end
842
836
  end
843
837
  end
838
+
839
+ def test_resolving_inherited_constants
840
+ index(<<~RUBY)
841
+ module Foo
842
+ CONST = 1
843
+ end
844
+
845
+ module Baz
846
+ CONST = 2
847
+ end
848
+
849
+ module Qux
850
+ include Foo
851
+ end
852
+
853
+ module Namespace
854
+ CONST = 3
855
+
856
+ include Baz
857
+
858
+ class Bar
859
+ include Qux
860
+ end
861
+ end
862
+
863
+ CONST = 4
864
+ RUBY
865
+
866
+ entry = T.must(@index.resolve("CONST", ["Namespace", "Bar"])&.first)
867
+ assert_equal(14, entry.location.start_line)
868
+ end
869
+
870
+ def test_resolving_inherited_alised_namespace
871
+ index(<<~RUBY)
872
+ module Bar
873
+ TARGET = 123
874
+ end
875
+
876
+ module Foo
877
+ CONST = Bar
878
+ end
879
+
880
+ module Namespace
881
+ class Bar
882
+ include Foo
883
+ end
884
+ end
885
+ RUBY
886
+
887
+ entry = T.must(@index.resolve("Foo::CONST::TARGET", [])&.first)
888
+ assert_equal(2, entry.location.start_line)
889
+
890
+ entry = T.must(@index.resolve("Namespace::Bar::CONST::TARGET", [])&.first)
891
+ assert_equal(2, entry.location.start_line)
892
+ end
893
+
894
+ def test_resolving_same_constant_from_different_scopes
895
+ index(<<~RUBY)
896
+ module Namespace
897
+ CONST = 123
898
+
899
+ class Parent
900
+ CONST = 321
901
+ end
902
+
903
+ class Child < Parent
904
+ end
905
+ end
906
+ RUBY
907
+
908
+ entry = T.must(@index.resolve("CONST", ["Namespace", "Child"])&.first)
909
+ assert_equal(2, entry.location.start_line)
910
+
911
+ entry = T.must(@index.resolve("Namespace::Child::CONST", [])&.first)
912
+ assert_equal(5, entry.location.start_line)
913
+ end
914
+
915
+ def test_resolving_prepended_constants
916
+ index(<<~RUBY)
917
+ module Included
918
+ CONST = 123
919
+ end
920
+
921
+ module Prepended
922
+ CONST = 321
923
+ end
924
+
925
+ class Foo
926
+ include Included
927
+ prepend Prepended
928
+ end
929
+
930
+ class Bar
931
+ CONST = 456
932
+ include Included
933
+ prepend Prepended
934
+ end
935
+ RUBY
936
+
937
+ entry = T.must(@index.resolve("CONST", ["Foo"])&.first)
938
+ assert_equal(6, entry.location.start_line)
939
+
940
+ entry = T.must(@index.resolve("Foo::CONST", [])&.first)
941
+ assert_equal(6, entry.location.start_line)
942
+
943
+ entry = T.must(@index.resolve("Bar::CONST", [])&.first)
944
+ assert_equal(15, entry.location.start_line)
945
+ end
946
+
947
+ def test_resolving_constants_favors_ancestors_over_top_level
948
+ index(<<~RUBY)
949
+ module Value1
950
+ CONST = 1
951
+ end
952
+
953
+ module Value2
954
+ CONST = 2
955
+ end
956
+
957
+ CONST = 3
958
+ module First
959
+ include Value1
960
+
961
+ module Second
962
+ include Value2
963
+ end
964
+ end
965
+ RUBY
966
+
967
+ entry = T.must(@index.resolve("CONST", ["First", "Second"])&.first)
968
+ assert_equal(6, entry.location.start_line)
969
+ end
970
+
971
+ def test_resolving_circular_alias
972
+ index(<<~RUBY)
973
+ module Namespace
974
+ FOO = BAR
975
+ BAR = FOO
976
+ end
977
+ RUBY
978
+
979
+ foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
980
+ assert_equal(2, foo_entry.location.start_line)
981
+ assert_instance_of(Entry::Alias, foo_entry)
982
+
983
+ bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
984
+ assert_equal(3, bar_entry.location.start_line)
985
+ assert_instance_of(Entry::Alias, bar_entry)
986
+ end
987
+
988
+ def test_resolving_circular_alias_three_levels
989
+ index(<<~RUBY)
990
+ module Namespace
991
+ FOO = BAR
992
+ BAR = BAZ
993
+ BAZ = FOO
994
+ end
995
+ RUBY
996
+
997
+ foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
998
+ assert_equal(2, foo_entry.location.start_line)
999
+ assert_instance_of(Entry::Alias, foo_entry)
1000
+
1001
+ bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
1002
+ assert_equal(3, bar_entry.location.start_line)
1003
+ assert_instance_of(Entry::Alias, bar_entry)
1004
+
1005
+ baz_entry = T.must(@index.resolve("BAZ", ["Namespace"])&.first)
1006
+ assert_equal(4, baz_entry.location.start_line)
1007
+ assert_instance_of(Entry::Alias, baz_entry)
1008
+ end
1009
+
1010
+ def test_resolving_top_level_compact_reference
1011
+ index(<<~RUBY)
1012
+ class Foo::Bar
1013
+ end
1014
+ RUBY
1015
+
1016
+ foo_entry = T.must(@index.resolve("Foo::Bar", [])&.first)
1017
+ assert_equal(1, foo_entry.location.start_line)
1018
+ assert_instance_of(Entry::Class, foo_entry)
1019
+ end
1020
+
1021
+ def test_resolving_references_with_redundant_namespaces
1022
+ index(<<~RUBY)
1023
+ module Bar
1024
+ CONST = 1
1025
+ end
1026
+
1027
+ module A
1028
+ CONST = 2
1029
+
1030
+ module B
1031
+ CONST = 3
1032
+
1033
+ class Foo
1034
+ include Bar
1035
+ end
1036
+
1037
+ A::B::Foo::CONST
1038
+ end
1039
+ end
1040
+ RUBY
1041
+
1042
+ foo_entry = T.must(@index.resolve("A::B::Foo::CONST", ["A", "B"])&.first)
1043
+ assert_equal(2, foo_entry.location.start_line)
1044
+ end
1045
+
1046
+ def test_resolving_qualified_references
1047
+ index(<<~RUBY)
1048
+ module Namespace
1049
+ class Entry
1050
+ CONST = 1
1051
+ end
1052
+ end
1053
+
1054
+ module Namespace
1055
+ class Index
1056
+ end
1057
+ end
1058
+ RUBY
1059
+
1060
+ foo_entry = T.must(@index.resolve("Entry::CONST", ["Namespace", "Index"])&.first)
1061
+ assert_equal(3, foo_entry.location.start_line)
1062
+ end
1063
+
1064
+ def test_resolving_unqualified_references
1065
+ index(<<~RUBY)
1066
+ module Foo
1067
+ CONST = 1
1068
+ end
1069
+
1070
+ module Namespace
1071
+ CONST = 2
1072
+
1073
+ class Index
1074
+ include Foo
1075
+ end
1076
+ end
1077
+ RUBY
1078
+
1079
+ foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
1080
+ assert_equal(6, foo_entry.location.start_line)
1081
+ end
1082
+
1083
+ def test_resolving_references_with_only_top_level_declaration
1084
+ index(<<~RUBY)
1085
+ CONST = 1
1086
+
1087
+ module Foo; end
1088
+
1089
+ module Namespace
1090
+ class Index
1091
+ include Foo
1092
+ end
1093
+ end
1094
+ RUBY
1095
+
1096
+ foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
1097
+ assert_equal(1, foo_entry.location.start_line)
1098
+ end
1099
+
1100
+ def test_instance_variables_completions_from_different_owners_with_conflicting_names
1101
+ index(<<~RUBY)
1102
+ class Foo
1103
+ def initialize
1104
+ @bar = 1
1105
+ end
1106
+ end
1107
+
1108
+ class Bar
1109
+ def initialize
1110
+ @bar = 2
1111
+ end
1112
+ end
1113
+ RUBY
1114
+
1115
+ entry = T.must(@index.instance_variable_completion_candidates("@", "Bar")&.first)
1116
+ assert_equal("@bar", entry.name)
1117
+ assert_equal("Bar", T.must(entry.owner).name)
1118
+ end
1119
+
1120
+ def test_resolving_a_qualified_reference
1121
+ index(<<~RUBY)
1122
+ class Base
1123
+ module Third
1124
+ CONST = 1
1125
+ end
1126
+ end
1127
+
1128
+ class Foo
1129
+ module Third
1130
+ CONST = 2
1131
+ end
1132
+
1133
+ class Second < Base
1134
+ end
1135
+ end
1136
+ RUBY
1137
+
1138
+ foo_entry = T.must(@index.resolve("Third::CONST", ["Foo"])&.first)
1139
+ assert_equal(9, foo_entry.location.start_line)
1140
+ end
1141
+
1142
+ def test_resolving_unindexed_constant_with_no_nesting
1143
+ assert_nil(@index.resolve("RSpec", []))
1144
+ end
1145
+
1146
+ def test_object_superclass_indexing_and_resolution_with_reopened_object_class
1147
+ index(<<~RUBY)
1148
+ class Object; end
1149
+ RUBY
1150
+
1151
+ entries = @index["Object"]
1152
+ assert_equal(2, entries.length)
1153
+ reopened_entry = entries.last
1154
+ assert_equal("::BasicObject", reopened_entry.parent_class)
1155
+ assert_equal(["Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Object"))
1156
+ end
1157
+
1158
+ def test_object_superclass_indexing_and_resolution_with_reopened_basic_object_class
1159
+ index(<<~RUBY)
1160
+ class BasicObject; end
1161
+ RUBY
1162
+
1163
+ entries = @index["BasicObject"]
1164
+ assert_equal(2, entries.length)
1165
+ reopened_entry = entries.last
1166
+ assert_nil(reopened_entry.parent_class)
1167
+ assert_equal(["BasicObject"], @index.linearized_ancestors_of("BasicObject"))
1168
+ end
1169
+
1170
+ def test_object_superclass_resolution
1171
+ index(<<~RUBY)
1172
+ module Foo
1173
+ class Object; end
1174
+
1175
+ class Bar; end
1176
+ class Baz < Object; end
1177
+ end
1178
+ RUBY
1179
+
1180
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1181
+ assert_equal(
1182
+ ["Foo::Baz", "Foo::Object", "Object", "Kernel", "BasicObject"],
1183
+ @index.linearized_ancestors_of("Foo::Baz"),
1184
+ )
1185
+ end
1186
+
1187
+ def test_basic_object_superclass_resolution
1188
+ index(<<~RUBY)
1189
+ module Foo
1190
+ class BasicObject; end
1191
+
1192
+ class Bar; end
1193
+ class Baz < BasicObject; end
1194
+ end
1195
+ RUBY
1196
+
1197
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1198
+ assert_equal(
1199
+ ["Foo::Baz", "Foo::BasicObject", "Object", "Kernel", "BasicObject"],
1200
+ @index.linearized_ancestors_of("Foo::Baz"),
1201
+ )
1202
+ end
1203
+
1204
+ def test_top_level_object_superclass_resolution
1205
+ index(<<~RUBY)
1206
+ module Foo
1207
+ class Object; end
1208
+
1209
+ class Bar < ::Object; end
1210
+ end
1211
+ RUBY
1212
+
1213
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1214
+ end
1215
+
1216
+ def test_top_level_basic_object_superclass_resolution
1217
+ index(<<~RUBY)
1218
+ module Foo
1219
+ class BasicObject; end
1220
+
1221
+ class Bar < ::BasicObject; end
1222
+ end
1223
+ RUBY
1224
+
1225
+ assert_equal(["Foo::Bar", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1226
+ end
1227
+
1228
+ def test_resolving_method_inside_singleton_context
1229
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1230
+ module Foo
1231
+ class Bar
1232
+ class << self
1233
+ class Baz
1234
+ class << self
1235
+ def found_me!; end
1236
+ end
1237
+ end
1238
+ end
1239
+ end
1240
+ end
1241
+ RUBY
1242
+
1243
+ entry = @index.resolve_method("found_me!", "Foo::Bar::<Class:Bar>::Baz::<Class:Baz>")&.first
1244
+ refute_nil(entry)
1245
+
1246
+ assert_equal("found_me!", T.must(entry).name)
1247
+ end
1248
+
1249
+ def test_resolving_constants_in_singleton_contexts
1250
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1251
+ module Foo
1252
+ class Bar
1253
+ CONST = 3
1254
+
1255
+ class << self
1256
+ CONST = 2
1257
+
1258
+ class Baz
1259
+ CONST = 1
1260
+
1261
+ class << self
1262
+ end
1263
+ end
1264
+ end
1265
+ end
1266
+ end
1267
+ RUBY
1268
+
1269
+ entry = @index.resolve("CONST", ["Foo", "Bar", "<Class:Bar>", "Baz", "<Class:Baz>"])&.first
1270
+ refute_nil(entry)
1271
+ assert_equal(9, T.must(entry).location.start_line)
1272
+ end
1273
+
1274
+ def test_resolving_instance_variables_in_singleton_contexts
1275
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1276
+ module Foo
1277
+ class Bar
1278
+ @a = 123
1279
+
1280
+ class << self
1281
+ def hello
1282
+ @b = 123
1283
+ end
1284
+
1285
+ @c = 123
1286
+ end
1287
+ end
1288
+ end
1289
+ RUBY
1290
+
1291
+ entry = @index.resolve_instance_variable("@a", "Foo::Bar::<Class:Bar>")&.first
1292
+ refute_nil(entry)
1293
+ assert_equal("@a", T.must(entry).name)
1294
+
1295
+ entry = @index.resolve_instance_variable("@b", "Foo::Bar::<Class:Bar>")&.first
1296
+ refute_nil(entry)
1297
+ assert_equal("@b", T.must(entry).name)
1298
+
1299
+ entry = @index.resolve_instance_variable("@c", "Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>")&.first
1300
+ refute_nil(entry)
1301
+ assert_equal("@c", T.must(entry).name)
1302
+ end
1303
+
1304
+ def test_instance_variable_completion_in_singleton_contexts
1305
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1306
+ module Foo
1307
+ class Bar
1308
+ @a = 123
1309
+
1310
+ class << self
1311
+ def hello
1312
+ @b = 123
1313
+ end
1314
+
1315
+ @c = 123
1316
+ end
1317
+ end
1318
+ end
1319
+ RUBY
1320
+
1321
+ entries = @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>").map(&:name)
1322
+ assert_includes(entries, "@a")
1323
+ assert_includes(entries, "@b")
1324
+
1325
+ assert_includes(
1326
+ @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>").map(&:name),
1327
+ "@c",
1328
+ )
1329
+ end
1330
+
1331
+ def test_singletons_are_excluded_from_prefix_search
1332
+ index(<<~RUBY)
1333
+ class Zwq
1334
+ class << self
1335
+ end
1336
+ end
1337
+ RUBY
1338
+
1339
+ assert_empty(@index.prefix_search("Zwq::<C"))
1340
+ end
1341
+
1342
+ def test_singletons_are_excluded_from_fuzzy_search
1343
+ index(<<~RUBY)
1344
+ class Zwq
1345
+ class << self
1346
+ end
1347
+ end
1348
+ RUBY
1349
+
1350
+ results = @index.fuzzy_search("Zwq")
1351
+ assert_equal(1, results.length)
1352
+ assert_equal("Zwq", results.first.name)
1353
+ end
1354
+
1355
+ def test_resolving_method_aliases
1356
+ index(<<~RUBY)
1357
+ class Foo
1358
+ def bar(a, b, c)
1359
+ end
1360
+
1361
+ alias double_alias bar
1362
+ end
1363
+
1364
+ class Bar < Foo
1365
+ def hello(b); end
1366
+
1367
+ alias baz bar
1368
+ alias_method :qux, :hello
1369
+ alias double double_alias
1370
+ end
1371
+ RUBY
1372
+
1373
+ # baz
1374
+ methods = @index.resolve_method("baz", "Bar")
1375
+ refute_nil(methods)
1376
+
1377
+ entry = T.must(methods.first)
1378
+ assert_kind_of(Entry::MethodAlias, entry)
1379
+ assert_equal("bar", entry.target.name)
1380
+ assert_equal("Foo", T.must(entry.target.owner).name)
1381
+
1382
+ # qux
1383
+ methods = @index.resolve_method("qux", "Bar")
1384
+ refute_nil(methods)
1385
+
1386
+ entry = T.must(methods.first)
1387
+ assert_kind_of(Entry::MethodAlias, entry)
1388
+ assert_equal("hello", entry.target.name)
1389
+ assert_equal("Bar", T.must(entry.target.owner).name)
1390
+
1391
+ # double
1392
+ methods = @index.resolve_method("double", "Bar")
1393
+ refute_nil(methods)
1394
+
1395
+ entry = T.must(methods.first)
1396
+ assert_kind_of(Entry::MethodAlias, entry)
1397
+
1398
+ target = entry.target
1399
+ assert_equal("double_alias", target.name)
1400
+ assert_kind_of(Entry::MethodAlias, target)
1401
+ assert_equal("Foo", T.must(target.owner).name)
1402
+
1403
+ final_target = target.target
1404
+ assert_equal("bar", final_target.name)
1405
+ assert_kind_of(Entry::Method, final_target)
1406
+ assert_equal("Foo", T.must(final_target.owner).name)
1407
+ end
1408
+
1409
+ def test_resolving_circular_method_aliases
1410
+ index(<<~RUBY)
1411
+ class Foo
1412
+ alias bar bar
1413
+ end
1414
+ RUBY
1415
+
1416
+ # It's not possible to resolve an alias that points to itself
1417
+ methods = @index.resolve_method("bar", "Foo")
1418
+ assert_nil(methods)
1419
+
1420
+ entry = T.must(@index["bar"].first)
1421
+ assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1422
+ end
1423
+
1424
+ def test_unresolable_method_aliases
1425
+ index(<<~RUBY)
1426
+ class Foo
1427
+ alias bar baz
1428
+ end
1429
+ RUBY
1430
+
1431
+ # `baz` does not exist, so resolving `bar` is not possible
1432
+ methods = @index.resolve_method("bar", "Foo")
1433
+ assert_nil(methods)
1434
+
1435
+ entry = T.must(@index["bar"].first)
1436
+ assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1437
+ end
1438
+
1439
+ def test_only_aliases_for_the_right_owner_are_resolved
1440
+ index(<<~RUBY)
1441
+ class Foo
1442
+ attr_reader :name
1443
+ alias_method :decorated_name, :name
1444
+ end
1445
+
1446
+ class Bar
1447
+ alias_method :decorated_name, :to_s
1448
+ end
1449
+ RUBY
1450
+
1451
+ methods = @index.resolve_method("decorated_name", "Foo")
1452
+ refute_nil(methods)
1453
+
1454
+ entry = T.must(methods.first)
1455
+ assert_kind_of(Entry::MethodAlias, entry)
1456
+
1457
+ target = entry.target
1458
+ assert_equal("name", target.name)
1459
+ assert_kind_of(Entry::Accessor, target)
1460
+ assert_equal("Foo", T.must(target.owner).name)
1461
+
1462
+ other_decorated_name = T.must(@index["decorated_name"].find { |e| e.is_a?(Entry::UnresolvedMethodAlias) })
1463
+ assert_kind_of(Entry::UnresolvedMethodAlias, other_decorated_name)
1464
+ end
1465
+
1466
+ def test_completion_does_not_include_unresolved_aliases
1467
+ index(<<~RUBY)
1468
+ class Foo
1469
+ alias_method :bar, :missing
1470
+ end
1471
+ RUBY
1472
+
1473
+ assert_empty(@index.method_completion_candidates("bar", "Foo"))
1474
+ end
844
1475
  end
845
1476
  end