Skip to content

Commit 2beae82

Browse files
committed
Don’t catch CancellationError for document diagnostics
We were catching errors during diagnostic generation because VS Code will not request diagnostics again if SourceKit-LSP returns an error to any diagnostic request. We were, however, a little over-eager when doing this and also caught cancellation errors, which means that if the user made multiple edits in quick succession (which would cancel the diagnostics request from the first edit), we would return empty diagnostics, clearing the displayed diagnostics.
1 parent d439d12 commit 2beae82

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,16 @@ public final class TestSourceKitLSPClient: MessageHandler {
206206
///
207207
/// This version of the `send` function should only be used if some action needs to be performed after the request is
208208
/// sent but before it returns a result.
209-
public func send<R: RequestType>(_ request: R, completionHandler: @escaping (LSPResult<R.Response>) -> Void) {
210-
server.handle(request, id: .number(Int(nextRequestID.fetchAndIncrement()))) { result in
209+
@discardableResult
210+
public func send<R: RequestType>(
211+
_ request: R,
212+
completionHandler: @escaping (LSPResult<R.Response>) -> Void
213+
) -> RequestID {
214+
let requestID = RequestID.number(Int(nextRequestID.fetchAndIncrement()))
215+
server.handle(request, id: requestID) { result in
211216
completionHandler(result)
212217
}
218+
return requestID
213219
}
214220

215221
/// Send the notification to `server`.

Sources/SourceKitLSP/Swift/SwiftLanguageService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,8 @@ extension SwiftLanguageService {
888888
buildSettings: buildSettings
889889
)
890890
return .full(diagnosticReport)
891+
} catch let error as CancellationError {
892+
throw error
891893
} catch {
892894
// VS Code does not request diagnostics again for a document if the diagnostics request failed.
893895
// Since sourcekit-lsp usually recovers from failures (e.g. after sourcekitd crashes), this is undesirable.

Tests/SourceKitLSPTests/PullDiagnosticsTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,32 @@ final class PullDiagnosticsTests: XCTestCase {
309309
diagnosticRequestSent.value = true
310310
try await fulfillmentOfOrThrow([receivedDiagnostics])
311311
}
312+
313+
func testDontReturnEmptyDiagnosticsIfDiagnosticRequestIsCancelled() async throws {
314+
let diagnosticRequestCancelled = self.expectation(description: "diagnostic request cancelled")
315+
var serverOptions = SourceKitLSPServer.Options.testDefault
316+
serverOptions.indexTestHooks.preparationTaskDidStart = { _ in
317+
await self.fulfillment(of: [diagnosticRequestCancelled], timeout: defaultTimeout)
318+
}
319+
let project = try await SwiftPMTestProject(
320+
files: [
321+
"Lib.swift": "let x: String = 1"
322+
],
323+
serverOptions: serverOptions,
324+
enableBackgroundIndexing: true,
325+
pollIndex: false
326+
)
327+
let (uri, _) = try project.openDocument("Lib.swift")
328+
329+
let diagnosticResponseReceived = self.expectation(description: "Received diagnostic response")
330+
let requestID = project.testClient.send(
331+
DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri))
332+
) { result in
333+
XCTAssertEqual(result.failure?.code, .cancelled)
334+
diagnosticResponseReceived.fulfill()
335+
}
336+
project.testClient.send(CancelRequestNotification(id: requestID))
337+
diagnosticRequestCancelled.fulfill()
338+
try await fulfillmentOfOrThrow([diagnosticResponseReceived])
339+
}
312340
}

0 commit comments

Comments
 (0)