ruby-lsp 0.23.11 → 0.26.1

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +45 -22
  7. data/exe/ruby-lsp-test-exec +6 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +107 -236
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +166 -281
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  22. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  23. data/lib/ruby_indexer/test/configuration_test.rb +49 -9
  24. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  25. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  26. data/lib/ruby_indexer/test/index_test.rb +185 -135
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
  28. data/lib/ruby_indexer/test/method_test.rb +166 -123
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  32. data/lib/ruby_indexer/test/test_case.rb +9 -3
  33. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  34. data/lib/ruby_lsp/addon.rb +88 -86
  35. data/lib/ruby_lsp/base_server.rb +59 -54
  36. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  37. data/lib/ruby_lsp/document.rb +205 -104
  38. data/lib/ruby_lsp/erb_document.rb +45 -47
  39. data/lib/ruby_lsp/global_state.rb +73 -57
  40. data/lib/ruby_lsp/internal.rb +8 -3
  41. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  42. data/lib/ruby_lsp/listeners/completion.rb +81 -76
  43. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  44. data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
  45. data/lib/ruby_lsp/listeners/document_link.rb +50 -70
  46. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  47. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  48. data/lib/ruby_lsp/listeners/hover.rb +107 -115
  49. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  50. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  51. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  52. data/lib/ruby_lsp/listeners/spec_style.rb +214 -0
  53. data/lib/ruby_lsp/listeners/test_discovery.rb +92 -0
  54. data/lib/ruby_lsp/listeners/test_style.rb +205 -95
  55. data/lib/ruby_lsp/node_context.rb +12 -39
  56. data/lib/ruby_lsp/rbs_document.rb +10 -11
  57. data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
  58. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  59. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  60. data/lib/ruby_lsp/requests/completion.rb +8 -21
  61. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  62. data/lib/ruby_lsp/requests/definition.rb +8 -20
  63. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  64. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  65. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  66. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  67. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  68. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  69. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  70. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +85 -0
  71. data/lib/ruby_lsp/requests/hover.rb +12 -25
  72. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  73. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  74. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  75. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  76. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  77. data/lib/ruby_lsp/requests/references.rb +17 -57
  78. data/lib/ruby_lsp/requests/rename.rb +27 -51
  79. data/lib/ruby_lsp/requests/request.rb +13 -25
  80. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  81. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  82. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  83. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  84. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  85. data/lib/ruby_lsp/requests/support/common.rb +16 -58
  86. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  87. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  88. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  89. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
  90. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  91. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  92. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  93. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  94. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  95. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  96. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  97. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  98. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  99. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  100. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  101. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  102. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  103. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  104. data/lib/ruby_lsp/ruby_document.rb +32 -98
  105. data/lib/ruby_lsp/scope.rb +7 -11
  106. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  107. data/lib/ruby_lsp/server.rb +303 -196
  108. data/lib/ruby_lsp/setup_bundler.rb +121 -82
  109. data/lib/ruby_lsp/static_docs.rb +12 -7
  110. data/lib/ruby_lsp/store.rb +21 -49
  111. data/lib/ruby_lsp/test_helper.rb +3 -16
  112. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +233 -0
  113. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  114. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  115. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  116. data/lib/ruby_lsp/utils.rb +138 -93
  117. data/static_docs/break.md +103 -0
  118. metadata +14 -20
  119. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -22,19 +22,19 @@ module RubyIndexer
22
22
  end
23
23
 
24
24
  def test_multiple_items
25
- tree = PrefixTree[String].new
25
+ tree = PrefixTree.new #: PrefixTree[String]
26
26
  ["foo", "bar", "baz"].each { |item| tree.insert(item, item) }
27
27
 
28
- assert_equal(["foo", "bar", "baz"], tree.search(""))
29
- assert_equal(["bar", "baz"], tree.search("b"))
28
+ assert_equal(["baz", "bar", "foo"], tree.search(""))
29
+ assert_equal(["baz", "bar"], tree.search("b"))
30
30
  assert_equal(["foo"], tree.search("fo"))
31
- assert_equal(["bar", "baz"], tree.search("ba"))
31
+ assert_equal(["baz", "bar"], tree.search("ba"))
32
32
  assert_equal(["baz"], tree.search("baz"))
33
33
  assert_empty(tree.search("qux"))
34
34
  end
35
35
 
36
36
  def test_multiple_prefixes
