ruby-lsp 0.17.3 → 0.17.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|