ruby-lsp 0.17.5 → 0.17.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30ab87e9f42251fafcf8c085d14272b6e0cc0fb6e6968db3fc4c304e92000c63
4
- data.tar.gz: 305592ad82c3e41b72dff4c0a48ff60e6158ffba6d06b802844418c3873a6ef9
3
+ metadata.gz: 7299237468ae17d80028a1454903f58b1be4ff34428a6c8a538530b5caad54d1
4
+ data.tar.gz: 26351e5be1671219a9b3624076b2f50fb68c5838303fe1a021eecb39c4e3e9f1
5
5
  SHA512:
6
- metadata.gz: 3a38745ee99e4e62843f3bc2a698ec8c447d9bbb39091e158b2a64e36e46a1612962d1062635a007e13aabd3709733b9726a302ef680bd2881673e6abd48e038
7
- data.tar.gz: 57b5327b0f17af4530b21ba3c51eb2bff13912e76df77f78284cd9644cebef252e1cbdd38b960de19cc64a68d9daf3788c6e78ef3b95b4bb5d6dc7f97e56c58f
6
+ metadata.gz: 54cc76a3506a268398cfc51645a70300e2d14bda5b39c12274863270f70ed666b33bfebdf50dac8e013410e8ddba5645f4f435863af795d268710e0ccf9d8814
7
+ data.tar.gz: 95e52a4aa6f68785495f7435fe54cc395c062809ad3754703f808c68d2599bc34a619578bbb8453cb54de88a8312ac49eff8dd2e72a82bc04554c7b659c477cd
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.17.5
1
+ 0.17.6
@@ -288,6 +288,14 @@ module RubyIndexer
288
288
  class BlockParameter < Parameter
289
289
  DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
290
290
 
291
+ class << self
292
+ extend T::Sig
293
+ sig { returns(BlockParameter) }
294
+ def anonymous
295
+ new(name: DEFAULT_NAME)
296
+ end
297
+ end
298
+
291
299
  sig { override.returns(Symbol) }
292
300
  def decorated_name
293
301
  :"&#{@name}"
@@ -389,7 +389,7 @@ module RubyIndexer
389
389
  # If we don't have an entry for `name`, raise
390
390
  entries = self[fully_qualified_name]
391
391
 
392
- if singleton_levels > 0 && !entries
392
+ if singleton_levels > 0 && !entries && indexed?(attached_class_name)
393
393
  entries = [existing_or_new_singleton_class(attached_class_name)]
394
394
  end
395
395
 
@@ -15,20 +15,25 @@ module RubyIndexer
15
15
  loader = RBS::EnvironmentLoader.new
16
16
  RBS::Environment.from_loader(loader).resolve_type_names
17
17
 
18
- loader.each_signature do |source, pathname, _buffer, declarations, _directives|
19
- process_signature(source, pathname, declarations)
18
+ loader.each_signature do |_source, pathname, _buffer, declarations, _directives|
19
+ process_signature(pathname, declarations)
20
20
  end
21
21
  end
22
22
 
23
- private
24
-
25
- sig { params(source: T.untyped, pathname: Pathname, declarations: T::Array[RBS::AST::Declarations::Base]).void }
26
- def process_signature(source, pathname, declarations)
23
+ sig do
24
+ params(
25
+ pathname: Pathname,
26
+ declarations: T::Array[RBS::AST::Declarations::Base],
27
+ ).void
28
+ end
29
+ def process_signature(pathname, declarations)
27
30
  declarations.each do |declaration|
28
31
  process_declaration(declaration, pathname)
29
32
  end
30
33
  end
31
34
 
35
+ private
36
+
32
37
  sig { params(declaration: RBS::AST::Declarations::Base, pathname: Pathname).void }
33
38
  def process_declaration(declaration, pathname)
34
39
  case declaration
@@ -122,7 +127,102 @@ module RubyIndexer
122
127
  end
123
128
 
124
129
  real_owner = member.singleton? ? @index.existing_or_new_singleton_class(owner.name) : owner
