ruby-lsp 0.27.0.beta1 → 0.27.0.beta3

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +0 -46
  4. data/exe/ruby-lsp-check +0 -15
  5. data/lib/ruby_lsp/addon.rb +19 -19
  6. data/lib/ruby_lsp/global_state.rb +1 -6
  7. data/lib/ruby_lsp/internal.rb +3 -2
  8. data/lib/ruby_lsp/listeners/code_lens.rb +1 -1
  9. data/lib/ruby_lsp/listeners/completion.rb +246 -382
  10. data/lib/ruby_lsp/listeners/definition.rb +7 -10
  11. data/lib/ruby_lsp/listeners/document_link.rb +4 -0
  12. data/lib/ruby_lsp/listeners/hover.rb +234 -82
  13. data/lib/ruby_lsp/listeners/signature_help.rb +11 -12
  14. data/lib/ruby_lsp/listeners/spec_style.rb +6 -1
  15. data/lib/ruby_lsp/listeners/test_discovery.rb +38 -15
  16. data/lib/ruby_lsp/listeners/test_style.rb +21 -9
  17. data/lib/ruby_lsp/node_context.rb +31 -8
  18. data/lib/ruby_lsp/requests/completion_resolve.rb +55 -39
  19. data/lib/ruby_lsp/requests/discover_tests.rb +5 -41
  20. data/lib/ruby_lsp/requests/hover.rb +2 -5
  21. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +66 -22
  22. data/lib/ruby_lsp/requests/references.rb +180 -66
  23. data/lib/ruby_lsp/requests/rename.rb +1 -1
  24. data/lib/ruby_lsp/requests/request.rb +3 -33
  25. data/lib/ruby_lsp/requests/support/common.rb +82 -68
  26. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +82 -46
  27. data/lib/ruby_lsp/ruby_document.rb +0 -73
  28. data/lib/ruby_lsp/rubydex/declaration.rb +174 -0
  29. data/lib/ruby_lsp/rubydex/definition.rb +73 -0
  30. data/lib/ruby_lsp/rubydex/reference.rb +6 -1
  31. data/lib/ruby_lsp/rubydex/signature.rb +107 -0
  32. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  33. data/lib/ruby_lsp/server.rb +56 -171
  34. data/lib/ruby_lsp/test_helper.rb +0 -1
  35. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +1 -1
  36. data/lib/ruby_lsp/type_inferrer.rb +89 -11
  37. metadata +12 -18
  38. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +0 -276
  39. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +0 -1101
  40. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +0 -44
  41. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +0 -605
  42. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +0 -1077
  43. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +0 -37
  44. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +0 -149
  45. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +0 -294
  46. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +0 -335
  47. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +0 -32
  48. data/lib/ruby_indexer/ruby_indexer.rb +0 -20
  49. data/lib/ruby_lsp/static_docs.rb +0 -20
  50. data/static_docs/break.md +0 -103
  51. data/static_docs/yield.md +0 -81
  52. /data/lib/{ruby_indexer/lib/ruby_indexer → ruby_lsp}/uri.rb +0 -0
@@ -3,7 +3,11 @@
3
3
 
4
4
  module RubyLsp
5
5
  class Server < BaseServer
6
- NON_REPORTABLE_SETUP_ERRORS = [Bundler::GemNotFound, Bundler::GitError].freeze #: Array[singleton(StandardError)]
6
+ NON_REPORTABLE_SETUP_ERRORS = [
7
+ Bundler::GemNotFound,
8
+ Bundler::GitError,
9
+ Bundler::Dsl::DSLError,
10
+ ].freeze #: Array[singleton(StandardError)]
7
11
 
8
12
  # Only for testing
9
13
  #: GlobalState
@@ -120,6 +124,16 @@ module RubyLsp
120
124
  @global_state.synchronize { @cancelled_requests << message[:params][:id] }
121
125
  when nil
122
126
  process_response(message) if message[:result]
