From b4fcea85eac5c740318bce27b2aa30a4f73b0da8 Mon Sep 17 00:00:00 2001 From: Dmitrii Galimzianov Date: Sat, 3 Aug 2024 04:47:20 +0200 Subject: [PATCH] [Diagnostics] Support for all the flags of the warning treating group This commit adds support for the warning treating option group, including the following options: -warnings-as-errors, -no-warnings-as-errors, -Werror, and -Wwarning. Options in this group are now preserved as-is. It is forbidden to reorder or drop any of them. These changes reflect the modifications made to the frontend in https://github.com/swiftlang/swift/pull/74466. --- Sources/SwiftDriver/Driver/Driver.swift | 17 ++++-- .../SwiftDriver/Jobs/FrontendJobHelpers.swift | 6 ++- Sources/SwiftOptions/Options.swift | 13 ++++- Tests/SwiftDriverTests/SwiftDriverTests.swift | 52 +++++++++++++++++-- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index e5d272b02..55f3ce3c5 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -2929,10 +2929,19 @@ extension Diagnostic.Message { extension Driver { static func validateWarningControlArgs(_ parsedOptions: inout ParsedOptions, diagnosticEngine: DiagnosticsEngine) { - if parsedOptions.hasArgument(.suppressWarnings) && - parsedOptions.hasFlag(positive: .warningsAsErrors, negative: .noWarningsAsErrors, default: false) { - diagnosticEngine.emit(.error(Error.conflictingOptions(.warningsAsErrors, .suppressWarnings)), - location: nil) + if parsedOptions.hasArgument(.suppressWarnings) { + if parsedOptions.hasFlag(positive: .warningsAsErrors, negative: .noWarningsAsErrors, default: false) { + diagnosticEngine.emit(.error(Error.conflictingOptions(.warningsAsErrors, .suppressWarnings)), + location: nil) + } + if parsedOptions.hasArgument(.Wwarning) { + diagnosticEngine.emit(.error(Error.conflictingOptions(.Wwarning, .suppressWarnings)), + location: nil) + } + if parsedOptions.hasArgument(.Werror) { + diagnosticEngine.emit(.error(Error.conflictingOptions(.Werror, .suppressWarnings)), + location: nil) + } } } diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index 249faca09..019cb0716 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -228,7 +228,11 @@ extension Driver { try commandLine.appendLast(.profileGenerate, from: &parsedOptions) try commandLine.appendLast(.profileUse, from: &parsedOptions) try commandLine.appendLast(.profileCoverageMapping, from: &parsedOptions) - try commandLine.appendLast(.warningsAsErrors, .noWarningsAsErrors, from: &parsedOptions) + try commandLine.appendAllExcept( + includeList: [.warningTreating], + excludeList: [], + from: &parsedOptions + ) try commandLine.appendLast(.sanitizeEQ, from: &parsedOptions) try commandLine.appendLast(.sanitizeRecoverEQ, from: &parsedOptions) try commandLine.appendLast(.sanitizeAddressUseOdrIndicator, from: &parsedOptions) diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index 6162fb5f1..6e51b1aae 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -640,7 +640,7 @@ extension Option { public static let noStrictImplicitModuleContext: Option = Option("-no-strict-implicit-module-context", .flag, attributes: [.helpHidden, .frontend], helpText: "Disable the strict forwarding of compilation context to downstream implicit module dependencies") public static let noToolchainStdlibRpath: Option = Option("-no-toolchain-stdlib-rpath", .flag, attributes: [.helpHidden, .doesNotAffectIncrementalBuild], helpText: "Do not add an rpath entry for the toolchain's standard library (default)") public static let noVerifyEmittedModuleInterface: Option = Option("-no-verify-emitted-module-interface", .flag, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild], helpText: "Don't check that module interfaces emitted during compilation typecheck") - public static let noWarningsAsErrors: Option = Option("-no-warnings-as-errors", .flag, attributes: [.frontend], helpText: "Don't treat warnings as errors") + public static let noWarningsAsErrors: Option = Option("-no-warnings-as-errors", .flag, attributes: [.frontend], helpText: "Treat warnings as warnings", group: .warningTreating) public static let noWholeModuleOptimization: Option = Option("-no-whole-module-optimization", .flag, attributes: [.frontend, .noInteractive], helpText: "Disable optimizing input files together instead of individually") public static let driverScanDependenciesNonLib: Option = Option("-nonlib-dependency-scanner", .flag, attributes: [.helpHidden], helpText: "Use calls to `swift-frontend -scan-dependencies` instead of dedicated dependency scanning library") public static let nostartfiles: Option = Option("-nostartfiles", .flag, attributes: [.helpHidden, .frontend, .noInteractive, .doesNotAffectIncrementalBuild], helpText: "Do not link in the Swift language startup routines") @@ -872,14 +872,16 @@ extension Option { public static let warnSwift3ObjcInferenceComplete: Option = Option("-warn-swift3-objc-inference-complete", .flag, attributes: [.helpHidden, .frontend, .doesNotAffectIncrementalBuild], helpText: "Deprecated, has no effect") public static let warnSwift3ObjcInferenceMinimal: Option = Option("-warn-swift3-objc-inference-minimal", .flag, attributes: [.helpHidden, .frontend, .doesNotAffectIncrementalBuild], helpText: "Deprecated, has no effect") public static let warnSwift3ObjcInference: Option = Option("-warn-swift3-objc-inference", .flag, alias: Option.warnSwift3ObjcInferenceComplete, attributes: [.helpHidden, .frontend, .doesNotAffectIncrementalBuild]) - public static let warningsAsErrors: Option = Option("-warnings-as-errors", .flag, attributes: [.frontend], helpText: "Treat warnings as errors") + public static let warningsAsErrors: Option = Option("-warnings-as-errors", .flag, attributes: [.frontend], helpText: "Treat warnings as errors", group: .warningTreating) public static let weakLinkAtTarget: Option = Option("-weak-link-at-target", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Weakly link symbols for declarations that were introduced at the deployment target. Symbols introduced before the deployment target are still strongly linked.") + public static let Werror: Option = Option("-Werror", .separate, attributes: [.helpHidden, .frontend], metaVar: "", helpText: "Treat this warning group as error", group: .warningTreating) public static let wholeModuleOptimization: Option = Option("-whole-module-optimization", .flag, attributes: [.frontend, .noInteractive], helpText: "Optimize input files together instead of individually") public static let windowsSdkRoot: Option = Option("-windows-sdk-root", .separate, attributes: [.frontend, .argumentIsPath], metaVar: "", helpText: "Windows SDK Root") public static let windowsSdkVersion: Option = Option("-windows-sdk-version", .separate, attributes: [.frontend], metaVar: "", helpText: "Windows SDK Version") public static let wmo: Option = Option("-wmo", .flag, alias: Option.wholeModuleOptimization, attributes: [.helpHidden, .frontend, .noInteractive]) public static let workingDirectoryEQ: Option = Option("-working-directory=", .joined, alias: Option.workingDirectory) public static let workingDirectory: Option = Option("-working-directory", .separate, metaVar: "", helpText: "Resolve file paths relative to the specified directory") + public static let Wwarning: Option = Option("-Wwarning", .separate, attributes: [.helpHidden, .frontend], metaVar: "", helpText: "Treat this warning group as warning", group: .warningTreating) public static let Xcc: Option = Option("-Xcc", .separate, attributes: [.frontend], metaVar: "", helpText: "Pass to the C/C++/Objective-C compiler") public static let XclangLinker: Option = Option("-Xclang-linker", .separate, attributes: [.helpHidden], metaVar: "", helpText: "Pass to Clang when it is use for linking.") public static let Xfrontend: Option = Option("-Xfrontend", .separate, attributes: [.helpHidden], metaVar: "", helpText: "Pass to the Swift frontend") @@ -1747,12 +1749,14 @@ extension Option { Option.warnSwift3ObjcInference, Option.warningsAsErrors, Option.weakLinkAtTarget, + Option.Werror, Option.wholeModuleOptimization, Option.windowsSdkRoot, Option.windowsSdkVersion, Option.wmo, Option.workingDirectoryEQ, Option.workingDirectory, + Option.Wwarning, Option.Xcc, Option.XclangLinker, Option.Xfrontend, @@ -1774,6 +1778,7 @@ extension Option { case linkerOption case modes case pluginSearch + case warningTreating } } @@ -1798,6 +1803,8 @@ extension Option.Group { return "" case .pluginSearch: return "" + case .warningTreating: + return "" } } } @@ -1823,6 +1830,8 @@ extension Option.Group { return "MODES" case .pluginSearch: return nil + case .warningTreating: + return nil } } } diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index d57954e04..ae910d19c 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -5662,7 +5662,9 @@ final class SwiftDriverTests: XCTestCase { let plannedJobs = try driver.planBuild() XCTAssertEqual(plannedJobs.count, 1) let job = plannedJobs[0] - XCTAssertTrue(job.commandLine.contains(.flag("-warnings-as-errors"))) + XCTAssertTrue(job.commandLine.contains( + subsequence: [.flag("-no-warnings-as-errors"), .flag("-warnings-as-errors")] + )) } do { @@ -5670,7 +5672,9 @@ final class SwiftDriverTests: XCTestCase { let plannedJobs = try driver.planBuild() XCTAssertEqual(plannedJobs.count, 1) let job = plannedJobs[0] - XCTAssertTrue(job.commandLine.contains(.flag("-no-warnings-as-errors"))) + XCTAssertTrue(job.commandLine.contains( + subsequence: [.flag("-warnings-as-errors"), .flag("-no-warnings-as-errors")] + )) } do { @@ -5678,16 +5682,58 @@ final class SwiftDriverTests: XCTestCase { let plannedJobs = try driver.planBuild() XCTAssertEqual(plannedJobs.count, 1) let job = plannedJobs[0] - XCTAssertTrue(job.commandLine.contains(.flag("-no-warnings-as-errors"))) + XCTAssertTrue(job.commandLine.contains( + subsequence: [.flag("-warnings-as-errors"), .flag("-no-warnings-as-errors")] + )) XCTAssertTrue(job.commandLine.contains(.flag("-suppress-warnings"))) } + do { + var driver = try Driver(args: [ + "swift", + "-warnings-as-errors", + "-no-warnings-as-errors", + "-Werror", "A", + "-Wwarning", "B", + "-Werror", "C", + "-Wwarning", "C", + "foo.swift", + ]) + let plannedJobs = try driver.planBuild() + XCTAssertEqual(plannedJobs.count, 1) + let job = plannedJobs[0] + XCTAssertTrue(job.commandLine.contains(subsequence: [ + .flag("-warnings-as-errors"), + .flag("-no-warnings-as-errors"), + .flag("-Werror"), + .flag("A"), + .flag("-Wwarning"), + .flag("B"), + .flag("-Werror"), + .flag("C"), + .flag("-Wwarning"), + .flag("C"), + ])) + } + do { try assertDriverDiagnostics(args: ["swift", "-no-warnings-as-errors", "-warnings-as-errors", "-suppress-warnings", "foo.swift"]) { $1.expect(.error(Driver.Error.conflictingOptions(.warningsAsErrors, .suppressWarnings))) } } + do { + try assertDriverDiagnostics(args: ["swift", "-Wwarning", "test", "-suppress-warnings", "foo.swift"]) { + $1.expect(.error(Driver.Error.conflictingOptions(.Wwarning, .suppressWarnings))) + } + } + + do { + try assertDriverDiagnostics(args: ["swift", "-Werror", "test", "-suppress-warnings", "foo.swift"]) { + $1.expect(.error(Driver.Error.conflictingOptions(.Werror, .suppressWarnings))) + } + } + do { var driver = try Driver(args: ["swift", "-print-educational-notes", "foo.swift"]) let plannedJobs = try driver.planBuild()