37
- tree = PrefixTree[String].new
37
+ tree = PrefixTree.new #: PrefixTree[String]
38
38
  ["fo", "foo"].each { |item| tree.insert(item, item) }
39
39
 
40
40
  assert_equal(["fo", "foo"], tree.search(""))
@@ -45,7 +45,7 @@ module RubyIndexer
45
45
  end
46
46
 
47
47
  def test_multiple_prefixes_with_shuffled_order
48
- tree = PrefixTree[String].new
48
+ tree = PrefixTree.new #: PrefixTree[String]
49
49
  [
50
50
  "foo/bar/base",
51
51
  "foo/bar/on",
@@ -80,26 +80,26 @@ module RubyIndexer
80
80
 
81
81
  assert_equal(
82
82
  [
83
- "foo/bar/support/selection",
84
- "foo/bar/support/semantic",
85
- "foo/bar/support/syntax",
86
- "foo/bar/support/source",
83
+ "foo/bar/support/formatting",
84
+ "foo/bar/support/prefix",
85
+ "foo/bar/support/highlight",
86
+ "foo/bar/support/diagnostic",
87
+ "foo/bar/support/rails",
87
88
  "foo/bar/support/runner",
88
89
  "foo/bar/support/runner2",
89
- "foo/bar/support/rails",
90
- "foo/bar/support/diagnostic",
91
- "foo/bar/support/highlight",
92
- "foo/bar/support/prefix",
93
- "foo/bar/support/formatting",
90
+ "foo/bar/support/source",
91
+ "foo/bar/support/syntax",
92
+ "foo/bar/support/semantic",
93
+ "foo/bar/support/selection",
94
94
  ],
95
95
  tree.search("foo/bar/support"),
96
96
  )
97
97
  end
98
98
 
99
99
  def test_deletion
100
- tree = PrefixTree[String].new
100
+ tree = PrefixTree.new #: PrefixTree[String]
101
101
  ["foo/bar", "foo/baz"].each { |item| tree.insert(item, item) }
102
- assert_equal(["foo/bar", "foo/baz"], tree.search("foo"))
102
+ assert_equal(["foo/baz", "foo/bar"], tree.search("foo"))
103
103
 
104
104
  tree.delete("foo/bar")
105
105
  assert_empty(tree.search("foo/bar"))
@@ -107,7 +107,7 @@ module RubyIndexer
107
107
  end
108
108
 
109
109
  def test_delete_does_not_impact_other_keys_with_the_same_value
110
- tree = PrefixTree[String].new
110
+ tree = PrefixTree.new #: PrefixTree[String]
111
111
  tree.insert("key1", "value")
112
112
  tree.insert("key2", "value")
113
113
  assert_equal(["value", "value"], tree.search("key"))
@@ -118,7 +118,7 @@ module RubyIndexer
118
118
  end
119
119
 
120
120
  def test_deleted_node_is_removed_from_the_tree
121
- tree = PrefixTree[String].new
121
+ tree = PrefixTree.new #: PrefixTree[String]
122
122
  tree.insert("foo/bar", "foo/bar")
123
123
  assert_equal(["foo/bar"], tree.search("foo"))
124
124
 
@@ -128,7 +128,7 @@ module RubyIndexer
128
128
  end
129
129
 
130
130
  def test_deleting_non_terminal_nodes
131
- tree = PrefixTree[String].new
131
+ tree = PrefixTree.new #: PrefixTree[String]
132
132
  tree.insert("abc", "value1")
133
133
  tree.insert("abcdef", "value2")
134
134
 
@@ -138,7 +138,7 @@ module RubyIndexer
138
138
  end
139
139
 
140
140
  def test_overriding_values
141
- tree = PrefixTree[Integer].new
141
+ tree = PrefixTree.new #: PrefixTree[Integer]
142
142
 
143
143
  tree.insert("foo/bar", 123)
144
144
  assert_equal([123], tree.search("foo/bar"))
@@ -6,16 +6,16 @@ require_relative "test_case"
6
6
  module RubyIndexer
7
7
  class RBSIndexerTest < TestCase
8
8
  def test_index_core_classes
9
- entries = @index["Array"]
9
+ entries = @index["Array"] #: as !nil
10
10
  refute_nil(entries)
11
11
  # Array is a class but also an instance method on Kernel
12
12
  assert_equal(2, entries.length)
13
- entry = entries.find { |entry| entry.is_a?(RubyIndexer::Entry::Class) }
13
+ entry = entries.find { |entry| entry.is_a?(Entry::Class) } #: as Entry::Class
14
14
  assert_match(%r{/gems/rbs-.*/core/array.rbs}, entry.file_path)
15
15
  assert_equal("array.rbs", entry.file_name)
16
16
  assert_equal("Object", entry.parent_class)
17
17
  assert_equal(1, entry.mixin_operations.length)
18
- enumerable_include = entry.mixin_operations.first
18
+ enumerable_include = entry.mixin_operations.first #: as !nil
19
19
  assert_equal("Enumerable", enumerable_include.module_name)
20
20
 
21
21
  # Using fixed positions would be fragile, so let's just check some basics.
@@ -26,10 +26,10 @@ module RubyIndexer
26
26
  end
27
27
 
28
28
  def test_index_core_modules
29
- entries = @index["Kernel"]
29
+ entries = @index["Kernel"] #: as !nil
30
30
  refute_nil(entries)
31
31
  assert_equal(1, entries.length)
32
- entry = entries.first
32
+ entry = entries.first #: as Entry::Module
33
33
  assert_match(%r{/gems/rbs-.*/core/kernel.rbs}, entry.file_path)
34
34
  assert_equal("kernel.rbs", entry.file_name)
35
35
 
@@ -41,33 +41,26 @@ module RubyIndexer
41
41
  end
42
42
 
43
43
  def test_index_core_constants
44
- entries = @index["RUBY_VERSION"]
44
+ entries = @index["RUBY_VERSION"] #: as !nil
45
45
  refute_nil(entries)
46
46
  assert_equal(1, entries.length)
47
47
 
48
- # Complex::I is defined as `Complex::I = ...`
49
- entries = @index["Complex::I"]
48
+ entries = @index["Complex::I"] #: as !nil
50
49
  refute_nil(entries)
51
50
  assert_equal(1, entries.length)
52
51
 
53
- # Encoding::US_ASCII is defined as
54
- # ```
55
- # module Encoding
56
- # US_ASCII = ...
57
- # ...
58
- # ````
59
- entries = @index["Encoding::US_ASCII"]
52
+ entries = @index["Encoding::US_ASCII"] #: as !nil
60
53
  refute_nil(entries)
61
54
  assert_equal(1, entries.length)
62
55
  end
63
56
 
64
57
  def test_index_methods
65
- entries = @index["initialize"]
58
+ entries = @index["initialize"] #: as Array[Entry::Method]
66
59
  refute_nil(entries)
67
- entry = entries.find { |entry| entry.owner.name == "Array" }
60
+ entry = entries.find { |entry| entry.owner&.name == "Array" } #: as Entry::Method
68
61
  assert_match(%r{/gems/rbs-.*/core/array.rbs}, entry.file_path)
69
62
  assert_equal("array.rbs", entry.file_name)
70
- assert_equal(Entry::Visibility::PUBLIC, entry.visibility)
63
+ assert_equal(:public, entry.visibility)
71
64
 
72
65
  # Using fixed positions would be fragile, so let's just check some basics.
73
66
  assert_operator(entry.location.start_line, :>, 0)
@@ -77,11 +70,11 @@ module RubyIndexer
77
70
  end
78
71
 
79
72
  def test_index_global_declaration
80
- entries = @index["$DEBUG"]
73
+ entries = @index["$DEBUG"] #: as Array[Entry::GlobalVariable]
81
74
  refute_nil(entries)
82
75
  assert_equal(1, entries.length)
83
76
 
84
- entry = entries.first
77
+ entry = entries.first #: as Entry::GlobalVariable
85
78
 
86
79
  assert_instance_of(Entry::GlobalVariable, entry)
87
80
  assert_equal("$DEBUG", entry.name)
@@ -91,10 +84,10 @@ module RubyIndexer
91
84
  end
92
85
 
93
86
  def test_attaches_correct_owner_to_singleton_methods
94
- entries = @index["basename"]
87
+ entries = @index["basename"] #: as Array[Entry::Method]
95
88
  refute_nil(entries)
96
89
 
97
- owner = entries.first.owner
90
+ owner = entries.first&.owner #: as Entry::SingletonClass
98
91
  assert_instance_of(Entry::SingletonClass, owner)
99
92
  assert_equal("File::<Class:File>", owner.name)
100
93
  end
@@ -103,47 +96,47 @@ module RubyIndexer
103
96
  # NOTE: RBS does not store the name location for classes, modules or methods. This behavior is not exactly what
104
97
  # we would like, but for now we assign the same location to both
105
98
 
106
- entries = @index["Array"]
99
+ entries = @index["Array"] #: as Array[Entry::Class]
107
100
  refute_nil(entries)
108
- entry = entries.find { |entry| entry.is_a?(Entry::Class) }
101
+ entry = entries.find { |entry| entry.is_a?(Entry::Class) } #: as Entry::Class
109
102
 
110
103
  assert_same(entry.location, entry.name_location)
111
104
  end
112
105
 
113
106
  def test_rbs_method_with_required_positionals
114
- entries = @index["crypt"]
107
+ entries = @index["crypt"] #: as Array[Entry::Method]
115
108
  assert_equal(1, entries.length)
116
109
 
117
- entry = entries.first
110
+ entry = entries.first #: as Entry::Method
118
111
  signatures = entry.signatures
119
112
  assert_equal(1, signatures.length)
120
113
 
121
- first_signature = signatures.first
114
+ first_signature = signatures.first #: as Entry::Signature
122
115
 
123
116
  # (::string salt_str) -> ::String
124
117
 
125
118
  assert_equal(1, first_signature.parameters.length)
126
119
  assert_kind_of(Entry::RequiredParameter, first_signature.parameters[0])
127
- assert_equal(:salt_str, first_signature.parameters[0].name)
120
+ assert_equal(:salt_str, first_signature.parameters[0]&.name)
128
121
  end
129
122
 
130
123
  def test_rbs_method_with_unnamed_required_positionals
131
- entries = @index["try_convert"]
132
- entry = entries.find { |entry| entry.owner.name == "Array::<Class:Array>" }
124
+ entries = @index["try_convert"] #: as Array[Entry::Method]
125
+ entry = entries.find { |entry| entry.owner&.name == "Array::<Class:Array>" } #: as Entry::Method
133
126
 
134
- parameters = entry.signatures[0].parameters
127
+ parameters = entry.signatures[0]&.parameters #: as Array[Entry::Parameter]
135
128
 
136
129
  assert_equal([:arg0], parameters.map(&:name))
137
130
  assert_kind_of(Entry::RequiredParameter, parameters[0])
138
131
  end
139
132
 
140
133
  def test_rbs_method_with_optional_positionals
141
- entries = @index["polar"]
142
- entry = entries.find { |entry| entry.owner.name == "Complex::<Class:Complex>" }
134
+ entries = @index["polar"] #: as Array[Entry::Method]
135
+ entry = entries.find { |entry| entry.owner&.name == "Complex::<Class:Complex>" } #: as Entry::Method
143
136
 
144
137
  # def self.polar: (Numeric, ?Numeric) -> Complex
145
138
 
146
- parameters = entry.signatures[0].parameters
139
+ parameters = entry.signatures[0]&.parameters #: as Array[Entry::Parameter]
147
140
 
148
141
  assert_equal([:arg0, :arg1], parameters.map(&:name))
149
142
  assert_kind_of(Entry::RequiredParameter, parameters[0])
@@ -151,27 +144,27 @@ module RubyIndexer
151
144
  end
152
145
 
153
146
  def test_rbs_method_with_optional_parameter
154
- entries = @index["chomp"]
147
+ entries = @index["chomp"] #: as Array[Entry::Method]
155
148
  assert_equal(1, entries.length)
156
149
 
157
- entry = entries.first
150
+ entry = entries.first #: as Entry::Method
158
151
  signatures = entry.signatures
159
152
  assert_equal(1, signatures.length)
160
153
 
161
- first_signature = signatures.first
154
+ first_signature = signatures.first #: as Entry::Signature
162
155
 
163
156
  # (?::string? separator) -> ::String
164
157
 
165
158
  assert_equal(1, first_signature.parameters.length)
166
159
  assert_kind_of(Entry::OptionalParameter, first_signature.parameters[0])
167
- assert_equal(:separator, first_signature.parameters[0].name)
160
+ assert_equal(:separator, first_signature.parameters[0]&.name)
168
161
  end
169
162
 
170
163
  def test_rbs_method_with_required_and_optional_parameters
171
- entries = @index["gsub"]
164
+ entries = @index["gsub"] #: as Array[Entry::Method]
172
165
  assert_equal(1, entries.length)
173
166
 
174
- entry = entries.first
167
+ entry = entries.first #: as Entry::Method
175
168
 
176
169
  signatures = entry.signatures
177
170
  assert_equal(3, signatures.length)
@@ -180,37 +173,37 @@ module RubyIndexer
180
173
  # | (::Regexp | ::string pattern) -> ::Enumerator[::String, ::String]
181
174
  # | (::Regexp | ::string pattern) { (::String match) -> ::_ToS } -> ::String
182
175
 
183
- parameters = signatures[0].parameters
176
+ parameters = signatures[0]&.parameters #: as !nil
184
177
  assert_equal([:pattern, :replacement], parameters.map(&:name))
185
178
  assert_kind_of(Entry::RequiredParameter, parameters[0])
186
179
  assert_kind_of(Entry::RequiredParameter, parameters[1])
187
180
 
188
- parameters = signatures[1].parameters
181
+ parameters = signatures[1]&.parameters #: as !nil
189
182
  assert_equal([:pattern], parameters.map(&:name))
190
183
  assert_kind_of(Entry::RequiredParameter, parameters[0])
191
184
 
192
- parameters = signatures[2].parameters
185
+ parameters = signatures[2]&.parameters #: as !nil
193
186
  assert_equal([:pattern, :"<anonymous block>"], parameters.map(&:name))
194
187
  assert_kind_of(Entry::RequiredParameter, parameters[0])
195
188
  assert_kind_of(Entry::BlockParameter, parameters[1])
196
189
  end
197
190
 
198
191
  def test_rbs_anonymous_block_parameter
199
- entries = @index["open"]
200
- entry = entries.find { |entry| entry.owner.name == "File::<Class:File>" }
192
+ entries = @index["open"] #: as Array[Entry::Method]
193
+ entry = entries.find { |entry| entry.owner&.name == "File::<Class:File>" } #: as Entry::Method
201
194
 
202
195
  assert_equal(2, entry.signatures.length)
203
196
 
204
197
  # (::String name, ?::String mode, ?::Integer perm) -> ::IO?
205
198
  # | [T] (::String name, ?::String mode, ?::Integer perm) { (::IO) -> T } -> T
206
199
 
207
- parameters = entry.signatures[0].parameters
200
+ parameters = entry.signatures[0]&.parameters #: as !nil
208
201
  assert_equal([:file_name, :mode, :perm], parameters.map(&:name))
209
202
  assert_kind_of(Entry::RequiredParameter, parameters[0])
210
203
  assert_kind_of(Entry::OptionalParameter, parameters[1])
211
204
  assert_kind_of(Entry::OptionalParameter, parameters[2])
212
205
 
213
- parameters = entry.signatures[1].parameters
206
+ parameters = entry.signatures[1]&.parameters #: as !nil
214
207
  assert_equal([:file_name, :mode, :perm, :"<anonymous block>"], parameters.map(&:name))
215
208
  assert_kind_of(Entry::RequiredParameter, parameters[0])
216
209
  assert_kind_of(Entry::OptionalParameter, parameters[1])
@@ -219,10 +212,10 @@ module RubyIndexer
219
212
  end
220
213
 
221
214
  def test_rbs_method_with_rest_positionals
222
- entries = @index["count"]
223
- entry = entries.find { |entry| entry.owner.name == "String" }
215
+ entries = @index["count"] #: as Array[Entry::Method]
216
+ entry = entries.find { |entry| entry.owner&.name == "String" } #: as Entry::Method
224
217
 
225
- parameters = entry.signatures.first.parameters
218
+ parameters = entry.signatures.first&.parameters #: as !nil
226
219
  assert_equal(1, entry.signatures.length)
227
220
 
228
221
  # (::String::selector selector_0, *::String::selector more_selectors) -> ::Integer
@@ -233,22 +226,22 @@ module RubyIndexer
233
226
  end
234
227
 
235
228
  def test_rbs_method_with_trailing_positionals
236
- entries = @index["select"] # https://ruby-doc.org/3.3.3/IO.html#method-c-select
237
- entry = entries.find { |entry| entry.owner.name == "IO::<Class:IO>" }
229
+ entries = @index["select"] #: as Array[Entry::Method]
230
+ entry = entries.find { |entry| entry.owner&.name == "IO::<Class:IO>" } #: as !nil
238
231
 
239
232
  signatures = entry.signatures
240
233
  assert_equal(2, signatures.length)
241
234
 
242
- # def self.select: [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array) -> [ Array[X], Array[Y], Array[Z] ] # rubocop:disable Layout/LineLength
243
- # | [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array, Time::_Timeout? timeout) -> [ Array[X], Array[Y], Array[Z] ]? # rubocop:disable Layout/LineLength
235
+ # def self.select: [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array) -> [ Array[X], Array[Y], Array[Z] ]
236
+ # | [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array, Time::_Timeout? timeout) -> [ Array[X], Array[Y], Array[Z] ]?
244
237
 
245
- parameters = signatures[0].parameters
238
+ parameters = signatures[0]&.parameters #: as !nil
246
239
  assert_equal([:read_array, :write_array, :error_array], parameters.map(&:name))
247
240
  assert_kind_of(Entry::RequiredParameter, parameters[0])
248
241
  assert_kind_of(Entry::OptionalParameter, parameters[1])
249
242
  assert_kind_of(Entry::OptionalParameter, parameters[2])
250
243
 
251
- parameters = signatures[1].parameters
244
+ parameters = signatures[1]&.parameters #: as !nil
252
245
  assert_equal([:read_array, :write_array, :error_array, :timeout], parameters.map(&:name))
253
246
  assert_kind_of(Entry::RequiredParameter, parameters[0])
254
247
  assert_kind_of(Entry::OptionalParameter, parameters[1])
@@ -257,8 +250,8 @@ module RubyIndexer
257
250
  end
258
251
 
259
252
  def test_rbs_method_with_optional_keywords
260
- entries = @index["step"]
261
- entry = entries.find { |entry| entry.owner.name == "Numeric" }
253
+ entries = @index["step"] #: as Array[Entry::Method]
254
+ entry = entries.find { |entry| entry.owner&.name == "Numeric" } #: as !nil
262
255
 
263
256
  signatures = entry.signatures
264
257
  assert_equal(4, signatures.length)
@@ -268,24 +261,24 @@ module RubyIndexer
268
261
  # | (?by: ::Numeric, ?to: ::Numeric) { (::Numeric) -> void } -> self
269
262
  # | (?by: ::Numeric, ?to: ::Numeric) -> ::Enumerator[::Numeric, self]
270
263
 
271
- parameters = signatures[0].parameters
264
+ parameters = signatures[0]&.parameters #: as !nil
272
265
  assert_equal([:limit, :step, :"<anonymous block>"], parameters.map(&:name))
273
266
  assert_kind_of(Entry::OptionalParameter, parameters[0])
274
267
  assert_kind_of(Entry::OptionalParameter, parameters[1])
275
268
  assert_kind_of(Entry::BlockParameter, parameters[2])
276
269
 
277
- parameters = signatures[1].parameters
270
+ parameters = signatures[1]&.parameters #: as !nil
278
271
  assert_equal([:limit, :step], parameters.map(&:name))
279
272
  assert_kind_of(Entry::OptionalParameter, parameters[0])
280
273
  assert_kind_of(Entry::OptionalParameter, parameters[1])
281
274
 
282
- parameters = signatures[2].parameters
275
+ parameters = signatures[2]&.parameters #: as !nil
283
276
  assert_equal([:by, :to, :"<anonymous block>"], parameters.map(&:name))
284
277
  assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
285
278
  assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
286
279
  assert_kind_of(Entry::BlockParameter, parameters[2])
287
280
 
288
- parameters = signatures[3].parameters
281
+ parameters = signatures[3]&.parameters #: as !nil
289
282
  assert_equal([:by, :to], parameters.map(&:name))
290
283
  assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
291
284
  assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
@@ -308,14 +301,14 @@ module RubyIndexer
308
301
  end
309
302
 
310
303
  def test_rbs_method_with_rest_keywords
311
- entries = @index["method_missing"]
312
- entry = entries.find { |entry| entry.owner.name == "BasicObject" }
304
+ entries = @index["method_missing"] #: as Array[Entry::Method]
305
+ entry = entries.find { |entry| entry.owner&.name == "BasicObject" } #: as !nil
313
306
  signatures = entry.signatures
314
307
  assert_equal(1, signatures.length)
315
308
 
316
309
  # (Symbol, *untyped, **untyped) ?{ (*untyped, **untyped) -> untyped } -> untyped
317
310
 
318
- parameters = signatures[0].parameters
311
+ parameters = signatures[0]&.parameters #: as !nil
319
312
  assert_equal([:arg0, :"<anonymous splat>", :"<anonymous keyword splat>"], parameters.map(&:name))
320
313
  assert_kind_of(Entry::RequiredParameter, parameters[0])
321
314
  assert_kind_of(Entry::RestParameter, parameters[1])
@@ -348,24 +341,24 @@ module RubyIndexer
348
341
  def test_signature_alias
349
342
  # In RBS, an alias means that two methods have the same signature.
350
343
  # It does not mean the same thing as a Ruby alias.
351
- any_entries = @index["any?"]
344
+ any_entries = @index["any?"] #: as Array[Entry::UnresolvedMethodAlias]
352
345
 
353
- assert_equal(["Array", "Enumerable", "Hash"], any_entries.map { _1.owner.name })
346
+ assert_equal(["Array", "Enumerable", "Hash"], any_entries.map { _1.owner&.name })
354
347
 
355
- entry = any_entries.find { |entry| entry.owner.name == "Array" }
348
+ entry = any_entries.find { |entry| entry.owner&.name == "Array" } #: as !nil
356
349
 
357
350
  assert_kind_of(RubyIndexer::Entry::UnresolvedMethodAlias, entry)
358
351
  assert_equal("any?", entry.name)
359
352
  assert_equal("all?", entry.old_name)
360
- assert_equal("Array", entry.owner.name)
361
- assert(entry.file_path.end_with?("core/array.rbs"))
362
- assert_includes(entry.comments, "Returns `true` if any element of `self` meets a given criterion.")
353
+ assert_equal("Array", entry.owner&.name)
354
+ assert(entry.file_path&.end_with?("core/array.rbs"))
355
+ refute_empty(entry.comments)
363
356
  end
364
357
 
365
358
  def test_indexing_untyped_functions
366
- entries = @index.resolve_method("call", "Method")
359
+ entries = @index.resolve_method("call", "Method") #: as Array[Entry::Method]
367
360
 
368
- parameters = entries.first.signatures.first.parameters
361
+ parameters = entries.first&.signatures&.first&.parameters #: as !nil
369
362
  assert_equal(1, parameters.length)
370
363
  assert_instance_of(Entry::ForwardingParameter, parameters.first)
371
364
  end
@@ -379,8 +372,10 @@ module RubyIndexer
379
372
  indexer = RubyIndexer::RBSIndexer.new(index)
380
373
  pathname = Pathname.new("/file.rbs")
381
374
  indexer.process_signature(pathname, declarations)
382
- entry = T.must(index[method_name]).first
383
- T.cast(entry, Entry::Method).signatures
375
+ entry = index[method_name] #: as !nil
376
+ .first #: as Entry::Method
377
+
378
+ entry.signatures
384
379
  end
385
380
  end
386
381
  end
@@ -216,22 +216,43 @@ 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)
219
+ def test_finds_instance_variable_references
220
+ refs = find_instance_variable_references("@name", ["Foo"], <<~RUBY)
221
221
  class Foo
