ruby-lsp 0.17.4 → 0.17.13
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 +11 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp +26 -1
- data/exe/ruby-lsp-check +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +74 -43
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +26 -0
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +147 -29
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +383 -79
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +195 -61
- data/lib/ruby_indexer/ruby_indexer.rb +1 -8
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +71 -3
- data/lib/ruby_indexer/test/configuration_test.rb +1 -1
- data/lib/ruby_indexer/test/constant_test.rb +17 -17
- data/lib/ruby_indexer/test/enhancements_test.rb +197 -0
- data/lib/ruby_indexer/test/index_test.rb +367 -17
- data/lib/ruby_indexer/test/method_test.rb +58 -25
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +297 -0
- data/lib/ruby_indexer/test/test_case.rb +1 -5
- data/lib/ruby_lsp/addon.rb +22 -5
- data/lib/ruby_lsp/base_server.rb +8 -3
- data/lib/ruby_lsp/document.rb +27 -46
- data/lib/ruby_lsp/erb_document.rb +125 -0
- data/lib/ruby_lsp/global_state.rb +47 -19
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/completion.rb +161 -57
- data/lib/ruby_lsp/listeners/definition.rb +91 -27
- data/lib/ruby_lsp/listeners/document_highlight.rb +5 -1
- data/lib/ruby_lsp/listeners/hover.rb +61 -19
- data/lib/ruby_lsp/listeners/signature_help.rb +13 -6
- data/lib/ruby_lsp/node_context.rb +65 -5
- data/lib/ruby_lsp/requests/code_action_resolve.rb +107 -9
- data/lib/ruby_lsp/requests/code_actions.rb +11 -2
- data/lib/ruby_lsp/requests/completion.rb +4 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +14 -9
- data/lib/ruby_lsp/requests/definition.rb +18 -8
- data/lib/ruby_lsp/requests/diagnostics.rb +6 -5
- data/lib/ruby_lsp/requests/document_symbol.rb +2 -7
- data/lib/ruby_lsp/requests/folding_ranges.rb +6 -2
- data/lib/ruby_lsp/requests/formatting.rb +15 -0
- data/lib/ruby_lsp/requests/hover.rb +5 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +6 -4
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -2
- data/lib/ruby_lsp/requests/signature_help.rb +3 -3
- data/lib/ruby_lsp/requests/support/common.rb +11 -2
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +2 -6
- data/lib/ruby_lsp/ruby_document.rb +74 -0
- data/lib/ruby_lsp/server.rb +129 -54
- data/lib/ruby_lsp/store.rb +33 -9
- data/lib/ruby_lsp/test_helper.rb +3 -1
- data/lib/ruby_lsp/type_inferrer.rb +61 -25
- data/lib/ruby_lsp/utils.rb +13 -0
- metadata +9 -8
- data/exe/ruby-lsp-doctor +0 -23
@@ -0,0 +1,197 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "test_case"
|
5
|
+
|
6
|
+
module RubyIndexer
|
7
|
+
class EnhancementTest < TestCase
|
8
|
+
def test_enhancing_indexing_included_hook
|
9
|
+
enhancement_class = Class.new do
|
10
|
+
include Enhancement
|
11
|
+
|
12
|
+
def on_call_node(index, owner, node, file_path)
|
13
|
+
return unless owner
|
14
|
+
return unless node.name == :extend
|
15
|
+
|
16
|
+
arguments = node.arguments&.arguments
|
17
|
+
return unless arguments
|
18
|
+
|
19
|
+
location = node.location
|
20
|
+
|
21
|
+
arguments.each do |node|
|
22
|
+
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
|
23
|
+
|
24
|
+
module_name = node.full_name
|
25
|
+
next unless module_name == "ActiveSupport::Concern"
|
26
|
+
|
27
|
+
index.register_included_hook(owner.name) do |index, base|
|
28
|
+
class_methods_name = "#{owner.name}::ClassMethods"
|
29
|
+
|
30
|
+
if index.indexed?(class_methods_name)
|
31
|
+
singleton = index.existing_or_new_singleton_class(base.name)
|
32
|
+
singleton.mixin_operations << Entry::Include.new(class_methods_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
index.add(Entry::Method.new(
|
37
|
+
"new_method",
|
38
|
+
file_path,
|
39
|
+
location,
|
40
|
+
location,
|
41
|
+
[],
|
42
|
+
[Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
|
43
|
+
Entry::Visibility::PUBLIC,
|
44
|
+
owner,
|
45
|
+
))
|
46
|
+
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
47
|
+
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
48
|
+
# Do nothing
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@index.register_enhancement(enhancement_class.new)
|
54
|
+
index(<<~RUBY)
|
55
|
+
module ActiveSupport
|
56
|
+
module Concern
|
57
|
+
def self.extended(base)
|
58
|
+
base.class_eval("def new_method(a); end")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module ActiveRecord
|
64
|
+
module Associations
|
65
|
+
extend ActiveSupport::Concern
|
66
|
+
|
67
|
+
module ClassMethods
|
68
|
+
def belongs_to(something); end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Base
|
73
|
+
include Associations
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class User < ActiveRecord::Base
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
assert_equal(
|
82
|
+
[
|
83
|
+
"User::<Class:User>",
|
84
|
+
"ActiveRecord::Base::<Class:Base>",
|
85
|
+
"ActiveRecord::Associations::ClassMethods",
|
86
|
+
"Object::<Class:Object>",
|
87
|
+
"BasicObject::<Class:BasicObject>",
|
88
|
+
"Class",
|
89
|
+
"Module",
|
90
|
+
"Object",
|
91
|
+
"Kernel",
|
92
|
+
"BasicObject",
|
93
|
+
],
|
94
|
+
@index.linearized_ancestors_of("User::<Class:User>"),
|
95
|
+
)
|
96
|
+
|
97
|
+
assert_entry("new_method", Entry::Method, "/fake/path/foo.rb:10-4:10-33")
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_enhancing_indexing_configuration_dsl
|
101
|
+
enhancement_class = Class.new do
|
102
|
+
include Enhancement
|
103
|
+
|
104
|
+
def on_call_node(index, owner, node, file_path)
|
105
|
+
return unless owner
|
106
|
+
|
107
|
+
name = node.name
|
108
|
+
return unless name == :has_many
|
109
|
+
|
110
|
+
arguments = node.arguments&.arguments
|
111
|
+
return unless arguments
|
112
|
+
|
113
|
+
association_name = arguments.first
|
114
|
+
return unless association_name.is_a?(Prism::SymbolNode)
|
115
|
+
|
116
|
+
location = association_name.location
|
117
|
+
|
118
|
+
index.add(Entry::Method.new(
|
119
|
+
T.must(association_name.value),
|
120
|
+
file_path,
|
121
|
+
location,
|
122
|
+
location,
|
123
|
+
[],
|
124
|
+
[],
|
125
|
+
Entry::Visibility::PUBLIC,
|
126
|
+
owner,
|
127
|
+
))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
@index.register_enhancement(enhancement_class.new)
|
132
|
+
index(<<~RUBY)
|
133
|
+
module ActiveSupport
|
134
|
+
module Concern
|
135
|
+
def self.extended(base)
|
136
|
+
base.class_eval("def new_method(a); end")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module ActiveRecord
|
142
|
+
module Associations
|
143
|
+
extend ActiveSupport::Concern
|
144
|
+
|
145
|
+
module ClassMethods
|
146
|
+
def belongs_to(something); end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Base
|
151
|
+
include Associations
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class User < ActiveRecord::Base
|
156
|
+
has_many :posts
|
157
|
+
end
|
158
|
+
RUBY
|
159
|
+
|
160
|
+
assert_entry("posts", Entry::Method, "/fake/path/foo.rb:23-11:23-17")
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_error_handling_in_enhancement
|
164
|
+
enhancement_class = Class.new do
|
165
|
+
include Enhancement
|
166
|
+
|
167
|
+
def on_call_node(index, owner, node, file_path)
|
168
|
+
raise "Error"
|
169
|
+
end
|
170
|
+
|
171
|
+
class << self
|
172
|
+
def name
|
173
|
+
"TestEnhancement"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
@index.register_enhancement(enhancement_class.new)
|
179
|
+
|
180
|
+
_stdout, stderr = capture_io do
|
181
|
+
index(<<~RUBY)
|
182
|
+
module ActiveSupport
|
183
|
+
module Concern
|
184
|
+
def self.extended(base)
|
185
|
+
base.class_eval("def new_method(a); end")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
RUBY
|
190
|
+
end
|
191
|
+
|
192
|
+
assert_match(%r{Indexing error in /fake/path/foo\.rb with 'TestEnhancement' enhancement}, stderr)
|
193
|
+
# The module should still be indexed
|
194
|
+
assert_entry("ActiveSupport::Concern", Entry::Module, "/fake/path/foo.rb:1-2:5-5")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -181,20 +181,20 @@ module RubyIndexer
|
|
181
181
|
|
182
182
|
def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
|
183
183
|
@index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
|
184
|
-
class
|
184
|
+
class Bar
|
185
185
|
end
|
186
186
|
|
187
187
|
module Foo
|
188
|
-
class
|
189
|
-
|
188
|
+
class Bar < self
|
189
|
+
BAZ = ::Bar::BAZ
|
190
190
|
end
|
191
191
|
end
|
192
192
|
RUBY
|
193
193
|
|
194
|
-
entry = @index.resolve("
|
194
|
+
entry = @index.resolve("BAZ", ["Foo", "Bar"]).first
|
195
195
|
refute_nil(entry)
|
196
196
|
|
197
|
-
assert_instance_of(Entry::
|
197
|
+
assert_instance_of(Entry::UnresolvedConstantAlias, entry)
|
198
198
|
end
|
199
199
|
|
200
200
|
def test_visitor_does_not_visit_unnecessary_nodes
|
@@ -285,6 +285,43 @@ module RubyIndexer
|
|
285
285
|
assert_includes(second_entry.comments, "Hello from second `bar`")
|
286
286
|
end
|
287
287
|
|
288
|
+
def test_resolve_method_inherited_only
|
289
|
+
index(<<~RUBY)
|
290
|
+
class Bar
|
291
|
+
def baz; end
|
292
|
+
end
|
293
|
+
|
294
|
+
class Foo < Bar
|
295
|
+
def baz; end
|
296
|
+
end
|
297
|
+
RUBY
|
298
|
+
|
299
|
+
entry = T.must(@index.resolve_method("baz", "Foo", inherited_only: true).first)
|
300
|
+
|
301
|
+
assert_equal("Bar", T.must(entry.owner).name)
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_resolve_method_inherited_only_for_prepended_module
|
305
|
+
index(<<~RUBY)
|
306
|
+
module Bar
|
307
|
+
def baz
|
308
|
+
super
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class Foo
|
313
|
+
prepend Bar
|
314
|
+
|
315
|
+
def baz; end
|
316
|
+
end
|
317
|
+
RUBY
|
318
|
+
|
319
|
+
# This test is just to document the fact that we don't yet support resolving inherited methods for modules that
|
320
|
+
# are prepended. The only way to support this is to find all namespaces that have the module a subtype, so that we
|
321
|
+
# can show the results for everywhere the module has been prepended.
|
322
|
+
assert_nil(@index.resolve_method("baz", "Bar", inherited_only: true))
|
323
|
+
end
|
324
|
+
|
288
325
|
def test_prefix_search_for_methods
|
289
326
|
index(<<~RUBY)
|
290
327
|
module Foo
|
@@ -313,12 +350,12 @@ module RubyIndexer
|
|
313
350
|
@index.index_single(indexable_path)
|
314
351
|
end
|
315
352
|
|
316
|
-
refute_empty(@index
|
353
|
+
refute_empty(@index)
|
317
354
|
end
|
318
355
|
|
319
356
|
def test_index_single_does_not_fail_for_non_existing_file
|
320
357
|
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"))
|
321
|
-
entries_after_indexing = @index.
|
358
|
+
entries_after_indexing = @index.names
|
322
359
|
assert_equal(@default_indexed_entries.keys, entries_after_indexing)
|
323
360
|
end
|
324
361
|
|
@@ -978,11 +1015,11 @@ module RubyIndexer
|
|
978
1015
|
|
979
1016
|
foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
|
980
1017
|
assert_equal(2, foo_entry.location.start_line)
|
981
|
-
assert_instance_of(Entry::
|
1018
|
+
assert_instance_of(Entry::ConstantAlias, foo_entry)
|
982
1019
|
|
983
1020
|
bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
|
984
1021
|
assert_equal(3, bar_entry.location.start_line)
|
985
|
-
assert_instance_of(Entry::
|
1022
|
+
assert_instance_of(Entry::ConstantAlias, bar_entry)
|
986
1023
|
end
|
987
1024
|
|
988
1025
|
def test_resolving_circular_alias_three_levels
|
@@ -996,15 +1033,52 @@ module RubyIndexer
|
|
996
1033
|
|
997
1034
|
foo_entry = T.must(@index.resolve("FOO", ["Namespace"])&.first)
|
998
1035
|
assert_equal(2, foo_entry.location.start_line)
|
999
|
-
assert_instance_of(Entry::
|
1036
|
+
assert_instance_of(Entry::ConstantAlias, foo_entry)
|
1000
1037
|
|
1001
1038
|
bar_entry = T.must(@index.resolve("BAR", ["Namespace"])&.first)
|
1002
1039
|
assert_equal(3, bar_entry.location.start_line)
|
1003
|
-
assert_instance_of(Entry::
|
1040
|
+
assert_instance_of(Entry::ConstantAlias, bar_entry)
|
1004
1041
|
|
1005
1042
|
baz_entry = T.must(@index.resolve("BAZ", ["Namespace"])&.first)
|
1006
1043
|
assert_equal(4, baz_entry.location.start_line)
|
1007
|
-
assert_instance_of(Entry::
|
1044
|
+
assert_instance_of(Entry::ConstantAlias, baz_entry)
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
def test_resolving_constants_in_aliased_namespace
|
1048
|
+
index(<<~RUBY)
|
1049
|
+
module Original
|
1050
|
+
module Something
|
1051
|
+
CONST = 123
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
module Other
|
1056
|
+
ALIAS = Original::Something
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
module Third
|
1060
|
+
Other::ALIAS::CONST
|
1061
|
+
end
|
1062
|
+
RUBY
|
1063
|
+
|
1064
|
+
entry = T.must(@index.resolve("Other::ALIAS::CONST", ["Third"])&.first)
|
1065
|
+
assert_kind_of(Entry::Constant, entry)
|
1066
|
+
assert_equal("Original::Something::CONST", entry.name)
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
def test_resolving_top_level_aliases
|
1070
|
+
index(<<~RUBY)
|
1071
|
+
class Foo
|
1072
|
+
CONST = 123
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
FOO = Foo
|
1076
|
+
FOO::CONST
|
1077
|
+
RUBY
|
1078
|
+
|
1079
|
+
entry = T.must(@index.resolve("FOO::CONST", [])&.first)
|
1080
|
+
assert_kind_of(Entry::Constant, entry)
|
1081
|
+
assert_equal("Foo::CONST", entry.name)
|
1008
1082
|
end
|
1009
1083
|
|
1010
1084
|
def test_resolving_top_level_compact_reference
|
@@ -1321,11 +1395,6 @@ module RubyIndexer
|
|
1321
1395
|
entries = @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>").map(&:name)
|
1322
1396
|
assert_includes(entries, "@a")
|
1323
1397
|
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
1398
|
end
|
1330
1399
|
|
1331
1400
|
def test_singletons_are_excluded_from_prefix_search
|
@@ -1472,5 +1541,286 @@ module RubyIndexer
|
|
1472
1541
|
|
1473
1542
|
assert_empty(@index.method_completion_candidates("bar", "Foo"))
|
1474
1543
|
end
|
1544
|
+
|
1545
|
+
def test_first_unqualified_const
|
1546
|
+
index(<<~RUBY)
|
1547
|
+
module Foo
|
1548
|
+
class Bar; end
|
1549
|
+
end
|
1550
|
+
|
1551
|
+
module Baz
|
1552
|
+
class Bar; end
|
1553
|
+
end
|
1554
|
+
RUBY
|
1555
|
+
|
1556
|
+
entry = T.must(@index.first_unqualified_const("Bar")&.first)
|
1557
|
+
assert_equal("Foo::Bar", entry.name)
|
1558
|
+
end
|
1559
|
+
|
1560
|
+
def test_completion_does_not_duplicate_overridden_methods
|
1561
|
+
index(<<~RUBY)
|
1562
|
+
class Foo
|
1563
|
+
def bar; end
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
class Baz < Foo
|
1567
|
+
def bar; end
|
1568
|
+
end
|
1569
|
+
RUBY
|
1570
|
+
|
1571
|
+
entries = @index.method_completion_candidates("bar", "Baz")
|
1572
|
+
assert_equal(["bar"], entries.map(&:name))
|
1573
|
+
assert_equal("Baz", T.must(entries.first.owner).name)
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
def test_completion_does_not_duplicate_methods_overridden_by_aliases
|
1577
|
+
index(<<~RUBY)
|
1578
|
+
class Foo
|
1579
|
+
def bar; end
|
1580
|
+
end
|
1581
|
+
|
1582
|
+
class Baz < Foo
|
1583
|
+
alias bar to_s
|
1584
|
+
end
|
1585
|
+
RUBY
|
1586
|
+
|
1587
|
+
entries = @index.method_completion_candidates("bar", "Baz")
|
1588
|
+
assert_equal(["bar"], entries.map(&:name))
|
1589
|
+
assert_equal("Baz", T.must(entries.first.owner).name)
|
1590
|
+
end
|
1591
|
+
|
1592
|
+
def test_decorated_parameters
|
1593
|
+
index(<<~RUBY)
|
1594
|
+
class Foo
|
1595
|
+
def bar(a, b = 1, c: 2)
|
1596
|
+
end
|
1597
|
+
end
|
1598
|
+
RUBY
|
1599
|
+
|
1600
|
+
methods = @index.resolve_method("bar", "Foo")
|
1601
|
+
refute_nil(methods)
|
1602
|
+
|
1603
|
+
entry = T.must(methods.first)
|
1604
|
+
|
1605
|
+
assert_equal("(a, b = <default>, c: <default>)", entry.decorated_parameters)
|
1606
|
+
end
|
1607
|
+
|
1608
|
+
def test_decorated_parameters_when_method_has_no_parameters
|
1609
|
+
index(<<~RUBY)
|
1610
|
+
class Foo
|
1611
|
+
def bar
|
1612
|
+
end
|
1613
|
+
end
|
1614
|
+
RUBY
|
1615
|
+
|
1616
|
+
methods = @index.resolve_method("bar", "Foo")
|
1617
|
+
refute_nil(methods)
|
1618
|
+
|
1619
|
+
entry = T.must(methods.first)
|
1620
|
+
|
1621
|
+
assert_equal("()", entry.decorated_parameters)
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
def test_linearizing_singleton_ancestors_of_singleton_when_class_has_parent
|
1625
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1626
|
+
class Foo; end
|
1627
|
+
|
1628
|
+
class Bar < Foo
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
class Baz < Bar
|
1632
|
+
class << self
|
1633
|
+
class << self
|
1634
|
+
end
|
1635
|
+
end
|
1636
|
+
end
|
1637
|
+
RUBY
|
1638
|
+
|
1639
|
+
assert_equal(
|
1640
|
+
[
|
1641
|
+
"Baz::<Class:Baz>::<Class:<Class:Baz>>",
|
1642
|
+
"Bar::<Class:Bar>::<Class:<Class:Bar>>",
|
1643
|
+
"Foo::<Class:Foo>::<Class:<Class:Foo>>",
|
1644
|
+
"Object::<Class:Object>::<Class:<Class:Object>>",
|
1645
|
+
"BasicObject::<Class:BasicObject>::<Class:<Class:BasicObject>>",
|
1646
|
+
"Class::<Class:Class>",
|
1647
|
+
"Module::<Class:Module>",
|
1648
|
+
"Object::<Class:Object>",
|
1649
|
+
"BasicObject::<Class:BasicObject>",
|
1650
|
+
"Class",
|
1651
|
+
"Module",
|
1652
|
+
"Object",
|
1653
|
+
"Kernel",
|
1654
|
+
"BasicObject",
|
1655
|
+
],
|
1656
|
+
@index.linearized_ancestors_of("Baz::<Class:Baz>::<Class:<Class:Baz>>"),
|
1657
|
+
)
|
1658
|
+
end
|
1659
|
+
|
1660
|
+
def test_linearizing_singleton_object
|
1661
|
+
assert_equal(
|
1662
|
+
[
|
1663
|
+
"Object::<Class:Object>",
|
1664
|
+
"BasicObject::<Class:BasicObject>",
|
1665
|
+
"Class",
|
1666
|
+
"Module",
|
1667
|
+
"Object",
|
1668
|
+
"Kernel",
|
1669
|
+
"BasicObject",
|
1670
|
+
],
|
1671
|
+
@index.linearized_ancestors_of("Object::<Class:Object>"),
|
1672
|
+
)
|
1673
|
+
end
|
1674
|
+
|
1675
|
+
def test_linearizing_singleton_ancestors
|
1676
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1677
|
+
module First
|
1678
|
+
end
|
1679
|
+
|
1680
|
+
module Second
|
1681
|
+
include First
|
1682
|
+
end
|
1683
|
+
|
1684
|
+
module Foo
|
1685
|
+
class Bar
|
1686
|
+
class << self
|
1687
|
+
class Baz
|
1688
|
+
extend Second
|
1689
|
+
|
1690
|
+
class << self
|
1691
|
+
include First
|
1692
|
+
end
|
1693
|
+
end
|
1694
|
+
end
|
1695
|
+
end
|
1696
|
+
end
|
1697
|
+
RUBY
|
1698
|
+
|
1699
|
+
assert_equal(
|
1700
|
+
[
|
1701
|
+
"Foo::Bar::<Class:Bar>::Baz::<Class:Baz>",
|
1702
|
+
"Second",
|
1703
|
+
"First",
|
1704
|
+
"Object::<Class:Object>",
|
1705
|
+
"BasicObject::<Class:BasicObject>",
|
1706
|
+
"Class",
|
1707
|
+
"Module",
|
1708
|
+
"Object",
|
1709
|
+
"Kernel",
|
1710
|
+
"BasicObject",
|
1711
|
+
],
|
1712
|
+
@index.linearized_ancestors_of("Foo::Bar::<Class:Bar>::Baz::<Class:Baz>"),
|
1713
|
+
)
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
def test_linearizing_singleton_ancestors_when_class_has_parent
|
1717
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1718
|
+
class Foo; end
|
1719
|
+
|
1720
|
+
class Bar < Foo
|
1721
|
+
end
|
1722
|
+
|
1723
|
+
class Baz < Bar
|
1724
|
+
class << self
|
1725
|
+
end
|
1726
|
+
end
|
1727
|
+
RUBY
|
1728
|
+
|
1729
|
+
assert_equal(
|
1730
|
+
[
|
1731
|
+
"Baz::<Class:Baz>",
|
1732
|
+
"Bar::<Class:Bar>",
|
1733
|
+
"Foo::<Class:Foo>",
|
1734
|
+
"Object::<Class:Object>",
|
1735
|
+
"BasicObject::<Class:BasicObject>",
|
1736
|
+
"Class",
|
1737
|
+
"Module",
|
1738
|
+
"Object",
|
1739
|
+
"Kernel",
|
1740
|
+
"BasicObject",
|
1741
|
+
],
|
1742
|
+
@index.linearized_ancestors_of("Baz::<Class:Baz>"),
|
1743
|
+
)
|
1744
|
+
end
|
1745
|
+
|
1746
|
+
def test_linearizing_a_module_singleton_class
|
1747
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
|
1748
|
+
module A; end
|
1749
|
+
RUBY
|
1750
|
+
|
1751
|
+
assert_equal(
|
1752
|
+
[
|
1753
|
+
"A::<Class:A>",
|
1754
|
+
"Module",
|
1755
|
+
"Object",
|
1756
|
+
"Kernel",
|
1757
|
+
"BasicObject",
|
1758
|
+
],
|
1759
|
+
@index.linearized_ancestors_of("A::<Class:A>"),
|
1760
|
+
)
|
1761
|
+
end
|
1762
|
+
|
1763
|
+
def test_linearizing_a_singleton_class_with_no_attached
|
1764
|
+
assert_raises(Index::NonExistingNamespaceError) do
|
1765
|
+
@index.linearized_ancestors_of("A::<Class:A>")
|
1766
|
+
end
|
1767
|
+
end
|
1768
|
+
|
1769
|
+
def test_linearizing_singleton_parent_class_with_namespace
|
1770
|
+
index(<<~RUBY)
|
1771
|
+
class ActiveRecord::Base; end
|
1772
|
+
|
1773
|
+
class User < ActiveRecord::Base
|
1774
|
+
end
|
1775
|
+
RUBY
|
1776
|
+
|
1777
|
+
assert_equal(
|
1778
|
+
[
|
1779
|
+
"User::<Class:User>",
|
1780
|
+
"ActiveRecord::Base::<Class:Base>",
|
1781
|
+
"Object::<Class:Object>",
|
1782
|
+
"BasicObject::<Class:BasicObject>",
|
1783
|
+
"Class",
|
1784
|
+
"Module",
|
1785
|
+
"Object",
|
1786
|
+
"Kernel",
|
1787
|
+
"BasicObject",
|
1788
|
+
],
|
1789
|
+
@index.linearized_ancestors_of("User::<Class:User>"),
|
1790
|
+
)
|
1791
|
+
end
|
1792
|
+
|
1793
|
+
def test_singleton_nesting_is_correctly_split_during_linearization
|
1794
|
+
index(<<~RUBY)
|
1795
|
+
module Bar; end
|
1796
|
+
|
1797
|
+
module Foo
|
1798
|
+
class Namespace::Parent
|
1799
|
+
extend Bar
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
module Foo
|
1804
|
+
class Child < Namespace::Parent
|
1805
|
+
end
|
1806
|
+
end
|
1807
|
+
RUBY
|
1808
|
+
|
1809
|
+
assert_equal(
|
1810
|
+
[
|
1811
|
+
"Foo::Child::<Class:Child>",
|
1812
|
+
"Foo::Namespace::Parent::<Class:Parent>",
|
1813
|
+
"Bar",
|
1814
|
+
"Object::<Class:Object>",
|
1815
|
+
"BasicObject::<Class:BasicObject>",
|
1816
|
+
"Class",
|
1817
|
+
"Module",
|
1818
|
+
"Object",
|
1819
|
+
"Kernel",
|
1820
|
+
"BasicObject",
|
1821
|
+
],
|
1822
|
+
@index.linearized_ancestors_of("Foo::Child::<Class:Child>"),
|
1823
|
+
)
|
1824
|
+
end
|
1475
1825
|
end
|
1476
1826
|
end
|