127
+ else
128
+ id = message[:id]
129
+
130
+ if id
131
+ send_message(Error.new(
132
+ id: id,
133
+ code: Constant::ErrorCodes::METHOD_NOT_FOUND,
134
+ message: "Method not found: #{message[:method]}",
135
+ ))
136
+ end
123
137
  end
124
138
  rescue DelegateRequestError
125
139
  send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
@@ -311,8 +325,6 @@ module RubyLsp
311
325
  ))
312
326
  end
313
327
 
314
- process_indexing_configuration(options.dig(:initializationOptions, :indexing))
315
-
316
328
  begin_progress("indexing-progress", "Ruby LSP: indexing files")
317
329
 
318
330
  global_state_notifications.each { |notification| send_message(notification) }
@@ -422,8 +434,11 @@ module RubyLsp
422
434
 
423
435
  if [:ruby, :rbs].include?(language_id)
424
436
  graph = @global_state.graph
425
- graph.index_source(text_document[:uri].to_s, document.source, language_id.to_s)
426
- graph.resolve
437
+
438
+ benchmark("index_source") do
439
+ graph.index_source(text_document[:uri].to_s, document.source, language_id.to_s)
440
+ end
441
+ benchmark("incremental_resolve") { graph.resolve }
427
442
  end
428
443
  end
429
444
 
@@ -482,39 +497,15 @@ module RubyLsp
482
497
  document,
483
498
  dispatcher,
484
499
  )
485
-
486
- # The code lens listener requires the index to be populated, so the DeclarationListener must be inserted first in
487
- # the dispatcher's state
488
- code_lens = nil #: Requests::CodeLens?
489
-
490
- if document.is_a?(RubyDocument) && document.should_index?
491
- # Re-index the file as it is modified. This mode of indexing updates entries only. Require path trees are only
492
- # updated on save
493
- @global_state.synchronize do
494
- send_log_message("Determined that document should be indexed: #{uri}")
495
-
496
- @global_state.index.handle_change(uri) do |index|
497
- index.delete(uri, skip_require_paths_tree: true)
498
- RubyIndexer::DeclarationListener.new(index, dispatcher, parse_result, uri, collect_comments: true)
499
- code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
500
- dispatcher.dispatch(document.ast)
501
- end
502
- end
503
- else
504
- code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
505
- dispatcher.dispatch(document.ast)
506
- end
500
+ code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
501
+ dispatcher.dispatch(document.ast)
507
502
 
508
503
  # Store all responses retrieve in this round of visits in the cache and then return the response for the request
509
504
  # we actually received
510
505
  document.cache_set("textDocument/foldingRange", folding_range.perform)
511
506
  document.cache_set("textDocument/documentSymbol", document_symbol.perform)
512
507
  document.cache_set("textDocument/documentLink", document_link.perform)
513
- document.cache_set(
514
- "textDocument/codeLens",
515
- code_lens #: as !nil
516
- .perform,
517
- )
508
+ document.cache_set("textDocument/codeLens", code_lens.perform)
518
509
  document.cache_set("textDocument/inlayHint", inlay_hint.perform)
519
510
 
520
511
  send_message(Result.new(id: message[:id], response: document.cache_get(message[:method])))
@@ -1021,21 +1012,6 @@ module RubyLsp
1021
1012
 
1022
1013
  #: (Hash[Symbol, untyped] message) -> void
1023
1014
  def workspace_did_change_watched_files(message)
1024
- # If indexing is not complete yet, delay processing did change watched file notifications. We need initial
1025
- # indexing to be in place so that we can handle file changes appropriately without risking duplicates. We also
1026
- # have to sleep before re-inserting the notification in the queue otherwise the worker can get stuck in its own
1027
- # loop of pushing and popping the same notification
1028
- unless @global_state.index.initial_indexing_completed
1029
- Thread.new do
1030
- sleep(2)
1031
- # We have to ensure that the queue is not closed yet, since nothing stops the user from saving a file and then
1032
- # immediately telling the LSP to shutdown
1033
- @incoming_queue << message unless @incoming_queue.closed?
1034
- end
1035
-
1036
- return
1037
- end
1038
-
1039
1015
  changes = message.dig(:params, :changes)