222
- def foo
223
- @foo
222
+ def initialize
223
+ @name = "foo"
224
+ end
225
+ def name
226
+ @name
227
+ end
228
+ def name_capital
229
+ @name[0]
230
+ end
231
+ end
232
+
233
+ class Bar
234
+ def initialize
235
+ @name = "foo"
236
+ end
237
+ def name
238
+ @name
224
239
  end
225
240
  end
226
241
  RUBY
227
- assert_equal(1, refs.size)
242
+ assert_equal(3, refs.size)
228
243
 
229
- assert_equal("@foo", refs[0].name)
244
+ assert_equal("@name", refs[0].name)
230
245
  assert_equal(3, refs[0].location.start_line)
246
+
247
+ assert_equal("@name", refs[1].name)
248
+ assert_equal(6, refs[1].location.start_line)
249
+
250
+ assert_equal("@name", refs[2].name)
251
+ assert_equal(9, refs[2].location.start_line)
231
252
  end
232
253
 
233
254
  def test_finds_instance_variable_write_references
234
- refs = find_instance_variable_references("@foo", <<~RUBY)
255
+ refs = find_instance_variable_references("@foo", ["Foo"], <<~RUBY)
235
256
  class Foo
236
257
  def write
237
258
  @foo = 1
@@ -252,26 +273,70 @@ module RubyIndexer
252
273
  assert_equal(7, refs[4].location.start_line)
