ruby-lsp 0.17.3 → 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/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +241 -91
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +74 -102
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +81 -19
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +50 -2
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
- data/lib/ruby_indexer/test/index_test.rb +326 -27
- data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
- data/lib/ruby_indexer/test/method_test.rb +54 -24
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +27 -2
- data/lib/ruby_lsp/document.rb +37 -8
- data/lib/ruby_lsp/global_state.rb +7 -3
- data/lib/ruby_lsp/internal.rb +1 -0
- 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 -15
- data/lib/ruby_lsp/test_helper.rb +1 -1
- data/lib/ruby_lsp/type_inferrer.rb +86 -0
- metadata +5 -2
@@ -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(["
|
112
|
-
|
113
|
-
result = @index.fuzzy_search("foobarsomeking")
|
114
|
-
assert_equal(6, result.length)
|
115
|
-
assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Base", "Bar"], result.map(&:name))
|
109
|
+
result = @index.fuzzy_search("Zws")
|
110
|
+
assert_equal(2, result.length)
|
111
|
+
assert_equal(["Zws", "Qtl::Zwo::Something"], result.map(&:name))
|
116
112
|
|
117
|
-
result = @index.fuzzy_search("
|
113
|
+
result = @index.fuzzy_search("qtlzwssomeking")
|
118
114
|
assert_equal(5, result.length)
|
119
|
-
assert_equal(["
|
115
|
+
assert_equal(["Qtl::Zwo::Something", "Qtl::Zws", "Qtl::Zwo", "Qtl", "Zws"], result.map(&:name))
|
116
|
+
|
117
|
+
result = @index.fuzzy_search("QltZwo")
|
118
|
+
assert_equal(4, result.length)
|
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
|
@@ -140,25 +140,23 @@ module RubyIndexer
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def test_searching_for_entries_based_on_prefix
|
143
|
-
# For this test, it's easier if we don't include core classes and modules
|
144
|
-
@index = Index.new
|
145
143
|
@index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
|
146
|
-
class Foo::
|
144
|
+
class Foo::Bizw
|
147
145
|
end
|
148
146
|
RUBY
|
149
147
|
@index.index_single(IndexablePath.new("/fake", "/fake/path/other_foo.rb"), <<~RUBY)
|
150
|
-
class Foo::
|
148
|
+
class Foo::Bizw
|
151
149
|
end
|
152
150
|
|
153
|
-
class Foo::
|
151
|
+
class Foo::Bizt
|
154
152
|
end
|
155
153
|
RUBY
|
156
154
|
|
157
155
|
results = @index.prefix_search("Foo", []).map { |entries| entries.map(&:name) }
|
158
|
-
assert_equal([["Foo::
|
156
|
+
assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
|
159
157
|
|
160
|
-
results = @index.prefix_search("
|
161
|
-
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)
|
162
160
|
end
|
163
161
|
|
164
162
|
def test_resolve_normalizes_top_level_names
|
@@ -291,16 +289,16 @@ module RubyIndexer
|
|
291
289
|
index(<<~RUBY)
|
292
290
|
module Foo
|
293
291
|
module Bar
|
294
|
-
def
|
292
|
+
def qzx; end
|
295
293
|
end
|
296
294
|
end
|
297
295
|
RUBY
|
298
296
|
|
299
|
-
entries = @index.prefix_search("
|
297
|
+
entries = @index.prefix_search("qz")
|
300
298
|
refute_empty(entries)
|
301
299
|
|
302
|
-
entry = T.must(entries.first).first
|
303
|
-
assert_equal("
|
300
|
+
entry = T.must(T.must(entries.first).first)
|
301
|
+
assert_equal("qzx", entry.name)
|
304
302
|
end
|
305
303
|
|
306
304
|
def test_indexing_prism_fixtures_succeeds
|
@@ -1145,8 +1143,32 @@ module RubyIndexer
|
|
1145
1143
|
assert_nil(@index.resolve("RSpec", []))
|
1146
1144
|
end
|
1147
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
|
+
|
1148
1170
|
def test_object_superclass_resolution
|
1149
|
-
|
1171
|
+
index(<<~RUBY)
|
1150
1172
|
module Foo
|
1151
1173
|
class Object; end
|
1152
1174
|
|
@@ -1162,8 +1184,25 @@ module RubyIndexer
|
|
1162
1184
|
)
|
1163
1185
|
end
|
1164
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
|
+
|
1165
1204
|
def test_top_level_object_superclass_resolution
|
1166
|
-
|
1205
|
+
index(<<~RUBY)
|
1167
1206
|
module Foo
|
1168
1207
|
class Object; end
|
1169
1208
|
|
@@ -1173,5 +1212,265 @@ module RubyIndexer
|
|
1173
1212
|
|
1174
1213
|
assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
|
1175
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
|
1176
1475
|
end
|
1177
1476
|
end
|
@@ -20,7 +20,9 @@ module RubyIndexer
|
|
20
20
|
assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
|
21
21
|
|
22
22
|
entry = T.must(@index["@a"]&.first)
|
23
|
-
|
23
|
+
owner = T.must(entry.owner)
|
24
|
+
assert_instance_of(Entry::Class, owner)
|
25
|
+
assert_equal("Foo::Bar", owner.name)
|
24
26
|
end
|
25
27
|
|
26
28
|
def test_instance_variable_and_write
|
@@ -38,7 +40,9 @@ module RubyIndexer
|
|
38
40
|
assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
|
39
41
|
|
40
42
|
entry = T.must(@index["@a"]&.first)
|
41
|
-
|
43
|
+
owner = T.must(entry.owner)
|
44
|
+
assert_instance_of(Entry::Class, owner)
|
45
|
+
assert_equal("Foo::Bar", owner.name)
|
42
46
|
end
|
43
47
|
|
44
48
|
def test_instance_variable_operator_write
|
@@ -56,7 +60,9 @@ module RubyIndexer
|
|
56
60
|
assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
|
57
61
|
|
58
62
|
entry = T.must(@index["@a"]&.first)
|
59
|
-
|
63
|
+
owner = T.must(entry.owner)
|
64
|
+
assert_instance_of(Entry::Class, owner)
|
65
|
+
assert_equal("Foo::Bar", owner.name)
|
60
66
|
end
|
61
67
|
|
62
68
|
def test_instance_variable_or_write
|
@@ -74,7 +80,9 @@ module RubyIndexer
|
|
74
80
|
assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
|
75
81
|
|
76
82
|
entry = T.must(@index["@a"]&.first)
|
77
|
-
|
83
|
+
owner = T.must(entry.owner)
|
84
|
+
assert_instance_of(Entry::Class, owner)
|
85
|
+
assert_equal("Foo::Bar", owner.name)
|
78
86
|
end
|
79
87
|
|
80
88
|
def test_instance_variable_target
|
@@ -93,10 +101,14 @@ module RubyIndexer
|
|
93
101
|
assert_entry("@b", Entry::InstanceVariable, "/fake/path/foo.rb:4-10:4-12")
|
94
102
|
|
95
103
|
entry = T.must(@index["@a"]&.first)
|
96
|
-
|
104
|
+
owner = T.must(entry.owner)
|
105
|
+
assert_instance_of(Entry::Class, owner)
|
106
|
+
assert_equal("Foo::Bar", owner.name)
|
97
107
|
|
98
108
|
entry = T.must(@index["@b"]&.first)
|
99
|
-
|
109
|
+
owner = T.must(entry.owner)
|
110
|
+
assert_instance_of(Entry::Class, owner)
|
111
|
+
assert_equal("Foo::Bar", owner.name)
|
100
112
|
end
|
101
113
|
|
102
114
|
def test_empty_name_instance_variables
|
@@ -118,6 +130,14 @@ module RubyIndexer
|
|
118
130
|
module Foo
|
119
131
|
class Bar
|
120
132
|
@a = 123
|
133
|
+
|
134
|
+
class << self
|
135
|
+
def hello
|
136
|
+
@b = 123
|
137
|
+
end
|
138
|
+
|
139
|
+
@c = 123
|
140
|
+
end
|
121
141
|
end
|
122
142
|
end
|
123
143
|
RUBY
|
@@ -125,7 +145,64 @@ module RubyIndexer
|
|
125
145
|
assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:2-4:2-6")
|
126
146
|
|
127
147
|
entry = T.must(@index["@a"]&.first)
|
128
|
-
|
148
|
+
owner = T.must(entry.owner)
|
149
|
+
assert_instance_of(Entry::SingletonClass, owner)
|
150
|
+
assert_equal("Foo::Bar::<Class:Bar>", owner.name)
|
151
|
+
|
152
|
+
assert_entry("@b", Entry::InstanceVariable, "/fake/path/foo.rb:6-8:6-10")
|
153
|
+
|
154
|
+
entry = T.must(@index["@b"]&.first)
|
155
|
+
owner = T.must(entry.owner)
|
156
|
+
assert_instance_of(Entry::SingletonClass, owner)
|
157
|
+
assert_equal("Foo::Bar::<Class:Bar>", owner.name)
|
158
|
+
|
159
|
+
assert_entry("@c", Entry::InstanceVariable, "/fake/path/foo.rb:9-6:9-8")
|
160
|
+
|
161
|
+
entry = T.must(@index["@c"]&.first)
|
162
|
+
owner = T.must(entry.owner)
|
163
|
+
assert_instance_of(Entry::SingletonClass, owner)
|
164
|
+
assert_equal("Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>", owner.name)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_top_level_instance_variables
|
168
|
+
index(<<~RUBY)
|
169
|
+
@a = 123
|
170
|
+
RUBY
|
171
|
+
|
172
|
+
entry = T.must(@index["@a"]&.first)
|
173
|
+
assert_nil(entry.owner)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_class_instance_variables_inside_self_method
|
177
|
+
index(<<~RUBY)
|
178
|
+
class Foo
|
179
|
+
def self.bar
|
180
|
+
@a = 123
|
181
|
+
end
|
182
|
+
end
|
183
|
+
RUBY
|
184
|
+
|
185
|
+
entry = T.must(@index["@a"]&.first)
|
186
|
+
owner = T.must(entry.owner)
|
187
|
+
assert_instance_of(Entry::SingletonClass, owner)
|
188
|
+
assert_equal("Foo::<Class:Foo>", owner.name)
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_instance_variable_inside_dynamic_method_declaration
|
192
|
+
index(<<~RUBY)
|
193
|
+
class Foo
|
194
|
+
def something.bar
|
195
|
+
@a = 123
|
196
|
+
end
|
197
|
+
end
|
198
|
+
RUBY
|
199
|
+
|
200
|
+
# If the surrounding method is beind defined on any dynamic value that isn't `self`, then we attribute the
|
201
|
+
# instance variable to the wrong owner since there's no way to understand that statically
|
202
|
+
entry = T.must(@index["@a"]&.first)
|
203
|
+
owner = T.must(entry.owner)
|
204
|
+
assert_instance_of(Entry::Class, owner)
|
205
|
+
assert_equal("Foo", owner.name)
|
129
206
|
end
|
130
207
|
end
|
131
208
|
end
|