mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
120 lines
4.3 KiB
Swift
120 lines
4.3 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import BuildServerIntegration
|
|
import Foundation
|
|
@_spi(SourceKitLSP) import LanguageServerProtocol
|
|
import SKTestSupport
|
|
import ToolchainRegistry
|
|
|
|
/// A SwiftPM project that is built from files specified inside the test case and that can provide compiler arguments
|
|
/// for those files.
|
|
///
|
|
/// Compared to `SwiftPMTestProject`, the main difference is that this does not start a SourceKit-LSP server.
|
|
final class PluginSwiftPMTestProject {
|
|
/// The directory in which the temporary files are being placed.
|
|
let scratchDirectory: URL
|
|
|
|
private let fileData: [String: MultiFileTestProject.FileData]
|
|
|
|
private var _buildServerManager: BuildServerManager?
|
|
private var buildServerManager: BuildServerManager {
|
|
get async throws {
|
|
if let _buildServerManager {
|
|
return _buildServerManager
|
|
}
|
|
let buildServerManager = await BuildServerManager(
|
|
buildServerSpec: BuildServerSpec(
|
|
kind: .swiftPM,
|
|
projectRoot: scratchDirectory,
|
|
configPath: scratchDirectory.appending(component: "Package.swift")
|
|
),
|
|
toolchainRegistry: .forTesting,
|
|
options: try .testDefault(backgroundIndexing: false),
|
|
connectionToClient: DummyBuildServerManagerConnectionToClient(),
|
|
buildServerHooks: BuildServerHooks(),
|
|
createMainFilesProvider: { _, _ in nil }
|
|
)
|
|
_buildServerManager = buildServerManager
|
|
return buildServerManager
|
|
}
|
|
}
|
|
|
|
enum Error: Swift.Error {
|
|
/// No file with the given filename is known to the `PluginSwiftPMTestProject`.
|
|
case fileNotFound
|
|
|
|
/// `PluginSwiftPMTestProject` did not produce compiler arguments for a file.
|
|
case failedToRetrieveCompilerArguments
|
|
}
|
|
|
|
package init(
|
|
files: [RelativeFileLocation: String],
|
|
testName: String = #function
|
|
) async throws {
|
|
scratchDirectory = try testScratchDir(testName: testName)
|
|
self.fileData = try MultiFileTestProject.writeFilesToDisk(files: files, scratchDirectory: scratchDirectory)
|
|
|
|
// Build package
|
|
try await SwiftPMTestProject.build(at: scratchDirectory)
|
|
}
|
|
|
|
deinit {
|
|
if cleanScratchDirectories {
|
|
try? FileManager.default.removeItem(at: scratchDirectory)
|
|
}
|
|
}
|
|
|
|
/// Returns the URI of the file with the given name.
|
|
package func uri(for fileName: String) throws -> DocumentURI {
|
|
guard let fileData = self.fileData[fileName] else {
|
|
throw Error.fileNotFound
|
|
}
|
|
return fileData.uri
|
|
}
|
|
|
|
/// Returns the position of the given marker in the given file.
|
|
package func position(of marker: String, in fileName: String) throws -> Position {
|
|
guard let fileData = self.fileData[fileName] else {
|
|
throw Error.fileNotFound
|
|
}
|
|
return DocumentPositions(markedText: fileData.markedText)[marker]
|
|
}
|
|
|
|
/// Returns the contents of the file with the given name.
|
|
package func contents(of fileName: String) throws -> String {
|
|
guard let fileData = self.fileData[fileName] else {
|
|
throw Error.fileNotFound
|
|
}
|
|
return extractMarkers(fileData.markedText).textWithoutMarkers
|
|
}
|
|
|
|
package func compilerArguments(for fileName: String) async throws -> [String] {
|
|
try await buildServerManager.waitForUpToDateBuildGraph()
|
|
let buildSettings = try await buildServerManager.buildSettingsInferredFromMainFile(
|
|
for: try uri(for: fileName),
|
|
language: .swift,
|
|
fallbackAfterTimeout: false
|
|
)
|
|
guard let buildSettings else {
|
|
throw Error.failedToRetrieveCompilerArguments
|
|
}
|
|
let compilerArguments = buildSettings.compilerArguments
|
|
if compilerArguments.first?.hasSuffix("swiftc") ?? false {
|
|
// Compiler arguments returned from SwiftPMWorkspace contain the compiler executable.
|
|
// sourcekitd does not expect the compiler arguments to contain the executable.
|
|
return Array(compilerArguments.dropFirst())
|
|
}
|
|
return compilerArguments
|
|
}
|
|
}
|