1040
1016
  # We allow add-ons to register for watching files and we have no restrictions for what they register for. If the
1041
1017
  # same pattern is registered more than once, the LSP will receive duplicate change notifications. Receiving them
@@ -1056,21 +1032,15 @@ module RubyLsp
1056
1032
  acc << path
1057
1033
  end
1058
1034
  end
1059
- graph.index_all(additions_and_changes)
1060
- graph.resolve
1035
+ benchmark("index_all") { graph.index_all(additions_and_changes) }
1036
+ benchmark("incremental_resolve") { graph.resolve }
1061
1037
 
1062
- index = @global_state.index
1063
1038
  changes.each do |change|
1064
1039
  # File change events include folders, but we're only interested in files
1065
1040
  uri = URI(change[:uri])
1066
1041
  file_path = uri.to_standardized_path
1067
1042
  next if file_path.nil? || File.directory?(file_path)
1068
1043
 
1069
- if file_path.end_with?(".rb")
1070
- handle_ruby_file_change(index, file_path, change[:type])
1071
- next
1072
- end
1073
-
1074
1044
  file_name = File.basename(file_path)
1075
1045
 
1076
1046
  if file_name == ".rubocop.yml" || file_name == ".rubocop" || file_name == ".rubocop_todo.yml"
@@ -1089,33 +1059,6 @@ module RubyLsp
1089
1059
  end
1090
1060
  end
1091
1061
 
1092
- #: (RubyIndexer::Index index, String file_path, Integer change_type) -> void
1093
- def handle_ruby_file_change(index, file_path, change_type)
1094
- @global_state.synchronize do
1095
- load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
1096
- uri = URI::Generic.from_path(load_path_entry: load_path_entry, path: file_path)
1097
-
1098
- case change_type
1099
- when Constant::FileChangeType::CREATED
1100
- content = File.read(file_path)
1101
- # If we receive a late created notification for a file that has already been claimed by the client, we want to
1102
- # handle change for that URI so that the require path tree is updated
1103
- @store.key?(uri) ? index.handle_change(uri, content) : index.index_single(uri, content)
1104
- when Constant::FileChangeType::CHANGED
1105
- content = File.read(file_path)
1106
- # We only handle changes on file watched notifications if the client is not the one managing this URI.
1107
- # Otherwise, these changes are handled when running the combined requests
1108
- index.handle_change(uri, content) unless @store.key?(uri)
1109
- when Constant::FileChangeType::DELETED
1110
- index.delete(uri)
1111
- end
1112
- rescue Errno::ENOENT
1113
- # If a file is created and then delete immediately afterwards, we will process the created notification before
1114
- # we receive the deleted one, but the file no longer exists. This may happen when running a test suite that
1115
- # creates and deletes files automatically.
1116
- end
1117
- end
1118
-
1119
1062
  #: (URI::Generic uri) -> void
1120
1063
  def handle_rubocop_config_change(uri)
1121
1064
  return unless defined?(Requests::Support::RuboCopFormatter)
@@ -1195,7 +1138,7 @@ module RubyLsp
1195
1138
 
1196
1139
  response = Requests::PrepareTypeHierarchy.new(
1197
1140
  document,
1198
- @global_state.index,
1141
+ @global_state,
1199
1142
  params[:position],
1200
1143
  ).perform
1201
1144
 
@@ -1205,7 +1148,7 @@ module RubyLsp
1205
1148
  #: (Hash[Symbol, untyped] message) -> void
1206
1149
  def type_hierarchy_supertypes(message)
1207
1150
  response = Requests::TypeHierarchySupertypes.new(
1208
- @global_state.index,
1151
+ @global_state,
1209
1152
  message.dig(:params, :item),
1210
1153
  ).perform
1211
1154
  send_message(Result.new(id: message[:id], response: response))
@@ -1254,56 +1197,16 @@ module RubyLsp
1254
1197
 
1255
1198
  #: -> void
1256
1199
  def perform_initial_indexing
1200
+ # Index
1257
1201
  progress("indexing-progress", message: "Indexing workspace...")
