Skip to content

Commit f57980a

Browse files
authored
Merge pull request #1879 from ahoppen/merge-main-6.1-2024-12-10
Merge `main` into `release/6.1`
2 parents 4d4423f + fd79c3d commit f57980a

File tree

79 files changed

+2122
-1383
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2122
-1383
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
1212
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
1313
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
1414

15-
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-upcoming-feature InternalImportsByDefault>")
15+
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-upcoming-feature InternalImportsByDefault -enable-upcoming-feature MemberImportVisibility>")
1616

1717
find_package(dispatch QUIET)
1818
find_package(Foundation QUIET)

Documentation/Configuration File.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The structure of the file is currently not guaranteed to be stable. Options may
1515

1616
- `swiftPM`: Dictionary with the following keys, defining options for SwiftPM workspaces
1717
- `configuration: "debug"|"release"`: The configuration to build the project for during background indexing and the configuration whose build folder should be used for Swift modules if background indexing is disabled. Equivalent to SwiftPM's `--configuration` option.
18-
- `scratchPath: string`: Build artifacts directory path. If nil, the build system may choose a default value. Equivalent to SwiftPM's `--scratch-path` option.
18+
- `scratchPath: string`: Build artifacts directory path. If nil, the build system may choose a default value. This path can be specified as a relative path, which will be interpreted relative to the project root. Equivalent to SwiftPM's `--scratch-path` option.
1919
- `swiftSDKsDirectory: string`: Equivalent to SwiftPM's `--swift-sdks-path` option
2020
- `swiftSDK: string`: Equivalent to SwiftPM's `--swift-sdk` option
2121
- `triple: string`: Equivalent to SwiftPM's `--triple` option
@@ -51,5 +51,5 @@ The structure of the file is currently not guaranteed to be stable. Options may
5151
- `noLazy`: Prepare a target without generating object files but do not do lazy type checking and function body skipping
5252
- `enabled`: Prepare a target without generating object files and the like
5353
- `cancelTextDocumentRequestsOnEditAndClose: bool`: Whether sending a `textDocument/didChange` or `textDocument/didClose` notification for a document should cancel all pending requests for that document.
54-
- `experimentalFeatures: string[]`: Experimental features to enable
54+
- `experimentalFeatures: string[]`: Experimental features to enable. Available features: on-type-formatting
5555
- `swiftPublishDiagnosticsDebounceDuration: double`: The time that `SwiftLanguageService` should wait after an edit before starting to compute diagnostics and sending a `PublishDiagnosticsNotification`.

Package.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ var targets: [Target] = [
9797
"SKTestSupport",
9898
"SourceKitLSP",
9999
"ToolchainRegistry",
100+
"TSCExtensions",
100101
],
101102
swiftSettings: globalSwiftSettings
102103
),
@@ -348,7 +349,6 @@ var targets: [Target] = [
348349
"Csourcekitd",
349350
"SKLogging",
350351
"SwiftExtensions",
351-
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
352352
],
353353
exclude: ["CMakeLists.txt", "sourcekitd_uids.swift.gyb"],
354354
swiftSettings: globalSwiftSettings
@@ -487,7 +487,6 @@ var targets: [Target] = [
487487
"SwiftExtensions",
488488
"TSCExtensions",
489489
],
490-
exclude: ["CMakeLists.txt"],
491490
swiftSettings: globalSwiftSettings
492491
),
493492
]

Sources/BuildSystemIntegration/BuildSystemManager.swift

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#if compiler(>=6)
1414
package import BuildServerProtocol
1515
import Dispatch
16-
import Foundation
16+
package import Foundation
1717
package import LanguageServerProtocol
1818
package import LanguageServerProtocolExtensions
1919
import SKLogging
@@ -23,8 +23,7 @@ package import SwiftExtensions
2323
package import ToolchainRegistry
2424
import TSCExtensions
2525

26-
package import struct TSCBasic.AbsolutePath
27-
package import struct TSCBasic.RelativePath
26+
import struct TSCBasic.RelativePath
2827
#else
2928
import BuildServerProtocol
3029
import Dispatch
@@ -38,7 +37,6 @@ import SwiftExtensions
3837
import ToolchainRegistry
3938
import TSCExtensions
4039

41-
import struct TSCBasic.AbsolutePath
4240
import struct TSCBasic.RelativePath
4341
#endif
4442

