From eca2bf0fd5fc783e2980905052bb2f5ab562f6a0 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 3 Jan 2024 13:37:33 -0800 Subject: [PATCH] [Dependency Scanning] Upon scan failure, ensure scanner diagnostics are emitted --- .../ModuleDependencyScanning.swift | 64 +++++++++++-------- .../SwiftScan/DependencyGraphBuilder.swift | 2 +- Sources/SwiftDriver/SwiftScan/SwiftScan.swift | 22 +++---- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift index c0af39cb5..bb7513f59 100644 --- a/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift +++ b/Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift @@ -27,7 +27,7 @@ extension Diagnostic.Message { .warning("Fallback to `swift-frontend` dependency scanner invocation") } static func scanner_diagnostic_error(_ message: String) -> Diagnostic.Message { - .error("Dependency scanning failure: \(message)") + .error(message) } static func scanner_diagnostic_warn(_ message: String) -> Diagnostic.Message { .warning(message) @@ -198,11 +198,15 @@ public extension Driver { useResponseFiles: .disabled, using: executor.resolver) Self.sanitizeCommandForLibScanInvocation(&command) - imports = - try interModuleDependencyOracle.getImports(workingDirectory: cwd, - moduleAliases: moduleOutputInfo.aliases, - commandLine: command) - + do { + imports = try interModuleDependencyOracle.getImports(workingDirectory: cwd, + moduleAliases: moduleOutputInfo.aliases, + commandLine: command) + } catch let DependencyScanningError.dependencyScanFailed(reason) { + try emitScannerDiagnostics() + throw DependencyScanningError.dependencyScanFailed(reason) + } + try emitScannerDiagnostics() } else { // Fallback to legacy invocation of the dependency scanner with // `swift-frontend -scan-dependencies -import-prescan` @@ -215,6 +219,26 @@ public extension Driver { return imports } + mutating internal func emitScannerDiagnostics() throws { + let possibleDiags = try interModuleDependencyOracle.getScannerDiagnostics() + if let diags = possibleDiags { + for diagnostic in diags { + switch diagnostic.severity { + case .error: + diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message)) + case .warning: + diagnosticEngine.emit(.scanner_diagnostic_warn(diagnostic.message)) + case .note: + diagnosticEngine.emit(.scanner_diagnostic_note(diagnostic.message)) + case .remark: + diagnosticEngine.emit(.scanner_diagnostic_remark(diagnostic.message)) + case .ignored: + diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message)) + } + } + } + } + mutating internal func performDependencyScan() throws -> InterModuleDependencyGraph { let scannerJob = try dependencyScanningJob() let forceResponseFiles = parsedOptions.hasArgument(.driverForceResponseFiles) @@ -234,27 +258,15 @@ public extension Driver { useResponseFiles: .disabled, using: executor.resolver) Self.sanitizeCommandForLibScanInvocation(&command) - dependencyGraph = - try interModuleDependencyOracle.getDependencies(workingDirectory: cwd, - moduleAliases: moduleOutputInfo.aliases, - commandLine: command) - let possibleDiags = try interModuleDependencyOracle.getScannerDiagnostics() - if let diags = possibleDiags { - for diagnostic in diags { - switch diagnostic.severity { - case .error: - diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message)) - case .warning: - diagnosticEngine.emit(.scanner_diagnostic_warn(diagnostic.message)) - case .note: - diagnosticEngine.emit(.scanner_diagnostic_note(diagnostic.message)) - case .remark: - diagnosticEngine.emit(.scanner_diagnostic_remark(diagnostic.message)) - case .ignored: - diagnosticEngine.emit(.scanner_diagnostic_error(diagnostic.message)) - } - } + do { + dependencyGraph = try interModuleDependencyOracle.getDependencies(workingDirectory: cwd, + moduleAliases: moduleOutputInfo.aliases, + commandLine: command) + } catch let DependencyScanningError.dependencyScanFailed(reason) { + try emitScannerDiagnostics() + throw DependencyScanningError.dependencyScanFailed(reason) } + try emitScannerDiagnostics() } else { // Fallback to legacy invocation of the dependency scanner with // `swift-frontend -scan-dependencies` diff --git a/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift b/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift index f639ba108..542fb5fbc 100644 --- a/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift +++ b/Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift @@ -67,7 +67,7 @@ internal extension SwiftScan { // Note, respective indices of the batch scan input and the returned result must be aligned. for (index, resultGraphRefOrNull) in resultGraphRefArray.enumerated() { guard let resultGraphRef = resultGraphRefOrNull else { - throw DependencyScanningError.dependencyScanFailed + throw DependencyScanningError.dependencyScanFailed("Unable to produce dependency graph from batch scan result") } let decodedGraph = try constructGraph(from: resultGraphRef, moduleAliases: moduleAliases) diff --git a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift index a77cb1227..cbd6d7e80 100644 --- a/Sources/SwiftDriver/SwiftScan/SwiftScan.swift +++ b/Sources/SwiftDriver/SwiftScan/SwiftScan.swift @@ -23,7 +23,7 @@ import struct TSCBasic.Diagnostic public enum DependencyScanningError: Error, DiagnosticData { case missingRequiredSymbol(String) - case dependencyScanFailed + case dependencyScanFailed(String) case failedToInstantiateScanner case casError(String) case missingField(String) @@ -38,14 +38,14 @@ public enum DependencyScanningError: Error, DiagnosticData { switch self { case .missingRequiredSymbol(let symbolName): return "libSwiftScan missing required symbol: '\(symbolName)'" - case .dependencyScanFailed: - return "libSwiftScan dependency scan query failed" + case .dependencyScanFailed(let reason): + return "Dependency scan query failed: `\(reason)`" case .failedToInstantiateScanner: - return "libSwiftScan failed to create scanner instance" + return "Failed to create scanner instance" case .casError(let reason): - return "libSwiftScan CAS error: \(reason)" + return "CAS error: \(reason)" case .missingField(let fieldName): - return "libSwiftScan scan result missing required field: `\(fieldName)`" + return "Scan result missing required field: `\(fieldName)`" case .moduleNameDecodeFailure(let encodedName): return "Failed to decode dependency module name: `\(encodedName)`" case .unsupportedDependencyDetailsKind(let kindRawValue): @@ -57,7 +57,7 @@ public enum DependencyScanningError: Error, DiagnosticData { case .scanningLibraryNotFound(let path): return "Dependency Scanning library not found at path: \(path)" case .argumentQueryFailed: - return "libSwiftScan supported compiler argument query failed" + return "Supported compiler argument query failed" } } } @@ -143,7 +143,7 @@ internal extension swiftscan_diagnostic_severity_t { let importSetRefOrNull = api.swiftscan_import_set_create(scanner, invocation) guard let importSetRef = importSetRefOrNull else { - throw DependencyScanningError.dependencyScanFailed + throw DependencyScanningError.dependencyScanFailed("Unable to produce import set") } let importSet = try constructImportSet(from: importSetRef, with: moduleAliases) @@ -171,7 +171,7 @@ internal extension swiftscan_diagnostic_severity_t { let graphRefOrNull = api.swiftscan_dependency_graph_create(scanner, invocation) guard let graphRef = graphRefOrNull else { - throw DependencyScanningError.dependencyScanFailed + throw DependencyScanningError.dependencyScanFailed("Unable to produce dependency graph") } let dependencyGraph = try constructGraph(from: graphRef, moduleAliases: moduleAliases) @@ -232,7 +232,7 @@ internal extension swiftscan_diagnostic_severity_t { inputRef, invocationRef) guard let batchResultRef = batchResultRefOrNull else { - throw DependencyScanningError.dependencyScanFailed + throw DependencyScanningError.dependencyScanFailed("Unable to produce batch scan results") } // Translate `swiftscan_batch_scan_result_t` // into `[ModuleDependencyId: [InterModuleDependencyGraph]]` @@ -332,7 +332,7 @@ internal extension swiftscan_diagnostic_severity_t { for diagnosticRefOrNull in diagnosticRefArray { guard let diagnosticRef = diagnosticRefOrNull else { - throw DependencyScanningError.dependencyScanFailed + throw DependencyScanningError.dependencyScanFailed("Unable to produce scanner diagnostics") } let message = try toSwiftString(api.swiftscan_diagnostic_get_message(diagnosticRef)) let severity = api.swiftscan_diagnostic_get_severity(diagnosticRef)