1258
- @global_state.graph.index_workspace
1202
+ benchmark("index_workspace") { @global_state.graph.index_workspace }
1259
1203
 
1204
+ # Resolve
1260
1205
  progress("indexing-progress", message: "Resolving graph...")
1261
- @global_state.graph.resolve
1262
-
1263
- # The begin progress invocation happens during `initialize`, so that the notification is sent before we are
1264
- # stuck indexing files
1265
- Thread.new do
1266
- begin
1267
- @global_state.index.index_all do |percentage|
1268
- progress("indexing-progress", percentage: percentage)
1269
- true
1270
- rescue ClosedQueueError
1271
- # Since we run indexing on a separate thread, it's possible to kill the server before indexing is complete.
1272
- # In those cases, the message queue will be closed and raise a ClosedQueueError. By returning `false`, we
1273
- # tell the index to stop working immediately
1274
- false
1275
- end
1276
- rescue StandardError => error
1277
- message = "Error while indexing (see [troubleshooting steps]" \
1278
- "(https://shopify.github.io/ruby-lsp/troubleshooting#indexing)): #{error.message}"
1279
- send_message(Notification.window_show_message(message, type: Constant::MessageType::ERROR))
1280
- end
1281
-
1282
- # Indexing produces a high number of short lived object allocations. That might lead to some fragmentation and
1283
- # an unnecessarily expanded heap. Compacting ensures that the heap is as small as possible and that future
1284
- # allocations and garbage collections are faster
1285
- GC.compact unless @test_mode
1286
-
1287
- @global_state.synchronize do
1288
- # If we linearize ancestors while the index is not fully populated, we may end up caching incorrect results
1289
- # that were missing namespaces. After indexing is complete, we need to clear the ancestors cache and start
1290
- # again
1291
- @global_state.index.clear_ancestors
1292
-
1293
- # The results for code lens depend on ancestor linearization, so we need to clear any previously computed
1294
- # responses
1295
- @store.each { |_uri, document| document.clear_cache("textDocument/codeLens") }
1296
- end
1297
-
1298
- # Always end the progress notification even if indexing failed or else it never goes away and the user has no
1299
- # way of dismissing it
1300
- end_progress("indexing-progress")
1206
+ benchmark("full_resolve") { @global_state.graph.resolve }
1301
1207
 
1302
- # Request a code lens refresh if we populated them before all test parent classes were indexed
1303
- if @global_state.client_capabilities.supports_code_lens_refresh
1304
- send_message(Request.new(id: @current_request_id, method: "workspace/codeLens/refresh", params: nil))
1305
- end
1306
- end
1208
+ # End
1209
+ end_progress("indexing-progress")
1307
1210
  end
1308
1211
 
1309
1212
  #: (String id, String title, ?percentage: Integer) -> void
@@ -1356,47 +1259,6 @@ module RubyLsp
1356
1259
  end
1357
1260
  end
1358
1261
 
1359
- #: (Hash[Symbol, untyped]? indexing_options) -> void
1360
- def process_indexing_configuration(indexing_options)
1361
- # Need to use the workspace URI, otherwise, this will fail for people working on a project that is a symlink.
1362
- index_path = File.join(@global_state.workspace_path, ".index.yml")
1363
-
1364
- if File.exist?(index_path)
1365
- begin
1366
- @global_state.index.configuration.apply_config(YAML.parse_file(index_path).to_ruby)
1367
- send_message(
1368
- Notification.new(
1369
- method: "window/showMessage",
1370
- params: Interface::ShowMessageParams.new(
1371
- type: Constant::MessageType::WARNING,
1372
- message: "The .index.yml configuration file is deprecated. " \
1373
- "Please use editor settings to configure the index",
1374
- ),
1375
- ),
1376
- )
1377
- rescue Psych::SyntaxError => e
1378
- message = "Syntax error while loading configuration: #{e.message}"
1379
- send_message(
1380
- Notification.new(
1381
- method: "window/showMessage",
1382
- params: Interface::ShowMessageParams.new(
1383
- type: Constant::MessageType::WARNING,
1384
- message: message,
1385
- ),
1386
- ),
1387
- )
1388
- end
1389
- return
1390
- end
1391
-
1392
- configuration = @global_state.index.configuration
1393
- configuration.workspace_path = @global_state.workspace_path
1394
- return unless indexing_options
1395
-
1396
- # The index expects snake case configurations, but VS Code standardizes on camel case settings
1397
- configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
1398
- end
1399
-
1400
1262
  #: (Hash[Symbol, untyped] message) -> void