253
274
  end
254
275
 
255
- def test_finds_instance_variable_references_ignore_context
256
- refs = find_instance_variable_references("@name", <<~RUBY)
257
- class Foo
276
+ def test_finds_instance_variable_references_in_owner_ancestors
277
+ refs = find_instance_variable_references("@name", ["Foo", "Base", "Top", "Parent"], <<~RUBY)
278
+ module Base
279
+ def change_name(name)
280
+ @name = name
281
+ end
258
282
  def name
283
+ @name
284
+ end
285
+
286
+ module ::Top
287
+ def name
288
+ @name
289
+ end
290
+ end
291
+ end
292
+
293
+ class Parent
294
+ def initialize
295
+ @name = "parent"
296
+ end
297
+ def name_capital
298
+ @name[0]
299
+ end
300
+ end
301
+
302
+ class Foo < Parent
303
+ include Base
304
+ def initialize
259
305
  @name = "foo"
260
306
  end
307
+ def name
308
+ @name
309
+ end
261
310
  end
311
+
262
312
  class Bar
263
313
  def name
264
314
  @name = "bar"
265
315
  end
266
316
  end
267
317
  RUBY
268
- assert_equal(2, refs.size)
318
+ assert_equal(7, refs.size)
269
319
 
270
320
  assert_equal("@name", refs[0].name)
