Skip to content

Commit 534427c

Browse files
committed
[PackageLoading] Print warnings when loading manifests
We were supressing the warnings while loading the manifests because we considered any type of output from the compiler as a sign of error. This changes the error state to depend on the exit code. The warnings will be printed when loading a resolved package graph and not during dependency resolution. This makes sense because the manifest we look at during dependency resolution might not be used in the final resolved graph. <rdar://problem/41180566> SwiftPM should not suppress compiler warnings in the manifest file
1 parent 30be346 commit 534427c

File tree

6 files changed

+68
-25
lines changed

6 files changed

+68
-25
lines changed

Sources/PackageGraph/RepositoryPackageContainerProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ public class LocalPackageContainer: BasePackageContainer, CustomStringConvertibl
186186

187187
// Load the manifest.
188188
_manifest = try manifestLoader.load(
189-
packagePath: AbsolutePath(identifier.path),
189+
package: AbsolutePath(identifier.path),
190190
baseURL: identifier.path,
191191
version: nil,
192192
manifestVersion: toolsVersion.manifestVersion,

Sources/PackageLoading/Diagnostics.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,16 @@ public enum PackageBuilderDiagnostics {
139139
let path: String
140140
}
141141
}
142+
143+
public struct ManifestLoadingDiagnostic: DiagnosticData {
144+
public static let id = DiagnosticID(
145+
type: ManifestLoadingDiagnostic.self,
146+
name: "org.swift.diags.pkg-loading.manifest-output",
147+
defaultBehavior: .warning,
148+
description: {
149+
$0 <<< { $0.output }
150+
}
151+
)
152+
153+
public let output: String
154+
}

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ public protocol ManifestLoaderProtocol {
8383
baseURL: String,
8484
version: Version?,
8585
manifestVersion: ManifestVersion,
86-
fileSystem: FileSystem?
86+
fileSystem: FileSystem?,
87+
diagnostics: DiagnosticsEngine?
8788
) throws -> Manifest
8889
}
8990

@@ -100,14 +101,17 @@ extension ManifestLoaderProtocol {
100101
baseURL: String,
101102
version: Version? = nil,
102103
manifestVersion: ManifestVersion,
103-
fileSystem: FileSystem? = nil
104+
fileSystem: FileSystem? = nil,
105+
diagnostics: DiagnosticsEngine? = nil
104106
) throws -> Manifest {
105107
return try load(
106108
packagePath: path,
107109
baseURL: baseURL,
108110
version: version,
109111
manifestVersion: manifestVersion,
110-
fileSystem: fileSystem)
112+
fileSystem: fileSystem,
113+
diagnostics: diagnostics
114+
)
111115
}
112116
}
113117

@@ -163,14 +167,17 @@ public final class ManifestLoader: ManifestLoaderProtocol {
163167
baseURL: String,
164168
version: Version?,
165169
manifestVersion: ManifestVersion,
166-
fileSystem: FileSystem? = nil
170+
fileSystem: FileSystem? = nil,
171+
diagnostics: DiagnosticsEngine? = nil
167172
) throws -> Manifest {
168173
return try loadFile(
169174
path: Manifest.path(atPackagePath: path, fileSystem: fileSystem ?? localFileSystem),
170175
baseURL: baseURL,
171176
version: version,
172177
manifestVersion: manifestVersion,
173-
fileSystem: fileSystem)
178+
fileSystem: fileSystem,
179+
diagnostics: diagnostics
180+
)
174181
}
175182

