ruby-lsp 0.11.1 → 0.12.0

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +2 -1
  4. data/exe/ruby-lsp-doctor +16 -0
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +5 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +205 -0
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +28 -108
  8. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +6 -6
  9. data/lib/ruby_indexer/lib/ruby_indexer/visitor.rb +160 -64
  10. data/lib/ruby_indexer/ruby_indexer.rb +1 -0
  11. data/lib/ruby_indexer/test/classes_and_modules_test.rb +49 -16
  12. data/lib/ruby_indexer/test/constant_test.rb +111 -30
  13. data/lib/ruby_indexer/test/index_test.rb +15 -0
  14. data/lib/ruby_indexer/test/method_test.rb +73 -0
  15. data/lib/ruby_indexer/test/test_case.rb +5 -1
  16. data/lib/ruby_lsp/addon.rb +8 -8
  17. data/lib/ruby_lsp/document.rb +14 -14
  18. data/lib/ruby_lsp/executor.rb +89 -53
  19. data/lib/ruby_lsp/internal.rb +8 -2
  20. data/lib/ruby_lsp/listener.rb +6 -6
  21. data/lib/ruby_lsp/requests/base_request.rb +1 -9
  22. data/lib/ruby_lsp/requests/code_action_resolve.rb +3 -3
  23. data/lib/ruby_lsp/requests/code_lens.rb +30 -30
  24. data/lib/ruby_lsp/requests/completion.rb +83 -32
  25. data/lib/ruby_lsp/requests/definition.rb +21 -15
  26. data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
  27. data/lib/ruby_lsp/requests/document_highlight.rb +508 -31
  28. data/lib/ruby_lsp/requests/document_link.rb +24 -17
  29. data/lib/ruby_lsp/requests/document_symbol.rb +42 -42
  30. data/lib/ruby_lsp/requests/folding_ranges.rb +84 -82
  31. data/lib/ruby_lsp/requests/hover.rb +22 -17
  32. data/lib/ruby_lsp/requests/inlay_hints.rb +6 -6
  33. data/lib/ruby_lsp/requests/selection_ranges.rb +13 -105
  34. data/lib/ruby_lsp/requests/semantic_highlighting.rb +92 -92
  35. data/lib/ruby_lsp/requests/support/annotation.rb +3 -3
  36. data/lib/ruby_lsp/requests/support/common.rb +5 -5
  37. data/lib/ruby_lsp/requests/support/dependency_detector.rb +12 -4
  38. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +15 -6
  39. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +10 -7
  40. data/lib/ruby_lsp/requests/support/sorbet.rb +28 -28
  41. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  42. data/lib/ruby_lsp/requests.rb +0 -1
  43. data/lib/ruby_lsp/setup_bundler.rb +8 -5
  44. metadata +19 -17
  45. data/lib/ruby_lsp/event_emitter.rb +0 -351
  46. data/lib/ruby_lsp/requests/support/highlight_target.rb +0 -118
@@ -20,123 +20,31 @@ module RubyLsp
20
20
  # puts "Hello, world!" # --> Cursor is on this line
21
21
  # end
22
22
  # ```
23
- class SelectionRanges < BaseRequest
23
+ class SelectionRanges
24
24
  extend T::Sig
25
-
26
- NODES_THAT_CAN_BE_PARENTS = T.let(
27
- [
28
- YARP::ArgumentsNode,
29
- YARP::ArrayNode,
30
- YARP::AssocNode,
31
- YARP::BeginNode,
32
- YARP::BlockNode,
33
- YARP::CallNode,
34
- YARP::CaseNode,
35
- YARP::ClassNode,
36
- YARP::DefNode,
37
- YARP::ElseNode,
38
- YARP::EnsureNode,
39
- YARP::ForNode,
40
- YARP::HashNode,
41
- YARP::HashPatternNode,
42
- YARP::IfNode,
43
- YARP::InNode,
44
- YARP::InterpolatedStringNode,
45
- YARP::KeywordHashNode,
46
- YARP::LambdaNode,
47
- YARP::LocalVariableWriteNode,
48
- YARP::ModuleNode,
49
- YARP::ParametersNode,
50
- YARP::RescueNode,
51
- YARP::StringConcatNode,
52
- YARP::StringNode,
53
- YARP::UnlessNode,
54
- YARP::UntilNode,
55
- YARP::WhenNode,
56
- YARP::WhileNode,
57
- ].freeze,
58
- T::Array[T.class_of(YARP::Node)],
59
- )
60
-
25
+ include Support::Common
61
26
  sig { params(document: Document).void }