125
- @index.add(Entry::Method.new(name, file_path, location, location, comments, [], visibility, real_owner))
130
+ signatures = signatures(member)
131
+ @index.add(Entry::Method.new(name, file_path, location, location, comments, signatures, visibility, real_owner))
132
+ end
133
+
134
+ sig { params(member: RBS::AST::Members::MethodDefinition).returns(T::Array[Entry::Signature]) }
135
+ def signatures(member)
136
+ member.overloads.map do |overload|
137
+ parameters = process_overload(overload)
138
+ Entry::Signature.new(parameters)
139
+ end
140
+ end
141
+
142
+ sig { params(overload: RBS::AST::Members::MethodDefinition::Overload).returns(T::Array[Entry::Parameter]) }
143
+ def process_overload(overload)
144
+ function = T.cast(overload.method_type.type, RBS::Types::Function)
145
+ parameters = parse_arguments(function)
146
+
147
+ block = overload.method_type.block
148
+ parameters << Entry::BlockParameter.anonymous if block&.required
149
+
150
+ parameters
151
+ end
152
+
153
+ sig { params(function: RBS::Types::Function).returns(T::Array[Entry::Parameter]) }
154
+ def parse_arguments(function)
155
+ parameters = []
156
+ parameters.concat(process_required_and_optional_positionals(function))
157
+ parameters.concat(process_trailing_positionals(function)) if function.trailing_positionals
158
+ parameters << process_rest_positionals(function) if function.rest_positionals
159
+ parameters.concat(process_required_keywords(function)) if function.required_keywords
160
+ parameters.concat(process_optional_keywords(function)) if function.optional_keywords
161
+ parameters << process_rest_keywords(function) if function.rest_keywords
162
+ parameters
163
+ end
164
+
165
+ sig { params(function: RBS::Types::Function).returns(T::Array[Entry::RequiredParameter]) }
166
+ def process_required_and_optional_positionals(function)
167
+ argument_offset = 0
168
+
169
+ required = function.required_positionals.map.with_index(argument_offset) do |param, i|
170
+ # Some parameters don't have names, e.g.
171
+ # def self.try_convert: [U] (untyped) -> ::Array[U]?
172
+ name = param.name || :"arg#{i}"
173
+ argument_offset += 1
174
+
175
+ Entry::RequiredParameter.new(name: name)
176
+ end
177
+
178
+ optional = function.optional_positionals.map.with_index(argument_offset) do |param, i|
179
+ # Optional positionals may be unnamed, e.g.
180
+ # def self.polar: (Numeric, ?Numeric) -> Complex
181
+ name = param.name || :"arg#{i}"
182
+
183
+ Entry::OptionalParameter.new(name: name)
184
+ end
185
+
186
+ required + optional
187
+ end
188
+
189
+ sig { params(function: RBS::Types::Function).returns(T::Array[Entry::OptionalParameter]) }
190
+ def process_trailing_positionals(function)
191
+ function.trailing_positionals.map do |param|
192
+ Entry::OptionalParameter.new(name: param.name)
193
+ end
194
+ end
195
+
196
+ sig { params(function: RBS::Types::Function).returns(Entry::RestParameter) }
197
+ def process_rest_positionals(function)
198
+ rest = function.rest_positionals
199
+
200
+ rest_name = rest.name || Entry::RestParameter::DEFAULT_NAME
201
+
202
+ Entry::RestParameter.new(name: rest_name)
203
+ end
204
+
205
+ sig { params(function: RBS::Types::Function).returns(T::Array[Entry::KeywordParameter]) }
206
+ def process_required_keywords(function)
207
+ function.required_keywords.map do |name, _param|
208
+ Entry::KeywordParameter.new(name: name)
209
+ end
210
+ end
211
+
212
+ sig { params(function: RBS::Types::Function).returns(T::Array[Entry::OptionalKeywordParameter]) }
213
+ def process_optional_keywords(function)
214
+ function.optional_keywords.map do |name, _param|
215
+ Entry::OptionalKeywordParameter.new(name: name)
216
+ end
217
+ end
218
+
219
+ sig { params(function: RBS::Types::Function).returns(Entry::KeywordRestParameter) }
220
+ def process_rest_keywords(function)
221
+ param = function.rest_keywords
222
+
223
+ name = param.name || Entry::KeywordRestParameter::DEFAULT_NAME
224
+
225
+ Entry::KeywordRestParameter.new(name: name)
126
226
  end
127
227
  end
128
228
  end
@@ -1707,5 +1707,11 @@ module RubyIndexer
1707
1707
  @index.linearized_ancestors_of("A::<Class:A>"),
1708
1708
  )
1709
1709
  end
1710
+
1711
+ def test_linearizing_a_singleton_class_with_no_attached
1712
+ assert_raises(Index::NonExistingNamespaceError) do
1713
+ @index.linearized_ancestors_of("A::<Class:A>")
1714
+ end
1715
+ end
1710
1716
  end