176183
/// Create a manifest by loading a specific manifest file from the given `path`.
@@ -185,7 +192,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
185192
baseURL: String,
186193
version: Version?,
187194
manifestVersion: ManifestVersion,
188-
fileSystem: FileSystem? = nil
195+
fileSystem: FileSystem? = nil,
196+
diagnostics: DiagnosticsEngine? = nil
189197
) throws -> Manifest {
190198

191199
// Inform the delegate.
@@ -201,7 +209,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
201209
let jsonString: String
202210
do {
203211
jsonString = try loadJSONString(
204-
path: inputPath, manifestVersion: manifestVersion, fs: fileSystem)
212+
path: inputPath, manifestVersion: manifestVersion,
213+
fs: fileSystem, diagnostics: diagnostics)
205214
} catch let error as StringError {
206215
throw ManifestParseError.invalidManifestFormat(error.description)
207216
}
@@ -248,19 +257,20 @@ public final class ManifestLoader: ManifestLoaderProtocol {
248257
func loadJSONString(
249258
path inputPath: AbsolutePath,
250259
manifestVersion: ManifestVersion,
251-
fs: FileSystem? = nil
260+
fs: FileSystem? = nil,
261+
diagnostics: DiagnosticsEngine? = nil
252262
) throws -> String {
253263
// If we were given a filesystem, load via a temporary file.
254264
if let fs = fs {
255265
let contents = try fs.readFileContents(inputPath)
256266
let tmpFile = try TemporaryFile(suffix: ".swift")
257267
try localFileSystem.writeFileContents(tmpFile.path, bytes: contents)
258-
return try parse(path: tmpFile.path, manifestVersion: manifestVersion)
268+
return try parse(path: tmpFile.path, manifestVersion: manifestVersion, diagnostics: diagnostics)
259269
}
260270

261271
// Load directly if manifest caching is not enabled.
262272
if !self.isManifestCachingEnabled {
263-
return try parse(path: inputPath, manifestVersion: manifestVersion)
273+
return try parse(path: inputPath, manifestVersion: manifestVersion, diagnostics: diagnostics)
264274
}
265275

266276
// Otherwise load via llbuild.
@@ -274,7 +284,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
274284
/// Parse the manifest at the given path to JSON.
275285
func parse(
276286
path manifestPath: AbsolutePath,
277-
manifestVersion: ManifestVersion
287+
manifestVersion: ManifestVersion,
288+
diagnostics: DiagnosticsEngine? = nil
278289
) throws -> String {
279290
self.delegate?.willParse(manifest: manifestPath)
280291

@@ -304,7 +315,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
304315
cmd += [resources.swiftCompiler.asString]
305316
cmd += ["--driver-mode=swift"]
306317
cmd += verbosity.ccArgs
307-
cmd += ["-L", runtimePath, "-lPackageDescription", "-suppress-warnings"]
318+
cmd += ["-L", runtimePath, "-lPackageDescription"]
308319
cmd += interpreterFlags
309320
cmd += [manifestPath.asString]
310321

@@ -317,10 +328,13 @@ public final class ManifestLoader: ManifestLoaderProtocol {
317328
let result = try Process.popen(arguments: cmd)
318329
let output = try (result.utf8Output() + result.utf8stderrOutput()).chuzzle()
319330

320-
// We expect output from interpreter to be empty, if something was emitted
321-
// throw and report it.
322-
if let output = output {
323-
throw StringError(output)
331+
// Throw an error if there was a non-zero exit or emit the output
332+
// produced by the process. A process output will usually mean there
333+
// was a warning emitted by the Swift compiler.
334+
if result.exitStatus != .terminated(code: 0) {
335+
throw StringError(output ?? "<unknown>")
336+
} else if let output = output {
337+
diagnostics?.emit(data: ManifestLoadingDiagnostic(output: output))
324338
}
325339

326340
guard let json = try localFileSystem.readFileContents(file.path).asString else {

Sources/TestSupport/MockManifestLoader.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public final class MockManifestLoader: ManifestLoaderProtocol {
5656
baseURL: String,
5757
version: Version?,
5858
manifestVersion: ManifestVersion,
59-
fileSystem: FileSystem?
59+
fileSystem: FileSystem?,
60+
diagnostics: DiagnosticsEngine?
6061
) throws -> PackageModel.Manifest {
6162
let key = Key(url: PackageReference.computeIdentity(packageURL: baseURL), version: version)
6263
if let result = manifests[key] {

Sources/Workspace/Workspace.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,8 @@ extension Workspace {
987987
package: packagePath,
988988
baseURL: url,
989989
version: version,
990-
manifestVersion: toolsVersion.manifestVersion
990+
manifestVersion: toolsVersion.manifestVersion,
991+
diagnostics: diagnostics
991992
)
992993
})
993994
}

Tests/PackageLoadingTests/PD4LoadingTests.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,11 @@ class PackageDescription4LoadingTests: XCTestCase {
365365
}
366366
}
367367

368-
func testManifestWithWarnings() {
368+
func testManifestWithWarnings() throws {
369+
let fs = InMemoryFileSystem()
370+
let manifestPath = AbsolutePath.root.appending(component: Manifest.filename)
369371
let stream = BufferedOutputByteStream()
372+
370373
stream <<< """
371374
import PackageDescription
372375
func foo() {
@@ -377,11 +380,22 @@ class PackageDescription4LoadingTests: XCTestCase {
377380
)
378381
"""
379382

380-
loadManifest(stream.bytes) { manifest in
381-
XCTAssertEqual(manifest.name, "Trivial")
382-
XCTAssertEqual(manifest.manifestVersion, .v4)
383-
XCTAssertEqual(manifest.targets, [])
384-
XCTAssertEqual(manifest.dependencies, [])
383+
try fs.writeFileContents(manifestPath, bytes: stream.bytes)
384+
385+
let diagnostics = DiagnosticsEngine()
386+
let manifest = try manifestLoader.load(
387+
package: .root, baseURL: AbsolutePath.root.asString,
388+
manifestVersion: .v4, fileSystem: fs,
389+
diagnostics: diagnostics
390+
)
391+
392+
XCTAssertEqual(manifest.name, "Trivial")
393+
XCTAssertEqual(manifest.manifestVersion, .v4)
394+
XCTAssertEqual(manifest.targets, [])
395+
XCTAssertEqual(manifest.dependencies, [])
396+
397+
DiagnosticsEngineTester(diagnostics) { result in
398+
result.check(diagnostic: .contains("initialization of immutable value 'a' was never used"), behavior: .warning)
385399
}
386400
}
387401
}

0 commit comments

Comments
 (0)