Skip to content

Commit 96e0e48

Browse files
committed
Make DocumentManager.latestSnapshot throw if no snapshot exists for the URI
This simplifies most calls that would log an error + return an empty response if no document was found.
1 parent 182deb7 commit 96e0e48

14 files changed

+41
-106
lines changed

Sources/SourceKitLSP/DocumentManager.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ public final class DocumentManager {
184184
}
185185
}
186186

187-
public func latestSnapshot(_ uri: DocumentURI) -> DocumentSnapshot? {
188-
return queue.sync {
187+
public func latestSnapshot(_ uri: DocumentURI) throws -> DocumentSnapshot {
188+
return try queue.sync {
189189
guard let document = documents[uri] else {
190-
return nil
190+
throw ResponseError.unknown("Failed to find snapshot for '\(uri)'")
191191
}
192192
return document.latestSnapshot
193193
}

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ public actor SourceKitServer {
456456
guard workspace.documentService[documentUri] === languageService else {
457457
continue
458458
}
459-
guard let snapshot = self.documentManager.latestSnapshot(documentUri) else {
459+
guard let snapshot = try? self.documentManager.latestSnapshot(documentUri) else {
460460
// The document has been closed since we retrieved its URI. We don't care about it anymore.
461461
continue
462462
}
@@ -1293,7 +1293,7 @@ extension SourceKitServer {
12931293
let oldWorkspace = preChangeWorkspaces[docUri]
12941294
let newWorkspace = await self.workspaceForDocument(uri: docUri)
12951295
if newWorkspace !== oldWorkspace {
1296-
guard let snapshot = documentManager.latestSnapshot(docUri) else {
1296+
guard let snapshot = try? documentManager.latestSnapshot(docUri) else {
12971297
continue
12981298
}
12991299
if let oldWorkspace = oldWorkspace {

Sources/SourceKitLSP/Swift/CodeCompletion.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ import SourceKitD
1818
extension SwiftLanguageServer {
1919

2020
public func completion(_ req: CompletionRequest) async throws -> CompletionList {
21-
guard let snapshot = documentManager.latestSnapshot(req.textDocument.uri) else {
22-
logger.error("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
23-
return CompletionList(isIncomplete: true, items: [])
24-
}
21+
let snapshot = try documentManager.latestSnapshot(req.textDocument.uri)
2522

2623
guard let completionPos = adjustCompletionLocation(req.position, in: snapshot) else {
2724
logger.error("invalid completion position \(req.position, privacy: .public)")

Sources/SourceKitLSP/Swift/CursorInfo.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ struct CursorInfo {
5050

5151
/// An error from a cursor info request.
5252
enum CursorInfoError: Error, Equatable {
53-
54-
/// The given URL is not a known document.
55-
case unknownDocument(DocumentURI)
56-
5753
/// The given range is not valid in the document snapshot.
5854
case invalidRange(Range<Position>)
5955

@@ -64,8 +60,6 @@ enum CursorInfoError: Error, Equatable {
6460
extension CursorInfoError: CustomStringConvertible {
6561
var description: String {
6662
switch self {
67-
case .unknownDocument(let url):
68-
return "failed to find snapshot for url \(url)"
6963
case .invalidRange(let range):
7064
return "invalid range \(range)"
7165
case .responseError(let error):
@@ -90,9 +84,7 @@ extension SwiftLanguageServer {
9084
_ range: Range<Position>,
9185
additionalParameters appendAdditionalParameters: ((SKDRequestDictionary) -> Void)? = nil
9286
) async throws -> CursorInfo? {
93-
guard let snapshot = documentManager.latestSnapshot(uri) else {
94-
throw CursorInfoError.unknownDocument(uri)
95-
}
87+
let snapshot = try documentManager.latestSnapshot(uri)
9688

9789
guard let offsetRange = snapshot.utf8OffsetRange(of: range) else {
9890
throw CursorInfoError.invalidRange(range)

Sources/SourceKitLSP/Swift/DocumentSymbols.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ import LSPLogging
1616

1717
extension SwiftLanguageServer {
1818
public func documentSymbol(_ req: DocumentSymbolRequest) async throws -> DocumentSymbolResponse? {
19-
guard let snapshot = self.documentManager.latestSnapshot(req.textDocument.uri) else {
20-
logger.error("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
21-
return nil
22-
}
19+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
2320

2421
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
2522

Sources/SourceKitLSP/Swift/OpenInterface.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extension SwiftLanguageServer {
2929
let interfaceFilePath = self.generatedInterfacesPath.appendingPathComponent("\(name).swiftinterface")
3030
let interfaceDocURI = DocumentURI(interfaceFilePath)
3131
// has interface already been generated
32-
if let snapshot = self.documentManager.latestSnapshot(interfaceDocURI) {
32+
if let snapshot = try? self.documentManager.latestSnapshot(interfaceDocURI) {
3333
return await self.interfaceDetails(request: request, uri: interfaceDocURI, snapshot: snapshot, symbol: symbol)
3434
} else {
3535
// generate interface

Sources/SourceKitLSP/Swift/SemanticRefactoring.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ struct SemanticRefactoring {
8484

8585
/// An error from a semantic refactoring request.
8686
enum SemanticRefactoringError: Error {
87-
88-
/// The given URL is not a known document.
89-
case unknownDocument(DocumentURI)
90-
9187
/// The given position range is invalid.
9288
case invalidRange(Range<Position>)
9389

@@ -104,8 +100,6 @@ enum SemanticRefactoringError: Error {
104100
extension SemanticRefactoringError: CustomStringConvertible {
105101
var description: String {
106102
switch self {
107-
case .unknownDocument(let url):
108-
return "failed to find snapshot for url \(url)"
109103
case .invalidRange(let range):
110104
return "failed to refactor due to invalid range: \(range)"
111105
case .failedToRetrieveOffset(let range):
@@ -134,9 +128,7 @@ extension SwiftLanguageServer {
134128
let keys = self.keys
135129

136130
let uri = refactorCommand.textDocument.uri
137-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
138-
throw SemanticRefactoringError.unknownDocument(uri)
139-
}
131+
let snapshot = try self.documentManager.latestSnapshot(uri)
140132
guard let offsetRange = snapshot.utf8OffsetRange(of: refactorCommand.positionRange) else {
141133
throw SemanticRefactoringError.failedToRetrieveOffset(refactorCommand.positionRange)
142134
}

Sources/SourceKitLSP/Swift/SemanticTokens.swift

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,7 @@ extension SwiftLanguageServer {
7171
public func documentSemanticTokens(
7272
_ req: DocumentSemanticTokensRequest
7373
) async throws -> DocumentSemanticTokensResponse? {
74-
let uri = req.textDocument.uri
75-
76-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
77-
logger.error("failed to find snapshot for uri \(uri.forLogging)")
78-
return DocumentSemanticTokensResponse(data: [])
79-
}
74+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
8075

8176
let tokens = await mergedAndSortedTokens(for: snapshot)
8277
let encodedTokens = tokens.lspEncoded
@@ -93,15 +88,9 @@ extension SwiftLanguageServer {
9388
public func documentSemanticTokensRange(
9489
_ req: DocumentSemanticTokensRangeRequest
9590
) async throws -> DocumentSemanticTokensResponse? {
96-
let uri = req.textDocument.uri
97-
let range = req.range
98-
99-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
100-
logger.error("failed to find snapshot for uri \(uri.forLogging)")
101-
return DocumentSemanticTokensResponse(data: [])
102-
}
91+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
10392

104-
let tokens = await mergedAndSortedTokens(for: snapshot, in: range)
93+
let tokens = await mergedAndSortedTokens(for: snapshot, in: req.range)
10594
let encodedTokens = tokens.lspEncoded
10695

10796
return DocumentSemanticTokensResponse(data: encodedTokens)

Sources/SourceKitLSP/Swift/SwiftLanguageServer.swift

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ extension SwiftLanguageServer {
293293

294294
public func documentUpdatedBuildSettings(_ uri: DocumentURI) async {
295295
// We may not have a snapshot if this is called just before `openDocument`.
296-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
296+
guard let snapshot = try? self.documentManager.latestSnapshot(uri) else {
297297
return
298298
}
299299

@@ -303,7 +303,7 @@ extension SwiftLanguageServer {
303303
}
304304

305305
public func documentDependenciesUpdated(_ uri: DocumentURI) async {
306-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
306+
guard let snapshot = try? self.documentManager.latestSnapshot(uri) else {
307307
return
308308
}
309309

@@ -530,10 +530,7 @@ extension SwiftLanguageServer {
530530
}
531531

532532
public func documentColor(_ req: DocumentColorRequest) async throws -> [ColorInformation] {
533-
guard let snapshot = self.documentManager.latestSnapshot(req.textDocument.uri) else {
534-
logger.error("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
535-
return []
536-
}
533+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
537534

538535
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
539536

@@ -605,12 +602,7 @@ extension SwiftLanguageServer {
605602
}
606603

607604
public func documentSymbolHighlight(_ req: DocumentHighlightRequest) async throws -> [DocumentHighlight]? {
608-
let keys = self.keys
609-
610-
guard let snapshot = self.documentManager.latestSnapshot(req.textDocument.uri) else {
611-
logger.error("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
612-
return nil
613-
}
605+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
614606

615607
guard let offset = snapshot.utf8Offset(of: req.position) else {
616608
logger.error("invalid position \(req.position, privacy: .public)")
@@ -658,11 +650,7 @@ extension SwiftLanguageServer {
658650

659651
public func foldingRange(_ req: FoldingRangeRequest) async throws -> [FoldingRange]? {
660652
let foldingRangeCapabilities = capabilityRegistry.clientCapabilities.textDocument?.foldingRange
661-
let uri = req.textDocument.uri
662-
guard let snapshot = self.documentManager.latestSnapshot(uri) else {
663-
logger.error("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
664-
return nil
665-
}
653+
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
666654

667655
let sourceFile = await syntaxTreeManager.syntaxTree(for: snapshot)
668656

@@ -1059,9 +1047,7 @@ extension SwiftLanguageServer {
10591047
private func fullDocumentDiagnosticReport(
10601048
_ req: DocumentDiagnosticsRequest
10611049
) async throws -> RelatedFullDocumentDiagnosticReport {
1062-
guard let snapshot = documentManager.latestSnapshot(req.textDocument.uri) else {
1063-
throw ResponseError.unknown("failed to find snapshot for url \(req.textDocument.uri.forLogging)")
1064-
}
1050+
let snapshot = try documentManager.latestSnapshot(req.textDocument.uri)
10651051
guard let buildSettings = await self.buildSettings(for: req.textDocument.uri), !buildSettings.isFallback else {
10661052
logger.log(
10671053
"Producing syntactic diagnostics from the built-in swift-syntax because we have fallback arguments"
@@ -1087,7 +1073,7 @@ extension SwiftLanguageServer {
10871073
let dict = try await self.sourcekitd.send(skreq)
10881074

10891075
try Task.checkCancellation()
1090-
guard documentManager.latestSnapshot(req.textDocument.uri)?.id == snapshot.id else {
1076+
guard (try? documentManager.latestSnapshot(req.textDocument.uri).id) == snapshot.id else {
10911077
// Check that the document wasn't modified while we were getting diagnostics. This could happen because we are
10921078
// calling `fullDocumentDiagnosticReport` from `publishDiagnosticsIfNeeded` outside of `messageHandlingQueue`
10931079
// and thus a concurrent edit is possible while we are waiting for the sourcekitd request to return a result.

Sources/SourceKitLSP/Swift/VariableTypeInfo.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,6 @@ struct VariableTypeInfo {
7676
}
7777
}
7878

79-
enum VariableTypeInfoError: Error, Equatable {
80-
/// The given URL is not a known document.
81-
case unknownDocument(DocumentURI)
82-
83-
/// The underlying sourcekitd request failed with the given error.
84-
case responseError(ResponseError)
85-
}
86-
8779
extension SwiftLanguageServer {
8880
/// Provides typed variable declarations in a document.
8981
///
@@ -93,11 +85,7 @@ extension SwiftLanguageServer {
9385
_ uri: DocumentURI,
9486
_ range: Range<Position>? = nil
9587
) async throws -> [VariableTypeInfo] {
96-
guard let snapshot = documentManager.latestSnapshot(uri) else {
97-
throw VariableTypeInfoError.unknownDocument(uri)
98-
}
99-
100-
let keys = self.keys
88+
let snapshot = try documentManager.latestSnapshot(uri)
10189

10290
let skreq = SKDRequestDictionary(sourcekitd: sourcekitd)
10391
skreq[keys.request] = requests.variable_type

Tests/SourceKitDTests/CrashRecoveryTests.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ final class CrashRecoveryTests: XCTestCase {
100100
try await fulfillmentOfOrThrow([sourcekitdCrashed], timeout: 5)
101101
try await fulfillmentOfOrThrow([sourcekitdRestarted], timeout: 30)
102102

103-
// Check that we have syntactic functionality again
104-
105-
_ = try await testClient.send(FoldingRangeRequest(textDocument: TextDocumentIdentifier(uri)))
106-
107103
// sourcekitd's semantic request timer is only started when the first semantic request comes in.
108104
// Send a hover request (which will fail) to trigger that timer.
109105
// Afterwards wait for semantic functionality to be restored.

Tests/SourceKitLSPTests/BuildSystemTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ final class BuildSystemTests: XCTestCase {
143143

144144
let diags = try await testClient.nextDiagnosticsNotification()
145145
XCTAssertEqual(diags.diagnostics.count, 1)
146-
XCTAssertEqual(text, documentManager.latestSnapshot(doc)!.text)
146+
XCTAssertEqual(text, try documentManager.latestSnapshot(doc).text)
147147

148148
// Modify the build settings and inform the delegate.
149149
// This should trigger a new publish diagnostics and we should no longer have errors.
@@ -155,7 +155,7 @@ final class BuildSystemTests: XCTestCase {
155155
var receivedCorrectDiagnostic = false
156156
for _ in 0..<Int(defaultTimeout) {
157157
let refreshedDiags = try await testClient.nextDiagnosticsNotification(timeout: 1)
158-
if refreshedDiags.diagnostics.count == 0, text == documentManager.latestSnapshot(doc)!.text {
158+
if refreshedDiags.diagnostics.count == 0, try text == documentManager.latestSnapshot(doc).text {
159159
receivedCorrectDiagnostic = true
160160
break
161161
}
@@ -182,7 +182,7 @@ final class BuildSystemTests: XCTestCase {
182182
testClient.openDocument(text, uri: doc)
183183
let diags1 = try await testClient.nextDiagnosticsNotification()
184184
XCTAssertEqual(diags1.diagnostics.count, 1)
185-
XCTAssertEqual(text, documentManager.latestSnapshot(doc)!.text)
185+
XCTAssertEqual(text, try documentManager.latestSnapshot(doc).text)
186186

187187
// Modify the build settings and inform the delegate.
188188
// This should trigger a new publish diagnostics and we should no longer have errors.
@@ -218,7 +218,7 @@ final class BuildSystemTests: XCTestCase {
218218
let openDiags = try await testClient.nextDiagnosticsNotification()
219219
// Expect diagnostics to be withheld.
220220
XCTAssertEqual(openDiags.diagnostics.count, 0)
221-
XCTAssertEqual(text, documentManager.latestSnapshot(doc)!.text)
221+
XCTAssertEqual(text, try documentManager.latestSnapshot(doc).text)
222222

223223
// Modify the build settings and inform the delegate.
224224
// This should trigger a new publish diagnostics and we should see a diagnostic.
@@ -229,7 +229,7 @@ final class BuildSystemTests: XCTestCase {
229229

230230
let refreshedDiags = try await testClient.nextDiagnosticsNotification()
231231
XCTAssertEqual(refreshedDiags.diagnostics.count, 1)
232-
XCTAssertEqual(text, documentManager.latestSnapshot(doc)!.text)
232+
XCTAssertEqual(text, try documentManager.latestSnapshot(doc).text)
233233
}
234234

235235
func testSwiftDocumentFallbackWithholdsSemanticDiagnostics() async throws {
@@ -254,7 +254,7 @@ final class BuildSystemTests: XCTestCase {
254254
testClient.openDocument(text, uri: doc)
255255
let openDiags = try await testClient.nextDiagnosticsNotification()
256256
XCTAssertEqual(openDiags.diagnostics.count, 1)
257-
XCTAssertEqual(text, documentManager.latestSnapshot(doc)!.text)
257+
XCTAssertEqual(text, try documentManager.latestSnapshot(doc).text)
258258

259259
// Swap from fallback settings to primary build system settings.
260260
buildSystem.buildSettingsByFile[doc] = primarySettings

0 commit comments

Comments
 (0)