ruby-lsp 0.16.7 → 0.17.3
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 +3 -1
- data/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +195 -18
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +129 -12
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +333 -44
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +99 -0
- data/lib/ruby_indexer/ruby_indexer.rb +1 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +58 -11
- data/lib/ruby_indexer/test/configuration_test.rb +5 -6
- data/lib/ruby_indexer/test/constant_test.rb +9 -9
- data/lib/ruby_indexer/test/index_test.rb +867 -7
- data/lib/ruby_indexer/test/instance_variables_test.rb +131 -0
- data/lib/ruby_indexer/test/method_test.rb +57 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +42 -0
- data/lib/ruby_indexer/test/test_case.rb +10 -1
- data/lib/ruby_lsp/addon.rb +8 -8
- data/lib/ruby_lsp/document.rb +26 -3
- data/lib/ruby_lsp/global_state.rb +37 -16
- 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 +74 -17
- data/lib/ruby_lsp/listeners/definition.rb +82 -24
- data/lib/ruby_lsp/listeners/hover.rb +62 -6
- data/lib/ruby_lsp/listeners/signature_help.rb +4 -4
- data/lib/ruby_lsp/node_context.rb +39 -0
- data/lib/ruby_lsp/requests/code_action_resolve.rb +73 -2
- data/lib/ruby_lsp/requests/code_actions.rb +16 -15
- data/lib/ruby_lsp/requests/completion.rb +21 -13
- data/lib/ruby_lsp/requests/completion_resolve.rb +9 -0
- data/lib/ruby_lsp/requests/definition.rb +25 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +2 -2
- data/lib/ruby_lsp/requests/hover.rb +5 -6
- data/lib/ruby_lsp/requests/on_type_formatting.rb +8 -4
- data/lib/ruby_lsp/requests/signature_help.rb +3 -3
- data/lib/ruby_lsp/requests/support/common.rb +4 -3
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +23 -6
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +5 -1
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +7 -4
- data/lib/ruby_lsp/server.rb +22 -5
- data/lib/ruby_lsp/test_helper.rb +1 -0
- metadata +29 -5
@@ -107,16 +107,16 @@ module RubyIndexer
|
|
107
107
|
RUBY
|
108
108
|
|
109
109
|
result = @index.fuzzy_search("Bar")
|
110
|
-
assert_equal(
|
111
|
-
assert_equal(
|
110
|
+
assert_equal(3, result.length)
|
111
|
+
assert_equal(["Bar", "Backtrace", "Base"], result.map(&:name))
|
112
112
|
|
113
113
|
result = @index.fuzzy_search("foobarsomeking")
|
114
|
-
assert_equal(
|
115
|
-
assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Bar"], result.map(&:name))
|
114
|
+
assert_equal(6, result.length)
|
115
|
+
assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Base", "Bar"], result.map(&:name))
|
116
116
|
|
117
117
|
result = @index.fuzzy_search("FooBaz")
|
118
|
-
assert_equal(
|
119
|
-
assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something"], result.map(&:name))
|
118
|
+
assert_equal(5, result.length)
|
119
|
+
assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something", "Float"], result.map(&:name))
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_index_single_ignores_directories
|
@@ -140,6 +140,8 @@ 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
|
143
145
|
@index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
|
144
146
|
class Foo::Bar
|
145
147
|
end
|
@@ -181,6 +183,9 @@ module RubyIndexer
|
|
181
183
|
|
182
184
|
def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
|
183
185
|
@index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
|
186
|
+
class Float
|
187
|
+
end
|
188
|
+
|
184
189
|
module Foo
|
185
190
|
class Float < self
|
186
191
|
INFINITY = ::Float::INFINITY
|
@@ -299,6 +304,10 @@ module RubyIndexer
|
|
299
304
|
end
|
300
305
|
|
301
306
|
def test_indexing_prism_fixtures_succeeds
|
307
|
+
unless Dir.exist?("test/fixtures/prism/test/prism/fixtures")
|
308
|
+
raise "Prism fixtures not found. Run `git submodule update --init` to fetch them."
|
309
|
+
end
|
310
|
+
|
302
311
|
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
303
312
|
|
304
313
|
fixtures.each do |fixture|
|
@@ -311,7 +320,858 @@ module RubyIndexer
|
|
311
320
|
|
312
321
|
def test_index_single_does_not_fail_for_non_existing_file
|
313
322
|
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"))
|
314
|
-
|
323
|
+
entries_after_indexing = @index.instance_variable_get(:@entries).keys
|
324
|
+
assert_equal(@default_indexed_entries.keys, entries_after_indexing)
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_linearized_ancestors_basic_ordering
|
328
|
+
index(<<~RUBY)
|
329
|
+
module A; end
|
330
|
+
module B; end
|
331
|
+
|
332
|
+
class Foo
|
333
|
+
prepend A
|
334
|
+
prepend B
|
335
|
+
end
|
336
|
+
|
337
|
+
class Bar
|
338
|
+
include A
|
339
|
+
include B
|
340
|
+
end
|
341
|
+
RUBY
|
342
|
+
|
343
|
+
assert_equal(
|
344
|
+
[
|
345
|
+
"B",
|
346
|
+
"A",
|
347
|
+
"Foo",
|
348
|
+
"Object",
|
349
|
+
"Kernel",
|
350
|
+
"BasicObject",
|
351
|
+
],
|
352
|
+
@index.linearized_ancestors_of("Foo"),
|
353
|
+
)
|
354
|
+
|
355
|
+
assert_equal(
|
356
|
+
[
|
357
|
+
"Bar",
|
358
|
+
"B",
|
359
|
+
"A",
|
360
|
+
"Object",
|
361
|
+
"Kernel",
|
362
|
+
"BasicObject",
|
363
|
+
],
|
364
|
+
@index.linearized_ancestors_of("Bar"),
|
365
|
+
)
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_linearized_ancestors
|
369
|
+
index(<<~RUBY)
|
370
|
+
module A; end
|
371
|
+
module B; end
|
372
|
+
module C; end
|
373
|
+
|
374
|
+
module D
|
375
|
+
include A
|
376
|
+
end
|
377
|
+
|
378
|
+
module E
|
379
|
+
prepend B
|
380
|
+
end
|
381
|
+
|
382
|
+
module F
|
383
|
+
include C
|
384
|
+
include A
|
385
|
+
end
|
386
|
+
|
387
|
+
class Bar
|
388
|
+
prepend F
|
389
|
+
end
|
390
|
+
|
391
|
+
class Foo < Bar
|
392
|
+
include E
|
393
|
+
prepend D
|
394
|
+
end
|
395
|
+
RUBY
|
396
|
+
|
397
|
+
# Object, Kernel and BasicObject are intentionally commented out for now until we develop a strategy for indexing
|
398
|
+
# declarations made in C code
|
399
|
+
assert_equal(
|
400
|
+
[
|
401
|
+
"D",
|
402
|
+
"A",
|
403
|
+
"Foo",
|
404
|
+
"B",
|
405
|
+
"E",
|
406
|
+
"F",
|
407
|
+
"A",
|
408
|
+
"C",
|
409
|
+
"Bar",
|
410
|
+
"Object",
|
411
|
+
"Kernel",
|
412
|
+
"BasicObject",
|
413
|
+
],
|
414
|
+
@index.linearized_ancestors_of("Foo"),
|
415
|
+
)
|
416
|
+
end
|
417
|
+
|
418
|
+
def test_linearized_ancestors_duplicates
|
419
|
+
index(<<~RUBY)
|
420
|
+
module A; end
|
421
|
+
module B
|
422
|
+
include A
|
423
|
+
end
|
424
|
+
|
425
|
+
class Foo
|
426
|
+
include B
|
427
|
+
include A
|
428
|
+
end
|
429
|
+
|
430
|
+
class Bar
|
431
|
+
prepend B
|
432
|
+
prepend A
|
433
|
+
end
|
434
|
+
RUBY
|
435
|
+
|
436
|
+
assert_equal(
|
437
|
+
[
|
438
|
+
"Foo",
|
439
|
+
"B",
|
440
|
+
"A",
|
441
|
+
"Object",
|
442
|
+
"Kernel",
|
443
|
+
"BasicObject",
|
444
|
+
],
|
445
|
+
@index.linearized_ancestors_of("Foo"),
|
446
|
+
)
|
447
|
+
|
448
|
+
assert_equal(
|
449
|
+
[
|
450
|
+
"B",
|
451
|
+
"A",
|
452
|
+
"Bar",
|
453
|
+
"Object",
|
454
|
+
"Kernel",
|
455
|
+
"BasicObject",
|
456
|
+
],
|
457
|
+
@index.linearized_ancestors_of("Bar"),
|
458
|
+
)
|
459
|
+
end
|
460
|
+
|
461
|
+
def test_linearizing_ancestors_is_cached
|
462
|
+
index(<<~RUBY)
|
463
|
+
module C; end
|
464
|
+
module A; end
|
465
|
+
module B
|
466
|
+
include A
|
467
|
+
end
|
468
|
+
|
469
|
+
class Foo
|
470
|
+
include B
|
471
|
+
include A
|
472
|
+
end
|
473
|
+
RUBY
|
474
|
+
|
475
|
+
@index.linearized_ancestors_of("Foo")
|
476
|
+
ancestors = @index.instance_variable_get(:@ancestors)
|
477
|
+
assert(ancestors.key?("Foo"))
|
478
|
+
assert(ancestors.key?("A"))
|
479
|
+
assert(ancestors.key?("B"))
|
480
|
+
refute(ancestors.key?("C"))
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_duplicate_prepend_include
|
484
|
+
index(<<~RUBY)
|
485
|
+
module A; end
|
486
|
+
|
487
|
+
class Foo
|
488
|
+
prepend A
|
489
|
+
include A
|
490
|
+
end
|
491
|
+
|
492
|
+
class Bar
|
493
|
+
include A
|
494
|
+
prepend A
|
495
|
+
end
|
496
|
+
RUBY
|
497
|
+
|
498
|
+
assert_equal(
|
499
|
+
[
|
500
|
+
"A",
|
501
|
+
"Foo",
|
502
|
+
"Object",
|
503
|
+
"Kernel",
|
504
|
+
"BasicObject",
|
505
|
+
],
|
506
|
+
@index.linearized_ancestors_of("Foo"),
|
507
|
+
)
|
508
|
+
|
509
|
+
assert_equal(
|
510
|
+
[
|
511
|
+
"A",
|
512
|
+
"Bar",
|
513
|
+
"A",
|
514
|
+
"Object",
|
515
|
+
"Kernel",
|
516
|
+
"BasicObject",
|
517
|
+
],
|
518
|
+
@index.linearized_ancestors_of("Bar"),
|
519
|
+
)
|
520
|
+
end
|
521
|
+
|
522
|
+
def test_linearizing_ancestors_handles_circular_parent_class
|
523
|
+
index(<<~RUBY)
|
524
|
+
class Foo < Foo
|
525
|
+
end
|
526
|
+
RUBY
|
527
|
+
|
528
|
+
assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
|
529
|
+
end
|
530
|
+
|
531
|
+
def test_ancestors_linearization_complex_prepend_duplication
|
532
|
+
index(<<~RUBY)
|
533
|
+
module A; end
|
534
|
+
module B
|
535
|
+
prepend A
|
536
|
+
end
|
537
|
+
module C
|
538
|
+
prepend B
|
539
|
+
end
|
540
|
+
|
541
|
+
class Foo
|
542
|
+
prepend A
|
543
|
+
prepend C
|
544
|
+
end
|
545
|
+
RUBY
|
546
|
+
|
547
|
+
assert_equal(
|
548
|
+
[
|
549
|
+
"A",
|
550
|
+
"B",
|
551
|
+
"C",
|
552
|
+
"Foo",
|
553
|
+
"Object",
|
554
|
+
"Kernel",
|
555
|
+
"BasicObject",
|
556
|
+
],
|
557
|
+
@index.linearized_ancestors_of("Foo"),
|
558
|
+
)
|
559
|
+
end
|
560
|
+
|
561
|
+
def test_ancestors_linearization_complex_include_duplication
|
562
|
+
index(<<~RUBY)
|
563
|
+
module A; end
|
564
|
+
module B
|
565
|
+
include A
|
566
|
+
end
|
567
|
+
module C
|
568
|
+
include B
|
569
|
+
end
|
570
|
+
|
571
|
+
class Foo
|
572
|
+
include A
|
573
|
+
include C
|
574
|
+
end
|
575
|
+
RUBY
|
576
|
+
|
577
|
+
assert_equal(
|
578
|
+
[
|
579
|
+
"Foo",
|
580
|
+
"C",
|
581
|
+
"B",
|
582
|
+
"A",
|
583
|
+
"Object",
|
584
|
+
"Kernel",
|
585
|
+
"BasicObject",
|
586
|
+
],
|
587
|
+
@index.linearized_ancestors_of("Foo"),
|
588
|
+
)
|
589
|
+
end
|
590
|
+
|
591
|
+
def test_linearizing_ancestors_that_need_to_be_resolved
|
592
|
+
index(<<~RUBY)
|
593
|
+
module Foo
|
594
|
+
module Baz
|
595
|
+
end
|
596
|
+
module Qux
|
597
|
+
end
|
598
|
+
|
599
|
+
class Something; end
|
600
|
+
|
601
|
+
class Bar < Something
|
602
|
+
include Baz
|
603
|
+
prepend Qux
|
604
|
+
end
|
605
|
+
end
|
606
|
+
RUBY
|
607
|
+
|
608
|
+
assert_equal(
|
609
|
+
[
|
610
|
+
"Foo::Qux",
|
611
|
+
"Foo::Bar",
|
612
|
+
"Foo::Baz",
|
613
|
+
"Foo::Something",
|
614
|
+
"Object",
|
615
|
+
"Kernel",
|
616
|
+
"BasicObject",
|
617
|
+
],
|
618
|
+
@index.linearized_ancestors_of("Foo::Bar"),
|
619
|
+
)
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_linearizing_ancestors_for_non_existing_namespaces
|
623
|
+
index(<<~RUBY)
|
624
|
+
def Bar(a); end
|
625
|
+
RUBY
|
626
|
+
|
627
|
+
assert_raises(Index::NonExistingNamespaceError) do
|
628
|
+
@index.linearized_ancestors_of("Foo")
|
629
|
+
end
|
630
|
+
|
631
|
+
assert_raises(Index::NonExistingNamespaceError) do
|
632
|
+
@index.linearized_ancestors_of("Bar")
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
def test_linearizing_circular_ancestors
|
637
|
+
index(<<~RUBY)
|
638
|
+
module M1
|
639
|
+
include M2
|
640
|
+
end
|
641
|
+
|
642
|
+
module M2
|
643
|
+
include M1
|
644
|
+
end
|
645
|
+
|
646
|
+
module A1
|
647
|
+
include A2
|
648
|
+
end
|
649
|
+
|
650
|
+
module A2
|
651
|
+
include A3
|
652
|
+
end
|
653
|
+
|
654
|
+
module A3
|
655
|
+
include A1
|
656
|
+
end
|
657
|
+
|
658
|
+
class Foo < Foo
|
659
|
+
include Foo
|
660
|
+
end
|
661
|
+
|
662
|
+
module Bar
|
663
|
+
include Bar
|
664
|
+
end
|
665
|
+
RUBY
|
666
|
+
|
667
|
+
assert_equal(["M2", "M1"], @index.linearized_ancestors_of("M2"))
|
668
|
+
assert_equal(["A3", "A1", "A2"], @index.linearized_ancestors_of("A3"))
|
669
|
+
assert_equal(["Foo"], @index.linearized_ancestors_of("Foo"))
|
670
|
+
assert_equal(["Bar"], @index.linearized_ancestors_of("Bar"))
|
671
|
+
end
|
672
|
+
|
673
|
+
def test_linearizing_circular_aliased_dependency
|
674
|
+
index(<<~RUBY)
|
675
|
+
module A
|
676
|
+
end
|
677
|
+
|
678
|
+
ALIAS = A
|
679
|
+
|
680
|
+
module A
|
681
|
+
include ALIAS
|
682
|
+
end
|
683
|
+
RUBY
|
684
|
+
|
685
|
+
assert_equal(["A", "ALIAS"], @index.linearized_ancestors_of("A"))
|
686
|
+
end
|
687
|
+
|
688
|
+
def test_resolving_an_inherited_method
|
689
|
+
index(<<~RUBY)
|
690
|
+
module Foo
|
691
|
+
def baz; end
|
692
|
+
end
|
693
|
+
|
694
|
+
class Bar
|
695
|
+
def qux; end
|
696
|
+
end
|
697
|
+
|
698
|
+
class Wow < Bar
|
699
|
+
include Foo
|
700
|
+
end
|
701
|
+
RUBY
|
702
|
+
|
703
|
+
entry = T.must(@index.resolve_method("baz", "Wow")&.first)
|
704
|
+
assert_equal("baz", entry.name)
|
705
|
+
assert_equal("Foo", T.must(entry.owner).name)
|
706
|
+
|
707
|
+
entry = T.must(@index.resolve_method("qux", "Wow")&.first)
|
708
|
+
assert_equal("qux", entry.name)
|
709
|
+
assert_equal("Bar", T.must(entry.owner).name)
|
710
|
+
end
|
711
|
+
|
712
|
+
def test_resolving_an_inherited_method_lands_on_first_match
|
713
|
+
index(<<~RUBY)
|
714
|
+
module Foo
|
715
|
+
def qux; end
|
716
|
+
end
|
717
|
+
|
718
|
+
class Bar
|
719
|
+
def qux; end
|
720
|
+
end
|
721
|
+
|
722
|
+
class Wow < Bar
|
723
|
+
prepend Foo
|
724
|
+
|
725
|
+
def qux; end
|
726
|
+
end
|
727
|
+
RUBY
|
728
|
+
|
729
|
+
entries = T.must(@index.resolve_method("qux", "Wow"))
|
730
|
+
assert_equal(1, entries.length)
|
731
|
+
|
732
|
+
entry = T.must(entries.first)
|
733
|
+
assert_equal("qux", entry.name)
|
734
|
+
assert_equal("Foo", T.must(entry.owner).name)
|
735
|
+
end
|
736
|
+
|
737
|
+
def test_handle_change_clears_ancestor_cache_if_tree_changed
|
738
|
+
Dir.mktmpdir do |dir|
|
739
|
+
Dir.chdir(dir) do
|
740
|
+
# Write the original file
|
741
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
742
|
+
module Foo
|
743
|
+
end
|
744
|
+
|
745
|
+
class Bar
|
746
|
+
include Foo
|
747
|
+
end
|
748
|
+
RUBY
|
749
|
+
|
750
|
+
indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
|
751
|
+
@index.index_single(indexable_path)
|
752
|
+
|
753
|
+
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
754
|
+
|
755
|
+
# Remove include to invalidate the ancestor tree
|
756
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
757
|
+
module Foo
|
758
|
+
end
|
759
|
+
|
760
|
+
class Bar
|
761
|
+
end
|
762
|
+
RUBY
|
763
|
+
|
764
|
+
@index.handle_change(indexable_path)
|
765
|
+
assert_empty(@index.instance_variable_get(:@ancestors))
|
766
|
+
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
def test_handle_change_does_not_clear_ancestor_cache_if_tree_not_changed
|
772
|
+
Dir.mktmpdir do |dir|
|
773
|
+
Dir.chdir(dir) do
|
774
|
+
# Write the original file
|
775
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
776
|
+
module Foo
|
777
|
+
end
|
778
|
+
|
779
|
+
class Bar
|
780
|
+
include Foo
|
781
|
+
end
|
782
|
+
RUBY
|
783
|
+
|
784
|
+
indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
|
785
|
+
@index.index_single(indexable_path)
|
786
|
+
|
787
|
+
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
788
|
+
|
789
|
+
# Remove include to invalidate the ancestor tree
|
790
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
791
|
+
module Foo
|
792
|
+
end
|
793
|
+
|
794
|
+
class Bar
|
795
|
+
include Foo
|
796
|
+
|
797
|
+
def baz; end
|
798
|
+
end
|
799
|
+
RUBY
|
800
|
+
|
801
|
+
@index.handle_change(indexable_path)
|
802
|
+
refute_empty(@index.instance_variable_get(:@ancestors))
|
803
|
+
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
804
|
+
end
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
def test_handle_change_clears_ancestor_cache_if_parent_class_changed
|
809
|
+
Dir.mktmpdir do |dir|
|
810
|
+
Dir.chdir(dir) do
|
811
|
+
# Write the original file
|
812
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
813
|
+
class Foo
|
814
|
+
end
|
815
|
+
|
816
|
+
class Bar < Foo
|
817
|
+
end
|
818
|
+
RUBY
|
819
|
+
|
820
|
+
indexable_path = IndexablePath.new(nil, File.join(dir, "foo.rb"))
|
821
|
+
@index.index_single(indexable_path)
|
822
|
+
|
823
|
+
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
824
|
+
|
825
|
+
# Remove include to invalidate the ancestor tree
|
826
|
+
File.write(File.join(dir, "foo.rb"), <<~RUBY)
|
827
|
+
class Foo
|
828
|
+
end
|
829
|
+
|
830
|
+
class Bar
|
831
|
+
end
|
832
|
+
RUBY
|
833
|
+
|
834
|
+
@index.handle_change(indexable_path)
|
835
|
+
assert_empty(@index.instance_variable_get(:@ancestors))
|
836
|
+
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
837
|
+
end
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
def test_resolving_inherited_constants
|
842
|
+
index(<<~RUBY)
|
843
|
+
module Foo
|
844
|
+
CONST = 1
|
845
|
+
end
|
846
|
+
|
847
|
+
module Baz
|
848
|
+
CONST = 2
|
849
|
+
end
|
850
|
+
|
851
|
+
module Qux
|
852
|
+
include Foo
|
853
|
+
end
|
854
|
+
|
855
|
+
module Namespace
|
856
|
+
CONST = 3
|
857
|
+
|
858
|
+
include Baz
|
859
|
+
|
860
|
+
class Bar
|
861
|
+
include Qux
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
CONST = 4
|
866
|
+
RUBY
|
867
|
+
|
868
|
+
entry = T.must(@index.resolve("CONST", ["Namespace", "Bar"])&.first)
|
869
|
+
assert_equal(14, entry.location.start_line)
|
870
|
+
end
|
871
|
+
|
872
|
+
def test_resolving_inherited_alised_namespace
|
873
|
+
index(<<~RUBY)
|
874
|
+
module Bar
|
875
|
+
TARGET = 123
|
876
|
+
end
|
877
|
+
|
878
|
+
module Foo
|
879
|
+
CONST = Bar
|
880
|
+
end
|
881
|
+
|
882
|
+
module Namespace
|
883
|
+
class Bar
|
884
|
+
include Foo
|
885
|
+
end
|
886
|
+
end
|
887
|
+
RUBY
|
888
|
+
|
889
|
+
entry = T.must(@index.resolve("Foo::CONST::TARGET", [])&.first)
|
890
|
+
assert_equal(2, entry.location.start_line)
|
891
|
+
|
892
|
+
entry = T.must(@index.resolve("Namespace::Bar::CONST::TARGET", [])&.first)
|
893
|
+
assert_equal(2, entry.location.start_line)
|
894
|
+
end
|
895
|
+
|
896
|
+
def test_resolving_same_constant_from_different_scopes
|
897
|
+
index(<<~RUBY)
|
898
|
+
module Namespace
|
899
|
+
CONST = 123
|
900
|
+
|
901
|
+
class Parent
|
902
|
+
CONST = 321
|
903
|
+
end
|
904
|
+
|
905
|
+
class Child < Parent
|
906
|
+
end
|
907
|
+
end
|
908
|
+
RUBY
|
909
|
+
|
910
|
+
entry = T.must(@index.resolve("CONST", ["Namespace", "Child"])&.first)
|
911
|
+
assert_equal(2, entry.location.start_line)
|
912
|
+
|
913
|
+
entry = T.must(@index.resolve("Namespace::Child::CONST", [])&.first)
|
914
|
+
assert_equal(5, entry.location.start_line)
|
915
|
+
end
|
916
|
+
|
917
|
+
def test_resolving_prepended_constants
|
918
|
+
index(<<~RUBY)
|
919
|
+
module Included
|
920
|
+
CONST = 123
|
921
|
+
end
|
922
|
+
|
923
|
+
module Prepended
|
924
|
+
CONST = 321
|
925
|
+
end
|
926
|
+
|
927
|
+
class Foo
|
928
|
+
include Included
|
929
|
+
prepend Prepended
|
930
|
+
end
|
931
|
+
|
932
|
+
class Bar
|
933
|
+
CONST = 456
|
934
|
+
include Included
|
935
|
+
prepend Prepended
|
936
|
+
end
|
937
|
+
RUBY
|
938
|
+
|
939
|
+
entry = T.must(@index.resolve("CONST", ["Foo"])&.first)
|
940
|
+
assert_equal(6, entry.location.start_line)
|
941
|
+
|
942
|
+
entry = T.must(@index.resolve("Foo::CONST", [])&.first)
|
943
|
+
assert_equal(6, entry.location.start_line)
|
944
|
+
|
945
|
+
entry = T.must(@index.resolve("Bar::CONST", [])&.first)
|
946
|
+
assert_equal(15, entry.location.start_line)
|
947
|
+
end
|
948
|
+
|
949
|
+
def test_resolving_constants_favors_ancestors_over_top_level
|
950
|
+
index(<<~RUBY)
|
951
|
+
module Value1
|
952
|
+
CONST = 1
|
953
|
+
end
|
954
|
+
|
955
|
+
module Value2
|
956
|
+
CONST = 2
|
957
|
+
end
|
958
|
+
|
959
|
+
CONST = 3
|
960
|
+
module First
|
961
|
+
include Value1
|
962
|
+
|
963
|
+
module Second
|
964
|
+
include Value2
|
965
|
+
end
|
966
|
+
end
|
967
|
+
RUBY
|
968
|
+
|
969
|
+
entry = T.must(@index.resolve("CONST", ["First", "Second"])&.first)
|
970
|
+
assert_equal(6, entry.location.start_line)
|
971
|
+
end
|
972
|
+
|
973
|
+
def test_resolving_circular_alias
|
974
|
+
index(<<~RUBY)
|
975
|
+
module Namespace
|
976
|
+
FOO = BAR
|
977
|
+
BAR = FOO
|
978
|
+
end
|
979
|
+
RUBY
|
980
|
+
|
981
|
+
foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
|
982
|
+
assert_equal(2, foo_entry.location.start_line)
|
983
|
+
assert_instance_of(Entry::Alias, foo_entry)
|
984
|
+
|
985
|
+
bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
|
986
|
+
assert_equal(3, bar_entry.location.start_line)
|
987
|
+
assert_instance_of(Entry::Alias, bar_entry)
|
988
|
+
end
|
989
|
+
|
990
|
+
def test_resolving_circular_alias_three_levels
|
991
|
+
index(<<~RUBY)
|
992
|
+
module Namespace
|
993
|
+
FOO = BAR
|
994
|
+
BAR = BAZ
|
995
|
+
BAZ = FOO
|
996
|
+
end
|
997
|
+
RUBY
|
998
|
+
|
999
|
+
foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
|
1000
|
+
assert_equal(2, foo_entry.location.start_line)
|
1001
|
+
assert_instance_of(Entry::Alias, foo_entry)
|
1002
|
+
|
1003
|
+
bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
|
1004
|
+
assert_equal(3, bar_entry.location.start_line)
|
1005
|
+
assert_instance_of(Entry::Alias, bar_entry)
|
1006
|
+
|
1007
|
+
baz_entry = T.must(@index.resolve("BAZ", ["Namespace"])&.first)
|
1008
|
+
assert_equal(4, baz_entry.location.start_line)
|
1009
|
+
assert_instance_of(Entry::Alias, baz_entry)
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def test_resolving_top_level_compact_reference
|
1013
|
+
index(<<~RUBY)
|
1014
|
+
class Foo::Bar
|
1015
|
+
end
|
1016
|
+
RUBY
|
1017
|
+
|
1018
|
+
foo_entry = T.must(@index.resolve("Foo::Bar", [])&.first)
|
1019
|
+
assert_equal(1, foo_entry.location.start_line)
|
1020
|
+
assert_instance_of(Entry::Class, foo_entry)
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
def test_resolving_references_with_redundant_namespaces
|
1024
|
+
index(<<~RUBY)
|
1025
|
+
module Bar
|
1026
|
+
CONST = 1
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
module A
|
1030
|
+
CONST = 2
|
1031
|
+
|
1032
|
+
module B
|
1033
|
+
CONST = 3
|
1034
|
+
|
1035
|
+
class Foo
|
1036
|
+
include Bar
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
A::B::Foo::CONST
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
RUBY
|
1043
|
+
|
1044
|
+
foo_entry = T.must(@index.resolve("A::B::Foo::CONST", ["A", "B"])&.first)
|
1045
|
+
assert_equal(2, foo_entry.location.start_line)
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def test_resolving_qualified_references
|
1049
|
+
index(<<~RUBY)
|
1050
|
+
module Namespace
|
1051
|
+
class Entry
|
1052
|
+
CONST = 1
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
module Namespace
|
1057
|
+
class Index
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
RUBY
|
1061
|
+
|
1062
|
+
foo_entry = T.must(@index.resolve("Entry::CONST", ["Namespace", "Index"])&.first)
|
1063
|
+
assert_equal(3, foo_entry.location.start_line)
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def test_resolving_unqualified_references
|
1067
|
+
index(<<~RUBY)
|
1068
|
+
module Foo
|
1069
|
+
CONST = 1
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
module Namespace
|
1073
|
+
CONST = 2
|
1074
|
+
|
1075
|
+
class Index
|
1076
|
+
include Foo
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
RUBY
|
1080
|
+
|
1081
|
+
foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
|
1082
|
+
assert_equal(6, foo_entry.location.start_line)
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
def test_resolving_references_with_only_top_level_declaration
|
1086
|
+
index(<<~RUBY)
|
1087
|
+
CONST = 1
|
1088
|
+
|
1089
|
+
module Foo; end
|
1090
|
+
|
1091
|
+
module Namespace
|
1092
|
+
class Index
|
1093
|
+
include Foo
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
RUBY
|
1097
|
+
|
1098
|
+
foo_entry = T.must(@index.resolve("CONST", ["Namespace", "Index"])&.first)
|
1099
|
+
assert_equal(1, foo_entry.location.start_line)
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
def test_instance_variables_completions_from_different_owners_with_conflicting_names
|
1103
|
+
index(<<~RUBY)
|
1104
|
+
class Foo
|
1105
|
+
def initialize
|
1106
|
+
@bar = 1
|
1107
|
+
end
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
class Bar
|
1111
|
+
def initialize
|
1112
|
+
@bar = 2
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
RUBY
|
1116
|
+
|
1117
|
+
entry = T.must(@index.instance_variable_completion_candidates("@", "Bar")&.first)
|
1118
|
+
assert_equal("@bar", entry.name)
|
1119
|
+
assert_equal("Bar", T.must(entry.owner).name)
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def test_resolving_a_qualified_reference
|
1123
|
+
index(<<~RUBY)
|
1124
|
+
class Base
|
1125
|
+
module Third
|
1126
|
+
CONST = 1
|
1127
|
+
end
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
class Foo
|
1131
|
+
module Third
|
1132
|
+
CONST = 2
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
class Second < Base
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
RUBY
|
1139
|
+
|
1140
|
+
foo_entry = T.must(@index.resolve("Third::CONST", ["Foo"])&.first)
|
1141
|
+
assert_equal(9, foo_entry.location.start_line)
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
def test_resolving_unindexed_constant_with_no_nesting
|
1145
|
+
assert_nil(@index.resolve("RSpec", []))
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
def test_object_superclass_resolution
|
1149
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1150
|
+
module Foo
|
1151
|
+
class Object; end
|
1152
|
+
|
1153
|
+
class Bar; end
|
1154
|
+
class Baz < Object; end
|
1155
|
+
end
|
1156
|
+
RUBY
|
1157
|
+
|
1158
|
+
assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
|
1159
|
+
assert_equal(
|
1160
|
+
["Foo::Baz", "Foo::Object", "Object", "Kernel", "BasicObject"],
|
1161
|
+
@index.linearized_ancestors_of("Foo::Baz"),
|
1162
|
+
)
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
def test_top_level_object_superclass_resolution
|
1166
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1167
|
+
module Foo
|
1168
|
+
class Object; end
|
1169
|
+
|
1170
|
+
class Bar < ::Object; end
|
1171
|
+
end
|
1172
|
+
RUBY
|
1173
|
+
|
1174
|
+
assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
|
315
1175
|
end
|
316
1176
|
end
|
317
1177
|
end
|