271
321
  assert_equal(3, refs[0].location.start_line)
272
322
 
273
323
  assert_equal("@name", refs[1].name)
274
- assert_equal(8, refs[1].location.start_line)
324
+ assert_equal(6, refs[1].location.start_line)
325
+
326
+ assert_equal("@name", refs[2].name)
327
+ assert_equal(11, refs[2].location.start_line)
328
+
329
+ assert_equal("@name", refs[3].name)
330
+ assert_equal(18, refs[3].location.start_line)
331
+
332
+ assert_equal("@name", refs[4].name)
333
+ assert_equal(21, refs[4].location.start_line)
334
+
335
+ assert_equal("@name", refs[5].name)
336
+ assert_equal(28, refs[5].location.start_line)
337
+
338
+ assert_equal("@name", refs[6].name)
339
+ assert_equal(31, refs[6].location.start_line)
275
340
  end
276
341
 
277
342
  def test_accounts_for_reopened_classes
@@ -310,8 +375,8 @@ module RubyIndexer
310
375
  find_references(target, source)
311
376
  end
312
377
 
313
- def find_instance_variable_references(instance_variable_name, source)
314
- target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name)
378
+ def find_instance_variable_references(instance_variable_name, owner_ancestors, source)
379
+ target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name, owner_ancestors)
315
380
  find_references(target, source)