1401
1263
  def window_show_message_request(message)
1402
1264
  result = message[:result]
@@ -1558,5 +1420,28 @@ module RubyLsp
1558
1420
  response: code_lens,
1559
1421
  ))
1560
1422
  end
1423
+
1424
+ #: [T] (String) { () -> T } -> T
1425
+ def benchmark(label, &block)
1426
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
1427
+ result = block.call
1428
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start
1429
+
1430
+ send_message(Notification.telemetry({
1431
+ type: "data",
1432
+ eventName: "ruby_lsp.response_time",
1433
+ data: {
1434
+ type: "histogram",
1435
+ value: duration,
1436
+ attributes: {
1437
+ message: label,
1438
+ lspVersion: RubyLsp::VERSION,
1439
+ rubyVersion: RUBY_VERSION,
1440
+ },
1441
+ },
1442
+ }))
1443
+
1444
+ result
1445
+ end
1561
1446
  end
1562
1447
  end
@@ -29,7 +29,6 @@ module RubyLsp
29
29
  },
30
30
  })
31
31
 
32
- server.global_state.index.index_single(uri, source)
33
32
  graph = server.global_state.graph
34
33
  graph.index_source(uri.to_s, source, "ruby")
35
34
  graph.resolve
@@ -5,7 +5,7 @@ require "English"
5
5
  require "json"
6
6
  require "socket"
7
7
  require "tmpdir"
8
- require_relative "../../ruby_indexer/lib/ruby_indexer/uri"
8
+ require_relative "../uri"
9
9
 
10
10
  module RubyLsp
11
11
  class LspReporter
@@ -19,7 +19,7 @@ module RubyLsp
19
19
  infer_receiver_for_call_node(node, node_context)
20
20
  when Prism::InstanceVariableReadNode, Prism::InstanceVariableAndWriteNode, Prism::InstanceVariableWriteNode,
21
21
  Prism::InstanceVariableOperatorWriteNode, Prism::InstanceVariableOrWriteNode, Prism::InstanceVariableTargetNode,
22
- Prism::SuperNode, Prism::ForwardingSuperNode
22
+ Prism::SuperNode, Prism::ForwardingSuperNode, Prism::DefNode
23
23
  self_receiver_handling(node_context)
24
24
  when Prism::ClassVariableAndWriteNode, Prism::ClassVariableWriteNode, Prism::ClassVariableOperatorWriteNode,
25
25
  Prism::ClassVariableOrWriteNode, Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
@@ -78,7 +78,7 @@ module RubyLsp
78
78
  # When the receiver is a constant reference, we have to try to resolve it to figure out the right
79
79
  # receiver. But since the invocation is directly on the constant, that's the singleton context of that
80
80
  # class/module
81
- receiver_name = RubyIndexer::Index.constant_name(receiver)
81
+ receiver_name = Requests::Support::Common.constant_name(receiver)
82
82
  return unless receiver_name
83
83
 
84
84
  resolved_receiver = @graph.resolve_constant(receiver_name, node_context.nesting)
@@ -124,26 +124,104 @@ module RubyLsp
124
124
 
125
125
  declaration = @graph.resolve_constant(guessed_name, nesting)
126
126
  declaration ||= @graph.search(guessed_name).first
127
- return unless declaration
127
+ return unless declaration.is_a?(Rubydex::Namespace)
128
128
 
129
129
  GuessedType.new(declaration.name)
130
130
  end
131
131
 
132
- #: (NodeContext node_context) -> Type
132
+ #: (NodeContext node_context) -> Type?
133
133
  def self_receiver_handling(node_context)
