Skip to content

Commit cec098d

Browse files
authored
Merge pull request #1213 from ahoppen/6.0/merge-main-2024-05-01
Merge `main` into `release/6.0`
2 parents d14ddcf + fe4bbd3 commit cec098d

18 files changed

+759
-43
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ let package = Package(
309309
.product(name: "SwiftRefactor", package: "swift-syntax"),
310310
.product(name: "SwiftSyntax", package: "swift-syntax"),
311311
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
312+
.product(name: "SwiftPM-auto", package: "swift-package-manager"),
312313
],
313314
exclude: ["CMakeLists.txt"]
314315
),

Sources/LanguageServerProtocol/SupportTypes/VersionedTextDocumentIdentifier.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,18 @@ public struct OptionalVersionedTextDocumentIdentifier: Hashable, Codable, Sendab
5353
self.uri = uri
5454
self.version = version
5555
}
56+
57+
enum CodingKeys: CodingKey {
58+
case uri
59+
case version
60+
}
61+
62+
public func encode(to encoder: any Encoder) throws {
63+
var container = encoder.container(keyedBy: CodingKeys.self)
64+
try container.encode(self.uri, forKey: .uri)
65+
66+
// Note: we use encode(_:forKey:) here instead of encodeIf(_:forKey:)
67+
// because VSCode will drop requests without the explicit 'null'.
68+
try container.encode(self.version, forKey: .version)
69+
}
5670
}

