Skip to content

Commit d86a32b

Browse files
committed
Remove custom decoding function from SourceKitLSPOptions
We forgot to decode the following keys in the custom decode function, which meant that you couldn’t set them using SourceKit-LSP’s `config.json` file. - `backgroundPreparationMode` - `sourcekitdRequestTimeout` - `cancelTextDocumentRequestsOnEditAndClose` We had the custom decoder function so that the keys weren’t required in the JSON but we could access eg. `SwiftPMOptions` without needing to deal with optionals in the codebase. Make the accesses to these nested options structs a little more verbose but eliminate the source of the above bug, which seems like a good tradeoff.
1 parent 17cc06d commit d86a32b

File tree

10 files changed

+86
-76
lines changed

10 files changed

+86
-76
lines changed

Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ package actor SwiftPMBuildSystem {
229229
let destinationSDK = try SwiftSDK.deriveTargetSwiftSDK(
230230
hostSwiftSDK: hostSDK,
231231
hostTriple: hostSwiftPMToolchain.targetTriple,
232-
customCompileTriple: options.swiftPM.triple.map { try Triple($0) },
233-
swiftSDKSelector: options.swiftPM.swiftSDK,
232+
customCompileTriple: options.swiftPMOrDefault.triple.map { try Triple($0) },
233+
swiftSDKSelector: options.swiftPMOrDefault.swiftSDK,
234234
store: SwiftSDKBundleStore(
235235
swiftSDKsDirectory: fileSystem.getSharedSwiftSDKsDirectory(
236-
explicitDirectory: options.swiftPM.swiftSDKsDirectory.map { try AbsolutePath(validating: $0) }
236+
explicitDirectory: options.swiftPMOrDefault.swiftSDKsDirectory.map { try AbsolutePath(validating: $0) }
237237
),
238238
fileSystem: fileSystem,
239239
observabilityScope: observabilitySystem.topScope,
@@ -251,7 +251,7 @@ package actor SwiftPMBuildSystem {
251251
)
252252
if options.backgroundIndexingOrDefault {
253253
location.scratchDirectory = AbsolutePath(packageRoot.appending(component: ".index-build"))
254-
} else if let scratchDirectory = options.swiftPM.scratchPath,
254+
} else if let scratchDirectory = options.swiftPMOrDefault.scratchPath,
255255
let scratchDirectoryPath = try? AbsolutePath(validating: scratchDirectory)
256256
{
257257
location.scratchDirectory = scratchDirectoryPath
@@ -267,25 +267,25 @@ package actor SwiftPMBuildSystem {
267267
customHostToolchain: hostSwiftPMToolchain,
268268
customManifestLoader: ManifestLoader(
269269
toolchain: hostSwiftPMToolchain,
270-
isManifestSandboxEnabled: !(options.swiftPM.disableSandbox ?? false),
270+
isManifestSandboxEnabled: !(options.swiftPMOrDefault.disableSandbox ?? false),
271271
cacheDir: location.sharedManifestsCacheDirectory,
272272
importRestrictions: configuration.manifestImportRestrictions
273273
)
274274
)
275275

276276
let buildConfiguration: PackageModel.BuildConfiguration
277-
switch options.swiftPM.configuration {
277+
switch options.swiftPMOrDefault.configuration {
278278
case .debug, nil:
279279
buildConfiguration = .debug
280280
case .release:
281281
buildConfiguration = .release
282282
}
283283

284284
let buildFlags = BuildFlags(
285-
cCompilerFlags: options.swiftPM.cCompilerFlags ?? [],
286-
cxxCompilerFlags: options.swiftPM.cxxCompilerFlags ?? [],
287-
swiftCompilerFlags: options.swiftPM.swiftCompilerFlags ?? [],
288-
linkerFlags: options.swiftPM.linkerFlags ?? []
285+
cCompilerFlags: options.swiftPMOrDefault.cCompilerFlags ?? [],
286+
cxxCompilerFlags: options.swiftPMOrDefault.cxxCompilerFlags ?? [],
287+
swiftCompilerFlags: options.swiftPMOrDefault.swiftCompilerFlags ?? [],
288+
linkerFlags: options.swiftPMOrDefault.linkerFlags ?? []
289289
)
290290

291291
self.toolsBuildParameters = try BuildParameters(
@@ -381,7 +381,7 @@ extension SwiftPMBuildSystem {
381381
destinationBuildParameters: destinationBuildParameters,
382382
toolsBuildParameters: toolsBuildParameters,
383383
graph: modulesGraph,
384-
disableSandbox: options.swiftPM.disableSandbox ?? false,
384+
disableSandbox: options.swiftPMOrDefault.disableSandbox ?? false,
385385
fileSystem: fileSystem,
386386
observabilityScope: observabilitySystem.topScope
387387
)
@@ -607,16 +607,16 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuildSystem {
607607
"--disable-index-store",
608608
"--target", target.targetID,
609609
]
610-
if options.swiftPM.disableSandbox ?? false {
610+
if options.swiftPMOrDefault.disableSandbox ?? false {
611611
arguments += ["--disable-sandbox"]
612612
}
613-
if let configuration = options.swiftPM.configuration {
613+
if let configuration = options.swiftPMOrDefault.configuration {
614614
arguments += ["-c", configuration.rawValue]
615615
}
616-
arguments += options.swiftPM.cCompilerFlags?.flatMap { ["-Xcc", $0] } ?? []
617-
arguments += options.swiftPM.cxxCompilerFlags?.flatMap { ["-Xcxx", $0] } ?? []
618-
arguments += options.swiftPM.swiftCompilerFlags?.flatMap { ["-Xswiftc", $0] } ?? []
619-
arguments += options.swiftPM.linkerFlags?.flatMap { ["-Xlinker", $0] } ?? []
616+
arguments += options.swiftPMOrDefault.cCompilerFlags?.flatMap { ["-Xcc", $0] } ?? []
617+
arguments += options.swiftPMOrDefault.cxxCompilerFlags?.flatMap { ["-Xcxx", $0] } ?? []
618+
arguments += options.swiftPMOrDefault.swiftCompilerFlags?.flatMap { ["-Xswiftc", $0] } ?? []
619+
arguments += options.swiftPMOrDefault.linkerFlags?.flatMap { ["-Xlinker", $0] } ?? []
620620
switch options.backgroundPreparationModeOrDefault {
621621
case .build: break
622622
case .noLazy: arguments += ["--experimental-prepare-for-indexing", "--experimental-prepare-for-indexing-no-lazy"]

Sources/SKOptions/SourceKitLSPOptions.swift

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import struct TSCBasic.AbsolutePath
2020
/// Options that can be used to modify SourceKit-LSP's behavior.
2121
///
2222
/// See `ConfigurationFile.md` for a description of the configuration file's behavior.
23-
public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible {
24-
public struct SwiftPMOptions: Sendable, Codable, CustomLogStringConvertible {
23+
public struct SourceKitLSPOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
24+
public struct SwiftPMOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
2525
/// Build configuration (debug|release).
2626
///
2727
/// Equivalent to SwiftPM's `--configuration` option.
@@ -104,7 +104,7 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
104104
}
105105
}
106106

107-
public struct CompilationDatabaseOptions: Sendable, Codable, CustomLogStringConvertible {
107+
public struct CompilationDatabaseOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
108108
/// Additional paths to search for a compilation database, relative to a workspace root.
109109
public var searchPaths: [String]?
110110

@@ -128,7 +128,7 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
128128
}
129129
}
130130

131-
public struct FallbackBuildSystemOptions: Sendable, Codable, CustomLogStringConvertible {
131+
public struct FallbackBuildSystemOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
132132
public var cCompilerFlags: [String]?
133133
public var cxxCompilerFlags: [String]?
134134
public var swiftCompilerFlags: [String]?
@@ -163,7 +163,7 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
163163
}
164164
}
165165

166-
public struct IndexOptions: Sendable, Codable, CustomLogStringConvertible {
166+
public struct IndexOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
167167
public var indexStorePath: String?
168168
public var indexDatabasePath: String?
169169
public var indexPrefixMap: [String: String]?
@@ -216,7 +216,7 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
216216
}
217217
}
218218

219-
public struct LoggingOptions: Sendable, Codable, CustomLogStringConvertible {
219+
public struct LoggingOptions: Sendable, Codable, Equatable, CustomLogStringConvertible {
220220
/// The level from which one onwards log messages should be written.
221221
public var level: String?
222222
/// Whether potentially sensitive information should be redacted.
@@ -259,12 +259,37 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
259259
case enabled
260260
}
261261

262-
public var swiftPM: SwiftPMOptions
263-
public var compilationDatabase: CompilationDatabaseOptions
264-
public var fallbackBuildSystem: FallbackBuildSystemOptions
262+
private var swiftPM: SwiftPMOptions?
263+
public var swiftPMOrDefault: SwiftPMOptions {
264+
get { swiftPM ?? .init() }
265+
set { swiftPM = newValue }
266+
}
267+
268+
private var compilationDatabase: CompilationDatabaseOptions?
269+
public var compilationDatabaseOrDefault: CompilationDatabaseOptions {
270+
get { compilationDatabase ?? .init() }
271+
set { compilationDatabase = newValue }
272+
}
273+
274+
private var fallbackBuildSystem: FallbackBuildSystemOptions?
275+
public var fallbackBuildSystemOrDefault: FallbackBuildSystemOptions {
276+
get { fallbackBuildSystem ?? .init() }
277+
set { fallbackBuildSystem = newValue }
278+
}
279+
265280
public var clangdOptions: [String]?
266-
public var index: IndexOptions
267-
public var logging: LoggingOptions
281+
282+
private var index: IndexOptions?
283+
public var indexOrDefault: IndexOptions {
284+
get { index ?? .init() }
285+
set { index = newValue }
286+
}
287+
288+
private var logging: LoggingOptions?
289+
public var loggingOrDefault: LoggingOptions {
290+
get { logging ?? .init() }
291+
set { logging = newValue }
292+
}
268293

269294
/// Default workspace type (buildserver|compdb|swiftpm). Overrides workspace type selection logic.
270295
public var defaultWorkspaceType: WorkspaceType?
@@ -406,18 +431,18 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
406431

407432
public static func merging(base: SourceKitLSPOptions, override: SourceKitLSPOptions?) -> SourceKitLSPOptions {
408433
return SourceKitLSPOptions(
409-
swiftPM: SwiftPMOptions.merging(base: base.swiftPM, override: override?.swiftPM),
434+
swiftPM: SwiftPMOptions.merging(base: base.swiftPMOrDefault, override: override?.swiftPM),
410435
fallbackBuildSystem: FallbackBuildSystemOptions.merging(
411-
base: base.fallbackBuildSystem,
436+
base: base.fallbackBuildSystemOrDefault,
412437
override: override?.fallbackBuildSystem
413438
),
414439
compilationDatabase: CompilationDatabaseOptions.merging(
415-
base: base.compilationDatabase,
440+
base: base.compilationDatabaseOrDefault,
416441
override: override?.compilationDatabase
417442
),
418443
clangdOptions: override?.clangdOptions ?? base.clangdOptions,
419-
index: IndexOptions.merging(base: base.index, override: override?.index),
420-
logging: LoggingOptions.merging(base: base.logging, override: override?.logging),
444+
index: IndexOptions.merging(base: base.indexOrDefault, override: override?.index),
445+
logging: LoggingOptions.merging(base: base.loggingOrDefault, override: override?.logging),
421446
defaultWorkspaceType: override?.defaultWorkspaceType ?? base.defaultWorkspaceType,
422447
generatedFilesPath: override?.generatedFilesPath ?? base.generatedFilesPath,
423448
backgroundIndexing: override?.backgroundIndexing ?? base.backgroundIndexing,
@@ -447,37 +472,6 @@ public struct SourceKitLSPOptions: Sendable, Codable, CustomLogStringConvertible
447472
return experimentalFeatures.contains(feature)
448473
}
449474

450-
public init(from decoder: any Decoder) throws {
451-
let container = try decoder.container(keyedBy: CodingKeys.self)
452-
453-
self.swiftPM = try container.decodeIfPresent(SwiftPMOptions.self, forKey: CodingKeys.swiftPM) ?? .init()
454-
self.compilationDatabase =
455-
try container.decodeIfPresent(CompilationDatabaseOptions.self, forKey: CodingKeys.compilationDatabase) ?? .init()
456-
self.fallbackBuildSystem =
457-
try container.decodeIfPresent(FallbackBuildSystemOptions.self, forKey: CodingKeys.fallbackBuildSystem) ?? .init()
458-
self.clangdOptions = try container.decodeIfPresent([String].self, forKey: CodingKeys.clangdOptions)
459-
self.index = try container.decodeIfPresent(IndexOptions.self, forKey: CodingKeys.index) ?? .init()
460-
self.logging = try container.decodeIfPresent(LoggingOptions.self, forKey: .logging) ?? .init()
461-
self.defaultWorkspaceType = try container.decodeIfPresent(
462-
WorkspaceType.self,
463-
forKey: CodingKeys.defaultWorkspaceType
464-
)
465-
self.generatedFilesPath = try container.decodeIfPresent(String.self, forKey: CodingKeys.generatedFilesPath)
466-
self.backgroundIndexing = try container.decodeIfPresent(Bool.self, forKey: CodingKeys.backgroundIndexing)
467-
self.experimentalFeatures = try container.decodeIfPresent(
468-
Set<ExperimentalFeature>.self,
469-
forKey: CodingKeys.experimentalFeatures
470-
)
471-
self.swiftPublishDiagnosticsDebounceDuration = try container.decodeIfPresent(
472-
Double.self,
473-
forKey: CodingKeys.swiftPublishDiagnosticsDebounceDuration
474-
)
475-
self.workDoneProgressDebounceDuration = try container.decodeIfPresent(
476-
Double.self,
477-
forKey: CodingKeys.workDoneProgressDebounceDuration
478-
)
479-
}
480-
481475
public var description: String {
482476
recursiveDescription(of: self)
483477
}

Sources/SKTestSupport/IndexedSingleSwiftFileTestProject.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ package struct IndexedSingleSwiftFileTestProject {
121121

122122
// Create the test client
123123
var options = SourceKitLSPOptions.testDefault()
124-
options.index = SourceKitLSPOptions.IndexOptions(indexStorePath: indexURL.path, indexDatabasePath: indexDBURL.path)
124+
options.indexOrDefault = SourceKitLSPOptions.IndexOptions(
125+
indexStorePath: indexURL.path,
126+
indexDatabasePath: indexDBURL.path
127+
)
125128
self.testClient = try await TestSourceKitLSPClient(
126129
options: options,
127130
workspaceFolders: [

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ package final class TestSourceKitLSPClient: MessageHandler, Sendable {
112112
) async throws {
113113
var options = options
114114
if let globalModuleCache {
115-
options.swiftPM.swiftCompilerFlags =
116-
(options.swiftPM.swiftCompilerFlags ?? []) + ["-module-cache-path", globalModuleCache.path]
115+
options.swiftPMOrDefault.swiftCompilerFlags =
116+
(options.swiftPMOrDefault.swiftCompilerFlags ?? []) + ["-module-cache-path", globalModuleCache.path]
117117
}
118118
options.backgroundIndexing = enableBackgroundIndexing
119119

Sources/SourceKitLSP/CreateBuildSystem.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ func createBuildSystem(
4848
func createCompilationDatabaseBuildSystem(rootPath: AbsolutePath) -> CompilationDatabaseBuildSystem? {
4949
return CompilationDatabaseBuildSystem(
5050
projectRoot: rootPath,
51-
searchPaths: (options.compilationDatabase.searchPaths ?? []).compactMap { try? RelativePath(validating: $0) }
51+
searchPaths: (options.compilationDatabaseOrDefault.searchPaths ?? []).compactMap {
52+
try? RelativePath(validating: $0)
53+
}
5254
)
5355
}
5456

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ package actor SourceKitLSPServer {
225225

226226
self.client = client
227227
let processorCount = ProcessInfo.processInfo.processorCount
228-
let lowPriorityCores = options.index.maxCoresPercentageToUseForBackgroundIndexingOrDefault * Double(processorCount)
228+
let lowPriorityCores =
229+
options.indexOrDefault.maxCoresPercentageToUseForBackgroundIndexingOrDefault * Double(processorCount)
229230
self.indexTaskScheduler = TaskScheduler(maxConcurrentTasksByPriority: [
230231
(TaskPriority.medium, processorCount),
231232
(TaskPriority.low, max(Int(lowPriorityCores), 1)),

Sources/SourceKitLSP/Workspace.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,15 @@ package final class Workspace: Sendable {
107107
self._uncheckedIndex = ThreadSafeBox(initialValue: uncheckedIndex)
108108
self.buildSystemManager = await BuildSystemManager(
109109
buildSystem: underlyingBuildSystem,
110-
fallbackBuildSystem: FallbackBuildSystem(options: options.fallbackBuildSystem),
110+
fallbackBuildSystem: FallbackBuildSystem(options: options.fallbackBuildSystemOrDefault),
111111
mainFilesProvider: uncheckedIndex,
112112
toolchainRegistry: toolchainRegistry
113113
)
114114
if options.backgroundIndexingOrDefault, let uncheckedIndex, await buildSystemManager.supportsPreparation {
115115
self.semanticIndexManager = SemanticIndexManager(
116116
index: uncheckedIndex,
117117
buildSystemManager: buildSystemManager,
118-
updateIndexStoreTimeout: options.index.updateIndexStoreTimeoutOrDefault,
118+
updateIndexStoreTimeout: options.indexOrDefault.updateIndexStoreTimeoutOrDefault,
119119
testHooks: testHooks.indexTestHooks,
120120
indexTaskScheduler: indexTaskScheduler,
121121
logMessageToIndexLog: logMessageToIndexLog,
@@ -163,7 +163,7 @@ package final class Workspace: Sendable {
163163
var index: IndexStoreDB? = nil
164164
var indexDelegate: SourceKitIndexDelegate? = nil
165165

166-
let indexOptions = options.index
166+
let indexOptions = options.indexOrDefault
167167
if let storePath = await firstNonNil(
168168
AbsolutePath(validatingOrNil: indexOptions.indexStorePath),
169169
await buildSystem?.indexStorePath

Sources/sourcekit-lsp/SourceKitLSP.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,12 @@ struct SourceKitLSP: AsyncParsableCommand {
277277
}
278278

279279
let globalConfigurationOptions = globalConfigurationOptions
280-
if let logLevelStr = globalConfigurationOptions.logging.level, let logLevel = NonDarwinLogLevel(logLevelStr) {
280+
if let logLevelStr = globalConfigurationOptions.loggingOrDefault.level,
281+
let logLevel = NonDarwinLogLevel(logLevelStr)
282+
{
281283
LogConfig.logLevel.value = logLevel
282284
}
283-
if let privacyLevelStr = globalConfigurationOptions.logging.privacyLevel,
285+
if let privacyLevelStr = globalConfigurationOptions.loggingOrDefault.privacyLevel,
284286
let privacyLevel = NonDarwinLogPrivacy(privacyLevelStr)
285287
{
286288
LogConfig.privacyLevel.value = privacyLevel

Tests/SourceKitLSPTests/BackgroundIndexingTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ final class BackgroundIndexingTests: XCTestCase {
965965

966966
func testUseBuildFlagsDuringPreparation() async throws {
967967
var options = SourceKitLSPOptions.testDefault()
968-
options.swiftPM.swiftCompilerFlags = ["-D", "MY_FLAG"]
968+
options.swiftPMOrDefault.swiftCompilerFlags = ["-D", "MY_FLAG"]
969969
let project = try await SwiftPMTestProject(
970970
files: [
971971
"Lib/Lib.swift": """
@@ -1390,7 +1390,7 @@ final class BackgroundIndexingTests: XCTestCase {
13901390

13911391
var options = SourceKitLSPOptions.testDefault()
13921392
options.backgroundPreparationMode = SourceKitLSPOptions.BackgroundPreparationMode.enabled.rawValue
1393-
options.index.updateIndexStoreTimeout = 1 /* second */
1393+
options.indexOrDefault.updateIndexStoreTimeout = 1 /* second */
13941394

13951395
let dateStarted = Date()
13961396
_ = try await SwiftPMTestProject(

Tests/SourceKitLSPTests/LifecycleTests.swift

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

1313
import LanguageServerProtocol
14+
import SKOptions
1415
import SKTestSupport
1516
import XCTest
1617

@@ -39,6 +40,13 @@ final class LifecycleTests: XCTestCase {
3940
XCTAssertNotNil(initResult.capabilities.completionProvider)
4041
}
4142

43+
func testEmptySourceKitLSPOptionsCanBeDecoded() {
44+
// Check that none of the keys in `SourceKitLSPOptions` are required.
45+
assertNoThrow {
46+
try JSONDecoder().decode(SourceKitLSPOptions.self, from: "{}") == SourceKitLSPOptions()
47+
}
48+
}
49+
4250
func testCancellation() async throws {
4351
let testClient = try await TestSourceKitLSPClient()
4452
let uri = DocumentURI(for: .swift)

0 commit comments

Comments
 (0)