ruby-lsp 0.22.1 → 0.23.10
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 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp +12 -11
- data/exe/ruby-lsp-check +5 -5
- data/exe/ruby-lsp-launcher +41 -15
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +191 -100
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +174 -61
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +12 -0
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +82 -61
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +36 -0
- data/lib/ruby_indexer/ruby_indexer.rb +2 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +30 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +143 -44
- data/lib/ruby_indexer/test/instance_variables_test.rb +20 -0
- data/lib/ruby_indexer/test/method_test.rb +86 -8
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +90 -2
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +17 -18
- data/lib/ruby_lsp/client_capabilities.rb +7 -1
- data/lib/ruby_lsp/document.rb +72 -10
- data/lib/ruby_lsp/erb_document.rb +5 -3
- data/lib/ruby_lsp/global_state.rb +42 -3
- data/lib/ruby_lsp/internal.rb +3 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +9 -5
- data/lib/ruby_lsp/listeners/completion.rb +78 -6
- data/lib/ruby_lsp/listeners/definition.rb +80 -19
- data/lib/ruby_lsp/listeners/document_highlight.rb +3 -2
- data/lib/ruby_lsp/listeners/document_link.rb +21 -3
- data/lib/ruby_lsp/listeners/document_symbol.rb +12 -1
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +59 -2
- data/lib/ruby_lsp/load_sorbet.rb +3 -3
- data/lib/ruby_lsp/rbs_document.rb +2 -2
- data/lib/ruby_lsp/requests/code_action_resolve.rb +90 -6
- data/lib/ruby_lsp/requests/code_actions.rb +57 -1
- data/lib/ruby_lsp/requests/completion.rb +8 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +7 -1
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
- data/lib/ruby_lsp/requests/folding_ranges.rb +2 -6
- data/lib/ruby_lsp/requests/formatting.rb +2 -6
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +2 -2
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/references.rb +29 -2
- data/lib/ruby_lsp/requests/rename.rb +17 -7
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -4
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +2 -9
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +3 -3
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -13
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -3
- data/lib/ruby_lsp/ruby_document.rb +80 -6
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +205 -61
- data/lib/ruby_lsp/setup_bundler.rb +50 -43
- data/lib/ruby_lsp/store.rb +7 -7
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +60 -31
- data/lib/ruby_lsp/utils.rb +63 -3
- metadata +8 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -6,11 +6,11 @@ require_relative "test_case"
|
|
6
6
|
module RubyIndexer
|
7
7
|
class IndexTest < TestCase
|
8
8
|
def test_deleting_one_entry_for_a_class
|
9
|
-
@index.index_single(
|
9
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
10
10
|
class Foo
|
11
11
|
end
|
12
12
|
RUBY
|
13
|
-
@index.index_single(
|
13
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb"), <<~RUBY)
|
14
14
|
class Foo
|
15
15
|
end
|
16
16
|
RUBY
|
@@ -18,13 +18,13 @@ module RubyIndexer
|
|
18
18
|
entries = @index["Foo"]
|
19
19
|
assert_equal(2, entries.length)
|
20
20
|
|
21
|
-
@index.delete(
|
21
|
+
@index.delete(URI::Generic.from_path(path: "/fake/path/other_foo.rb"))
|
22
22
|
entries = @index["Foo"]
|
23
23
|
assert_equal(1, entries.length)
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_deleting_all_entries_for_a_class
|
27
|
-
@index.index_single(
|
27
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
28
28
|
class Foo
|
29
29
|
end
|
30
30
|
RUBY
|
@@ -32,13 +32,13 @@ module RubyIndexer
|
|
32
32
|
entries = @index["Foo"]
|
33
33
|
assert_equal(1, entries.length)
|
34
34
|
|
35
|
-
@index.delete(
|
35
|
+
@index.delete(URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
36
36
|
entries = @index["Foo"]
|
37
37
|
assert_nil(entries)
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_index_resolve
|
41
|
-
@index.index_single(
|
41
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
42
42
|
class Bar; end
|
43
43
|
|
44
44
|
module Foo
|
@@ -72,7 +72,7 @@ module RubyIndexer
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_accessing_with_colon_colon_prefix
|
75
|
-
@index.index_single(
|
75
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
76
76
|
class Bar; end
|
77
77
|
|
78
78
|
module Foo
|
@@ -92,7 +92,7 @@ module RubyIndexer
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def test_fuzzy_search
|
95
|
-
@index.index_single(
|
95
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
96
96
|
class Zws; end
|
97
97
|
|
98
98
|
module Qtl
|
@@ -120,18 +120,22 @@ module RubyIndexer
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_index_single_ignores_directories
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
path = "#{Dir.pwd}/lib/this_is_a_dir.rb"
|
124
|
+
FileUtils.mkdir(path)
|
125
|
+
|
126
|
+
begin
|
127
|
+
@index.index_file(URI::Generic.from_path(path: path))
|
128
|
+
ensure
|
129
|
+
FileUtils.rm_r(path)
|
130
|
+
end
|
127
131
|
end
|
128
132
|
|
129
133
|
def test_searching_for_require_paths
|
130
|
-
@index.index_single(
|
134
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
131
135
|
class Foo
|
132
136
|
end
|
133
137
|
RUBY
|
134
|
-
@index.index_single(
|
138
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
135
139
|
class Foo
|
136
140
|
end
|
137
141
|
RUBY
|
@@ -140,11 +144,11 @@ module RubyIndexer
|
|
140
144
|
end
|
141
145
|
|
142
146
|
def test_searching_for_entries_based_on_prefix
|
143
|
-
@index.index_single(
|
147
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
144
148
|
class Foo::Bizw
|
145
149
|
end
|
146
150
|
RUBY
|
147
|
-
@index.index_single(
|
151
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
148
152
|
class Foo::Bizw
|
149
153
|
end
|
150
154
|
|
@@ -160,7 +164,7 @@ module RubyIndexer
|
|
160
164
|
end
|
161
165
|
|
162
166
|
def test_resolve_normalizes_top_level_names
|
163
|
-
@index.index_single(
|
167
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
164
168
|
class Bar; end
|
165
169
|
|
166
170
|
module Foo
|
@@ -180,7 +184,7 @@ module RubyIndexer
|
|
180
184
|
end
|
181
185
|
|
182
186
|
def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
|
183
|
-
@index.index_single(
|
187
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
184
188
|
class Bar
|
185
189
|
end
|
186
190
|
|
@@ -343,18 +347,18 @@ module RubyIndexer
|
|
343
347
|
raise "Prism fixtures not found. Run `git submodule update --init` to fetch them."
|
344
348
|
end
|
345
349
|
|
346
|
-
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
350
|
+
fixtures = Dir.glob("#{Dir.pwd}/test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
347
351
|
|
348
352
|
fixtures.each do |fixture|
|
349
|
-
|
350
|
-
@index.
|
353
|
+
uri = URI::Generic.from_path(path: fixture)
|
354
|
+
@index.index_file(uri)
|
351
355
|
end
|
352
356
|
|
353
357
|
refute_empty(@index)
|
354
358
|
end
|
355
359
|
|
356
360
|
def test_index_single_does_not_fail_for_non_existing_file
|
357
|
-
@index.
|
361
|
+
@index.index_file(URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
358
362
|
entries_after_indexing = @index.names
|
359
363
|
assert_equal(@default_indexed_entries.keys, entries_after_indexing)
|
360
364
|
end
|
@@ -782,8 +786,8 @@ module RubyIndexer
|
|
782
786
|
end
|
783
787
|
RUBY
|
784
788
|
|
785
|
-
|
786
|
-
@index.
|
789
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
790
|
+
@index.index_file(uri)
|
787
791
|
|
788
792
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
789
793
|
|
@@ -796,7 +800,7 @@ module RubyIndexer
|
|
796
800
|
end
|
797
801
|
RUBY
|
798
802
|
|
799
|
-
@index.handle_change(
|
803
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
800
804
|
assert_empty(@index.instance_variable_get(:@ancestors))
|
801
805
|
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
802
806
|
end
|
@@ -816,8 +820,8 @@ module RubyIndexer
|
|
816
820
|
end
|
817
821
|
RUBY
|
818
822
|
|
819
|
-
|
820
|
-
@index.
|
823
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
824
|
+
@index.index_file(uri)
|
821
825
|
|
822
826
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
823
827
|
|
@@ -833,7 +837,7 @@ module RubyIndexer
|
|
833
837
|
end
|
834
838
|
RUBY
|
835
839
|
|
836
|
-
@index.handle_change(
|
840
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
837
841
|
refute_empty(@index.instance_variable_get(:@ancestors))
|
838
842
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
839
843
|
end
|
@@ -852,8 +856,8 @@ module RubyIndexer
|
|
852
856
|
end
|
853
857
|
RUBY
|
854
858
|
|
855
|
-
|
856
|
-
@index.
|
859
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
860
|
+
@index.index_file(uri)
|
857
861
|
|
858
862
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
859
863
|
|
@@ -866,7 +870,7 @@ module RubyIndexer
|
|
866
870
|
end
|
867
871
|
RUBY
|
868
872
|
|
869
|
-
@index.handle_change(
|
873
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
870
874
|
assert_empty(@index.instance_variable_get(:@ancestors))
|
871
875
|
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
872
876
|
end
|
@@ -1300,7 +1304,7 @@ module RubyIndexer
|
|
1300
1304
|
end
|
1301
1305
|
|
1302
1306
|
def test_resolving_method_inside_singleton_context
|
1303
|
-
@index.index_single(
|
1307
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1304
1308
|
module Foo
|
1305
1309
|
class Bar
|
1306
1310
|
class << self
|
@@ -1321,7 +1325,7 @@ module RubyIndexer
|
|
1321
1325
|
end
|
1322
1326
|
|
1323
1327
|
def test_resolving_constants_in_singleton_contexts
|
1324
|
-
@index.index_single(
|
1328
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1325
1329
|
module Foo
|
1326
1330
|
class Bar
|
1327
1331
|
CONST = 3
|
@@ -1346,7 +1350,7 @@ module RubyIndexer
|
|
1346
1350
|
end
|
1347
1351
|
|
1348
1352
|
def test_resolving_instance_variables_in_singleton_contexts
|
1349
|
-
@index.index_single(
|
1353
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1350
1354
|
module Foo
|
1351
1355
|
class Bar
|
1352
1356
|
@a = 123
|
@@ -1376,7 +1380,7 @@ module RubyIndexer
|
|
1376
1380
|
end
|
1377
1381
|
|
1378
1382
|
def test_instance_variable_completion_in_singleton_contexts
|
1379
|
-
@index.index_single(
|
1383
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1380
1384
|
module Foo
|
1381
1385
|
class Bar
|
1382
1386
|
@a = 123
|
@@ -1557,6 +1561,23 @@ module RubyIndexer
|
|
1557
1561
|
assert_equal("Foo::Bar", entry.name)
|
1558
1562
|
end
|
1559
1563
|
|
1564
|
+
def test_first_unqualified_const_prefers_exact_matches
|
1565
|
+
index(<<~RUBY)
|
1566
|
+
module Foo
|
1567
|
+
class ParseResultType
|
1568
|
+
end
|
1569
|
+
end
|
1570
|
+
|
1571
|
+
module Namespace
|
1572
|
+
class Type
|
1573
|
+
end
|
1574
|
+
end
|
1575
|
+
RUBY
|
1576
|
+
|
1577
|
+
entry = T.must(@index.first_unqualified_const("Type")&.first)
|
1578
|
+
assert_equal("Namespace::Type", entry.name)
|
1579
|
+
end
|
1580
|
+
|
1560
1581
|
def test_completion_does_not_duplicate_overridden_methods
|
1561
1582
|
index(<<~RUBY)
|
1562
1583
|
class Foo
|
@@ -1622,7 +1643,7 @@ module RubyIndexer
|
|
1622
1643
|
end
|
1623
1644
|
|
1624
1645
|
def test_linearizing_singleton_ancestors_of_singleton_when_class_has_parent
|
1625
|
-
@index.index_single(
|
1646
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1626
1647
|
class Foo; end
|
1627
1648
|
|
1628
1649
|
class Bar < Foo
|
@@ -1673,7 +1694,7 @@ module RubyIndexer
|
|
1673
1694
|
end
|
1674
1695
|
|
1675
1696
|
def test_extend_self
|
1676
|
-
@index.index_single(
|
1697
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1677
1698
|
module Foo
|
1678
1699
|
def bar
|
1679
1700
|
end
|
@@ -1705,7 +1726,7 @@ module RubyIndexer
|
|
1705
1726
|
end
|
1706
1727
|
|
1707
1728
|
def test_linearizing_singleton_ancestors
|
1708
|
-
@index.index_single(
|
1729
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1709
1730
|
module First
|
1710
1731
|
end
|
1711
1732
|
|
@@ -1746,7 +1767,7 @@ module RubyIndexer
|
|
1746
1767
|
end
|
1747
1768
|
|
1748
1769
|
def test_linearizing_singleton_ancestors_when_class_has_parent
|
1749
|
-
@index.index_single(
|
1770
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1750
1771
|
class Foo; end
|
1751
1772
|
|
1752
1773
|
class Bar < Foo
|
@@ -1776,7 +1797,7 @@ module RubyIndexer
|
|
1776
1797
|
end
|
1777
1798
|
|
1778
1799
|
def test_linearizing_a_module_singleton_class
|
1779
|
-
@index.index_single(
|
1800
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1780
1801
|
module A; end
|
1781
1802
|
RUBY
|
1782
1803
|
|
@@ -1885,13 +1906,13 @@ module RubyIndexer
|
|
1885
1906
|
end
|
1886
1907
|
RUBY
|
1887
1908
|
|
1888
|
-
entries = @index.entries_for("
|
1909
|
+
entries = @index.entries_for("file:///fake/path/foo.rb", Entry)
|
1889
1910
|
assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
|
1890
1911
|
|
1891
|
-
entries = @index.entries_for("
|
1912
|
+
entries = @index.entries_for("file:///fake/path/foo.rb", RubyIndexer::Entry::Namespace)
|
1892
1913
|
assert_equal(["Foo", "Bar", "Bar::<Class:Bar>"], entries.map(&:name))
|
1893
1914
|
|
1894
|
-
entries = @index.entries_for("
|
1915
|
+
entries = @index.entries_for("file:///fake/path/foo.rb")
|
1895
1916
|
assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
|
1896
1917
|
end
|
1897
1918
|
|
@@ -2057,10 +2078,88 @@ module RubyIndexer
|
|
2057
2078
|
end
|
2058
2079
|
|
2059
2080
|
def test_prevents_multiple_calls_to_index_all
|
2060
|
-
|
2081
|
+
@index.index_all
|
2082
|
+
|
2061
2083
|
assert_raises(Index::IndexNotEmptyError) do
|
2062
2084
|
@index.index_all
|
2063
2085
|
end
|
2064
2086
|
end
|
2087
|
+
|
2088
|
+
def test_index_can_handle_entries_from_untitled_scheme
|
2089
|
+
uri = URI("untitled:Untitled-1")
|
2090
|
+
|
2091
|
+
index(<<~RUBY, uri: uri)
|
2092
|
+
class Foo
|
2093
|
+
end
|
2094
|
+
RUBY
|
2095
|
+
|
2096
|
+
entry = @index["Foo"]&.first
|
2097
|
+
refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
|
2098
|
+
assert_equal("untitled:Untitled-1", entry.uri.to_s)
|
2099
|
+
assert_equal("Untitled-1", entry.file_name)
|
2100
|
+
assert_nil(entry.file_path)
|
2101
|
+
|
2102
|
+
@index.handle_change(uri, <<~RUBY)
|
2103
|
+
# I added this comment!
|
2104
|
+
class Foo
|
2105
|
+
end
|
2106
|
+
RUBY
|
2107
|
+
|
2108
|
+
entry = @index["Foo"]&.first
|
2109
|
+
refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
|
2110
|
+
assert_equal("I added this comment!", entry.comments)
|
2111
|
+
end
|
2112
|
+
|
2113
|
+
def test_instance_variable_completion_returns_class_variables_too
|
2114
|
+
index(<<~RUBY)
|
2115
|
+
class Parent
|
2116
|
+
@@abc = 123
|
2117
|
+
end
|
2118
|
+
|
2119
|
+
class Child < Parent
|
2120
|
+
@@adf = 123
|
2121
|
+
|
2122
|
+
def self.do
|
2123
|
+
end
|
2124
|
+
end
|
2125
|
+
RUBY
|
2126
|
+
|
2127
|
+
abc, adf = @index.instance_variable_completion_candidates("@", "Child::<Class:Child>")
|
2128
|
+
|
2129
|
+
refute_nil(abc)
|
2130
|
+
refute_nil(adf)
|
2131
|
+
|
2132
|
+
assert_equal("@@abc", abc.name)
|
2133
|
+
assert_equal("@@adf", adf.name)
|
2134
|
+
end
|
2135
|
+
|
2136
|
+
def test_class_variable_completion_from_singleton_context
|
2137
|
+
index(<<~RUBY)
|
2138
|
+
class Foo
|
2139
|
+
@@hello = 123
|
2140
|
+
|
2141
|
+
def self.do
|
2142
|
+
end
|
2143
|
+
end
|
2144
|
+
RUBY
|
2145
|
+
|
2146
|
+
candidates = @index.class_variable_completion_candidates("@@", "Foo::<Class:Foo>")
|
2147
|
+
refute_empty(candidates)
|
2148
|
+
|
2149
|
+
assert_equal("@@hello", candidates.first&.name)
|
2150
|
+
end
|
2151
|
+
|
2152
|
+
def test_resolve_class_variable_in_singleton_context
|
2153
|
+
index(<<~RUBY)
|
2154
|
+
class Foo
|
2155
|
+
@@hello = 123
|
2156
|
+
end
|
2157
|
+
RUBY
|
2158
|
+
|
2159
|
+
candidates = @index.resolve_class_variable("@@hello", "Foo::<Class:Foo>")
|
2160
|
+
refute_empty(candidates)
|
2161
|
+
|
2162
|
+
assert_equal("@@hello", candidates.first&.name)
|
2163
|
+
end
|
2065
2164
|
end
|
2066
2165
|
end
|
@@ -216,5 +216,25 @@ module RubyIndexer
|
|
216
216
|
assert_instance_of(Entry::Class, owner)
|
217
217
|
assert_equal("Foo", owner.name)
|
218
218
|
end
|
219
|
+
|
220
|
+
def test_module_function_does_not_impact_instance_variables
|
221
|
+
# One possible way of implementing `module_function` would be to push a fake singleton class to the stack, so that
|
222
|
+
# methods are inserted into it. However, that would be incorrect because it would then bind instance variables to
|
223
|
+
# the wrong type. This test is here to prevent that from happening.
|
224
|
+
index(<<~RUBY)
|
225
|
+
module Foo
|
226
|
+
module_function
|
227
|
+
|
228
|
+
def something; end
|
229
|
+
|
230
|
+
@a = 123
|
231
|
+
end
|
232
|
+
RUBY
|
233
|
+
|
234
|
+
entry = T.must(@index["@a"]&.first)
|
235
|
+
owner = T.must(entry.owner)
|
236
|
+
assert_instance_of(Entry::SingletonClass, owner)
|
237
|
+
assert_equal("Foo::<Class:Foo>", owner.name)
|
238
|
+
end
|
219
239
|
end
|
220
240
|
end
|
@@ -88,19 +88,21 @@ module RubyIndexer
|
|
88
88
|
|
89
89
|
def test_visibility_tracking
|
90
90
|
index(<<~RUBY)
|
91
|
-
|
92
|
-
|
91
|
+
class Foo
|
92
|
+
private def foo
|
93
|
+
end
|
93
94
|
|
94
|
-
|
95
|
+
def bar; end
|
95
96
|
|
96
|
-
|
97
|
+
protected
|
97
98
|
|
98
|
-
|
99
|
+
def baz; end
|
100
|
+
end
|
99
101
|
RUBY
|
100
102
|
|
101
|
-
assert_entry("foo", Entry::Method, "/fake/path/foo.rb:
|
102
|
-
assert_entry("bar", Entry::Method, "/fake/path/foo.rb:
|
103
|
-
assert_entry("baz", Entry::Method, "/fake/path/foo.rb:
|
103
|
+
assert_entry("foo", Entry::Method, "/fake/path/foo.rb:1-10:2-5", visibility: Entry::Visibility::PRIVATE)
|
104
|
+
assert_entry("bar", Entry::Method, "/fake/path/foo.rb:4-2:4-14", visibility: Entry::Visibility::PUBLIC)
|
105
|
+
assert_entry("baz", Entry::Method, "/fake/path/foo.rb:8-2:8-14", visibility: Entry::Visibility::PROTECTED)
|
104
106
|
end
|
105
107
|
|
106
108
|
def test_visibility_tracking_with_nested_class_or_modules
|
@@ -846,6 +848,82 @@ module RubyIndexer
|
|
846
848
|
assert_signature_matches(entry, "baz(1)")
|
847
849
|
end
|
848
850
|
|
851
|
+
def test_module_function_with_no_arguments
|
852
|
+
index(<<~RUBY)
|
853
|
+
module Foo
|
854
|
+
def bar; end
|
855
|
+
|
856
|
+
module_function
|
857
|
+
|
858
|
+
def baz; end
|
859
|
+
attr_reader :attribute
|
860
|
+
|
861
|
+
public
|
862
|
+
|
863
|
+
def qux; end
|
864
|
+
end
|
865
|
+
RUBY
|
866
|
+
|
867
|
+
entry = T.must(@index["bar"].first)
|
868
|
+
assert_predicate(entry, :public?)
|
869
|
+
assert_equal("Foo", T.must(entry.owner).name)
|
870
|
+
|
871
|
+
instance_baz, singleton_baz = T.must(@index["baz"])
|
872
|
+
assert_predicate(instance_baz, :private?)
|
873
|
+
assert_equal("Foo", T.must(instance_baz.owner).name)
|
874
|
+
|
875
|
+
assert_predicate(singleton_baz, :public?)
|
876
|
+
assert_equal("Foo::<Class:Foo>", T.must(singleton_baz.owner).name)
|
877
|
+
|
878
|
+
# After invoking `public`, the state of `module_function` is reset
|
879
|
+
instance_qux, singleton_qux = T.must(@index["qux"])
|
880
|
+
assert_nil(singleton_qux)
|
881
|
+
assert_predicate(instance_qux, :public?)
|
882
|
+
assert_equal("Foo", T.must(instance_baz.owner).name)
|
883
|
+
|
884
|
+
# Attributes are not turned into class methods, they do become private
|
885
|
+
instance_attribute, singleton_attribute = @index["attribute"]
|
886
|
+
assert_nil(singleton_attribute)
|
887
|
+
assert_equal("Foo", T.must(instance_attribute.owner).name)
|
888
|
+
assert_predicate(instance_attribute, :private?)
|
889
|
+
end
|
890
|
+
|
891
|
+
def test_module_function_does_nothing_in_classes
|
892
|
+
# Invoking `module_function` in a class raises an error. We simply ignore it
|
893
|
+
index(<<~RUBY)
|
894
|
+
class Foo
|
895
|
+
def bar; end
|
896
|
+
|
897
|
+
module_function
|
898
|
+
|
899
|
+
def baz; end
|
900
|
+
end
|
901
|
+
RUBY
|
902
|
+
|
903
|
+
entry = T.must(@index["bar"].first)
|
904
|
+
assert_predicate(entry, :public?)
|
905
|
+
assert_equal("Foo", T.must(entry.owner).name)
|
906
|
+
|
907
|
+
entry = T.must(@index["baz"].first)
|
908
|
+
assert_predicate(entry, :public?)
|
909
|
+
assert_equal("Foo", T.must(entry.owner).name)
|
910
|
+
end
|
911
|
+
|
912
|
+
def test_making_several_class_methods_private
|
913
|
+
index(<<~RUBY)
|
914
|
+
class Foo
|
915
|
+
def self.bar; end
|
916
|
+
def self.baz; end
|
917
|
+
def self.qux; end
|
918
|
+
|
919
|
+
private_class_method :bar, :baz, :qux
|
920
|
+
|
921
|
+
def initialize
|
922
|
+
end
|
923
|
+
end
|
924
|
+
RUBY
|
925
|
+
end
|
926
|
+
|
849
927
|
private
|
850
928
|
|
851
929
|
sig { params(entry: Entry::Method, call_string: String).void }
|
@@ -377,7 +377,7 @@ module RubyIndexer
|
|
377
377
|
_, _, declarations = RBS::Parser.parse_signature(buffer)
|
378
378
|
index = RubyIndexer::Index.new
|
379
379
|
indexer = RubyIndexer::RBSIndexer.new(index)
|
380
|
-
pathname = Pathname.new("file.rbs")
|
380
|
+
pathname = Pathname.new("/file.rbs")
|
381
381
|
indexer.process_signature(pathname, declarations)
|
382
382
|
entry = T.must(index[method_name]).first
|
383
383
|
T.cast(entry, Entry::Method).signatures
|
@@ -216,6 +216,88 @@ module RubyIndexer
|
|
216
216
|
assert_equal(11, refs[2].location.start_line)
|
217
217
|
end
|
218
218
|
|
219
|
+
def test_finds_instance_variable_read_references
|
220
|
+
refs = find_instance_variable_references("@foo", <<~RUBY)
|
221
|
+
class Foo
|
222
|
+
def foo
|
223
|
+
@foo
|
224
|
+
end
|
225
|
+
end
|
226
|
+
RUBY
|
227
|
+
assert_equal(1, refs.size)
|
228
|
+
|
229
|
+
assert_equal("@foo", refs[0].name)
|
230
|
+
assert_equal(3, refs[0].location.start_line)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_finds_instance_variable_write_references
|
234
|
+
refs = find_instance_variable_references("@foo", <<~RUBY)
|
235
|
+
class Foo
|
236
|
+
def write
|
237
|
+
@foo = 1
|
238
|
+
@foo &&= 2
|
239
|
+
@foo ||= 3
|
240
|
+
@foo += 4
|
241
|
+
@foo, @bar = []
|
242
|
+
end
|
243
|
+
end
|
244
|
+
RUBY
|
245
|
+
assert_equal(5, refs.size)
|
246
|
+
|
247
|
+
assert_equal(["@foo"], refs.map(&:name).uniq)
|
248
|
+
assert_equal(3, refs[0].location.start_line)
|
249
|
+
assert_equal(4, refs[1].location.start_line)
|
250
|
+
assert_equal(5, refs[2].location.start_line)
|
251
|
+
assert_equal(6, refs[3].location.start_line)
|
252
|
+
assert_equal(7, refs[4].location.start_line)
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_finds_instance_variable_references_ignore_context
|
256
|
+
refs = find_instance_variable_references("@name", <<~RUBY)
|
257
|
+
class Foo
|
258
|
+
def name
|
259
|
+
@name = "foo"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
class Bar
|
263
|
+
def name
|
264
|
+
@name = "bar"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
RUBY
|
268
|
+
assert_equal(2, refs.size)
|
269
|
+
|
270
|
+
assert_equal("@name", refs[0].name)
|
271
|
+
assert_equal(3, refs[0].location.start_line)
|
272
|
+
|
273
|
+
assert_equal("@name", refs[1].name)
|
274
|
+
assert_equal(8, refs[1].location.start_line)
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_accounts_for_reopened_classes
|
278
|
+
refs = find_const_references("Foo", <<~RUBY)
|
279
|
+
class Foo
|
280
|
+
end
|
281
|
+
class Foo
|
282
|
+
class Bar
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
Foo.new
|
287
|
+
RUBY
|
288
|
+
|
289
|
+
assert_equal(3, refs.size)
|
290
|
+
|
291
|
+
assert_equal("Foo", refs[0].name)
|
292
|
+
assert_equal(1, refs[0].location.start_line)
|
293
|
+
|
294
|
+
assert_equal("Foo", refs[1].name)
|
295
|
+
assert_equal(3, refs[1].location.start_line)
|
296
|
+
|
297
|
+
assert_equal("Foo", refs[2].name)
|
298
|
+
assert_equal(8, refs[2].location.start_line)
|
299
|
+
end
|
300
|
+
|
219
301
|
private
|
220
302
|
|
221
303
|
def find_const_references(const_name, source)
|
@@ -228,13 +310,19 @@ module RubyIndexer
|
|
228
310
|
find_references(target, source)
|
229
311
|
end
|
230
312
|
|
313
|
+
def find_instance_variable_references(instance_variable_name, source)
|
314
|
+
target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name)
|
315
|
+
find_references(target, source)
|
316
|
+
end
|
317
|
+
|
231
318
|
def find_references(target, source)
|
232
319
|
file_path = "/fake.rb"
|
320
|
+
uri = URI::Generic.from_path(path: file_path)
|
233
321
|
index = Index.new
|
234
|
-
index.index_single(
|
322
|
+
index.index_single(uri, source)
|
235
323
|
parse_result = Prism.parse(source)
|
236
324
|
dispatcher = Prism::Dispatcher.new
|
237
|
-
finder = ReferenceFinder.new(target, index, dispatcher)
|
325
|
+
finder = ReferenceFinder.new(target, index, dispatcher, uri)
|
238
326
|
dispatcher.visit(parse_result.value)
|
239
327
|
finder.references
|
240
328
|
end
|
@@ -13,8 +13,8 @@ module RubyIndexer
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def index(source)
|
17
|
-
@index.index_single(
|
16
|
+
def index(source, uri: URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
17
|
+
@index.index_single(uri, source)
|
18
18
|
end
|
19
19
|
|
20
20
|
def assert_entry(expected_name, type, expected_location, visibility: nil)
|