diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Package.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Package.swift new file mode 100644 index 00000000000..638cb789758 --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Package.swift @@ -0,0 +1,13 @@ +// swift-tools-version:5.8 + +import PackageDescription + +let package = Package( + name: "ExistentialAnyMigration", + targets: [ + .target(name: "Library", dependencies: ["CommonLibrary"], plugins: [.plugin(name: "Plugin")]), + .plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]), + .executableTarget(name: "Tool", dependencies: ["CommonLibrary"]), + .target(name: "CommonLibrary"), + ] +) diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Plugins/Plugin/Plugin.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Plugins/Plugin/Plugin.swift new file mode 100644 index 00000000000..2410af9dbef --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Plugins/Plugin/Plugin.swift @@ -0,0 +1,17 @@ +import PackagePlugin +import Foundation + +@main struct Plugin: BuildToolPlugin { + func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { + let tool = try context.tool(named: "Tool") + let output = context.pluginWorkDirectory.appending(["generated.swift"]) + return [ + .buildCommand( + displayName: "Plugin", + executable: tool.path, + arguments: [output], + inputFiles: [], + outputFiles: [output]) + ] + } +} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/CommonLibrary/Common.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/CommonLibrary/Common.swift new file mode 100644 index 00000000000..4f6ab41fc9b --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/CommonLibrary/Common.swift @@ -0,0 +1,6 @@ +public func common() {} + + +protocol P {} + +func needsMigration(_ p: P) {} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Library/Test.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Library/Test.swift new file mode 100644 index 00000000000..bc8a65d8348 --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Library/Test.swift @@ -0,0 +1,6 @@ +import CommonLibrary + +func bar() { + generatedFunction() + common() +} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Tool/tool.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Tool/tool.swift new file mode 100644 index 00000000000..e69e49865a4 --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Tool/tool.swift @@ -0,0 +1,13 @@ +import Foundation +import CommonLibrary + +@main struct Entry { + public static func main() async throws { + common() + let outputPath = CommandLine.arguments[1] + let contents = """ + func generatedFunction() {} + """ + FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8)) + } +} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Package.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Package.swift new file mode 100644 index 00000000000..5a689efe60d --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Package.swift @@ -0,0 +1,12 @@ +// swift-tools-version:5.8 + +import PackageDescription + +let package = Package( + name: "ExistentialAnyMigration", + targets: [ + .target(name: "Library", plugins: [.plugin(name: "Plugin")]), + .plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]), + .executableTarget(name: "Tool"), + ] +) diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Plugins/Plugin/Plugin.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Plugins/Plugin/Plugin.swift new file mode 100644 index 00000000000..2410af9dbef --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Plugins/Plugin/Plugin.swift @@ -0,0 +1,17 @@ +import PackagePlugin +import Foundation + +@main struct Plugin: BuildToolPlugin { + func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { + let tool = try context.tool(named: "Tool") + let output = context.pluginWorkDirectory.appending(["generated.swift"]) + return [ + .buildCommand( + displayName: "Plugin", + executable: tool.path, + arguments: [output], + inputFiles: [], + outputFiles: [output]) + ] + } +} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Library/Test.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Library/Test.swift new file mode 100644 index 00000000000..dfae68a022d --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Library/Test.swift @@ -0,0 +1,20 @@ +protocol P { +} + +func test1(_: P) { +} + +func test2(_: P.Protocol) { +} + +func test3() { + let _: [P?] = [] +} + +func test4() { + var x = 42 +} + +func bar() { + generatedFunction() +} diff --git a/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Tool/tool.swift b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Tool/tool.swift new file mode 100644 index 00000000000..18c38c1df83 --- /dev/null +++ b/Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Tool/tool.swift @@ -0,0 +1,12 @@ +import Foundation + +@main struct Entry { + public static func main() async throws { + let outputPath = CommandLine.arguments[1] + let contents = """ + func generatedFunction() {} + func dontmodifyme(_: P) {} + """ + FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8)) + } +} diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 17b63ac880b..747c1ef7e44 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -396,9 +396,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS } /// Perform a build using the given build description and subset. - public func build(subset: BuildSubset) async throws { + public func build(subset: BuildSubset) async throws -> BuildResult { guard !self.config.shouldSkipBuilding(for: .target) else { - return + return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("Building was skipped"))) } let buildStartTime = DispatchTime.now() @@ -422,7 +422,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS // any errors up-front. Returns true if we should proceed with the build // or false if not. It will already have thrown any appropriate error. guard try await self.compilePlugins(in: subset) else { - return + return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("Plugin compilation failed"))) } let configuration = self.config.configuration(for: .target) @@ -452,6 +452,17 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS ) guard success else { throw Diagnostics.fatalError } + let serializedDiagnosticResult: Result<[String: [AbsolutePath]], Error> + var serializedDiagnosticPaths: [String: [AbsolutePath]] = [:] + do { + for module in try buildPlan.buildModules { + serializedDiagnosticPaths[module.module.name, default: []].append(contentsOf: module.diagnosticFiles) + } + serializedDiagnosticResult = .success(serializedDiagnosticPaths) + } catch { + serializedDiagnosticResult = .failure(error) + } + // Create backwards-compatibility symlink to old build path. let oldBuildPath = self.config.dataPath(for: .target).parentDirectory.appending( component: configuration.dirname @@ -463,7 +474,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS warning: "unable to delete \(oldBuildPath), skip creating symbolic link", underlyingError: error ) - return + return BuildResult(serializedDiagnosticPathsByTargetName: serializedDiagnosticResult) } } @@ -479,6 +490,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS underlyingError: error ) } + + return BuildResult(serializedDiagnosticPathsByTargetName: serializedDiagnosticResult) } /// Compiles any plugins specified or implied by the build subset, returning diff --git a/Sources/Commands/PackageCommands/Migrate.swift b/Sources/Commands/PackageCommands/Migrate.swift index 95098638934..4cc4663f27d 100644 --- a/Sources/Commands/PackageCommands/Migrate.swift +++ b/Sources/Commands/PackageCommands/Migrate.swift @@ -90,7 +90,7 @@ extension SwiftPackageCommand { features.append(feature) } - let targets = self.options.targets + var targets = self.options.targets let buildSystem = try await createBuildSystem( swiftCommandState, @@ -100,49 +100,29 @@ extension SwiftPackageCommand { // Next, let's build all of the individual targets or the // whole project to get diagnostic files. - print("> Starting the build") + var diagnosticsPaths: [String: [AbsolutePath]] = [:] if !targets.isEmpty { for target in targets { - try await buildSystem.build(subset: .target(target)) + let buildResult = try await buildSystem.build(subset: .target(target)) + diagnosticsPaths.merge(try buildResult.serializedDiagnosticPathsByTargetName.get(), uniquingKeysWith: { $0 + $1 }) } } else { - try await buildSystem.build(subset: .allIncludingTests) + diagnosticsPaths = try await buildSystem.build(subset: .allIncludingTests).serializedDiagnosticPathsByTargetName.get() } - // Determine all of the targets we need up update. - let buildPlan = try buildSystem.buildPlan - - var modules: [any ModuleBuildDescription] = [] - if !targets.isEmpty { - for buildDescription in buildPlan.buildModules - where targets.contains(buildDescription.module.name) { - modules.append(buildDescription) - } - } else { - let graph = try await buildSystem.getPackageGraph() - for buildDescription in buildPlan.buildModules - where graph.isRootPackage(buildDescription.package) - { - let module = buildDescription.module - guard module.type != .plugin, !module.implicit else { - continue - } - modules.append(buildDescription) - } + var summary = SwiftFixIt.Summary(numberOfFixItsApplied: 0, numberOfFilesChanged: 0) + let graph = try await buildSystem.getPackageGraph() + if targets.isEmpty { + targets = OrderedSet(graph.rootPackages.flatMap { $0.manifest.targets.filter { $0.type != .plugin }.map(\.name) }) } - - // If the build suceeded, let's extract all of the diagnostic - // files from build plan and feed them to the fix-it tool. - print("> Applying fix-its") - - var summary = SwiftFixIt.Summary(numberOfFixItsApplied: 0, numberOfFilesChanged: 0) let fixItDuration = try ContinuousClock().measure { - for module in modules { + for target in targets { let fixit = try SwiftFixIt( - diagnosticFiles: module.diagnosticFiles, + diagnosticFiles: Array(diagnosticsPaths[target] ?? []), categories: Set(features.flatMap(\.categories)), + excludedSourceDirectories: [swiftCommandState.scratchDirectory], fileSystem: swiftCommandState.fileSystem ) summary += try fixit.applyFixIts() @@ -176,10 +156,10 @@ extension SwiftPackageCommand { // manifest with newly adopted feature settings. print("> Updating manifest") - for module in modules.map(\.module) { - swiftCommandState.observabilityScope.emit(debug: "Adding feature(s) to '\(module.name)'") + for target in targets { + swiftCommandState.observabilityScope.emit(debug: "Adding feature(s) to '\(target)'") try self.updateManifest( - for: module.name, + for: target, add: features, using: swiftCommandState ) diff --git a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift index 9f29a66fdbc..9eb77b58637 100644 --- a/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift +++ b/Sources/SPMBuildCore/BuildSystem/BuildSystem.swift @@ -50,7 +50,8 @@ public protocol BuildSystem: Cancellable { /// Builds a subset of the package graph. /// - Parameters: /// - subset: The subset of the package graph to build. - func build(subset: BuildSubset) async throws + @discardableResult + func build(subset: BuildSubset) async throws -> BuildResult var buildPlan: BuildPlan { get throws } @@ -59,11 +60,20 @@ public protocol BuildSystem: Cancellable { extension BuildSystem { /// Builds the default subset: all targets excluding tests. - public func build() async throws { + @discardableResult + public func build() async throws -> BuildResult { try await build(subset: .allExcludingTests) } } +public struct BuildResult { + package init(serializedDiagnosticPathsByTargetName: Result<[String: [AbsolutePath]], Error>) { + self.serializedDiagnosticPathsByTargetName = serializedDiagnosticPathsByTargetName + } + + public var serializedDiagnosticPathsByTargetName: Result<[String: [AbsolutePath]], Error> +} + public protocol ProductBuildDescription { /// The reference to the product. var package: ResolvedPackage { get } diff --git a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift index aa36f988fd6..e759c5b4e12 100644 --- a/Sources/SwiftBuildSupport/SwiftBuildSystem.swift +++ b/Sources/SwiftBuildSupport/SwiftBuildSystem.swift @@ -41,20 +41,22 @@ struct SessionFailedError: Error { var diagnostics: [SwiftBuild.SwiftBuildMessage.DiagnosticInfo] } -func withService( +func withService( connectionMode: SWBBuildServiceConnectionMode = .default, variant: SWBBuildServiceVariant = .default, serviceBundleURL: URL? = nil, - body: @escaping (_ service: SWBBuildService) async throws -> Void -) async throws { + body: @escaping (_ service: SWBBuildService) async throws -> T +) async throws -> T { let service = try await SWBBuildService(connectionMode: connectionMode, variant: variant, serviceBundleURL: serviceBundleURL) + let result: T do { - try await body(service) + result = try await body(service) } catch { await service.close() throw error } await service.close() + return result } public func createSession( @@ -279,20 +281,20 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { SwiftLanguageVersion.supportedSwiftLanguageVersions } - public func build(subset: BuildSubset) async throws { + public func build(subset: BuildSubset) async throws -> BuildResult { guard !buildParameters.shouldSkipBuilding else { - return + return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("Building was skipped"))) } try await writePIF(buildParameters: buildParameters) - try await startSWBuildOperation(pifTargetName: subset.pifTargetName) + return try await startSWBuildOperation(pifTargetName: subset.pifTargetName) } - private func startSWBuildOperation(pifTargetName: String) async throws { + private func startSWBuildOperation(pifTargetName: String) async throws -> BuildResult { let buildStartTime = ContinuousClock.Instant.now - try await withService(connectionMode: .inProcessStatic(swiftbuildServiceEntryPoint)) { service in + return try await withService(connectionMode: .inProcessStatic(swiftbuildServiceEntryPoint)) { service in let derivedDataPath = self.buildParameters.dataPath let progressAnimation = ProgressAnimation.percent( @@ -302,6 +304,7 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { isColorized: self.buildParameters.outputParameters.isColorized ) + var serializedDiagnosticPathsByTargetName: [String: [Basics.AbsolutePath]] = [:] do { try await withSession(service: service, name: self.buildParameters.pifManifest.pathString, toolchainPath: self.buildParameters.toolchain.toolchainDir, packageManagerResourcesDirectory: self.packageManagerResourcesDirectory) { session, _ in self.outputStream.send("Building for \(self.buildParameters.configuration == .debug ? "debugging" : "production")...\n") @@ -451,6 +454,11 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { } let targetInfo = try buildState.target(for: startedInfo) self.delegate?.buildSystem(self, didFinishCommand: BuildSystemCommand(startedInfo, targetInfo: targetInfo)) + if let targetName = targetInfo?.targetName { + serializedDiagnosticPathsByTargetName[targetName, default: []].append(contentsOf: startedInfo.serializedDiagnosticsPaths.compactMap { + try? Basics.AbsolutePath(validating: $0.pathString) + }) + } case .targetStarted(let info): try buildState.started(target: info) case .planningOperationStarted, .planningOperationCompleted, .reportBuildDescription, .reportPathMap, .preparedForIndex, .backtraceFrame, .buildStarted, .preparationComplete, .targetUpToDate, .targetComplete, .taskUpToDate: @@ -503,6 +511,7 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem { } catch { throw error } + return BuildResult(serializedDiagnosticPathsByTargetName: .success(serializedDiagnosticPathsByTargetName)) } } diff --git a/Sources/SwiftFixIt/SwiftFixIt.swift b/Sources/SwiftFixIt/SwiftFixIt.swift index b1539933afc..1fba05aa10c 100644 --- a/Sources/SwiftFixIt/SwiftFixIt.swift +++ b/Sources/SwiftFixIt/SwiftFixIt.swift @@ -124,9 +124,11 @@ private struct PrimaryDiagnosticFilter: ~Copyable { private var uniquePrimaryDiagnostics: Set = [] let categories: Set + let excludedSourceDirectories: Set - init(categories: Set) { + init(categories: Set, excludedSourceDirectories: Set) { self.categories = categories + self.excludedSourceDirectories = excludedSourceDirectories } /// Returns a Boolean value indicating whether to skip the given primary @@ -153,6 +155,13 @@ private struct PrimaryDiagnosticFilter: ~Copyable { } } + // Skip if the source file the diagnostic appears in is in an excluded directory. + if let sourceFilePath = try? diagnostic.location.map({ try AbsolutePath(validating: $0.filename) }) { + guard !self.excludedSourceDirectories.contains(where: { $0.isAncestor(of: sourceFilePath) }) else { + return true + } + } + let notes = primaryDiagnosticWithNotes.dropFirst() precondition(notes.allSatisfy(\.isNote)) @@ -201,6 +210,7 @@ package struct SwiftFixIt /*: ~Copyable */ { // TODO: Crashes with ~Copyable package init( diagnosticFiles: [AbsolutePath], categories: Set = [], + excludedSourceDirectories: Set = [], fileSystem: any FileSystem ) throws { // Deserialize the diagnostics. @@ -212,6 +222,7 @@ package struct SwiftFixIt /*: ~Copyable */ { // TODO: Crashes with ~Copyable self = try SwiftFixIt( diagnostics: diagnostics, categories: categories, + excludedSourceDirectories: excludedSourceDirectories, fileSystem: fileSystem ) } @@ -219,11 +230,12 @@ package struct SwiftFixIt /*: ~Copyable */ { // TODO: Crashes with ~Copyable init( diagnostics: some Collection, categories: Set, + excludedSourceDirectories: Set, fileSystem: any FileSystem ) throws { self.fileSystem = fileSystem - var filter = PrimaryDiagnosticFilter(categories: categories) + var filter = PrimaryDiagnosticFilter(categories: categories, excludedSourceDirectories: excludedSourceDirectories) _ = consume categories // Build a map from source files to `SwiftDiagnostics` diagnostics. diff --git a/Sources/XCBuildSupport/XcodeBuildSystem.swift b/Sources/XCBuildSupport/XcodeBuildSystem.swift index 64b5adf9623..0cf4eb014f6 100644 --- a/Sources/XCBuildSupport/XcodeBuildSystem.swift +++ b/Sources/XCBuildSupport/XcodeBuildSystem.swift @@ -160,9 +160,9 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem { return [] } - public func build(subset: BuildSubset) async throws { + public func build(subset: BuildSubset) async throws -> BuildResult { guard !buildParameters.shouldSkipBuilding else { - return + return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("XCBuild does not support reporting serialized diagnostics."))) } let pifBuilder = try await getPIFBuilder() @@ -244,9 +244,12 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem { throw Diagnostics.fatalError } - guard !self.logLevel.isQuiet else { return } - self.outputStream.send("Build complete!\n") - self.outputStream.flush() + if !logLevel.isQuiet { + self.outputStream.send("Build complete!\n") + self.outputStream.flush() + } + + return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("XCBuild does not support reporting serialized diagnostics."))) } func createBuildParametersFile() throws -> AbsolutePath { diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 3b96873e169..6a86089eb51 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -2156,6 +2156,44 @@ class PackageCommandTestCase: CommandsBuildProviderTestCase { try await doMigration(featureName: "InferIsolatedConformances", expectedSummary: "Applied 1 fix-it in 1 file") } + func testMigrateCommandWithBuildToolPlugins() async throws { + try XCTSkipIf( + !UserToolchain.default.supportesSupportedFeatures, + "skipping because test environment compiler doesn't support `-print-supported-features`" + ) + + try await fixture(name: "SwiftMigrate/ExistentialAnyWithPluginMigration") { fixturePath in + let (stdout, _) = try await self.execute( + ["migrate", "--to-feature", "ExistentialAny"], + packagePath: fixturePath + ) + + // Check the plugin target in the manifest wasn't updated + let manifestContent = try localFileSystem.readFileContents(fixturePath.appending(component: "Package.swift")).description + XCTAssertTrue(manifestContent.contains(".plugin(name: \"Plugin\", capability: .buildTool, dependencies: [\"Tool\"]),")) + + // Building the package produces migration fix-its in both an authored and generated source file. Check we only applied fix-its to the hand-authored one. + XCTAssertMatch(stdout, .regex("> \("Applied 3 fix-its in 1 file")" + #" \([0-9]\.[0-9]{1,3}s\)"#)) + } + } + + func testMigrateCommandWhenDependencyBuildsForHostAndTarget() async throws { + try XCTSkipIf( + !UserToolchain.default.supportesSupportedFeatures, + "skipping because test environment compiler doesn't support `-print-supported-features`" + ) + + try await fixture(name: "SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration") { fixturePath in + let (stdout, _) = try await self.execute( + ["migrate", "--to-feature", "ExistentialAny"], + packagePath: fixturePath + ) + + // Even though the CommonLibrary dependency built for both the host and destination, we should only apply a single fix-it once to its sources. + XCTAssertMatch(stdout, .regex("> \("Applied 1 fix-it in 1 file")" + #" \([0-9]\.[0-9]{1,3}s\)"#)) + } + } + func testBuildToolPlugin() async throws { try await testBuildToolPlugin(staticStdlib: false) } @@ -4125,10 +4163,6 @@ class PackageCommandSwiftBuildTests: PackageCommandTestCase { try await super.testCommandPluginBuildingCallbacks() } - override func testMigrateCommand() async throws { - throw XCTSkip("SWBINTTODO: Build plan is not currently supported") - } - override func testCommandPluginTestingCallbacks() async throws { try XCTSkipOnWindows(because: "TSCBasic/Path.swift:969: Assertion failed, https://github.com/swiftlang/swift-package-manager/issues/8602") try await super.testCommandPluginTestingCallbacks() diff --git a/Tests/SwiftFixItTests/Utilities.swift b/Tests/SwiftFixItTests/Utilities.swift index a1643bf485d..60b0f39ffeb 100644 --- a/Tests/SwiftFixItTests/Utilities.swift +++ b/Tests/SwiftFixItTests/Utilities.swift @@ -233,6 +233,7 @@ private func _testAPI( let swiftFixIt = try SwiftFixIt( diagnostics: flatDiagnostics, categories: categories, + excludedSourceDirectories: [], fileSystem: localFileSystem ) let actualSummary = try swiftFixIt.applyFixIts()