1711
1717
  end
@@ -123,8 +123,9 @@ module RubyIndexer
123
123
 
124
124
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
125
125
  entry = T.must(@index["bar"].first)
126
- assert_equal(1, entry.parameters.length)
127
- parameter = entry.parameters.first
126
+ parameters = entry.signatures.first.parameters
127
+ assert_equal(1, parameters.length)
128
+ parameter = parameters.first
128
129
  assert_equal(:a, parameter.name)
129
130
  assert_instance_of(Entry::RequiredParameter, parameter)
130
131
  end
@@ -139,8 +140,9 @@ module RubyIndexer
139
140
 
140
141
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
141
142
  entry = T.must(@index["bar"].first)
142
- assert_equal(1, entry.parameters.length)
143
- parameter = entry.parameters.first
143
+ parameters = entry.signatures.first.parameters
144
+ assert_equal(1, parameters.length)
145
+ parameter = parameters.first
144
146
  assert_equal(:"(a, (b, ))", parameter.name)
145
147
  assert_instance_of(Entry::RequiredParameter, parameter)
146
148
  end
@@ -155,8 +157,9 @@ module RubyIndexer
155
157
 
156
158
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
157
159
  entry = T.must(@index["bar"].first)
158
- assert_equal(1, entry.parameters.length)
159
- parameter = entry.parameters.first
160
+ parameters = entry.signatures.first.parameters
161
+ assert_equal(1, parameters.length)
162
+ parameter = parameters.first
160
163
  assert_equal(:a, parameter.name)
161
164
  assert_instance_of(Entry::OptionalParameter, parameter)
162
165
  end
@@ -171,8 +174,9 @@ module RubyIndexer
171
174
 
172
175
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
173
176
  entry = T.must(@index["bar"].first)
174
- assert_equal(2, entry.parameters.length)
175
- a, b = entry.parameters
177
+ parameters = entry.signatures.first.parameters
178
+ assert_equal(2, parameters.length)
179
+ a, b = parameters
176
180
 
177
181
  assert_equal(:a, a.name)
178
182
  assert_instance_of(Entry::KeywordParameter, a)
@@ -191,8 +195,9 @@ module RubyIndexer
191
195
 
192
196
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
193
197
  entry = T.must(@index["bar"].first)
194
- assert_equal(2, entry.parameters.length)
195
- a, b = entry.parameters
198
+ parameters = entry.signatures.first.parameters
199
+ assert_equal(2, parameters.length)
200
+ a, b = parameters
196
201
 
197
202
  assert_equal(:a, a.name)
198
203
  assert_instance_of(Entry::RestParameter, a)
@@ -216,8 +221,9 @@ module RubyIndexer
216
221
 
217
222
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
218
223
  entry = T.must(@index["bar"].first)
219
- assert_equal(2, entry.parameters.length)
220
- a, b = entry.parameters
224
+ parameters = entry.signatures.first.parameters
225
+ assert_equal(2, parameters.length)
226
+ a, b = parameters
221
227
 
222
228
  assert_equal(:a, a.name)
223
229
  assert_instance_of(Entry::RestParameter, a)
@@ -226,8 +232,9 @@ module RubyIndexer
226
232
  assert_instance_of(Entry::RequiredParameter, b)
227
233
 
228
234
  entry = T.must(@index["baz"].first)
229
- assert_equal(2, entry.parameters.length)
230
- a, b = entry.parameters
235
+ parameters = entry.signatures.first.parameters
236
+ assert_equal(2, parameters.length)
237
+ a, b = parameters
231
238
 
232
239
  assert_equal(:a, a.name)
233
240
  assert_instance_of(Entry::KeywordRestParameter, a)
@@ -236,8 +243,9 @@ module RubyIndexer
236
243
  assert_instance_of(Entry::RequiredParameter, b)
237
244
 
238
245
  entry = T.must(@index["qux"].first)
239
- assert_equal(2, entry.parameters.length)
240
- _a, second = entry.parameters
246
+ parameters = entry.signatures.first.parameters
247
+ assert_equal(2, parameters.length)
248
+ _a, second = parameters
241
249
 
242
250
  assert_equal(:"(b, c)", second.name)
243
251
  assert_instance_of(Entry::RequiredParameter, second)
@@ -253,8 +261,9 @@ module RubyIndexer
253
261
 
