Skip to content

Commit 7a65050

Browse files
committed
Don’t fatalError if encoding a message to the client could not be encoded
1 parent 34acdb0 commit 7a65050

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

Sources/LanguageServerProtocolJSONRPC/JSONRPCConnection.swift

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,13 @@ public final class JSONRPCConnection: Connection {
230230
}
231231
}
232232

233-
/// Send a notification to the client that informs the user about a message decoding error and tells them to file an
234-
/// issue.
233+
/// Send a notification to the client that informs the user about a message encoding or decoding error and asks them
234+
/// to file an issue.
235235
///
236236
/// `message` describes what has gone wrong to the user.
237237
///
238238
/// - Important: Must be called on `queue`
239-
private func sendMessageDecodingErrorNotificationToClient(message: String) {
239+
private func sendMessageCodingErrorNotificationToClient(message: String) {
240240
dispatchPrecondition(condition: .onQueue(queue))
241241
let showMessage = ShowMessageNotification(
242242
type: .error,
@@ -302,7 +302,7 @@ public final class JSONRPCConnection: Connection {
302302
// That way the user at least knows that something is going wrong even if the client never gets a response
303303
// for the request.
304304
logger.fault("Ignoring request because we failed to decode the request and don't have a request ID")
305-
sendMessageDecodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a request")
305+
sendMessageCodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a request")
306306
return nil
307307
case .response:
308308
if let id = error.id {
@@ -338,19 +338,19 @@ public final class JSONRPCConnection: Connection {
338338
// `textDocument/didChange` will result in an out-of-sync state between the editor and sourcekit-lsp.
339339
// Warn the user about the error.
340340
logger.fault("Ignoring notification that may cause corrupted behavior")
341-
sendMessageDecodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a notification")
341+
sendMessageCodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a notification")
342342
return nil
343343
case .unknown:
344344
// We don't know what has gone wrong. This could be any level of badness. Inform the user about it.
345345
logger.fault("Ignoring unknown message")
346-
sendMessageDecodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a message")
346+
sendMessageCodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode a message")
347347
return nil
348348
}
349349
} catch {
350350
// We don't know what has gone wrong. This could be any level of badness. Inform the user about it and ignore the
351351
// message.
352352
logger.fault("Ignoring unknown message")
353-
sendMessageDecodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode an unknown message")
353+
sendMessageCodingErrorNotificationToClient(message: "sourcekit-lsp failed to decode an unknown message")
354354
return nil
355355
}
356356
}
@@ -391,7 +391,7 @@ public final class JSONRPCConnection: Connection {
391391
// We failed to parse the message header. There isn't really much we can do to recover because we lost our
392392
// anchor in the stream where new messages start. Crashing and letting ourselves be restarted by the client is
393393
// probably the best option.
394-
sendMessageDecodingErrorNotificationToClient(message: "Failed to find next message in connection to editor")
394+
sendMessageCodingErrorNotificationToClient(message: "Failed to find next message in connection to editor")
395395
fatalError("fatal error encountered while splitting JSON RPC messages \(error)")
396396
}
397397

@@ -481,8 +481,40 @@ public final class JSONRPCConnection: Connection {
481481
do {
482482
data = try encoder.encode(message)
483483
} catch {
484-
// FIXME: attempt recovery?
485-
fatalError("unexpected error while encoding response: \(error)")
484+
logger.fault("Failed to encode message: \(error.forLogging)")
485+
logger.fault("Malformed message: \(String(describing: message))")
486+
switch message {
487+
case .notification(_):
488+
// We want to send a notification to the editor but failed to encode it. Since dropping the notification might
489+
// result in getting out-of-sync state-wise with the editor (eg. for work progress notifications), inform the
490+
// user about it.
491+
sendMessageCodingErrorNotificationToClient(
492+
message: "sourcekit-lsp failed to encode a notification to the editor"
493+
)
494+
return
495+
case .request(_, _):
496+
// We want to send a notification to the editor but failed to encode it. We don't know the `reply` handle for
497+
// the request at this point so we can't synthesize an errorResponse for the request. This means that the
498+
// request will never receive a reply. Inform the user about it.
499+
sendMessageCodingErrorNotificationToClient(
500+
message: "sourcekit-lsp failed to encode a request to the editor"
501+
)
502+
return
503+
case .response(_, _):
504+
// The editor sent a request to sourcekit-lsp, which failed but we can't serialize the result back to the
505+
// client. This means that the request will never receive a reply. Inform the user about it and accept that
506+
// we'll never send a reply.
507+
sendMessageCodingErrorNotificationToClient(
508+
message: "sourcekit-lsp failed to encode a response to the editor"
509+
)
510+
return
511+
case .errorResponse(_, _):
512+
// Same as `.response`. Has an optional `id`, so can't share the case.
513+
sendMessageCodingErrorNotificationToClient(
514+
message: "sourcekit-lsp failed to encode an error response to the editor"
515+
)
516+
return
517+
}
486518
}
487519

488520
var dispatchData = DispatchData.empty

0 commit comments

Comments
 (0)