316
381
  end
317
382
 
@@ -11,6 +11,13 @@ module RubyIndexer
11
11
  @default_indexed_entries = @index.instance_variable_get(:@entries).dup
12
12
  end
13
13
 
14
+ def teardown
15
+ entries = @index.instance_variable_get(:@entries).values.flatten
16
+ entries.each do |entry|
17
+ assert_includes([:public, :private, :protected], entry.visibility)
18
+ end
19
+ end
20
+
14
21
  private
15
22
 
16
23
  def index(source, uri: URI::Generic.from_path(path: "/fake/path/foo.rb"))
@@ -18,11 +25,11 @@ module RubyIndexer
18
25
  end
19
26
 
20
27
  def assert_entry(expected_name, type, expected_location, visibility: nil)
21
- entries = @index[expected_name]
28
+ entries = @index[expected_name] #: as !nil
22
29
  refute_nil(entries, "Expected #{expected_name} to be indexed")
23
30
  refute_empty(entries, "Expected #{expected_name} to be indexed")
24
31
 
25
- entry = entries.first
32
+ entry = entries.first #: as !nil
26
33
  assert_instance_of(type, entry, "Expected #{expected_name} to be a #{type}")
27
34
 
28
35
  location = entry.location
@@ -31,7 +38,6 @@ module RubyIndexer
31
38
  ":#{location.end_line - 1}-#{location.end_column}"
32
39
 
33
40
  assert_equal(expected_location, location_string)
34
-
35
41
  assert_equal(visibility, entry.visibility) if visibility
36
42
  end
37
43