Skip to content

Commit 1fb087f

Browse files
authored
Merge pull request #1292 from ahoppen/sourcekitlsp-in-swift-6-mode
Make the `SourceKitLSP` module build in Swift 6 mode
2 parents 0f097e6 + 7e7df04 commit 1fb087f

31 files changed

+232
-157
lines changed

Sources/LSPLogging/Logging.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ public typealias LogLevel = os.OSLogType
2828
public typealias Logger = os.Logger
2929
public typealias Signposter = OSSignposter
3030

31+
#if compiler(<5.11)
32+
extension OSSignposter: @unchecked Sendable {}
33+
extension OSSignpostID: @unchecked Sendable {}
34+
extension OSSignpostIntervalState: @unchecked Sendable {}
35+
#else
36+
extension OSSignposter: @retroactive @unchecked Sendable {}
37+
extension OSSignpostID: @retroactive @unchecked Sendable {}
38+
extension OSSignpostIntervalState: @retroactive @unchecked Sendable {}
39+
#endif
40+
3141
extension os.Logger {
3242
public func makeSignposter() -> Signposter {
3343
return OSSignposter(logger: self)

Sources/LSPLogging/LoggingScope.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public func withLoggingScope<Result>(
8080
/// - SeeAlso: ``withLoggingScope(_:_:)-6qtga``
8181
public func withLoggingScope<Result>(
8282
_ scope: String,
83-
_ operation: () async throws -> Result
83+
@_inheritActorContext _ operation: @Sendable () async throws -> Result
8484
) async rethrows -> Result {
8585
return try await LoggingScope.$_scope.withValue(
8686
scope,

Sources/LSPLogging/NonDarwinLogging.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,14 @@ public struct NonDarwinLogger: Sendable {
361361

362362
// MARK: - Signposter
363363

364-
public struct NonDarwinSignpostID {}
364+
public struct NonDarwinSignpostID: Sendable {}
365365

366-
public struct NonDarwinSignpostIntervalState {}
366+
public struct NonDarwinSignpostIntervalState: Sendable {}
367367

368368
/// A type that is API-compatible to `OSLogMessage` for all uses within sourcekit-lsp.
369369
///
370370
/// Since non-Darwin platforms don't have signposts, the type just has no-op operations.
371-
public struct NonDarwinSignposter {
371+
public struct NonDarwinSignposter: Sendable {
372372
public func makeSignpostID() -> NonDarwinSignpostID {
373373
return NonDarwinSignpostID()
374374
}

Sources/LanguageServerProtocol/Connection.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public protocol MessageHandler: AnyObject, Sendable {
4444
func handle<Request: RequestType>(
4545
_ request: Request,
4646
id: RequestID,
47-
reply: @escaping (LSPResult<Request.Response>) -> Void
47+
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
4848
)
4949
}
5050

@@ -110,7 +110,7 @@ public final class LocalConnection: Connection, @unchecked Sendable {
110110

111111
public func send<Request: RequestType>(
112112
_ request: Request,
113-
reply: @escaping (LSPResult<Request.Response>) -> Void
113+
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
114114
) -> RequestID {
115115
let id = nextRequestID()
116116

Sources/LanguageServerProtocol/Message.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public protocol _RequestType: MessageType {
2424
func _handle(
2525
_ handler: MessageHandler,
2626
id: RequestID,
27-
reply: @escaping (LSPResult<ResponseType>, RequestID) -> Void
27+
reply: @Sendable @escaping (LSPResult<ResponseType>, RequestID) -> Void
2828
)
2929
}
3030

@@ -49,7 +49,7 @@ extension RequestType {
4949
public func _handle(
5050
_ handler: MessageHandler,
5151
id: RequestID,
52-
reply: @escaping (LSPResult<ResponseType>, RequestID) -> Void
52+
reply: @Sendable @escaping (LSPResult<ResponseType>, RequestID) -> Void
5353
) {
5454
handler.handle(self, id: id) { response in
5555
reply(response.map({ $0 as ResponseType }), id)

Sources/LanguageServerProtocol/Requests/CodeActionRequest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
public typealias CodeActionProvider = (CodeActionRequest) async throws -> [CodeAction]
13+
public typealias CodeActionProvider = @Sendable (CodeActionRequest) async throws -> [CodeAction]
1414

1515
/// Request for returning all possible code actions for a given text document and range.
1616
///

Sources/LanguageServerProtocol/SupportTypes/ServerCapabilities.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ public struct DocumentRangeFormattingOptions: WorkDoneProgressOptions, Codable,
587587
}
588588
}
589589

590-
public struct FoldingRangeOptions: Codable, Hashable {
590+
public struct FoldingRangeOptions: Codable, Hashable, Sendable {
591591
/// Currently empty in the spec.
592592
public init() {}
593593
}

Sources/SKCore/BuildSystemManager.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import LanguageServerProtocol
1717

1818
import struct TSCBasic.AbsolutePath
1919

20+
#if canImport(os)
21+
import os
22+
#endif
23+
2024
/// `BuildSystem` that integrates client-side information such as main-file lookup as well as providing
2125
/// common functionality such as caching.
2226
///
@@ -169,7 +173,7 @@ extension BuildSystemManager {
169173
logger.error("Getting build settings failed: \(error.forLogging)")
170174
}
171175

172-
guard var settings = fallbackBuildSystem?.buildSettings(for: document, language: language) else {
176+
guard var settings = await fallbackBuildSystem?.buildSettings(for: document, language: language) else {
173177
return nil
174178
}
175179
if buildSystem == nil {

Sources/SKCore/FallbackBuildSystem.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import struct TSCBasic.AbsolutePath
2121
import class TSCBasic.Process
2222

2323
/// A simple BuildSystem suitable as a fallback when accurate settings are unknown.
24-
public final class FallbackBuildSystem {
24+
public actor FallbackBuildSystem {
2525

2626
let buildSetup: BuildSetup
2727

@@ -38,6 +38,10 @@ public final class FallbackBuildSystem {
3838
)
3939
}()
4040

41+
@_spi(Testing) public func setSdkPath(_ newValue: AbsolutePath?) {
42+
self.sdkpath = newValue
43+
}
44+
4145
/// Delegate to handle any build system events.
4246
public weak var delegate: BuildSystemDelegate? = nil
4347

Sources/SKSupport/LineTable.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import LSPLogging
14+
#if canImport(os)
15+
import os
16+
#endif
1417

15-
public struct LineTable: Hashable {
18+
public struct LineTable: Hashable, Sendable {
1619
@usableFromInline
1720
var impl: [String.Index]
1821

Sources/SKSupport/ThreadSafeBox.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public class ThreadSafeBox<T>: @unchecked Sendable {
4747
_value = initialValue
4848
}
4949

50+
public func withLock<Result>(_ body: (inout T) -> Result) -> Result {
51+
return lock.withLock {
52+
return body(&_value)
53+
}
54+
}
55+
5056
/// If the value in the box is an optional, return it and reset it to `nil`
5157
/// in an atomic operation.
5258
public func takeValue<U>() -> T where U? == T {

Sources/SourceKitLSP/Clang/ClangLanguageService.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ extension NSLock {
3333
}
3434

3535
/// Gathers data from clangd's stderr pipe. When it has accumulated a full line, writes the the line to the logger.
36-
fileprivate class ClangdStderrLogForwarder {
36+
fileprivate actor ClangdStderrLogForwarder {
37+
/// Queue on which all data from `clangd`’s stderr will be forwarded to `stderr`. This allows us to have a
38+
/// nonisolated `handle` function but ensure that data gets processed in order.
39+
private let queue = AsyncQueue<Serial>()
3740
private var buffer = Data()
3841

39-
func handle(_ newData: Data) {
42+
private func handleImpl(_ newData: Data) {
4043
self.buffer += newData
4144
while let newlineIndex = self.buffer.firstIndex(of: UInt8(ascii: "\n")) {
4245
// Output a separate log message for every line in clangd's stderr.
@@ -50,6 +53,12 @@ fileprivate class ClangdStderrLogForwarder {
5053
buffer = buffer[buffer.index(after: newlineIndex)...]
5154
}
5255
}
56+
57+
nonisolated func handle(_ newData: Data) {
58+
queue.async {
59+
await self.handleImpl(newData)
60+
}
61+
}
5362
}
5463

5564
/// A thin wrapper over a connection to a clangd server providing build setting handling.
@@ -328,7 +337,7 @@ actor ClangLanguageService: LanguageService, MessageHandler {
328337
nonisolated func handle<R: RequestType>(
329338
_ params: R,
330339
id: RequestID,
331-
reply: @escaping (LSPResult<R.Response>) -> Void
340+
reply: @Sendable @escaping (LSPResult<R.Response>) -> Void
332341
) {
333342
logger.info(
334343
"""
@@ -442,10 +451,11 @@ extension ClangLanguageService {
442451
}
443452

444453
public func shutdown() async {
454+
let clangd = clangd!
445455
await withCheckedContinuation { continuation in
446456
_ = clangd.send(ShutdownRequest()) { _ in
447457
Task {
448-
await self.clangd.send(ExitNotification())
458+
clangd.send(ExitNotification())
449459
continuation.resume()
450460
}
451461
}

Sources/SourceKitLSP/DocumentManager.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ import SwiftSyntax
2323
/// data structure that is stored internally by the ``DocumentManager`` is a
2424
/// ``Document``. The purpose of a ``DocumentSnapshot`` is to be able to work
2525
/// with one version of a document without having to think about it changing.
26-
public struct DocumentSnapshot: Identifiable {
26+
public struct DocumentSnapshot: Identifiable, Sendable {
2727
/// An ID that uniquely identifies the version of the document stored in this
2828
/// snapshot.
29-
public struct ID: Hashable, Comparable {
29+
public struct ID: Hashable, Comparable, Sendable {
3030
public let uri: DocumentURI
3131
public let version: Int
3232

@@ -84,16 +84,18 @@ public final class Document {
8484
}
8585
}
8686

87-
public final class DocumentManager: InMemoryDocumentManager {
87+
public final class DocumentManager: InMemoryDocumentManager, Sendable {
8888

8989
public enum Error: Swift.Error {
9090
case alreadyOpen(DocumentURI)
9191
case missingDocument(DocumentURI)
9292
}
9393

94-
let queue: DispatchQueue = DispatchQueue(label: "document-manager-queue")
94+
// FIXME: (async) Migrate this to be an AsyncQueue
95+
private let queue: DispatchQueue = DispatchQueue(label: "document-manager-queue")
9596

96-
var documents: [DocumentURI: Document] = [:]
97+
// `nonisolated(unsafe)` is fine because `documents` is guarded by queue.
98+
nonisolated(unsafe) var documents: [DocumentURI: Document] = [:]
9799

98100
public init() {}
99101

Sources/SourceKitLSP/LanguageService.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public enum LanguageServerState {
2424
case semanticFunctionalityDisabled
2525
}
2626

27-
public struct RenameLocation {
27+
public struct RenameLocation: Sendable {
2828
/// How the identifier at a given location is being used.
2929
///
3030
/// This is primarily used to influence how argument labels should be renamed in Swift and if a location should be
@@ -64,7 +64,7 @@ public struct RenameLocation {
6464
///
6565
/// For example, we may have a language service that provides semantic functionality for c-family using a clangd server,
6666
/// launched from a specific toolchain or from sourcekitd.
67-
public protocol LanguageService: AnyObject {
67+
public protocol LanguageService: AnyObject, Sendable {
6868

6969
// MARK: - Creation
7070

@@ -90,7 +90,7 @@ public protocol LanguageService: AnyObject {
9090

9191
/// Add a handler that is called whenever the state of the language server changes.
9292
func addStateChangeHandler(
93-
handler: @escaping (_ oldState: LanguageServerState, _ newState: LanguageServerState) -> Void
93+
handler: @Sendable @escaping (_ oldState: LanguageServerState, _ newState: LanguageServerState) -> Void
9494
) async
9595

9696
// MARK: - Text synchronization

Sources/SourceKitLSP/Rename.swift

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
import IndexStoreDB
13+
@preconcurrency import IndexStoreDB
1414
import LSPLogging
1515
import LanguageServerProtocol
1616
import SKSupport
@@ -445,7 +445,7 @@ extension SwiftLanguageService {
445445
/// These names might differ. For example, an Objective-C method gets translated by the clang importer to form the Swift
446446
/// name or it could have a `SWIFT_NAME` attribute that defines the method's name in Swift. Similarly, a Swift symbol
447447
/// might specify the name by which it gets exposed to Objective-C using the `@objc` attribute.
448-
public struct CrossLanguageName {
448+
public struct CrossLanguageName: Sendable {
449449
/// The name of the symbol in clang languages or `nil` if the symbol is defined in Swift, doesn't have any references
450450
/// from clang languages and thus hasn't been translated.
451451
fileprivate let clangName: String?
@@ -564,6 +564,22 @@ extension SourceKitLSPServer {
564564
return nil
565565
}
566566

567+
// FIXME: (async-workaround): Needed to work around rdar://127977642
568+
private func translateClangNameToSwift(
569+
_ swiftLanguageService: SwiftLanguageService,
570+
at symbolLocation: SymbolLocation,
571+
in snapshot: DocumentSnapshot,
572+
isObjectiveCSelector: Bool,
573+
name: String
574+
) async throws -> String {
575+
return try await swiftLanguageService.translateClangNameToSwift(
576+
at: symbolLocation,
577+
in: snapshot,
578+
isObjectiveCSelector: isObjectiveCSelector,
579+
name: name
580+
)
581+
}
582+
567583
private func getCrossLanguageName(
568584
forDefinitionOccurrence definitionOccurrence: SymbolOccurrence,
569585
overrideName: String? = nil,
@@ -598,7 +614,8 @@ extension SourceKitLSPServer {
598614
let swiftName: String?
599615
if let swiftReference = await getReferenceFromSwift(usr: usr, index: index, workspace: workspace) {
600616
let isObjectiveCSelector = definitionLanguage == .objective_c && definitionSymbol.kind.isMethod
601-
swiftName = try await swiftReference.swiftLanguageService.translateClangNameToSwift(
617+
swiftName = try await self.translateClangNameToSwift(
618+
swiftReference.swiftLanguageService,
602619
at: swiftReference.location,
603620
in: swiftReference.snapshot,
604621
isObjectiveCSelector: isObjectiveCSelector,
@@ -670,7 +687,7 @@ extension SourceKitLSPServer {
670687
guard let workspace = await workspaceForDocument(uri: uri) else {
671688
throw ResponseError.workspaceNotOpen(uri)
672689
}
673-
guard let primaryFileLanguageService = workspace.documentService[uri] else {
690+
guard let primaryFileLanguageService = workspace.documentService.value[uri] else {
674691
return nil
675692
}
676693

@@ -716,24 +733,26 @@ extension SourceKitLSPServer {
716733
var locationsByFile: [URL: [RenameLocation]] = [:]
717734

718735
actor LanguageServerTypesCache {
719-
let index: CheckedIndex
736+
let index: UncheckedIndex
720737
var languageServerTypesCache: [URL: LanguageServerType?] = [:]
721738

722-
init(index: CheckedIndex) {
739+
init(index: UncheckedIndex) {
723740
self.index = index
724741
}
725742

726743
func languageServerType(for url: URL) -> LanguageServerType? {
727744
if let cachedValue = languageServerTypesCache[url] {
728745
return cachedValue
729746
}
730-
let serverType = LanguageServerType(symbolProvider: index.symbolProvider(for: url.path))
747+
let serverType = LanguageServerType(
748+
symbolProvider: index.checked(for: .deletedFiles).symbolProvider(for: url.path)
749+
)
731750
languageServerTypesCache[url] = serverType
732751
return serverType
733752
}
734753
}
735754

736-
let languageServerTypesCache = LanguageServerTypesCache(index: index)
755+
let languageServerTypesCache = LanguageServerTypesCache(index: index.unchecked)
737756

738757
let usrsToRename = overridingAndOverriddenUsrs(of: usr, index: index)
739758
let occurrencesToRename = usrsToRename.flatMap { index.occurrences(ofUSR: $0, roles: renameRoles) }

Sources/SourceKitLSP/Sequence+AsyncMap.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
extension Sequence {
1414
/// Just like `Sequence.map` but allows an `async` transform function.
1515
func asyncMap<T>(
16-
_ transform: (Element) async throws -> T
16+
@_inheritActorContext _ transform: @Sendable (Element) async throws -> T
1717
) async rethrows -> [T] {
1818
var result: [T] = []
1919
result.reserveCapacity(self.underestimatedCount)
@@ -27,7 +27,7 @@ extension Sequence {
2727

2828
/// Just like `Sequence.compactMap` but allows an `async` transform function.
2929
func asyncCompactMap<T>(
30-
_ transform: (Element) async throws -> T?
30+
@_inheritActorContext _ transform: @Sendable (Element) async throws -> T?
3131
) async rethrows -> [T] {
3232
var result: [T] = []
3333

0 commit comments

Comments
 (0)