Skip to content

Commit a61a285

Browse files
authored
Merge pull request swiftlang#243 from DavidGoldman/letsgetvirtual
Disable diagnostics for blacklisted document schemes
2 parents 9abe3ff + bb62772 commit a61a285

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

Sources/LanguageServerProtocol/SupportTypes/DocumentURI.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public struct DocumentURI: Codable, Hashable {
2424
}
2525
}
2626

27+
/// The document's URL scheme, if present.
28+
public var scheme: String? {
29+
return storage.scheme
30+
}
31+
2732
/// Returns a filepath if the URI is a URL. If the URI is not a URL, returns
2833
/// the full URI as a fallback.
2934
/// This value is intended to be used when interacting with sourcekitd which

Sources/SourceKit/sourcekitd/SwiftLanguageServer.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ fileprivate extension Range {
3737
}
3838
}
3939

40+
/// Explicitly blacklisted `DocumentURI` schemes.
41+
fileprivate let excludedDocumentURISchemes: [String] = [
42+
"git",
43+
"hg",
44+
]
45+
46+
/// Returns true if diagnostics should be emitted for the given document.
47+
///
48+
/// Some editors (like Visual Studio Code) use non-file URLs to manage source control diff bases
49+
/// for the active document, which can lead to duplicate diagnostics in the Problems view.
50+
/// As a workaround we explicitly blacklist those URIs and don't emit diagnostics for them.
51+
///
52+
/// Additionally, as of Xcode 11.4, sourcekitd does not properly handle non-file URLs when
53+
/// the `-working-directory` argument is passed since it incorrectly applies it to the input
54+
/// argument but not the internal primary file, leading sourcekitd to believe that the input
55+
/// file is missing.
56+
fileprivate func diagnosticsEnabled(for document: DocumentURI) -> Bool {
57+
guard let scheme = document.scheme else { return true }
58+
return !excludedDocumentURISchemes.contains(scheme)
59+
}
60+
4061
public final class SwiftLanguageServer: ToolchainLanguageServer {
4162

4263
/// The server's request queue, used to serialize requests and responses to `sourcekitd`.
@@ -79,6 +100,12 @@ public final class SwiftLanguageServer: ToolchainLanguageServer {
79100
response: SKResponseDictionary,
80101
for snapshot: DocumentSnapshot)
81102
{
103+
let documentUri = snapshot.document.uri
104+
guard diagnosticsEnabled(for: documentUri) else {
105+
log("Ignoring diagnostics for blacklisted file \(documentUri.pseudoPath)", level: .debug)
106+
return
107+
}
108+
82109
let stageUID: sourcekitd_uid_t? = response[sourcekitd.keys.diagnostic_stage]
83110
let stage = stageUID.flatMap { DiagnosticStage($0, sourcekitd: sourcekitd) } ?? .sema
84111

Tests/SourceKitTests/LocalSwiftTests.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,41 @@ final class LocalSwiftTests: XCTestCase {
307307
})
308308
}
309309

310+
func testExcludedDocumentSchemeDiagnostics() {
311+
let includedURL = URL(fileURLWithPath: "/a.swift")
312+
let includedURI = DocumentURI(includedURL)
313+
314+
let excludedURI = DocumentURI(string: "git:/a.swift")
315+
316+
let text = """
317+
func
318+
"""
319+
320+
sk.allowUnexpectedNotification = false
321+
322+
// Open the excluded URI first so our later notification handlers can confirm
323+
// that no diagnostics were emitted for this excluded URI.
324+
sk.send(DidOpenTextDocumentNotification(textDocument: TextDocumentItem(
325+
uri: excludedURI,
326+
language: .swift,
327+
version: 1,
328+
text: text
329+
)))
330+
331+
sk.sendNoteSync(DidOpenTextDocumentNotification(textDocument: TextDocumentItem(
332+
uri: includedURI,
333+
language: .swift,
334+
version: 1,
335+
text: text
336+
)), { (note: Notification<PublishDiagnosticsNotification>) in
337+
log("Received diagnostics for open - syntactic")
338+
XCTAssertEqual(note.params.uri, includedURI)
339+
}, { (note: Notification<PublishDiagnosticsNotification>) in
340+
log("Received diagnostics for open - semantic")
341+
XCTAssertEqual(note.params.uri, includedURI)
342+
})
343+
}
344+
310345
func testCrossFileDiagnostics() {
311346
let urlA = URL(fileURLWithPath: "/a.swift")
312347
let urlB = URL(fileURLWithPath: "/b.swift")

Tests/SourceKitTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ extension LocalSwiftTests {
109109
("testEditing", testEditing),
110110
("testEditingNonURL", testEditingNonURL),
111111
("testEditorPlaceholderParsing", testEditorPlaceholderParsing),
112+
("testExcludedDocumentSchemeDiagnostics", testExcludedDocumentSchemeDiagnostics),
112113
("testFixitInsert", testFixitInsert),
113114
("testFixitsAreIncludedInPublishDiagnostics", testFixitsAreIncludedInPublishDiagnostics),
114115
("testFixitsAreIncludedInPublishDiagnosticsNotes", testFixitsAreIncludedInPublishDiagnosticsNotes),

0 commit comments

Comments
 (0)