62
27
  def initialize(document)
63
- super(document)
64
-
28
+ @document = document
65
29
  @ranges = T.let([], T::Array[Support::SelectionRange])
66
30
  @stack = T.let([], T::Array[Support::SelectionRange])
67
31
  end
68
32
 
69
- sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
33
+ sig { returns(T.all(T::Array[Support::SelectionRange], Object)) }
70
34
  def run
71
- visit(@document.tree)
72
- @ranges.reverse!
73
- end
35
+ # [node, parent]
36
+ queue = [[@document.tree, nil]]
74
37
 
75
- private
38
+ until queue.empty?
39
+ node, parent = queue.shift
40
+ next unless node
76
41
 
77
- sig { override.params(node: T.nilable(YARP::Node)).void }
78
- def visit(node)
79
- return if node.nil?
80
-
81
- range = if node.is_a?(YARP::InterpolatedStringNode)
82
- create_heredoc_selection_range(node, @stack.last)
83
- else
84
- create_selection_range(node.location, @stack.last)
42
+ range = Support::SelectionRange.new(range: range_from_location(node.location), parent: parent)
43
+ T.unsafe(queue).unshift(*node.child_nodes.map { |child| [child, range] })
44
+ @ranges.unshift(range)
85
45
  end
86
- @ranges << range
87
-
88
- return if node.child_nodes.empty?
89
46
 
90
- @stack << range if NODES_THAT_CAN_BE_PARENTS.include?(node.class)
91
- visit_all(node.child_nodes)
92
- @stack.pop if NODES_THAT_CAN_BE_PARENTS.include?(node.class)
93
- end
94
-
95
- sig do
96
- params(
97
- node: YARP::InterpolatedStringNode,
98
- parent: T.nilable(Support::SelectionRange),
99
- ).returns(Support::SelectionRange)
100
- end
101
- def create_heredoc_selection_range(node, parent)
102
- opening_loc = node.opening_loc || node.location
103
- closing_loc = node.closing_loc || node.location
104
-
105
- RubyLsp::Requests::Support::SelectionRange.new(
106
- range: Interface::Range.new(
107
- start: Interface::Position.new(
108
- line: opening_loc.start_line - 1,
109
- character: opening_loc.start_column,
110
- ),
111
- end: Interface::Position.new(
112
- line: closing_loc.end_line - 1,
113
- character: closing_loc.end_column,
114
- ),
115
- ),
116
- parent: parent,
117
- )
118
- end
119
-
120
- sig do
121
- params(
122
- location: YARP::Location,
123
- parent: T.nilable(Support::SelectionRange),
124
- ).returns(Support::SelectionRange)
125
- end
126
- def create_selection_range(location, parent)
127
- RubyLsp::Requests::Support::SelectionRange.new(
128
- range: Interface::Range.new(
129
- start: Interface::Position.new(
130
- line: location.start_line - 1,
131
- character: location.start_column,
132
- ),
133
- end: Interface::Position.new(
134
- line: location.end_line - 1,
135
- character: location.end_column,
136
- ),
137
- ),
138
- parent: parent,
139
- )
47
+ @ranges
140
48
  end
141
49
  end
142
50
  end
@@ -83,7 +83,7 @@ module RubyLsp
83
83
  class SemanticToken
84
84
  extend T::Sig
85
85
 
86
- sig { returns(YARP::Location) }
86
+ sig { returns(Prism::Location) }
87
87
  attr_reader :location
88
88
 
89
89
  sig { returns(Integer) }
@@ -95,7 +95,7 @@ module RubyLsp
95
95
  sig { returns(T::Array[Integer]) }
96
96
  attr_reader :modifier
97
97
 