254
262
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
255
263
  entry = T.must(@index["bar"].first)
256
- assert_equal(1, entry.parameters.length)
257
- param = entry.parameters.first
264
+ parameters = entry.signatures.first.parameters
265
+ assert_equal(1, parameters.length)
266
+ param = parameters.first
258
267
 
259
268
  assert_equal(:"(a, *b)", param.name)
260
269
  assert_instance_of(Entry::RequiredParameter, param)
@@ -272,14 +281,16 @@ module RubyIndexer
272
281
  RUBY
273
282
 
274
283
  entry = T.must(@index["bar"].first)
275
- param = entry.parameters.first
284
+ parameters = entry.signatures.first.parameters
285
+ param = parameters.first
276
286
  assert_equal(:block, param.name)
277
287
  assert_instance_of(Entry::BlockParameter, param)
278
288
 
279
289
  entry = T.must(@index["baz"].first)
280
- assert_equal(1, entry.parameters.length)
290
+ parameters = entry.signatures.first.parameters
291
+ assert_equal(1, parameters.length)
281
292
 
282
- param = entry.parameters.first
293
+ param = parameters.first
283
294
  assert_equal(Entry::BlockParameter::DEFAULT_NAME, param.name)
284
295
  assert_instance_of(Entry::BlockParameter, param)
285
296
  end
@@ -294,8 +305,9 @@ module RubyIndexer
294
305
 
295
306
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
296
307
  entry = T.must(@index["bar"].first)
297
- assert_equal(2, entry.parameters.length)
298
- first, second = entry.parameters
308
+ parameters = entry.signatures.first.parameters
309
+ assert_equal(2, parameters.length)
310
+ first, second = parameters
299
311
 
300
312
  assert_equal(Entry::RestParameter::DEFAULT_NAME, first.name)
301
313
  assert_instance_of(Entry::RestParameter, first)
@@ -314,7 +326,8 @@ module RubyIndexer
314
326
 
315
327
  assert_entry("bar", Entry::Method, "/fake/path/foo.rb:1-2:2-5")
316
328
  entry = T.must(@index["bar"].first)
317
- assert_empty(entry.parameters)
329
+ parameters = entry.signatures.first.parameters
330
+ assert_empty(parameters)
318
331
  end
319
332
 
320
333
  def test_keeps_track_of_method_owner
@@ -74,5 +74,253 @@ module RubyIndexer
74
74
 
75
75
  assert_same(entry.location, entry.name_location)
76
76
  end
