From 6d36582498bbbbd5b0ece46479c2a54f31827ce4 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 09:04:31 -0500 Subject: [PATCH 1/7] Acknowledge unsafe API usages in code expanded from testing library macros Fixes: rdar://151238560 --- Package.swift | 17 ++++++++++++ Sources/TestingMacros/ConditionMacro.swift | 4 +-- .../TestingMacros/SuiteDeclarationMacro.swift | 4 +-- .../Support/TestContentGeneration.swift | 2 +- .../TestingMacros/TestDeclarationMacro.swift | 4 +-- .../MemorySafeTestDecls.swift | 27 +++++++++++++++++++ 6 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift diff --git a/Package.swift b/Package.swift index 3df51ca48..73c1ec13c 100644 --- a/Package.swift +++ b/Package.swift @@ -127,9 +127,18 @@ let package = Package( "Testing", "_Testing_CoreGraphics", "_Testing_Foundation", + "MemorySafeTestingTests", ], swiftSettings: .packageSettings ), + .target( + name: "MemorySafeTestingTests", + dependencies: [ + "Testing", + ], + path: "Tests/_MemorySafeTestingTests", + swiftSettings: .packageSettings + .strictMemorySafety + ), .macro( name: "TestingMacros", @@ -355,6 +364,14 @@ extension Array where Element == PackageDescription.SwiftSetting { return result } + + /// Settings necessary to enable Strict Memory Safety, introduced in + /// [SE-0458: Opt-in Strict Memory Safety Checking](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md#swiftpm-integration). + static var strictMemorySafety: Self { + // FIXME: Adopt official `.strictMemorySafety()` condition once the minimum + // supported toolchain is 6.2. + [.unsafeFlags(["-strict-memory-safety"])] + } } extension Array where Element == PackageDescription.CXXSetting { diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 49630cfc9..b8d80ba90 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -499,7 +499,7 @@ extension ExitTestConditionMacro { recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(enumName).testContentRecord + unsafe \(enumName).testContentRecord } } """ @@ -510,7 +510,7 @@ extension ExitTestConditionMacro { @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName) { private nonisolated static let accessor: Testing.__TestContentRecordAccessor = { outValue, type, hint, _ in - Testing.ExitTest.__store( + unsafe Testing.ExitTest.__store( \(idExpr), \(bodyThunkName), into: outValue, diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index 60a276689..2f835ad8f 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -150,7 +150,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private nonisolated static let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in - Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) + unsafe Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ ) @@ -174,7 +174,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(testContentRecordName) + unsafe \(testContentRecordName) } } """ diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index 9a2529cee..05214d1b8 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -68,7 +68,7 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( \(kindExpr), \(kind.commentRepresentation) 0, - \(accessorName), + unsafe \(accessorName), \(contextExpr), 0 ) diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index 0b2d43f1e..3b39e4868 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -475,7 +475,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private \(staticKeyword(for: typeName)) nonisolated let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in - Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) + unsafe Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ ) @@ -499,7 +499,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(testContentRecordName) + unsafe \(testContentRecordName) } } """ diff --git a/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift b/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift new file mode 100644 index 000000000..b2ecf8dd7 --- /dev/null +++ b/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift @@ -0,0 +1,27 @@ +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for Swift project authors +// + +@testable import Testing + +#if !hasFeature(StrictMemorySafety) +#error("This file requires strict memory safety to be enabled") +#endif + +@Test(.hidden) +func exampleTestFunction() {} + +@Suite(.hidden) +struct ExampleSuite { + @Test func example() {} +} + +func exampleExitTest() async { + await #expect(processExitsWith: .success) {} +} From 1c5447aa5ee23a2a62f09f4ecb1e82093e160e77 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 11:04:22 -0500 Subject: [PATCH 2/7] Fix building with 6.1 toolchain by conditionally passing -strict-memory-safety only on newer toolchains and only attempting to include the relevant test code in that situation --- Package.swift | 4 ++++ Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Package.swift b/Package.swift index 73c1ec13c..a50920a6b 100644 --- a/Package.swift +++ b/Package.swift @@ -368,9 +368,13 @@ extension Array where Element == PackageDescription.SwiftSetting { /// Settings necessary to enable Strict Memory Safety, introduced in /// [SE-0458: Opt-in Strict Memory Safety Checking](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md#swiftpm-integration). static var strictMemorySafety: Self { +#if compiler(>=6.2) // FIXME: Adopt official `.strictMemorySafety()` condition once the minimum // supported toolchain is 6.2. [.unsafeFlags(["-strict-memory-safety"])] +#else + [] +#endif } } diff --git a/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift b/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift index b2ecf8dd7..baf02c026 100644 --- a/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift +++ b/Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift @@ -8,6 +8,8 @@ // See https://swift.org/CONTRIBUTORS.txt for Swift project authors // +#if compiler(>=6.2) + @testable import Testing #if !hasFeature(StrictMemorySafety) @@ -25,3 +27,5 @@ struct ExampleSuite { func exampleExitTest() async { await #expect(processExitsWith: .success) {} } + +#endif From 6025ddc70ab76ef84bed7b22a3471afacd2a024e Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 11:06:54 -0500 Subject: [PATCH 3/7] Remove the need to acknowledge unsafety when calling the __store functions by (conditionally) marking them `@safe` when using a new-enough compiler --- Sources/Testing/ExitTests/ExitTest.swift | 3 +++ Sources/Testing/Test+Discovery.swift | 3 +++ Sources/TestingMacros/ConditionMacro.swift | 2 +- Sources/TestingMacros/SuiteDeclarationMacro.swift | 2 +- Sources/TestingMacros/TestDeclarationMacro.swift | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index 1e9c29c15..beda3eb4e 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -327,6 +327,9 @@ extension ExitTest { /// /// - Warning: This function is used to implement the /// `#expect(processExitsWith:)` macro. Do not use it directly. +#if compiler(>=6.2) + @safe +#endif public static func __store( _ id: (UInt64, UInt64, UInt64, UInt64), _ body: @escaping @Sendable (repeat each T) async throws -> Void, diff --git a/Sources/Testing/Test+Discovery.swift b/Sources/Testing/Test+Discovery.swift index 5e9632d70..71862943d 100644 --- a/Sources/Testing/Test+Discovery.swift +++ b/Sources/Testing/Test+Discovery.swift @@ -39,6 +39,9 @@ extension Test { /// /// - Warning: This function is used to implement the `@Test` macro. Do not /// use it directly. +#if compiler(>=6.2) + @safe +#endif public static func __store( _ generator: @escaping @Sendable () async -> Test, into outValue: UnsafeMutableRawPointer, diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index b8d80ba90..07ac8502f 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -510,7 +510,7 @@ extension ExitTestConditionMacro { @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName) { private nonisolated static let accessor: Testing.__TestContentRecordAccessor = { outValue, type, hint, _ in - unsafe Testing.ExitTest.__store( + Testing.ExitTest.__store( \(idExpr), \(bodyThunkName), into: outValue, diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index 2f835ad8f..4bee4c30f 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -150,7 +150,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private nonisolated static let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in - unsafe Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) + Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ ) diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index 3b39e4868..f700ba5e0 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -475,7 +475,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private \(staticKeyword(for: typeName)) nonisolated let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in - unsafe Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) + Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ ) From 7bdfaf1bd68df90470a1542da80a033572c1fe74 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 11:07:48 -0500 Subject: [PATCH 4/7] Fix building with a pre-6.2 toolchain by conditionalizing whether the 'unsafe' expression keyword is included. This expands the scope of a similar fix made earlier. --- Sources/TestingMacros/ConditionMacro.swift | 3 ++- .../TestingMacros/SuiteDeclarationMacro.swift | 3 ++- .../Support/EffectfulExpressionHandling.swift | 22 ++++++++++--------- .../Support/TestContentGeneration.swift | 3 ++- .../TestingMacros/TestDeclarationMacro.swift | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 07ac8502f..c651f0ed9 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -496,10 +496,11 @@ extension ExitTestConditionMacro { var recordDecl: DeclSyntax? #if !SWT_NO_LEGACY_TEST_DISCOVERY let legacyEnumName = context.makeUniqueName("__🟡$") + let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - unsafe \(enumName).testContentRecord + \(unsafeKeyword) \(enumName).testContentRecord } } """ diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index 4bee4c30f..cf3a87d17 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -169,12 +169,13 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName("__🟡$") + let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - unsafe \(testContentRecordName) + \(unsafeKeyword) \(testContentRecordName) } } """ diff --git a/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift b/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift index 494d2fcfc..32b219333 100644 --- a/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift +++ b/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift @@ -86,6 +86,17 @@ extension BidirectionalCollection { // MARK: - Inserting effect keywords/thunks +/// Whether or not the `unsafe` expression keyword is supported. +var isUnsafeKeywordSupported: Bool { + // The 'unsafe' keyword was introduced in 6.2 as part of SE-0458. Older + // toolchains are not aware of it. +#if compiler(>=6.2) + true +#else + false +#endif +} + /// Make a function call expression to an effectful thunk function provided by /// the testing library. /// @@ -127,12 +138,7 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp let needAwait = effectfulKeywords.contains(.await) && !expr.is(AwaitExprSyntax.self) let needTry = effectfulKeywords.contains(.try) && !expr.is(TryExprSyntax.self) - // The 'unsafe' keyword was introduced in 6.2 as part of SE-0458. Older - // toolchains are not aware of it, so avoid emitting expressions involving - // that keyword when the macro has been built using an older toolchain. -#if compiler(>=6.2) - let needUnsafe = effectfulKeywords.contains(.unsafe) && !expr.is(UnsafeExprSyntax.self) -#endif + let needUnsafe = isUnsafeKeywordSupported && effectfulKeywords.contains(.unsafe) && !expr.is(UnsafeExprSyntax.self) // First, add thunk function calls. if needAwait { @@ -141,11 +147,9 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp if needTry { expr = _makeCallToEffectfulThunk(.identifier("__requiringTry"), passing: expr) } -#if compiler(>=6.2) if needUnsafe { expr = _makeCallToEffectfulThunk(.identifier("__requiringUnsafe"), passing: expr) } -#endif // Then add keyword expressions. (We do this separately so we end up writing // `try await __r(__r(self))` instead of `try __r(await __r(self))` which is @@ -166,7 +170,6 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp ) ) } -#if compiler(>=6.2) if needUnsafe { expr = ExprSyntax( UnsafeExprSyntax( @@ -175,7 +178,6 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp ) ) } -#endif expr.leadingTrivia = originalExpr.leadingTrivia expr.trailingTrivia = originalExpr.trailingTrivia diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index 05214d1b8..c362b7b5a 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -63,12 +63,13 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? IntegerLiteralExprSyntax(context, radix: .binary) } + let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil var result: DeclSyntax = """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( \(kindExpr), \(kind.commentRepresentation) 0, - unsafe \(accessorName), + \(unsafeKeyword) \(accessorName), \(contextExpr), 0 ) diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index f700ba5e0..6db61d985 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -494,12 +494,13 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$") + let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - unsafe \(testContentRecordName) + \(unsafeKeyword) \(testContentRecordName) } } """ From ea720456f1ef54dc681818b05efa4961cb79a4c4 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 11:44:37 -0500 Subject: [PATCH 5/7] Add comment explaining the use of .target instead of .testTarget --- Package.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Package.swift b/Package.swift index a50920a6b..13dbf61cf 100644 --- a/Package.swift +++ b/Package.swift @@ -131,6 +131,12 @@ let package = Package( ], swiftSettings: .packageSettings ), + + // Use a plain `.target` instead of a `.testTarget` to avoid the unnecessary + // overhead of having a separate test target for this module. Conceptually, + // the content in this module is no different than content which would + // typically be placed in the `TestingTests` target, except this content + // needs the (module-wide) strict memory safety feature to be enabled. .target( name: "MemorySafeTestingTests", dependencies: [ From 74df57ad99777bcbcdbd6561d8a1f01f95ef81f0 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 12:54:05 -0500 Subject: [PATCH 6/7] Handle trailing trivia on unsafe keyword more elegantly --- Sources/TestingMacros/ConditionMacro.swift | 4 ++-- Sources/TestingMacros/SuiteDeclarationMacro.swift | 4 ++-- Sources/TestingMacros/Support/TestContentGeneration.swift | 4 ++-- Sources/TestingMacros/TestDeclarationMacro.swift | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index c651f0ed9..6d4fc4c69 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -496,11 +496,11 @@ extension ExitTestConditionMacro { var recordDecl: DeclSyntax? #if !SWT_NO_LEGACY_TEST_DISCOVERY let legacyEnumName = context.makeUniqueName("__🟡$") - let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(unsafeKeyword) \(enumName).testContentRecord + \(unsafeKeyword)\(enumName).testContentRecord } } """ diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index cf3a87d17..bb5945eb7 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -169,13 +169,13 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName("__🟡$") - let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(unsafeKeyword) \(testContentRecordName) + \(unsafeKeyword)\(testContentRecordName) } } """ diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index c362b7b5a..ea76528a6 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -63,13 +63,13 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? IntegerLiteralExprSyntax(context, radix: .binary) } - let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil var result: DeclSyntax = """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( \(kindExpr), \(kind.commentRepresentation) 0, - \(unsafeKeyword) \(accessorName), + \(unsafeKeyword)\(accessorName), \(contextExpr), 0 ) diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index 6db61d985..ce6cf64c2 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -494,13 +494,13 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$") - let unsafeKeyword = isUnsafeKeywordSupported ? TokenSyntax.keyword(.unsafe) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { - \(unsafeKeyword) \(testContentRecordName) + \(unsafeKeyword)\(testContentRecordName) } } """ From e2a4fbb0261fecb5289e5262815166d5baf8b76f Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Mon, 2 Jun 2025 13:10:46 -0500 Subject: [PATCH 7/7] Simplify how trailing trivia is specified --- Sources/TestingMacros/ConditionMacro.swift | 2 +- Sources/TestingMacros/SuiteDeclarationMacro.swift | 2 +- .../TestingMacros/Support/EffectfulExpressionHandling.swift | 6 +++--- Sources/TestingMacros/Support/TestContentGeneration.swift | 2 +- Sources/TestingMacros/TestDeclarationMacro.swift | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 6d4fc4c69..9f87dfbd3 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -496,7 +496,7 @@ extension ExitTestConditionMacro { var recordDecl: DeclSyntax? #if !SWT_NO_LEGACY_TEST_DISCOVERY let legacyEnumName = context.makeUniqueName("__🟡$") - let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe, trailingTrivia: .space) : nil recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { nonisolated static var __testContentRecord: Testing.__TestContentRecord { diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index bb5945eb7..e44b0460a 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -169,7 +169,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName("__🟡$") - let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe, trailingTrivia: .space) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") diff --git a/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift b/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift index 32b219333..a0b84e737 100644 --- a/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift +++ b/Sources/TestingMacros/Support/EffectfulExpressionHandling.swift @@ -157,7 +157,7 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp if needAwait { expr = ExprSyntax( AwaitExprSyntax( - awaitKeyword: .keyword(.await).with(\.trailingTrivia, .space), + awaitKeyword: .keyword(.await, trailingTrivia: .space), expression: expr ) ) @@ -165,7 +165,7 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp if needTry { expr = ExprSyntax( TryExprSyntax( - tryKeyword: .keyword(.try).with(\.trailingTrivia, .space), + tryKeyword: .keyword(.try, trailingTrivia: .space), expression: expr ) ) @@ -173,7 +173,7 @@ func applyEffectfulKeywords(_ effectfulKeywords: Set, to expr: some Exp if needUnsafe { expr = ExprSyntax( UnsafeExprSyntax( - unsafeKeyword: .keyword(.unsafe).with(\.trailingTrivia, .space), + unsafeKeyword: .keyword(.unsafe, trailingTrivia: .space), expression: expr ) ) diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index ea76528a6..2999478de 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -63,7 +63,7 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? IntegerLiteralExprSyntax(context, radix: .binary) } - let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe, trailingTrivia: .space) : nil var result: DeclSyntax = """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index ce6cf64c2..58e8259ec 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -494,7 +494,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { #if !SWT_NO_LEGACY_TEST_DISCOVERY // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$") - let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe).with(\.trailingTrivia, .space) : nil + let unsafeKeyword: TokenSyntax? = isUnsafeKeywordSupported ? .keyword(.unsafe, trailingTrivia: .space) : nil result.append( """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.")