134
134
  nesting = node_context.nesting
135
135
  # If we're at the top level, then the invocation is happening on `<main>`, which is a special singleton that
136
136
  # inherits from Object
137
137
  return Type.new("Object") if nesting.empty?
138
- return Type.new(node_context.fully_qualified_name) if node_context.surrounding_method
138
+
139
+ surrounding_method = node_context.surrounding_method
140
+
141
+ if surrounding_method
142
+ receiver_name = surrounding_method.receiver
143
+
144
+ case receiver_name
145
+ when "self"
146
+ # `def self.foo` — self is the singleton of the enclosing class/module
147
+ return resolve_singleton_type_from_nesting(nesting)
148
+ when "none"
149
+ # Instance method — self is an instance of the enclosing class/module
150
+ return resolve_type_from_nesting(nesting)
151
+ when nil
152
+ # Dynamic receiver that we cannot handle
153
+ return
154
+ else
155
+ # Explicit constant receiver (e.g. `def Bar.baz`) — self is that constant's singleton class
156
+ resolved = resolve_receiver_singleton_type(receiver_name, nesting)
157
+ return resolved if resolved
158
+
159
+ return resolve_type_from_nesting(nesting)
160
+ end
161
+ end
139
162
 
140
163
  # If we're not inside a method, then we're inside the body of a class or module, which is a singleton
141
- # context.
142
- #
143
- # If the class/module definition is using compact style (e.g.: `class Foo::Bar`), then we need to split the name
144
- # into its individual parts to build the correct singleton name
145
- parts = nesting.flat_map { |part| part.split("::") }
146
- Type.new("#{parts.join("::")}::<#{parts.last}>")
164
+ # context. Resolve through the graph to get the correct fully qualified name
165
+ resolve_singleton_type_from_nesting(nesting)
166
+ end
167
+
168
+ # Resolves the fully qualified name of the innermost constant from the nesting and returns it as a type.
169
+ # For instance methods, the nesting won't have singleton markers, so the result is an instance type.
170
+ # For `def self.` methods, the nesting includes a singleton marker, which is preserved in the result.
171
+ #: (Array[String] nesting) -> Type
172
+ def resolve_type_from_nesting(nesting)
173
+ resolved_name = resolve_nesting_fully_qualified_name(nesting)
174
+ Type.new(resolved_name)
175
+ end
176
+
177
+ # Resolves the nesting and returns a singleton type (appends `::<Last>`)
178
+ #: (Array[String] nesting) -> Type
179
+ def resolve_singleton_type_from_nesting(nesting)
180
+ resolved_name = resolve_nesting_fully_qualified_name(nesting)
181
+ last_part = resolved_name.split("::").last #: as !nil
182
+ Type.new("#{resolved_name}::<#{last_part}>")
183
+ end
184
+
185
+ # Resolves the innermost constant in the nesting through the graph, handling compact-path definitions
186
+ # like `class Bar::Baz` inside a different module where the lexical nesting doesn't reflect the true
187
+ # constant hierarchy. Falls back to lexical joining if resolution fails.
188
+ #: (Array[String] nesting) -> String
189
+ def resolve_nesting_fully_qualified_name(nesting)
190
+ nesting_parts = nesting.dup
191
+ trailing_singletons = [] #: Array[String]
192
+
193
+ nesting_parts.reverse_each do |part|
194
+ break unless part.start_with?("<")
195
+
196
+ popped = nesting_parts.pop #: as !nil
197
+ trailing_singletons.unshift(popped)
198
+ end
199
+
200
+ if nesting_parts.any?
201
+ resolved = @graph.resolve_constant(
202
+ nesting_parts.last, #: as !nil
203
+ nesting_parts[0...-1], #: as !nil
204
+ )
205
+
206
+ if resolved
207
+ parts = resolved.name.split("::") + trailing_singletons
208
+ return parts.join("::")
209
+ end
210
+ end
211
+
212
+ # Fallback to lexical joining if resolution fails
213
+ nesting.flat_map { |part| part.split("::") }.join("::")
214
+ end
215
+
216
+ #: (String, Array[String]) -> Type?
217
+ def resolve_receiver_singleton_type(receiver_name, nesting)
218
+ receiver_declaration = @graph.resolve_constant(receiver_name, nesting)
219
+ return unless receiver_declaration.is_a?(Rubydex::Namespace)
220
+
221
+ singleton = receiver_declaration.singleton_class
222
+ return unless singleton
223
+
224
+ Type.new(singleton.name)
147
225
  end