Sources/SKSwiftPMWorkspace/SwiftPMBuildSystem.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ extension SwiftPMBuildSystem {
263263
self.fileToTarget = [AbsolutePath: SwiftBuildTarget](
264264
modulesGraph.allTargets.flatMap { target in
265265
return target.sources.paths.compactMap {
266-
guard let buildTarget = buildDescription.getBuildTarget(for: target) else {
266+
guard let buildTarget = buildDescription.getBuildTarget(for: target, in: modulesGraph) else {
267267
return nil
268268
}
269269
return (key: $0, value: buildTarget)
@@ -277,7 +277,7 @@ extension SwiftPMBuildSystem {
277277

278278
self.sourceDirToTarget = [AbsolutePath: SwiftBuildTarget](
279279
modulesGraph.allTargets.compactMap { (target) -> (AbsolutePath, SwiftBuildTarget)? in
280-
guard let buildTarget = buildDescription.getBuildTarget(for: target) else {
280+
guard let buildTarget = buildDescription.getBuildTarget(for: target, in: modulesGraph) else {
281281
return nil
282282
}
283283
return (key: target.sources.root, value: buildTarget)
@@ -439,8 +439,13 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
439439
}
440440

441441
public func testFiles() -> [DocumentURI] {
442-
// We should only include source files from test targets (https://github.com/apple/sourcekit-lsp/issues/1174).
443-
return fileToTarget.map { DocumentURI($0.key.asURL) }
442+
return fileToTarget.compactMap { (path, target) -> DocumentURI? in
443+
guard target.isPartOfRootPackage else {
444+
// Don't consider files from package dependencies as possible test files.
445+
return nil
446+
}
447+
return DocumentURI(path.asURL)
448+
}
444449
}
445450

446451
public func addTestFilesDidChangeCallback(_ callback: @Sendable @escaping () async -> Void) async {

Sources/SKTestSupport/MultiFileTestProject.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ public struct RelativeFileLocation: Hashable, ExpressibleByStringLiteral {
3131
let components = value.components(separatedBy: "/")
3232
self.init(directories: components.dropLast(), components.last!)
3333
}
34+
35+
public func url(relativeTo: URL) -> URL {
36+
var url = relativeTo
37+
for directory in directories {
38+
url = url.appendingPathComponent(directory)
39+
}
40+
url = url.appendingPathComponent(fileName)
41+
return url
42+
}
3443
}
3544

3645
/// A test project that writes multiple files to disk and opens a `TestSourceKitLSPClient` client with a workspace
@@ -69,7 +78,7 @@ public class MultiFileTestProject {
6978
/// File contents can also contain `$TEST_DIR`, which gets replaced by the temporary directory.
7079
public init(
7180
files: [RelativeFileLocation: String],
72-
workspaces: (URL) -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
81+
workspaces: (URL) async throws -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
7382
usePullDiagnostics: Bool = true,
7483
testName: String = #function
7584
) async throws {
@@ -79,11 +88,7 @@ public class MultiFileTestProject {
7988
var fileData: [String: FileData] = [:]
8089
for (fileLocation, markedText) in files {
8190
let markedText = markedText.replacingOccurrences(of: "$TEST_DIR", with: scratchDirectory.path)
82-
var fileURL = scratchDirectory
83-
for directory in fileLocation.directories {
84-
fileURL = fileURL.appendingPathComponent(directory)
85-
}
86-
fileURL = fileURL.appendingPathComponent(fileLocation.fileName)
91+
let fileURL = fileLocation.url(relativeTo: scratchDirectory)
8792
try FileManager.default.createDirectory(
8893
at: fileURL.deletingLastPathComponent(),
8994
withIntermediateDirectories: true
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
import ISDBTibs
15+
import XCTest
16+
17+
import struct TSCBasic.AbsolutePath
18+
import class TSCBasic.Process
19+
import enum TSCBasic.ProcessEnv
20+
import struct TSCBasic.ProcessResult
21+
22+
/// A SwiftPM package that gets written to disk and for which a Git repository is initialized with a commit tagged
23+
/// `1.0.0`. This repository can then be used as a dependency for another package, usually a `SwiftPMTestProject`.
24+
public class SwiftPMDependencyProject {
25+
/// The directory in which the repository lives.
26+
public let packageDirectory: URL
27+
28+
private func runCommand(_ toolName: String, _ arguments: [String], workingDirectory: URL) async throws {
29+
enum Error: Swift.Error {
30+
case cannotFindTool(toolName: String)
31+
case processedTerminatedWithNonZeroExitCode(ProcessResult)
32+
}
33+
guard let toolUrl = findTool(name: toolName) else {
34+
if ProcessEnv.block["SWIFTCI_USE_LOCAL_DEPS"] == nil {
35+
// Never skip the test in CI, similar to what SkipUnless does.
36+
throw XCTSkip("\(toolName) cannot be found")
37+
}
38+
throw Error.cannotFindTool(toolName: toolName)
39+
}
40+
print([toolUrl.path] + arguments)
41+
let process = TSCBasic.Process(
42+
arguments: [toolUrl.path] + arguments,
43+
workingDirectory: try AbsolutePath(validating: workingDirectory.path)
44+
)
45+
try process.launch()
46+
let processResult = try await process.waitUntilExit()
47+
guard processResult.exitStatus == .terminated(code: 0) else {
48+
throw Error.processedTerminatedWithNonZeroExitCode(processResult)
49+
}
50+
}
51+
52+
public static let defaultPackageManifest: String = """
53+
// swift-tools-version: 5.7
54+
55+
import PackageDescription
56+
57+
let package = Package(
58+
name: "MyDependency",
59+
products: [.library(name: "MyDependency", targets: ["MyDependency"])],
60+
targets: [.target(name: "MyDependency")]
61+
)
62+
"""
63+
64+
public init(
65+
files: [RelativeFileLocation: String],
66+
manifest: String = defaultPackageManifest,
67+
testName: String = #function
68+
) async throws {
69+
packageDirectory = try testScratchDir(testName: testName).appendingPathComponent("MyDependency")
70+
71+
var files = files
72+
files["Package.swift"] = manifest
73+
74+
for (fileLocation, contents) in files {
75+
let fileURL = fileLocation.url(relativeTo: packageDirectory)
76+
try FileManager.default.createDirectory(
77+
at: fileURL.deletingLastPathComponent(),
78+
withIntermediateDirectories: true
79+
)
80+
try contents.write(to: fileURL, atomically: true, encoding: .utf8)
81+
}
82+
83+
try await runCommand("git", ["init"], workingDirectory: packageDirectory)
84+
try await runCommand(
85+
"git",
86+
["add"] + files.keys.map { $0.url(relativeTo: packageDirectory).path },
87+
workingDirectory: packageDirectory
88+
)
89+
try await runCommand(
90+
"git",
91+
["-c", "user.name=Dummy", "-c", "[email protected]", "commit", "-m", "Initial commit"],
92+
workingDirectory: packageDirectory
93+
)
94+
try await runCommand("git", ["tag", "1.0.0"], workingDirectory: packageDirectory)
95+
}
96+
97+
deinit {
98+
if cleanScratchDirectories {
99+
try? FileManager.default.removeItem(at: packageDirectory)
100+
}
101+
}
102+
103+
/// Function that makes sure the project stays alive until this is called. Otherwise, the `SwiftPMDependencyProject`
104+
/// might get deinitialized, which deletes the package on disk.
105+
public func keepAlive() {
106+
withExtendedLifetime(self) { _ in }
107+
}
108+
}

Sources/SKTestSupport/SwiftPMTestProject.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class SwiftPMTestProject: MultiFileTestProject {
3838
public init(
3939
files: [RelativeFileLocation: String],
4040
manifest: String = SwiftPMTestProject.defaultPackageManifest,
41-
workspaces: (URL) -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
41+
workspaces: (URL) async throws -> [WorkspaceFolder] = { [WorkspaceFolder(uri: DocumentURI($0))] },
4242
build: Bool = false,
4343
allowBuildFailure: Bool = false,
4444
usePullDiagnostics: Bool = true,
@@ -59,6 +59,7 @@ public class SwiftPMTestProject: MultiFileTestProject {
5959
filesByPath[RelativeFileLocation(directories: directories, fileLocation.fileName)] = contents
6060
}
6161
filesByPath["Package.swift"] = manifest
62+
6263
try await super.init(
6364
files: filesByPath,
6465
workspaces: workspaces,
@@ -96,4 +97,18 @@ public class SwiftPMTestProject: MultiFileTestProject {
9697
environment["SWIFTPM_ENABLE_CLANG_INDEX_STORE"] = "1"
9798
try await Process.checkNonZeroExit(arguments: arguments, environmentBlock: environment)
9899
}
100+
101+
/// Resolve package dependencies for the package at `path`.
102+
public static func resolvePackageDependencies(at path: URL) async throws {
103+
guard let swift = await ToolchainRegistry.forTesting.default?.swift?.asURL else {
104+
throw Error.swiftNotFound
105+
}
106+
let arguments = [
107+
swift.path,
108+
"package",
109+
"resolve",
110+
"--package-path", path.path,
111+
]
112+
try await Process.checkNonZeroExit(arguments: arguments)
113+
}
99114
}

Sources/SourceKitLSP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ target_sources(SourceKitLSP PRIVATE
2323
target_sources(SourceKitLSP PRIVATE
2424
Swift/AdjustPositionToStartOfIdentifier.swift
2525
Swift/CodeActions/ConvertIntegerLiteral.swift
26+
Swift/CodeActions/PackageManifestEdits.swift
2627
Swift/CodeActions/SyntaxCodeActionProvider.swift
2728
Swift/CodeActions/SyntaxCodeActions.swift
2829
Swift/CodeActions/SyntaxRefactoringCodeActionProvider.swift
@@ -74,5 +75,6 @@ target_link_libraries(SourceKitLSP PUBLIC
7475
SwiftSyntax::SwiftRefactor
7576
SwiftSyntax::SwiftSyntax)
7677
target_link_libraries(SourceKitLSP PRIVATE
78+
PackageModelSyntax
7779
$<$<NOT:$<PLATFORM_ID:Darwin>>:FoundationXML>)
7880

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ public actor SourceKitLSPServer {
821821
return nil
822822
}
823823

824-
logger.info("Using toolchain \(toolchain.displayName) (\(toolchain.identifier)) for \(uri.forLogging)")
824+
logger.log("Using toolchain \(toolchain.displayName) (\(toolchain.identifier)) for \(uri.forLogging)")
825825

826826
if let concurrentlySetService = workspace.documentService[uri] {
827827
// Since we await the construction of `service`, another call to this

0 commit comments

Comments
 (0)