ruby-lsp 0.17.2 → 0.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/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