98
- sig { params(location: YARP::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
98
+ sig { params(location: Prism::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
99
99
  def initialize(location:, length:, type:, modifier:)
100
100
  @location = location
101
101
  @length = length
@@ -109,53 +109,53 @@ module RubyLsp
109
109
 
110
110
  sig do
111
111
  params(
112
- emitter: EventEmitter,
112
+ dispatcher: Prism::Dispatcher,
113
113
  message_queue: Thread::Queue,
114
114
  range: T.nilable(T::Range[Integer]),
115
115
  ).void
116
116
  end
117
- def initialize(emitter, message_queue, range: nil)
118
- super(emitter, message_queue)
117
+ def initialize(dispatcher, message_queue, range: nil)
118
+ super(dispatcher, message_queue)
119
119
 
120
120
  @_response = T.let([], ResponseType)
121
121
  @range = range
122
122
  @special_methods = T.let(nil, T.nilable(T::Array[String]))
123
123
  @current_scope = T.let(ParameterScope.new, ParameterScope)
124
124
 
125
- emitter.register(
125
+ dispatcher.register(
126
126
  self,
127
- :on_call,
128
- :on_class,
129
- :on_def,
130
- :after_def,
131
- :on_block,
132
- :after_block,
133
- :on_self,
134
- :on_module,
135
- :on_local_variable_write,
136
- :on_local_variable_read,
137
- :on_block_parameter,
138
- :on_keyword_parameter,
139
- :on_keyword_rest_parameter,
140
- :on_optional_parameter,
141
- :on_required_parameter,
142
- :on_rest_parameter,
143
- :on_constant_read,
144
- :on_constant_write,
145
- :on_constant_and_write,
146
- :on_constant_operator_write,
147
- :on_constant_or_write,
148
- :on_constant_target,
149
- :on_local_variable_and_write,
150
- :on_local_variable_operator_write,
151
- :on_local_variable_or_write,
152
- :on_local_variable_target,
153
- :on_block_local_variable,
127
+ :on_call_node_enter,
128
+ :on_class_node_enter,
129
+ :on_def_node_enter,
130
+ :on_def_node_leave,
131
+ :on_block_node_enter,
132
+ :on_block_node_leave,
133
+ :on_self_node_enter,
134
+ :on_module_node_enter,
135
+ :on_local_variable_write_node_enter,
136
+ :on_local_variable_read_node_enter,
137
+ :on_block_parameter_node_enter,
138
+ :on_keyword_parameter_node_enter,
139
+ :on_keyword_rest_parameter_node_enter,
140
+ :on_optional_parameter_node_enter,
141
+ :on_required_parameter_node_enter,
142
+ :on_rest_parameter_node_enter,
143
+ :on_constant_read_node_enter,
144
+ :on_constant_write_node_enter,
145
+ :on_constant_and_write_node_enter,
146
+ :on_constant_operator_write_node_enter,
147
+ :on_constant_or_write_node_enter,
148
+ :on_constant_target_node_enter,
149
+ :on_local_variable_and_write_node_enter,
150
+ :on_local_variable_operator_write_node_enter,
151
+ :on_local_variable_or_write_node_enter,
152
+ :on_local_variable_target_node_enter,
153
+ :on_block_local_variable_node_enter,
154
154
  )
155
155
  end
156
156
 
157
- sig { params(node: YARP::CallNode).void }
158
- def on_call(node)
157
+ sig { params(node: Prism::CallNode).void }
158
+ def on_call_node_enter(node)
159
159
  return unless visible?(node, @range)
160
160
 
161
161
  message = node.message
@@ -172,8 +172,8 @@ module RubyLsp
172
172
  add_token(T.must(node.message_loc), type)
173
173
  end
174
174
 
175
- sig { params(node: YARP::ConstantReadNode).void }
176
- def on_constant_read(node)
175
+ sig { params(node: Prism::ConstantReadNode).void }
176
+ def on_constant_read_node_enter(node)
177
177
  return unless visible?(node, @range)
178
178
  # When finding a module or class definition, we will have already pushed a token related to this constant. We
179
179
  # need to look at the previous two tokens and if they match this locatione exactly, avoid pushing another token
@@ -183,77 +183,77 @@ module RubyLsp
183
183
  add_token(node.location, :namespace)
184
184
  end
185
185
 
186
- sig { params(node: YARP::ConstantWriteNode).void }
187
- def on_constant_write(node)
186
+ sig { params(node: Prism::ConstantWriteNode).void }
187
+ def on_constant_write_node_enter(node)
188
188
  return unless visible?(node, @range)
189
189
 
190
190
  add_token(node.name_loc, :namespace)
191
191
  end
192
192
 
193
- sig { params(node: YARP::ConstantAndWriteNode).void }
194
- def on_constant_and_write(node)
193
+ sig { params(node: Prism::ConstantAndWriteNode).void }
194
+ def on_constant_and_write_node_enter(node)
195
195
  return unless visible?(node, @range)
196
196
 
197
197
  add_token(node.name_loc, :namespace)
198
198
  end
199
199
 
200
- sig { params(node: YARP::ConstantOperatorWriteNode).void }
201
- def on_constant_operator_write(node)
200
+ sig { params(node: Prism::ConstantOperatorWriteNode).void }
201
+ def on_constant_operator_write_node_enter(node)
202
202
  return unless visible?(node, @range)
203
203
 
204
204
  add_token(node.name_loc, :namespace)
205
205
  end
206
206
 
207
- sig { params(node: YARP::ConstantOrWriteNode).void }
208
- def on_constant_or_write(node)
207
+ sig { params(node: Prism::ConstantOrWriteNode).void }
208
+ def on_constant_or_write_node_enter(node)
209
209
  return unless visible?(node, @range)
210
210
 
211
211
  add_token(node.name_loc, :namespace)
212
212
  end
213
213
 
214
- sig { params(node: YARP::ConstantTargetNode).void }
215
- def on_constant_target(node)
214
+ sig { params(node: Prism::ConstantTargetNode).void }
215
+ def on_constant_target_node_enter(node)
216
216
  return unless visible?(node, @range)
217
217
 
218
218
  add_token(node.location, :namespace)
219
219
  end
220
220
 
221
- sig { params(node: YARP::DefNode).void }
222
- def on_def(node)
221
+ sig { params(node: Prism::DefNode).void }
222
+ def on_def_node_enter(node)
223
223
  @current_scope = ParameterScope.new(@current_scope)
224
224
  return unless visible?(node, @range)
225
225
 
226
226
  add_token(node.name_loc, :method, [:declaration])
227
227
  end
228
228
 
229
- sig { params(node: YARP::DefNode).void }
230
- def after_def(node)
229
+ sig { params(node: Prism::DefNode).void }
230
+ def on_def_node_leave(node)
231
231
  @current_scope = T.must(@current_scope.parent)
232
232
  end
233
233
 
234
- sig { params(node: YARP::BlockNode).void }
235
- def on_block(node)
234
+ sig { params(node: Prism::BlockNode).void }
235
+ def on_block_node_enter(node)
236
236
  @current_scope = ParameterScope.new(@current_scope)
237
237
  end
238
238
 
239
- sig { params(node: YARP::BlockNode).void }
240
- def after_block(node)
239
+ sig { params(node: Prism::BlockNode).void }
240
+ def on_block_node_leave(node)
241
241
  @current_scope = T.must(@current_scope.parent)
242
242
  end
243
243
 
244
- sig { params(node: YARP::BlockLocalVariableNode).void }
245
- def on_block_local_variable(node)
244
+ sig { params(node: Prism::BlockLocalVariableNode).void }
245
+ def on_block_local_variable_node_enter(node)
246
246
  add_token(node.location, :variable)
247
247
  end
248
248
 
249
- sig { params(node: YARP::BlockParameterNode).void }
250
- def on_block_parameter(node)
249
+ sig { params(node: Prism::BlockParameterNode).void }
250
+ def on_block_parameter_node_enter(node)
251
251
  name = node.name
252
252
  @current_scope << name.to_sym if name
253
253
  end
254
254
 
255
- sig { params(node: YARP::KeywordParameterNode).void }
256
- def on_keyword_parameter(node)
255
+ sig { params(node: Prism::KeywordParameterNode).void }
256
+ def on_keyword_parameter_node_enter(node)
257
257
  name = node.name
258
258
  @current_scope << name.to_s.delete_suffix(":").to_sym if name
259
259
 
@@ -263,8 +263,8 @@ module RubyLsp
263
263
  add_token(location.copy(length: location.length - 1), :parameter)
264
264
  end
265
265
 
266
- sig { params(node: YARP::KeywordRestParameterNode).void }
267
- def on_keyword_rest_parameter(node)
266
+ sig { params(node: Prism::KeywordRestParameterNode).void }
267
+ def on_keyword_rest_parameter_node_enter(node)
268
268
  name = node.name
269
269
 
270
270
  if name
@@ -274,24 +274,24 @@ module RubyLsp
274
274
  end
275
275
  end
276
276
 
277
- sig { params(node: YARP::OptionalParameterNode).void }
278
- def on_optional_parameter(node)
277
+ sig { params(node: Prism::OptionalParameterNode).void }
278
+ def on_optional_parameter_node_enter(node)
279
279
  @current_scope << node.name
280
280
  return unless visible?(node, @range)
281
281
 
282
282
  add_token(node.name_loc, :parameter)
283
283
  end
284
284
 
285
- sig { params(node: YARP::RequiredParameterNode).void }
286
- def on_required_parameter(node)
285
+ sig { params(node: Prism::RequiredParameterNode).void }
286
+ def on_required_parameter_node_enter(node)
287
287
  @current_scope << node.name
288
288
  return unless visible?(node, @range)
289
289
 
290
290
  add_token(node.location, :parameter)
291
291
  end
292
292
 
293
- sig { params(node: YARP::RestParameterNode).void }
294
- def on_rest_parameter(node)
293
+ sig { params(node: Prism::RestParameterNode).void }
294
+ def on_rest_parameter_node_enter(node)
295
295
  name = node.name
296
296
 
297
297
  if name
@@ -301,22 +301,22 @@ module RubyLsp
301
301
  end
302
302
  end
303
303
 
304
- sig { params(node: YARP::SelfNode).void }
305
- def on_self(node)
304
+ sig { params(node: Prism::SelfNode).void }
305
+ def on_self_node_enter(node)
306
306
  return unless visible?(node, @range)
307
307
 
308
308
  add_token(node.location, :variable, [:default_library])
309
309
  end
310
310
 
311
- sig { params(node: YARP::LocalVariableWriteNode).void }
312
- def on_local_variable_write(node)
311
+ sig { params(node: Prism::LocalVariableWriteNode).void }
312
+ def on_local_variable_write_node_enter(node)
313
313
  return unless visible?(node, @range)
314
314
 
315
315
  add_token(node.name_loc, @current_scope.type_for(node.name))
316
316
  end
317
317
 
318
- sig { params(node: YARP::LocalVariableReadNode).void }
319
- def on_local_variable_read(node)
318
+ sig { params(node: Prism::LocalVariableReadNode).void }
319
+ def on_local_variable_read_node_enter(node)
320
320
  return unless visible?(node, @range)
321
321
 
322
322
  # Numbered parameters
@@ -328,36 +328,36 @@ module RubyLsp
328
328
  add_token(node.location, @current_scope.type_for(node.name))
329
329
  end
330
330
 
331
- sig { params(node: YARP::LocalVariableAndWriteNode).void }
332
- def on_local_variable_and_write(node)
331
+ sig { params(node: Prism::LocalVariableAndWriteNode).void }
332
+ def on_local_variable_and_write_node_enter(node)
333
333
  return unless visible?(node, @range)
334
334
 
335
335
  add_token(node.name_loc, @current_scope.type_for(node.name))
336
336
  end
337
337
 
338
- sig { params(node: YARP::LocalVariableOperatorWriteNode).void }
339
- def on_local_variable_operator_write(node)
338
+ sig { params(node: Prism::LocalVariableOperatorWriteNode).void }
339
+ def on_local_variable_operator_write_node_enter(node)
340
340
  return unless visible?(node, @range)
341
341
 
342
342
  add_token(node.name_loc, @current_scope.type_for(node.name))
343
343
  end
344
344
 
345
- sig { params(node: YARP::LocalVariableOrWriteNode).void }
346
- def on_local_variable_or_write(node)
345
+ sig { params(node: Prism::LocalVariableOrWriteNode).void }
346
+ def on_local_variable_or_write_node_enter(node)
347
347
  return unless visible?(node, @range)
348
348
 
349
349
  add_token(node.name_loc, @current_scope.type_for(node.name))
350
350
  end
351
351
 
352
- sig { params(node: YARP::LocalVariableTargetNode).void }
353
- def on_local_variable_target(node)
352
+ sig { params(node: Prism::LocalVariableTargetNode).void }
353
+ def on_local_variable_target_node_enter(node)
354
354
  return unless visible?(node, @range)
355
355
 
356
356
  add_token(node.location, @current_scope.type_for(node.name))
357
357
  end
358
358
 
359
- sig { params(node: YARP::ClassNode).void }
360
- def on_class(node)
359
+ sig { params(node: Prism::ClassNode).void }
360
+ def on_class_node_enter(node)
361
361
  return unless visible?(node, @range)
362
362
 
363
363
  add_token(node.constant_path.location, :class, [:declaration])
@@ -366,14 +366,16 @@ module RubyLsp
366
366
  add_token(superclass.location, :class) if superclass
367
367
  end
368
368
 
369
- sig { params(node: YARP::ModuleNode).void }
370
- def on_module(node)
369
+ sig { params(node: Prism::ModuleNode).void }
370
+ def on_module_node_enter(node)
371
371
  return unless visible?(node, @range)
372
372
 
373
373
  add_token(node.constant_path.location, :namespace, [:declaration])
374
374
  end
375
375
 
376
- sig { params(location: YARP::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
376
+ private
377
+
378
+ sig { params(location: Prism::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
377
379
  def add_token(location, type, modifiers = [])
378
380
  length = location.end_offset - location.start_offset
379
381
  modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
@@ -387,8 +389,6 @@ module RubyLsp
387
389
  )
388
390
  end
389
391
 
390
- private
391
-
392
392
  # Textmate provides highlighting for a subset of these special Ruby-specific methods. We want to utilize that
393
393
  # highlighting, so we avoid making a semantic token for it.
394
394
  sig { params(method_name: String).returns(T::Boolean) }
@@ -396,12 +396,12 @@ module RubyLsp
396
396
  SPECIAL_RUBY_METHODS.include?(method_name)
397
397
  end
398
398
 
399
- sig { params(node: YARP::CallNode).void }
399
+ sig { params(node: Prism::CallNode).void }
400
400
  def process_regexp_locals(node)
401
401
  receiver = node.receiver
402
402
 
403
403
  # The regexp needs to be the receiver of =~ for local variable capture
404
- return unless receiver.is_a?(YARP::RegularExpressionNode)
404
+ return unless receiver.is_a?(Prism::RegularExpressionNode)
405
405
 
406
406
  content = receiver.content
407
407
  loc = receiver.content_loc
@@ -17,20 +17,20 @@ module RubyLsp
17
17
  @receiver = receiver
18
18
  end
19
19
 
20
- sig { params(node: YARP::CallNode).returns(T::Boolean) }
20
+ sig { params(node: Prism::CallNode).returns(T::Boolean) }
21
21
  def match?(node)
22
22
  receiver_matches?(node) && arity_matches?(node)
23
23
  end
24
24
 
25
25
  private
26
26
 
27
- sig { params(node: YARP::CallNode).returns(T::Boolean) }
27
+ sig { params(node: Prism::CallNode).returns(T::Boolean) }
28
28
  def receiver_matches?(node)
29
29
  node_receiver = node.receiver
30
30
  (node_receiver && @receiver && node_receiver.location.slice == "T") || (!node_receiver && !@receiver)
31
31
  end
32
32
 
33
- sig { params(node: YARP::CallNode).returns(T::Boolean) }
33
+ sig { params(node: Prism::CallNode).returns(T::Boolean) }
34
34
  def arity_matches?(node)
35
35
  node_arity = node.arguments&.arguments&.size || 0
36
36
 
@@ -10,7 +10,7 @@ module RubyLsp
10
10
  # cautious of changing anything.
11
11
  extend T::Sig
12
12
 
13
- sig { params(node: YARP::Node).returns(Interface::Range) }
13
+ sig { params(node: Prism::Node).returns(Interface::Range) }
14
14
  def range_from_node(node)
15
15
  loc = node.location
16
16
 
@@ -23,7 +23,7 @@ module RubyLsp
23
23
  )
24
24
  end
25
25
 
26
- sig { params(location: YARP::Location).returns(Interface::Range) }
26
+ sig { params(location: Prism::Location).returns(Interface::Range) }
27
27
  def range_from_location(location)
28
28
  Interface::Range.new(
29
29
  start: Interface::Position.new(
@@ -34,7 +34,7 @@ module RubyLsp
34
34
  )
35
35
  end
36
36
 
37
- sig { params(node: T.nilable(YARP::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
37
+ sig { params(node: T.nilable(Prism::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
38
38
  def visible?(node, range)
39
39
  return true if range.nil?
40
40
  return false if node.nil?
@@ -45,7 +45,7 @@ module RubyLsp
45
45
 
46
46
  sig do
47
47
  params(
48
- node: YARP::Node,
48
+ node: Prism::Node,
49
49
  title: String,
50
50
  command_name: String,
51
51
  arguments: T.nilable(T::Array[T.untyped]),
@@ -66,7 +66,7 @@ module RubyLsp
66
66
  )
67
67
  end
68
68
 
69
- sig { params(title: String, entries: T::Array[RubyIndexer::Index::Entry]).returns(Interface::MarkupContent) }
69
+ sig { params(title: String, entries: T::Array[RubyIndexer::Entry]).returns(Interface::MarkupContent) }
70
70
  def markdown_from_index_entries(title, entries)
71
71
  markdown_title = "```ruby\n#{title}\n```"
72
72
  definitions = []
@@ -56,7 +56,7 @@ module RubyLsp
56
56
 
57
57
  sig { params(gem_pattern: Regexp).returns(T::Boolean) }
58
58
  def direct_dependency?(gem_pattern)
59
- dependency_keys.grep(gem_pattern).any?
59
+ dependencies.any?(gem_pattern)
60
60
  end
61
61
 
62
62
  sig { returns(T::Boolean) }
@@ -65,16 +65,24 @@ module RubyLsp
65
65
  end
66
66
 
67
67
  sig { returns(T::Array[String]) }
68
- def dependency_keys
69
- @dependency_keys ||= T.let(
68
+ def dependencies
69
+ # NOTE: If changing this behaviour, it's likely that the VS Code extension will also need changed.
70
+ @dependencies ||= T.let(
70
71
  begin
71
72
  Bundler.with_original_env { Bundler.default_gemfile }
72
- Bundler.locked_gems.dependencies.keys
73
+ Bundler.locked_gems.dependencies.keys + gemspec_dependencies
73
74
  rescue Bundler::GemfileNotFound
74
75
  []
75
76
  end,
76
77
  T.nilable(T::Array[String]),
77
78
  )
78
79
  end
80
+
81
+ sig { returns(T::Array[String]) }
82
+ def gemspec_dependencies
83
+ Bundler.locked_gems.sources
84
+ .grep(Bundler::Source::Gemspec)
85
+ .flat_map { _1.gemspec&.dependencies&.map(&:name) }
86
+ end
79
87
  end
80
88
  end
@@ -19,6 +19,12 @@ module RubyLsp
19
19
  T::Hash[Symbol, Integer],
20
20
  )
21
21
 
22
+ # Cache cops to attach URLs to diagnostics. Only built-in cops for now.
23
+ COP_TO_DOC_URL = T.let(
24
+ RuboCop::Cop::Registry.global.to_h,
25
+ T::Hash[String, [T.class_of(RuboCop::Cop::Base)]],
26
+ )
27
+
22
28
  sig { params(offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
23
29
  def initialize(offense, uri)
24
30
  @offense = offense
@@ -47,18 +53,21 @@ module RubyLsp
47
53
 
48
54
  sig { returns(Interface::Diagnostic) }
49
55
  def to_lsp_diagnostic
50
- if @offense.correctable?
51
- severity = RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name]
52
- message = @offense.message
53
- else
54
- severity = Constant::DiagnosticSeverity::WARNING
55
- message = "#{@offense.message}\n\nThis offense is not auto-correctable.\n"
56
+ severity = RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name]
57
+ message = @offense.message
58
+
59
+ message += "\n\nThis offense is not auto-correctable.\n" unless @offense.correctable?
60
+
61
+ cop = COP_TO_DOC_URL[@offense.cop_name]&.first
62
+ if cop&.documentation_url
63
+ code_description = { href: cop.documentation_url }
56
64
  end
57
65
 
58
66
  Interface::Diagnostic.new(
59
67
  message: message,
60
68
  source: "RuboCop",
61
69
  code: @offense.cop_name,
70
+ code_description: code_description,
62
71
  severity: severity,
63
72
  range: Interface::Range.new(
64
73
  start: Interface::Position.new(