ruby-lsp 0.23.11 → 0.26.6

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