From e5637488af24cba6aefb91507fea98856c05cac6 Mon Sep 17 00:00:00 2001 From: David Dresser Date: Fri, 20 Mar 2026 00:05:49 -0700 Subject: [PATCH 1/3] SSAST-11722 Log error and continue on TargetDependency decode error --- PIF/Sources/PIFSupport/PIF.swift | 19 ++++++++++++++++--- Sources/GenIR/Versions.swift | 5 +++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/PIF/Sources/PIFSupport/PIF.swift b/PIF/Sources/PIFSupport/PIF.swift index f413ffa..2f5eacf 100644 --- a/PIF/Sources/PIFSupport/PIF.swift +++ b/PIF/Sources/PIFSupport/PIF.swift @@ -378,6 +378,9 @@ public enum PIF { /// Represents a dependency on another target (identified by its PIF GUID). public struct TargetDependency: Decodable { + /// Name of dependency + public let name: String + /// Identifier of depended-upon target. public let targetGUID: String @@ -385,15 +388,25 @@ public enum PIF { public let platformFilters: [PlatformFilter] private enum CodingKeys: CodingKey { - case guid, platformFilters + case name, guid, platformFilters } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - targetGUID = try container.decode(String.self, forKey: .guid) + name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Unknown" + do { + targetGUID = try container.decode(String.self, forKey: .guid) + } catch { + targetGUID = "" + logger.info(" ------------------------------------------------------------------------------------------") + logger.info(" Error: dependency \(name) is missing a guid and will not be resolved!\n") + logger.info(" For more context rerun with --log-level=trace.") + logger.info(" Be aware the this may generate a LOT of output.") + logger.info(" ------------------------------------------------------------------------------------------") + } platformFilters = try container.decodeIfPresent([PlatformFilter].self, forKey: .platformFilters) ?? [] - logger.trace("---> Decoded TargetDependency: \(targetGUID)") + logger.trace("---> Decoded TargetDependency: \(name) \(targetGUID)") } } diff --git a/Sources/GenIR/Versions.swift b/Sources/GenIR/Versions.swift index 8c75e08..5165470 100644 --- a/Sources/GenIR/Versions.swift +++ b/Sources/GenIR/Versions.swift @@ -5,7 +5,8 @@ // Created by Thomas Hedderwick on 12/09/2022. // // History: -// 2025-nn-nn - 1.0.1 -- Use info logging to allow user to monitor progress. +// 2026-nn-nn - 1.0.2 -- SSAST-11722 don't fail on TargetDependency decode failure. +// 2026-01-08 - 1.0.1 -- Use info logging to allow user to monitor progress. // 2025-12-01 - 1.0.0 -- Don't chase through Dynamic Dependencies // 2025-09-19 - 0.5.4 -- Update release doc; warn multiple builds; capture debug data // 2025-04-18 - 0.5.3 -- PIF Tracing; log unique compiler commands @@ -15,5 +16,5 @@ import Foundation enum Versions { - static let version = "1.0.1" + static let version = "1.0.2" } From 87a9007eabaea74c0652f9e153dab6b86446124e Mon Sep 17 00:00:00 2001 From: David Dresser Date: Fri, 20 Mar 2026 09:34:49 -0700 Subject: [PATCH 2/3] SSAST-11722 Add report action --- PIF/Sources/PIFSupport/PIF.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/PIF/Sources/PIFSupport/PIF.swift b/PIF/Sources/PIFSupport/PIF.swift index 2f5eacf..c1f2bf9 100644 --- a/PIF/Sources/PIFSupport/PIF.swift +++ b/PIF/Sources/PIFSupport/PIF.swift @@ -403,6 +403,7 @@ public enum PIF { logger.info(" Error: dependency \(name) is missing a guid and will not be resolved!\n") logger.info(" For more context rerun with --log-level=trace.") logger.info(" Be aware the this may generate a LOT of output.") + logger.info(" This is an error in your project metadata you may want to report this to Apple.") logger.info(" ------------------------------------------------------------------------------------------") } platformFilters = try container.decodeIfPresent([PlatformFilter].self, forKey: .platformFilters) ?? [] From 554dc3b7c76f1801482cf33d9b9805aff7fe65e7 Mon Sep 17 00:00:00 2001 From: David Dresser Date: Wed, 25 Mar 2026 16:40:28 -0700 Subject: [PATCH 3/3] SSAST-12047 change targetGUID to optional. --- PIF/Sources/PIFSupport/PIF.swift | 12 ++++++------ Sources/GenIR/PIFCache.swift | 21 ++++++++++++++++----- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/PIF/Sources/PIFSupport/PIF.swift b/PIF/Sources/PIFSupport/PIF.swift index c1f2bf9..e2e27c1 100644 --- a/PIF/Sources/PIFSupport/PIF.swift +++ b/PIF/Sources/PIFSupport/PIF.swift @@ -382,7 +382,7 @@ public enum PIF { public let name: String /// Identifier of depended-upon target. - public let targetGUID: String + public let targetGUID: String? /// The platform filters for this target dependency. public let platformFilters: [PlatformFilter] @@ -395,10 +395,9 @@ public enum PIF { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Unknown" - do { - targetGUID = try container.decode(String.self, forKey: .guid) - } catch { - targetGUID = "" + targetGUID = try container.decodeIfPresent(String.self, forKey: .guid) + + if targetGUID == nil { logger.info(" ------------------------------------------------------------------------------------------") logger.info(" Error: dependency \(name) is missing a guid and will not be resolved!\n") logger.info(" For more context rerun with --log-level=trace.") @@ -406,8 +405,9 @@ public enum PIF { logger.info(" This is an error in your project metadata you may want to report this to Apple.") logger.info(" ------------------------------------------------------------------------------------------") } + platformFilters = try container.decodeIfPresent([PlatformFilter].self, forKey: .platformFilters) ?? [] - logger.trace("---> Decoded TargetDependency: \(name) \(targetGUID)") + logger.trace("---> Decoded TargetDependency: \(name) \(targetGUID ?? "")") } } diff --git a/Sources/GenIR/PIFCache.swift b/Sources/GenIR/PIFCache.swift index 536dba1..9415412 100644 --- a/Sources/GenIR/PIFCache.swift +++ b/Sources/GenIR/PIFCache.swift @@ -196,11 +196,17 @@ struct PIFDependencyProvider: DependencyProviding { let productTargetDependencies = cache.target(guid: product.guid)? .dependencies - .filter { $0.targetGUID.starts(with: targetToken) } + .compactMap { dependency -> PIF.TargetDependency? in + guard let guid = dependency.targetGUID, guid.starts(with: targetToken) else { return nil } + return dependency + } ?? [] let productUnderlyingTargets = productTargetDependencies - .filter { $0.targetGUID.dropFirst(targetToken.count) == productName } + .filter { dependency in + guard let guid = dependency.targetGUID else { return false } + return guid.dropFirst(targetToken.count) == productName + } if productUnderlyingTargets.isEmpty && !productTargetDependencies.isEmpty { // We likely have a stub target here (i.e. a precompiled framework) @@ -217,15 +223,20 @@ struct PIFDependencyProvider: DependencyProviding { return productTargetDependencies.first?.targetGUID } - GenIRLogger.logger.debug("\(packageProductGUID) resolves to \(target.targetGUID)") - return target.targetGUID + guard let targetGUID = target.targetGUID else { + GenIRLogger.logger.debug("\(packageProductGUID) resolves to a target with nil GUID") + return nil + } + + GenIRLogger.logger.debug("\(packageProductGUID) resolves to \(targetGUID)") + return targetGUID } func dependencies(for value: Target) -> [Target] { // Direct dependencies let dependencyTargetGUIDs = cache.target(guid: value.guid)? .dependencies - .map { $0.targetGUID } + .compactMap { $0.targetGUID } .compactMap { resolveSwiftPackage($0) } ?? []