Skip to content

[Dependency Scanning] Upon scan failure, ensure scanner diagnostics are emitted #1518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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`
Expand All @@ -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)
Expand All @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
22 changes: 11 additions & 11 deletions Sources/SwiftDriver/SwiftScan/SwiftScan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand All @@ -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"
}
}
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]]`
Expand Down Expand Up @@ -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)
Expand Down