@@ -138,31 +136,31 @@ private enum BuildSystemAdapter {
138136

139137
private extension BuildSystemSpec {
140138
private static func createBuiltInBuildSystemAdapter(
141-
projectRoot: AbsolutePath,
139+
projectRoot: URL,
142140
messagesToSourceKitLSPHandler: any MessageHandler,
143141
buildSystemTestHooks: BuildSystemTestHooks,
144142
_ createBuildSystem: @Sendable (_ connectionToSourceKitLSP: any Connection) async throws -> BuiltInBuildSystem?
145143
) async -> BuildSystemAdapter? {
146144
let connectionToSourceKitLSP = LocalConnection(
147-
receiverName: "BuildSystemManager for \(projectRoot.asURL.lastPathComponent)"
145+
receiverName: "BuildSystemManager for \(projectRoot.lastPathComponent)"
148146
)
149147
connectionToSourceKitLSP.start(handler: messagesToSourceKitLSPHandler)
150148

151149
let buildSystem = await orLog("Creating build system") {
152150
try await createBuildSystem(connectionToSourceKitLSP)
153151
}
154152
guard let buildSystem else {
155-
logger.log("Failed to create build system at \(projectRoot.pathString)")
153+
logger.log("Failed to create build system at \(projectRoot)")
156154
return nil
157155
}
158-
logger.log("Created \(type(of: buildSystem), privacy: .public) at \(projectRoot.pathString)")
156+
logger.log("Created \(type(of: buildSystem), privacy: .public) at \(projectRoot)")
159157
let buildSystemAdapter = BuiltInBuildSystemAdapter(
160158
underlyingBuildSystem: buildSystem,
161159
connectionToSourceKitLSP: connectionToSourceKitLSP,
162160
buildSystemTestHooks: buildSystemTestHooks
163161
)
164162
let connectionToBuildSystem = LocalConnection(
165-
receiverName: "\(type(of: buildSystem)) for \(projectRoot.asURL.lastPathComponent)"
163+
receiverName: "\(type(of: buildSystem)) for \(projectRoot.lastPathComponent)"
166164
)
167165
connectionToBuildSystem.start(handler: buildSystemAdapter)
168166
return .builtIn(buildSystemAdapter, connectionToBuildSystem: connectionToBuildSystem)
@@ -185,10 +183,10 @@ private extension BuildSystemSpec {
185183
)
186184
}
187185
guard let buildSystem else {
188-
logger.log("Failed to create external build system at \(projectRoot.pathString)")
186+
logger.log("Failed to create external build system at \(projectRoot)")
189187
return nil
190188
}
191-
logger.log("Created external build server at \(projectRoot.pathString)")
189+
logger.log("Created external build server at \(projectRoot)")
192190
return .external(buildSystem)
193191
case .compilationDatabase:
194192
return await Self.createBuiltInBuildSystemAdapter(
@@ -245,7 +243,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
245243
/// For compilation databases it is the root folder based on which the compilation database was found.
246244
///
247245
/// `nil` if the `BuildSystemManager` does not have an underlying build system.
248-
package let projectRoot: AbsolutePath?
246+
package let projectRoot: URL?
249247

250248
/// The files for which the delegate has requested change notifications, ie. the files for which the delegate wants to
251249
/// get `fileBuildSettingsChanged` and `filesDependenciesUpdated` callbacks.
@@ -340,7 +338,10 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
340338
let files: [DocumentURI: SourceFileInfo]
341339

342340
/// The source directories in the workspace, ie. all `SourceItem`s that have `kind == .directory`.
343-
let directories: [DocumentURI: SourceFileInfo]
341+
///
342+
/// `pathComponents` is the result of `key.fileURL?.pathComponents`. We frequently need these path components to
343+
/// determine if a file is descendent of the directory and computing them from the `DocumentURI` is expensive.
344+
let directories: [DocumentURI: (pathComponents: [String]?, info: SourceFileInfo)]
344345
}
345346

346347
private let cachedSourceFilesAndDirectories = Cache<SourceFilesAndDirectoriesKey, SourceFilesAndDirectories>()
@@ -402,7 +403,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
402403
displayName: "SourceKit-LSP",
403404
version: "",
404405
bspVersion: "2.2.0",
405-
rootUri: URI(buildSystemSpec.projectRoot.asURL),
406+
rootUri: URI(buildSystemSpec.projectRoot),
406407
capabilities: BuildClientCapabilities(languageIds: [.c, .cpp, .objective_c, .objective_cpp, .swift])
407408
)
408409
)
@@ -608,7 +609,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
608609
in target: BuildTargetIdentifier?,
609610
language: Language
610611
) async -> Toolchain? {
611-
let toolchainPath = await orLog("Getting toolchain from build targets") { () -> AbsolutePath? in
612+
let toolchainPath = await orLog("Getting toolchain from build targets") { () -> URL? in
612613
guard let target else {
613614
return nil
614615
}
@@ -624,7 +625,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
624625
logger.error("Toolchain is not a file URL")
625626
return nil
626627
}
627-
return try AbsolutePath(validating: toolchainUrl.filePath)
628+
return toolchainUrl
628629
}
629630
if let toolchainPath {
630631
if let toolchain = await self.toolchainRegistry.toolchain(withPath: toolchainPath) {
@@ -681,14 +682,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
681682
if let targets = filesAndDirectories.files[document]?.targets {
682683
result.formUnion(targets)
683684
}
684-
if !filesAndDirectories.directories.isEmpty,
685-
let documentPath = AbsolutePath(validatingOrNil: try? document.fileURL?.filePath)
686-
{
687-
for (directory, info) in filesAndDirectories.directories {
688-
guard let directoryPath = AbsolutePath(validatingOrNil: try? directory.fileURL?.filePath) else {
685+
if !filesAndDirectories.directories.isEmpty, let documentPathComponents = document.fileURL?.pathComponents {
686+
for (directory, (directoryPathComponents, info)) in filesAndDirectories.directories {
687+
guard let directoryPathComponents, let directoryPath = directory.fileURL else {
689688
continue
690689
}
691-
if documentPath.isDescendant(of: directoryPath) {
690+
if isDescendant(documentPathComponents, of: directoryPathComponents) {
692691
result.formUnion(info.targets)
693692
}
694693
}
@@ -1013,19 +1012,21 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
10131012
return []
10141013
}
10151014

1015+
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
1016+
10161017
// If we have a cached request for a superset of the targets, serve the result from that cache entry.
10171018
let fromSuperset = await orLog("Getting source files from superset request") {
1018-
try await cachedTargetSources.get(isolation: self) { request in
1019-
targets.isSubset(of: request.targets)
1020-
} transform: { response in
1021-
return BuildTargetSourcesResponse(items: response.items.filter { targets.contains($0.target) })
1022-
}
1019+
try await cachedTargetSources.getDerived(
1020+
isolation: self,
1021+
request,
1022+
canReuseKey: { targets.isSubset(of: $0.targets) },
1023+
transform: { BuildTargetSourcesResponse(items: $0.items.filter { targets.contains($0.target) }) }
1024+
)
10231025
}
10241026
if let fromSuperset {
10251027
return fromSuperset.items
10261028
}
10271029

1028-
let request = BuildTargetSourcesRequest(targets: targets.sorted { $0.uri.stringValue < $1.uri.stringValue })
10291030
let response = try await cachedTargetSources.get(request, isolation: self) { request in
10301031
try await buildSystemAdapter.send(request)
10311032
}
@@ -1059,7 +1060,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
10591060

10601061
return try await cachedSourceFilesAndDirectories.get(key, isolation: self) { key in
10611062
var files: [DocumentURI: SourceFileInfo] = [:]
1062-
var directories: [DocumentURI: SourceFileInfo] = [:]
1063+
var directories: [DocumentURI: (pathComponents: [String]?, info: SourceFileInfo)] = [:]
10631064
for sourcesItem in key.sourcesItems {
10641065
let target = targets[sourcesItem.target]?.target
10651066
let isPartOfRootProject = !(target?.tags.contains(.dependency) ?? false)
@@ -1081,7 +1082,9 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
10811082
case .file:
10821083
files[sourceItem.uri] = info.merging(files[sourceItem.uri])
10831084
case .directory:
1084-
directories[sourceItem.uri] = info.merging(directories[sourceItem.uri])
1085+
directories[sourceItem.uri] = (
1086+
sourceItem.uri.fileURL?.pathComponents, info.merging(directories[sourceItem.uri]?.info)
1087+
)
10851088
}
10861089
}
10871090
}
@@ -1230,3 +1233,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
12301233
}
12311234
}
12321235
}
1236+
1237+
/// Returns `true` if the path components `selfPathComponents`, retrieved from `URL.pathComponents` are a descendent
1238+
/// of the other path components.
1239+
///
1240+
/// This operates directly on path components instead of `URL`s because computing the path components of a URL is
1241+
/// expensive and this allows us to cache the path components.
1242+
private func isDescendant(_ selfPathComponents: [String], of otherPathComponents: [String]) -> Bool {
1243+
return selfPathComponents.dropLast().starts(with: otherPathComponents)
1244+
}

Sources/BuildSystemIntegration/BuildSystemMessageDependencyTracker.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import BuildServerProtocol
1515
package import LanguageServerProtocol
1616
import LanguageServerProtocolExtensions
1717
import SKLogging
18-
import SwiftExtensions
18+
package import SwiftExtensions
1919
#else
2020
import BuildServerProtocol
2121
import LanguageServerProtocol
@@ -82,6 +82,10 @@ package enum BuildSystemMessageDependencyTracker: QueueBasedMessageHandlerDepend
8282
}
8383
}
8484

85+
package func dependencies(in pendingTasks: [PendingTask<Self>]) -> [PendingTask<Self>] {
86+
return pendingTasks.filter { $0.metadata.isDependency(of: self) }
87+
}
88+
8589
package init(_ request: some RequestType) {
8690
switch request {
8791
case is BuildShutdownRequest:

Sources/BuildSystemIntegration/BuiltInBuildSystem.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,18 @@
1212

1313
#if compiler(>=6)
1414
package import BuildServerProtocol
15+
package import Foundation
1516
package import LanguageServerProtocol
1617
import SKLogging
1718
import SKOptions
1819
import ToolchainRegistry
19-
20-
package import struct TSCBasic.AbsolutePath
21-
package import struct TSCBasic.RelativePath
2220
#else
2321
import BuildServerProtocol
22+
import Foundation
2423
import LanguageServerProtocol
2524
import SKLogging
2625
import SKOptions
2726
import ToolchainRegistry
28-
29-
import struct TSCBasic.AbsolutePath
30-
import struct TSCBasic.RelativePath
3127
#endif
3228

3329
/// An error build systems can throw from `prepare` if they don't support preparation of targets.
@@ -42,16 +38,16 @@ package protocol BuiltInBuildSystem: AnyObject, Sendable {
4238
/// The root of the project that this build system manages. For example, for SwiftPM packages, this is the folder
4339
/// containing Package.swift. For compilation databases it is the root folder based on which the compilation database
4440
/// was found.
45-
var projectRoot: AbsolutePath { get async }
41+
var projectRoot: URL { get async }
4642

4743
/// The files to watch for changes.
4844
var fileWatchers: [FileSystemWatcher] { get async }
4945

5046
/// The path to the raw index store data, if any.
51-
var indexStorePath: AbsolutePath? { get async }
47+
var indexStorePath: URL? { get async }
5248

5349
/// The path to put the index database, if any.
54-
var indexDatabasePath: AbsolutePath? { get async }
50+
var indexDatabasePath: URL? { get async }
5551

5652
/// Whether the build system is capable of preparing a target for indexing, ie. if the `prepare` methods has been
5753
/// implemented.

Sources/BuildSystemIntegration/BuiltInBuildSystemAdapter.swift

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import BuildServerProtocol
14-
import Foundation
1514
import LanguageServerProtocol
1615
import LanguageServerProtocolExtensions
1716
import SKLogging
@@ -20,11 +19,9 @@ import SwiftExtensions
2019
import ToolchainRegistry
2120

2221
#if compiler(>=6)
23-
package import struct TSCBasic.AbsolutePath
24-
package import struct TSCBasic.RelativePath
22+
package import Foundation
2523
#else
26-
import struct TSCBasic.AbsolutePath
27-
import struct TSCBasic.RelativePath
24+
import Foundation
2825
#endif
2926

3027
/// The details necessary to create a `BuildSystemAdapter`.
@@ -38,9 +35,9 @@ package struct BuildSystemSpec {
3835

3936
package var kind: Kind
4037

41-
package var projectRoot: AbsolutePath
38+
package var projectRoot: URL
4239

43-
package init(kind: BuildSystemSpec.Kind, projectRoot: AbsolutePath) {
40+
package init(kind: BuildSystemSpec.Kind, projectRoot: URL) {
4441
self.kind = kind
4542
self.projectRoot = projectRoot
4643
}
@@ -95,8 +92,12 @@ actor BuiltInBuildSystemAdapter: QueueBasedMessageHandler {
9592
capabilities: BuildServerCapabilities(),
9693
dataKind: .sourceKit,
9794
data: SourceKitInitializeBuildResponseData(
98-
indexDatabasePath: await underlyingBuildSystem.indexDatabasePath?.pathString,
99-
indexStorePath: await underlyingBuildSystem.indexStorePath?.pathString,
95+
indexDatabasePath: await orLog("getting index database file path") {
96+
try await underlyingBuildSystem.indexDatabasePath?.filePath
97+
},
98+
indexStorePath: await orLog("getting index store file path") {
99+
try await underlyingBuildSystem.indexStorePath?.filePath
100+
},
100101
watchers: await underlyingBuildSystem.fileWatchers,
101102
prepareProvider: underlyingBuildSystem.supportsPreparation,
102103
sourceKitOptionsProvider: true

0 commit comments

Comments
 (0)