148
226
 
149
227
  #: (NodeContext node_context) -> Type?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0.beta1
4
+ version: 0.27.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
@@ -69,14 +69,20 @@ dependencies:
69
69
  requirements:
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
- version: 0.1.0.beta1
72
+ version: 0.2.0
73
+ - - "<"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.0
73
76
  type: :runtime
74
77
  prerelease: false
75
78
  version_requirements: !ruby/object:Gem::Requirement
76
79
  requirements:
77
80
  - - "~>"
78
81
  - !ruby/object:Gem::Version
79
- version: 0.1.0.beta1
82
+ version: 0.2.0
83
+ - - "<"
84
+ - !ruby/object:Gem::Version
85
+ version: 0.3.0
80
86
  description: An opinionated language server for Ruby
81
87
  email:
82
88
  - ruby@shopify.com
@@ -98,18 +104,6 @@ files:
98
104
  - lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb
99
105
  - lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb
100
106
  - lib/ruby-lsp.rb
101
- - lib/ruby_indexer/lib/ruby_indexer/configuration.rb
102
- - lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb
103
- - lib/ruby_indexer/lib/ruby_indexer/enhancement.rb
104
- - lib/ruby_indexer/lib/ruby_indexer/entry.rb
105
- - lib/ruby_indexer/lib/ruby_indexer/index.rb
106
- - lib/ruby_indexer/lib/ruby_indexer/location.rb
107
- - lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
108
- - lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb
109
- - lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb
110
- - lib/ruby_indexer/lib/ruby_indexer/uri.rb
111
- - lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb
112
- - lib/ruby_indexer/ruby_indexer.rb
113
107
  - lib/ruby_lsp/addon.rb
114
108
  - lib/ruby_lsp/base_server.rb
115
109
  - lib/ruby_lsp/client_capabilities.rb
@@ -182,23 +176,23 @@ files:
182
176
  - lib/ruby_lsp/response_builders/signature_help.rb
183
177
  - lib/ruby_lsp/response_builders/test_collection.rb
184
178
  - lib/ruby_lsp/ruby_document.rb
179
+ - lib/ruby_lsp/rubydex/declaration.rb
185
180
  - lib/ruby_lsp/rubydex/definition.rb
186
181
  - lib/ruby_lsp/rubydex/reference.rb
182
+ - lib/ruby_lsp/rubydex/signature.rb
187
183
  - lib/ruby_lsp/scope.rb
188
184
  - lib/ruby_lsp/scripts/compose_bundle.rb
189
185
  - lib/ruby_lsp/scripts/compose_bundle_windows.rb
190
186
  - lib/ruby_lsp/server.rb
191
187
  - lib/ruby_lsp/setup_bundler.rb
192
- - lib/ruby_lsp/static_docs.rb
193
188
  - lib/ruby_lsp/store.rb
194
189
  - lib/ruby_lsp/test_helper.rb
195
190
  - lib/ruby_lsp/test_reporters/lsp_reporter.rb
196
191
  - lib/ruby_lsp/test_reporters/minitest_reporter.rb
197
192
  - lib/ruby_lsp/test_reporters/test_unit_reporter.rb
198
193
  - lib/ruby_lsp/type_inferrer.rb
194
+ - lib/ruby_lsp/uri.rb
199
195
  - lib/ruby_lsp/utils.rb
200
- - static_docs/break.md
201
- - static_docs/yield.md
202
196
  homepage: https://github.com/Shopify/ruby-lsp
203
197
  licenses:
204
198
  - MIT