77
+
78
+ def test_rbs_method_with_required_positionals
79
+ entries = @index["crypt"]
80
+ assert_equal(1, entries.length)
81
+
82
+ entry = entries.first
83
+ signatures = entry.signatures
84
+ assert_equal(1, signatures.length)
85
+
86
+ first_signature = signatures.first
87
+
88
+ # (::string salt_str) -> ::String
89
+
90
+ assert_equal(1, first_signature.parameters.length)
91
+ assert_kind_of(Entry::RequiredParameter, first_signature.parameters[0])
92
+ assert_equal(:salt_str, first_signature.parameters[0].name)
93
+ end
94
+
95
+ def test_rbs_method_with_unnamed_required_positionals
96
+ entries = @index["try_convert"]
97
+ entry = entries.find { |entry| entry.owner.name == "Array::<Class:Array>" }
98
+
99
+ parameters = entry.signatures[0].parameters
100
+
101
+ assert_equal([:arg0], parameters.map(&:name))
102
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
103
+ end
104
+
105
+ def test_rbs_method_with_optional_positionals
106
+ entries = @index["polar"]
107
+ entry = entries.find { |entry| entry.owner.name == "Complex::<Class:Complex>" }
108
+
109
+ # def self.polar: (Numeric, ?Numeric) -> Complex
110
+
111
+ parameters = entry.signatures[0].parameters
112
+
113
+ assert_equal([:arg0, :arg1], parameters.map(&:name))
114
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
115
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
116
+ end
117
+
118
+ def test_rbs_method_with_optional_parameter
119
+ entries = @index["chomp"]
120
+ assert_equal(1, entries.length)
121
+
122
+ entry = entries.first
123
+ signatures = entry.signatures
124
+ assert_equal(1, signatures.length)
125
+
126
+ first_signature = signatures.first
127
+
128
+ # (?::string? separator) -> ::String
129
+
130
+ assert_equal(1, first_signature.parameters.length)
131
+ assert_kind_of(Entry::OptionalParameter, first_signature.parameters[0])
132
+ assert_equal(:separator, first_signature.parameters[0].name)
133
+ end
134
+
135
+ def test_rbs_method_with_required_and_optional_parameters
136
+ entries = @index["gsub"]
137
+ assert_equal(1, entries.length)
138
+
139
+ entry = entries.first
140
+
141
+ signatures = entry.signatures
142
+ assert_equal(3, signatures.length)
143
+
144
+ # (::Regexp | ::string pattern, ::string | ::hash[::String, ::_ToS] replacement) -> ::String
145
+ # | (::Regexp | ::string pattern) -> ::Enumerator[::String, ::String]
146
+ # | (::Regexp | ::string pattern) { (::String match) -> ::_ToS } -> ::String
147
+
148
+ parameters = signatures[0].parameters
149
+ assert_equal([:pattern, :replacement], parameters.map(&:name))
150
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
151
+ assert_kind_of(Entry::RequiredParameter, parameters[1])
152
+
153
+ parameters = signatures[1].parameters
154
+ assert_equal([:pattern], parameters.map(&:name))
155
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
156
+
157
+ parameters = signatures[2].parameters
158
+ assert_equal([:pattern, :"<anonymous block>"], parameters.map(&:name))
159
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
160
+ assert_kind_of(Entry::BlockParameter, parameters[1])
161
+ end
162
+
163
+ def test_rbs_anonymous_block_parameter
164
+ entries = @index["open"]
165
+ entry = entries.find { |entry| entry.owner.name == "File::<Class:File>" }
166
+
167
+ assert_equal(2, entry.signatures.length)
168
+
169
+ # (::String name, ?::String mode, ?::Integer perm) -> ::IO?
170
+ # | [T] (::String name, ?::String mode, ?::Integer perm) { (::IO) -> T } -> T
171
+
172
+ parameters = entry.signatures[0].parameters
173
+ assert_equal([:file_name, :mode, :perm], parameters.map(&:name))
174
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
175
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
176
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
177
+
178
+ parameters = entry.signatures[1].parameters
179
+ assert_equal([:file_name, :mode, :perm, :"<anonymous block>"], parameters.map(&:name))
180
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
181
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
182
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
183
+ assert_kind_of(Entry::BlockParameter, parameters[3])
184
+ end
185
+
186
+ def test_rbs_method_with_rest_positionals
187
+ entries = @index["count"]
188
+ entry = entries.find { |entry| entry.owner.name == "String" }
189
+
190
+ parameters = entry.signatures.first.parameters
191
+ assert_equal(1, entry.signatures.length)
192
+
193
+ # (::String::selector selector_0, *::String::selector more_selectors) -> ::Integer
194
+
195
+ assert_equal([:selector_0, :more_selectors], parameters.map(&:name))
196
+ assert_kind_of(RubyIndexer::Entry::RequiredParameter, parameters[0])
197
+ assert_kind_of(RubyIndexer::Entry::RestParameter, parameters[1])
198
+ end
199
+
200
+ def test_rbs_method_with_trailing_positionals
201
+ entries = @index["select"] # https://ruby-doc.org/3.3.3/IO.html#method-c-select
202
+ entry = entries.find { |entry| entry.owner.name == "IO::<Class:IO>" }
203
+
204
+ signatures = entry.signatures
205
+ assert_equal(2, signatures.length)
206
+
207
+ # 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
208
+ # | [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
209
+
210
+ parameters = signatures[0].parameters
211
+ assert_equal([:read_array, :write_array, :error_array], parameters.map(&:name))
212
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
213
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
214
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
215
+
216
+ parameters = signatures[1].parameters
217
+ assert_equal([:read_array, :write_array, :error_array, :timeout], parameters.map(&:name))
218
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
219
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
220
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
221
+ assert_kind_of(Entry::OptionalParameter, parameters[3])
222
+ end
223
+
224
+ def test_rbs_method_with_optional_keywords
225
+ entries = @index["step"]
226
+ entry = entries.find { |entry| entry.owner.name == "Numeric" }
227
+
228
+ signatures = entry.signatures
229
+ assert_equal(4, signatures.length)
230
+
231
+ # (?::Numeric limit, ?::Numeric step) { (::Numeric) -> void } -> self
232
+ # | (?::Numeric limit, ?::Numeric step) -> ::Enumerator[::Numeric, self]
233
+ # | (?by: ::Numeric, ?to: ::Numeric) { (::Numeric) -> void } -> self
234
+ # | (?by: ::Numeric, ?to: ::Numeric) -> ::Enumerator[::Numeric, self]
235
+
236
+ parameters = signatures[0].parameters
237
+ assert_equal([:limit, :step, :"<anonymous block>"], parameters.map(&:name))
238
+ assert_kind_of(Entry::OptionalParameter, parameters[0])
239
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
240
+ assert_kind_of(Entry::BlockParameter, parameters[2])
241
+
242
+ parameters = signatures[1].parameters
243
+ assert_equal([:limit, :step], parameters.map(&:name))
244
+ assert_kind_of(Entry::OptionalParameter, parameters[0])
245
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
246
+
247
+ parameters = signatures[2].parameters
248
+ assert_equal([:by, :to, :"<anonymous block>"], parameters.map(&:name))
249
+ assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
250
+ assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
251
+ assert_kind_of(Entry::BlockParameter, parameters[2])
252
+
253
+ parameters = signatures[3].parameters
254
+ assert_equal([:by, :to], parameters.map(&:name))
255
+ assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
256
+ assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
257
+ end
258
+
259
+ def test_rbs_method_with_required_keywords
260
+ # There are no methods in Core that have required keyword arguments,
261
+ # so we test against RBS directly
262
+
263
+ rbs = <<~RBS
264
+ class File
265
+ def foo: (a: ::Numeric sz, b: ::Numeric) -> void
266
+ end
267
+ RBS
268
+ signatures = parse_rbs_methods(rbs, "foo")
269
+ parameters = signatures[0].parameters
270
+ assert_equal([:a, :b], parameters.map(&:name))
271
+ assert_kind_of(Entry::KeywordParameter, parameters[0])
272
+ assert_kind_of(Entry::KeywordParameter, parameters[1])
273
+ end
274
+
275
+ def test_rbs_method_with_rest_keywords
276
+ entries = @index["method_missing"]
277
+ entry = entries.find { |entry| entry.owner.name == "BasicObject" }
278
+ signatures = entry.signatures
279
+ assert_equal(1, signatures.length)
280
+
281
+ # (Symbol, *untyped, **untyped) ?{ (*untyped, **untyped) -> untyped } -> untyped
282
+
283
+ parameters = signatures[0].parameters
284
+ assert_equal([:arg0, :"<anonymous splat>", :"<anonymous keyword splat>"], parameters.map(&:name))
285
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
286
+ assert_kind_of(Entry::RestParameter, parameters[1])
287
+ assert_kind_of(Entry::KeywordRestParameter, parameters[2])
288
+ end
289
+
290
+ def test_parse_simple_rbs
291
+ rbs = <<~RBS
292
+ class File
293
+ def self?.open: (String name, ?String mode, ?Integer perm) -> IO?
294
+ | [T] (String name, ?String mode, ?Integer perm) { (IO) -> T } -> T
295
+ end
296
+ RBS
297
+ signatures = parse_rbs_methods(rbs, "open")
298
+ assert_equal(2, signatures.length)
299
+ parameters = signatures[0].parameters
300
+ assert_equal([:name, :mode, :perm], parameters.map(&:name))
301
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
302
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
303
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
304
+
305
+ parameters = signatures[1].parameters
306
+ assert_equal([:name, :mode, :perm, :"<anonymous block>"], parameters.map(&:name))
307
+ assert_kind_of(Entry::RequiredParameter, parameters[0])
308
+ assert_kind_of(Entry::OptionalParameter, parameters[1])
309
+ assert_kind_of(Entry::OptionalParameter, parameters[2])
310
+ assert_kind_of(Entry::BlockParameter, parameters[3])
311
+ end
312
+
313
+ private
314
+
315
+ def parse_rbs_methods(rbs, method_name)
316
+ buffer = RBS::Buffer.new(content: rbs, name: "")
317
+ _, _, declarations = RBS::Parser.parse_signature(buffer)
318
+ index = RubyIndexer::Index.new
319
+ indexer = RubyIndexer::RBSIndexer.new(index)
320
+ pathname = Pathname.new("file.rbs")
321
+ indexer.process_signature(pathname, declarations)
322
+ entry = T.must(index[method_name]).first
323
+ T.cast(entry, Entry::Method).signatures
324
+ end
77
325
  end
78
326
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.5
4
+ version: 0.17.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-09 00:00:00.000000000 Z
11
+ date: 2024-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol