Skip to content

Commit 14804fb

Browse files
authored
Merge pull request swiftlang#169 from benlangmuir/diag-cache-fix
[diagnostics] Fix caching of diagnostics across files and reopens
2 parents c6ea6ea + 56bc7cc commit 14804fb

File tree

3 files changed

+110
-8
lines changed

3 files changed

+110
-8
lines changed

Sources/SourceKit/sourcekitd/SwiftLanguageServer.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public final class SwiftLanguageServer: LanguageServer {
2929
// FIXME: ideally we wouldn't need separate management from a parent server in the same process.
3030
var documentManager: DocumentManager
3131

32-
var currentDiagnostics: [CachedDiagnostic] = []
32+
var currentDiagnostics: [URL: [CachedDiagnostic]] = [:]
3333

3434
var buildSettingsByFile: [URL: FileBuildSettings] = [:]
3535

@@ -92,12 +92,14 @@ public final class SwiftLanguageServer: LanguageServer {
9292
return true
9393
}
9494

95-
let result = mergeDiagnostics(old: currentDiagnostics, new: newDiags, stage: stage)
96-
currentDiagnostics = result
95+
let document = snapshot.document.url
9796

98-
client.send(PublishDiagnostics(
99-
url: snapshot.document.url,
100-
diagnostics: result.map { $0.diagnostic }))
97+
let result = mergeDiagnostics(
98+
old: currentDiagnostics[document] ?? [],
99+
new: newDiags, stage: stage)
100+
currentDiagnostics[document] = result
101+
102+
client.send(PublishDiagnostics(url: document, diagnostics: result.map { $0.diagnostic }))
101103
}
102104

103105
func handleDocumentUpdate(url: URL) {
@@ -275,9 +277,9 @@ extension SwiftLanguageServer {
275277

276278
let url = note.params.textDocument.url
277279

278-
// Clear the build settings since there's no point in caching
279-
// them for a closed file.
280+
// Clear settings that should not be cached for closed documents.
280281
buildSettingsByFile[url] = nil
282+
currentDiagnostics[url] = nil
281283

282284
let req = SKRequestDictionary(sourcekitd: sourcekitd)
283285
req[keys.request] = requests.editor_close

Tests/SourceKitTests/LocalSwiftTests.swift

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,104 @@ final class LocalSwiftTests: XCTestCase {
164164
})
165165
}
166166

