@@ -42,17 +42,22 @@ public final class SwiftABICheckerToolSpec : GenericCommandLineToolSpec, SpecIde
4242 /// The path to the serialized diagnostic output. Every clang task must provide this path.
4343 let serializedDiagnosticsPath : Path
4444
45- init ( serializedDiagnosticsPath: Path ) {
45+ let downgradeErrors : Bool
46+
47+ init ( serializedDiagnosticsPath: Path , downgradeErrors: Bool ) {
4648 self . serializedDiagnosticsPath = serializedDiagnosticsPath
49+ self . downgradeErrors = downgradeErrors
4750 }
4851 public func serialize< T: Serializer > ( to serializer: T ) {
49- serializer. serializeAggregate ( 1 ) {
52+ serializer. serializeAggregate ( 2 ) {
5053 serializer. serialize ( serializedDiagnosticsPath)
54+ serializer. serialize ( downgradeErrors)
5155 }
5256 }
5357 public init ( from deserializer: any Deserializer ) throws {
54- try deserializer. beginAggregate ( 1 )
58+ try deserializer. beginAggregate ( 2 )
5559 self . serializedDiagnosticsPath = try deserializer. deserialize ( )
60+ self . downgradeErrors = try deserializer. deserialize ( )
5661 }
5762 }
5863
@@ -67,7 +72,12 @@ public final class SwiftABICheckerToolSpec : GenericCommandLineToolSpec, SpecIde
6772
6873 // Override this func to ensure we can see these diagnostics in unit tests.
6974 public override func customOutputParserType( for task: any ExecutableTask ) -> ( any TaskOutputParser . Type ) ? {
70- return SerializedDiagnosticsOutputParser . self
75+ let payload = task. payload! as! ABICheckerPayload
76+ if payload. downgradeErrors {
77+ return APIDigesterDowngradingSerializedDiagnosticsOutputParser . self
78+ } else {
79+ return SerializedDiagnosticsOutputParser . self
80+ }
7181 }
7282 public func constructABICheckingTask( _ cbc: CommandBuildContext , _ delegate: any TaskGenerationDelegate , _ serializedDiagsPath: Path , _ baselinePath: Path ? , _ allowlistPath: Path ? ) async {
7383 let toolSpecInfo : DiscoveredSwiftCompilerToolSpecInfo
@@ -86,6 +96,10 @@ public final class SwiftABICheckerToolSpec : GenericCommandLineToolSpec, SpecIde
8696 if let allowlistPath {
8797 commandLine += [ " -breakage-allowlist-path " , allowlistPath. normalize ( ) . str]
8898 }
99+ let downgradeErrors = cbc. scope. evaluate ( BuiltinMacros . SWIFT_ABI_CHECKER_DOWNGRADE_ERRORS)
100+ if downgradeErrors {
101+ commandLine += [ " -disable-fail-on-error " ]
102+ }
89103 let allInputs = cbc. inputs. map { delegate. createNode ( $0. absolutePath) } + [ baselinePath, allowlistPath] . compactMap { $0 } . map { delegate. createNode ( $0. normalize ( ) ) }
90104 // Add import search paths
91105 for searchPath in SwiftCompilerSpec . collectInputSearchPaths ( cbc, toolInfo: toolSpecInfo) {
@@ -95,7 +109,10 @@ public final class SwiftABICheckerToolSpec : GenericCommandLineToolSpec, SpecIde
95109 commandLine += cbc. scope. evaluate ( BuiltinMacros . SWIFT_SYSTEM_INCLUDE_PATHS) . flatMap { [ " -I " , $0] }
96110 commandLine += cbc. scope. evaluate ( BuiltinMacros . SYSTEM_FRAMEWORK_SEARCH_PATHS) . flatMap { [ " -F " , $0] }
97111 delegate. createTask ( type: self ,
98- payload: ABICheckerPayload ( serializedDiagnosticsPath: serializedDiagsPath) ,
112+ payload: ABICheckerPayload (
113+ serializedDiagnosticsPath: serializedDiagsPath,
114+ downgradeErrors: downgradeErrors
115+ ) ,
99116 ruleInfo: defaultRuleInfo ( cbc, delegate) ,
100117 commandLine: commandLine,
101118 environment: environmentFromSpec ( cbc, delegate) ,
@@ -105,3 +122,40 @@ public final class SwiftABICheckerToolSpec : GenericCommandLineToolSpec, SpecIde
105122 enableSandboxing: enableSandboxing)
106123 }
107124}
125+
126+ public final class APIDigesterDowngradingSerializedDiagnosticsOutputParser : TaskOutputParser {
127+ private let task : any ExecutableTask
128+
129+ public let workspaceContext : WorkspaceContext
130+ public let buildRequestContext : BuildRequestContext
131+ public let delegate : any TaskOutputParserDelegate
132+
133+ required public init ( for task: any ExecutableTask , workspaceContext: WorkspaceContext , buildRequestContext: BuildRequestContext , delegate: any TaskOutputParserDelegate , progressReporter: ( any SubtaskProgressReporter ) ? ) {
134+ self . task = task
135+ self . workspaceContext = workspaceContext
136+ self . buildRequestContext = buildRequestContext
137+ self . delegate = delegate
138+ }
139+
140+ public func write( bytes: ByteString ) {
141+ // Forward the unparsed bytes immediately (without line buffering).
142+ delegate. emitOutput ( bytes)
143+
144+ // Disable diagnostic scraping, since we use serialized diagnostics.
145+ }
146+
147+ public func close( result: TaskResult ? ) {
148+ defer {
149+ delegate. close ( )
150+ }
151+ // Don't try to read diagnostics if the process crashed or got cancelled as they were almost certainly not written in this case.
152+ if result. shouldSkipParsingDiagnostics { return }
153+
154+ for path in task. type. serializedDiagnosticsPaths ( task, workspaceContext. fs) {
155+ let diagnostics = delegate. readSerializedDiagnostics ( at: path, workingDirectory: task. workingDirectory, workspaceContext: workspaceContext)
156+ for diagnostic in diagnostics {
157+ delegate. diagnosticsEngine. emit ( diagnostic. with ( behavior: diagnostic. behavior == . error ? . warning : diagnostic. behavior) )
158+ }
159+ }
160+ }
161+ }
0 commit comments