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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +280 -74
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +102 -102
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +234 -56
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +147 -0
- data/lib/ruby_indexer/ruby_indexer.rb +1 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -2
- data/lib/ruby_indexer/test/configuration_test.rb +1 -1
- data/lib/ruby_indexer/test/constant_test.rb +1 -1
- data/lib/ruby_indexer/test/index_test.rb +702 -71
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +74 -24
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +67 -0
- data/lib/ruby_indexer/test/test_case.rb +7 -0
- data/lib/ruby_lsp/document.rb +37 -8
- data/lib/ruby_lsp/global_state.rb +43 -18
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +2 -2
- data/lib/ruby_lsp/listeners/completion.rb +53 -14
- data/lib/ruby_lsp/listeners/definition.rb +11 -7
- data/lib/ruby_lsp/listeners/hover.rb +14 -7
- data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
- data/lib/ruby_lsp/node_context.rb +6 -1
- data/lib/ruby_lsp/requests/completion.rb +5 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
- data/lib/ruby_lsp/requests/support/common.rb +19 -1
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +91 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/server.rb +54 -4
- data/lib/ruby_lsp/test_helper.rb +1 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- 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
|
96
|
+
class Zws; end
|
97
97
|
|
98
|
-
module
|
99
|
-
class
|
98
|
+
module Qtl
|
99
|
+
class Zws
|
100
100
|
end
|
101
101
|
|
102
|
-
class
|
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("
|
110
|
-
assert_equal(
|
111
|
-
assert_equal(
|
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("
|
113
|
+
result = @index.fuzzy_search("qtlzwssomeking")
|
114
114
|
assert_equal(5, result.length)
|
115
|
-
assert_equal(["
|
115
|
+
assert_equal(["Qtl::Zwo::Something", "Qtl::Zws", "Qtl::Zwo", "Qtl", "Zws"], result.map(&:name))
|
116
116
|
|
117
|
-
result = @index.fuzzy_search("
|
117
|
+
result = @index.fuzzy_search("QltZwo")
|
118
118
|
assert_equal(4, result.length)
|
119
|
-
assert_equal(["
|
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::
|
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::
|
148
|
+
class Foo::Bizw
|
149
149
|
end
|
150
150
|
|
151
|
-
class Foo::
|
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::
|
156
|
+
assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
|
157
157
|
|
158
|
-
results = @index.prefix_search("
|
159
|
-
assert_equal([["Foo::
|
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
|
292
|
+
def qzx; end
|
290
293
|
end
|
291
294
|
end
|
292
295
|
RUBY
|
293
296
|
|
294
|
-
entries = @index.prefix_search("
|
297
|
+
entries = @index.prefix_search("qz")
|
295
298
|
refute_empty(entries)
|
296
299
|
|
297
|
-
entry = T.must(entries.first).first
|
298
|
-
assert_equal("
|
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
|
-
|
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
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
355
|
-
|
356
|
-
|
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
|
-
|
405
|
-
|
406
|
-
|
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
|
-
|
436
|
-
|
437
|
-
|
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
|
-
|
448
|
-
|
449
|
-
|
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
|
-
|
497
|
-
|
498
|
-
|
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
|
-
|
509
|
-
|
510
|
-
|
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
|
-
|
556
|
-
|
557
|
-
|
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
|
-
|
586
|
-
|
587
|
-
|
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
|
-
|
617
|
-
|
618
|
-
|
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
|
-
|
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("
|
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
|