167+
func testCrossFileDiagnostics() {
168+
let urlA = URL(fileURLWithPath: "/a.swift")
169+
let urlB = URL(fileURLWithPath: "/b.swift")
170+
171+
sk.allowUnexpectedNotification = false
172+
173+
sk.sendNoteSync(DidOpenTextDocument(textDocument: TextDocumentItem(
174+
url: urlA, language: .swift, version: 12,
175+
text: """
176+
_ = foo()
177+
"""
178+
)), { (note: Notification<PublishDiagnostics>) in
179+
log("Received diagnostics for open - syntactic")
180+
// 1 = semantic update finished already
181+
// 0 = only syntactic
182+
XCTAssertLessThanOrEqual(note.params.diagnostics.count, 1)
183+
}, { (note: Notification<PublishDiagnostics>) in
184+
log("Received diagnostics for open - semantic")
185+
XCTAssertEqual(note.params.diagnostics.count, 1)
186+
XCTAssertEqual(
187+
note.params.diagnostics.first?.range.lowerBound,
188+
Position(line: 0, utf16index: 4))
189+
})
190+
191+
sk.sendNoteSync(DidOpenTextDocument(textDocument: TextDocumentItem(
192+
url: urlB, language: .swift, version: 12,
193+
text: """
194+
_ = bar()
195+
"""
196+
)), { (note: Notification<PublishDiagnostics>) in
197+
log("Received diagnostics for open - syntactic")
198+
// 1 = semantic update finished already
199+
// 0 = only syntactic
200+
XCTAssertLessThanOrEqual(note.params.diagnostics.count, 1)
201+
}, { (note: Notification<PublishDiagnostics>) in
202+
log("Received diagnostics for open - semantic")
203+
XCTAssertEqual(note.params.diagnostics.count, 1)
204+
XCTAssertEqual(
205+
note.params.diagnostics.first?.range.lowerBound,
206+
Position(line: 0, utf16index: 4))
207+
})
208+
209+
sk.sendNoteSync(DidChangeTextDocument(textDocument: .init(urlA, version: 13), contentChanges: [
210+
.init(range: nil, text: "_ = foo()\n")
211+
]), { (note: Notification<PublishDiagnostics>) in
212+
log("Received diagnostics for edit 1 - syntactic")
213+
XCTAssertEqual(note.params.diagnostics.count, 1)
214+
}, { (note: Notification<PublishDiagnostics>) in
215+
log("Received diagnostics for edit 1 - semantic")
216+
XCTAssertEqual(note.params.diagnostics.count, 1)
217+
})
218+
}
219+
220+
func testDiagnosticsReopen() {
221+
let urlA = URL(fileURLWithPath: "/a.swift")
222+
sk.allowUnexpectedNotification = false
223+
224+
sk.sendNoteSync(DidOpenTextDocument(textDocument: TextDocumentItem(
225+
url: urlA, language: .swift, version: 12,
226+
text: """
227+
_ = foo()
228+
"""
229+
)), { (note: Notification<PublishDiagnostics>) in
230+
log("Received diagnostics for open - syntactic")
231+
// 1 = semantic update finished already
232+
// 0 = only syntactic
233+
XCTAssertLessThanOrEqual(note.params.diagnostics.count, 1)
234+
}, { (note: Notification<PublishDiagnostics>) in
235+
log("Received diagnostics for open - semantic")
236+
XCTAssertEqual(note.params.diagnostics.count, 1)
237+
XCTAssertEqual(
238+
note.params.diagnostics.first?.range.lowerBound,
239+
Position(line: 0, utf16index: 4))
240+
})
241+
242+
sk.send(DidCloseTextDocument(textDocument: .init(urlA)))
243+
244+
sk.sendNoteSync(DidOpenTextDocument(textDocument: TextDocumentItem(
245+
url: urlA, language: .swift, version: 13,
246+
text: """
247+
var
248+
"""
249+
)), { (note: Notification<PublishDiagnostics>) in
250+
log("Received diagnostics for open - syntactic")
251+
// 1 = syntactic, no cached semantic diagnostic from previous version
252+
XCTAssertEqual(note.params.diagnostics.count, 1)
253+
XCTAssertEqual(
254+
note.params.diagnostics.first?.range.lowerBound,
255+
Position(line: 0, utf16index: 3))
256+
}, { (note: Notification<PublishDiagnostics>) in
257+
log("Received diagnostics for open - semantic")
258+
XCTAssertEqual(note.params.diagnostics.count, 1)
259+
XCTAssertEqual(
260+
note.params.diagnostics.first?.range.lowerBound,
261+
Position(line: 0, utf16index: 3))
262+
})
263+
}
264+
167265
func testXMLToMarkdownDeclaration() {
168266
XCTAssertEqual(try! xmlDocumentationToMarkdown("""
169267
<Declaration>func foo(_ bar: <Type usr="fake">Baz</Type>)</Declaration>

Tests/SourceKitTests/XCTestManifests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ extension LocalSwiftTests {
9696
// `swift test --generate-linuxmain`
9797
// to regenerate.
9898
static let __allTests__LocalSwiftTests = [
99+
("testCrossFileDiagnostics", testCrossFileDiagnostics),
100+
("testDiagnosticsReopen", testDiagnosticsReopen),
99101
("testDocumentSymbolHighlight", testDocumentSymbolHighlight),
100102
("testEditing", testEditing),
101103
("testEditorPlaceholderParsing", testEditorPlaceholderParsing),

0 commit comments

Comments
 (0)