From 989d2db2c21d698efd450743e5e7aa0a969b835b Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Fri, 31 Jul 2026 15:44:36 -0700 Subject: [PATCH 1/4] `@DependencyEntry`: Better isolation diagnostics --- Sources/DependenciesMacros/Macros.swift | 32 +++ .../DependencyEntryMacro.swift | 104 ++++++++- .../DependenciesMacrosPlugin/Plugins.swift | 3 + .../DependencyEntryMacroTests.swift | 204 ++++++++++++++---- 4 files changed, 305 insertions(+), 38 deletions(-) diff --git a/Sources/DependenciesMacros/Macros.swift b/Sources/DependenciesMacros/Macros.swift index 510f18bd..f721ed47 100644 --- a/Sources/DependenciesMacros/Macros.swift +++ b/Sources/DependenciesMacros/Macros.swift @@ -272,6 +272,38 @@ public macro _DependencyEntryDefaultValue() = type: "DependencyEntryDefaultValueMacro" ) +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(_: () -> Void) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryIsolationCheckMacro" + ) + +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(_: @MainActor () -> Void) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryMainActorIsolationCheckMacro" + ) + +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(keyPath: KeyPath) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryIsolationCheckMacro" + ) + +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(keyPath: KeyPath) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntrySendableCheckMacro" + ) + /// The error thrown by "unimplemented" closures produced by ``DependencyEndpoint(method:)`` public struct Unimplemented: Error { let endpoint: String diff --git a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift index 2db39d67..ea2e3444 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift @@ -23,7 +23,10 @@ extension DependencyEntryMacro: AccessorMacro { let keyName = keyTypeName(for: node, property: property, identifier: identifier) return [ """ - get { self[\(keyName).self] } + get { + \(isolationCheck(for: node, in: context)) + return self[\(keyName).self] + } """, """ set { self[\(keyName).self] = newValue } @@ -136,7 +139,7 @@ extension DependencyEntryMacro: PeerMacro { \(raw: body) } """ - return [keyDecl] + return sendableCheck(for: node, identifier: identifier, in: context) + [keyDecl] } } @@ -258,6 +261,103 @@ private func isInDependencyValuesExtension( return name == "DependencyValues" } +private let isolationProbeName = "__dependencyEntryIsolationProbe" + +private func isolationCheck( + for node: AttributeSyntax, + in context: some MacroExpansionContext +) -> CodeBlockItemListSyntax { + guard + let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath) + else { + return """ + func \(raw: isolationProbeName)() {} + #IsolationCheck(\(raw: isolationProbeName)) + """ + } + return """ + func \(raw: isolationProbeName)() {} + #sourceLocation(file: \(location.file), line: \(location.line)) + #IsolationCheck(\(raw: isolationProbeName)) + #sourceLocation() + """ +} + +private func sendableCheck( + for node: AttributeSyntax, + identifier: TokenSyntax, + in context: some MacroExpansionContext +) -> [DeclSyntax] { + guard + let extendedType = context.lexicalContext.first?.as(ExtensionDeclSyntax.self)? + .extendedType.trimmed + else { + return [] + } + let check: DeclSyntax = "#IsolationCheck(keyPath: \\\(extendedType).\(identifier))" + guard + let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath), + let line = location.line.as(IntegerLiteralExprSyntax.self), + let lineValue = Int(line.literal.text) + else { + return [check] + } + return [ + "#sourceLocation(file: \(location.file), line: \(raw: lineValue - 1))", + check, + "#sourceLocation()", + ] +} + +public enum DependencyEntryIsolationCheckMacro {} + +extension DependencyEntryIsolationCheckMacro: DeclarationMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + [] + } +} + +public enum DependencyEntryMainActorIsolationCheckMacro {} + +extension DependencyEntryMainActorIsolationCheckMacro: DeclarationMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + context.diagnose( + Diagnostic( + node: node, + message: MacroExpansionErrorMessage( + "entry must be 'nonisolated var' when default isolation is '@MainActor'" + ) + ) + ) + return [] + } +} + +public enum DependencyEntrySendableCheckMacro {} + +extension DependencyEntrySendableCheckMacro: DeclarationMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + context.diagnose( + Diagnostic( + node: node, + message: MacroExpansionErrorMessage( + "entry value must be 'Sendable'" + ) + ) + ) + return [] + } +} + public enum DependencyEntryDefaultValueMacro {} extension DependencyEntryDefaultValueMacro: AccessorMacro { diff --git a/Sources/DependenciesMacrosPlugin/Plugins.swift b/Sources/DependenciesMacrosPlugin/Plugins.swift index 7db35d98..a8771e6c 100644 --- a/Sources/DependenciesMacrosPlugin/Plugins.swift +++ b/Sources/DependenciesMacrosPlugin/Plugins.swift @@ -9,5 +9,8 @@ struct MacrosPlugin: CompilerPlugin { DependencyEndpointIgnoredMacro.self, DependencyEntryMacro.self, DependencyEntryDefaultValueMacro.self, + DependencyEntryIsolationCheckMacro.self, + DependencyEntryMainActorIsolationCheckMacro.self, + DependencyEntrySendableCheckMacro.self, ] } diff --git a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift index d9ec3460..0ac2cfb4 100644 --- a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift +++ b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift @@ -22,11 +22,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -36,12 +41,18 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var liveValue = Client.live @DependenciesMacros._DependencyEntryDefaultValue static var testValue = Client.test } } - """ + """# } } @@ -54,11 +65,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -68,13 +84,19 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var liveValue = Client.live @DependenciesMacros._DependencyEntryDefaultValue static var previewValue = Client.preview @DependenciesMacros._DependencyEntryDefaultValue static var testValue = Client.test } } - """ + """# } } @@ -87,11 +109,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -101,12 +128,18 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var previewValue = Client.preview @DependenciesMacros._DependencyEntryDefaultValue static var testValue = Client.test } } - """ + """# } } @@ -119,11 +152,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -133,11 +171,17 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var testValue = Client.test } } - """ + """# } } @@ -150,11 +194,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client: Client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -164,6 +213,12 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.DependencyKey { typealias Value = Client static var liveValue: Value { @@ -174,7 +229,7 @@ final class DependencyEntryMacroTests: BaseTestCase { } } } - """ + """# } } @@ -246,11 +301,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { var client: Client { get { - self[__Key_client.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[__Key_client.self] } set { self[__Key_client.self] = newValue @@ -260,6 +320,12 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + private nonisolated enum __Key_client: Dependencies.DependencyKey { typealias Value = Client static var liveValue: Value { @@ -267,7 +333,7 @@ final class DependencyEntryMacroTests: BaseTestCase { } } } - """ + """# } } @@ -280,11 +346,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { public var client { get { - self[APIClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[APIClientKey.self] } set { self[APIClientKey.self] = newValue @@ -294,12 +365,18 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + public nonisolated enum APIClientKey: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue public static var liveValue = Client.live @DependenciesMacros._DependencyEntryDefaultValue public static var testValue = Client.test } } - """ + """# } } @@ -312,11 +389,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { package var client { get { - self[ClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[ClientKey.self] } set { self[ClientKey.self] = newValue @@ -326,11 +408,17 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + package nonisolated enum ClientKey: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue package static var testValue = Client.test } } - """ + """# } } @@ -343,11 +431,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { public var client { get { - self[ClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[ClientKey.self] } set { self[ClientKey.self] = newValue @@ -357,12 +450,18 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + public nonisolated enum ClientKey: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue public static var liveValue = Client.live @DependenciesMacros._DependencyEntryDefaultValue public static var testValue = Client.test } } - """ + """# } } @@ -375,11 +474,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { public var client: any APIClient { get { - self[ExplicitAPIClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[ExplicitAPIClientKey.self] } set { self[ExplicitAPIClientKey.self] = newValue @@ -389,6 +493,12 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + public nonisolated enum ExplicitAPIClientKey: Dependencies.TestDependencyKey { public typealias Value = any APIClient public static var testValue: Value { @@ -396,7 +506,7 @@ final class DependencyEntryMacroTests: BaseTestCase { } } } - """ + """# } } @@ -409,11 +519,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { public var client: MockAPIClient { get { - self[MockAPIClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[MockAPIClientKey.self] } set { self[MockAPIClientKey.self] = newValue @@ -423,6 +538,12 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + public nonisolated enum MockAPIClientKey: Dependencies.TestDependencyKey { public typealias Value = MockAPIClient public static var testValue: Value { @@ -430,7 +551,7 @@ final class DependencyEntryMacroTests: BaseTestCase { } } } - """ + """# } } @@ -443,11 +564,16 @@ final class DependencyEntryMacroTests: BaseTestCase { } """ } expansion: { - """ + #""" extension DependencyValues { public var client: any APIClient { get { - self[APIClientKey.self] + func __dependencyEntryIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 2) + #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation() + return self[APIClientKey.self] } set { self[APIClientKey.self] = newValue @@ -457,6 +583,12 @@ final class DependencyEntryMacroTests: BaseTestCase { } } + #sourceLocation(file: "Test.swift", line: 1) + + #IsolationCheck(keyPath: \DependencyValues.client) + + #sourceLocation() + public nonisolated enum APIClientKey: Dependencies.TestDependencyKey { public typealias Value = any APIClient public static var testValue: Value { @@ -464,7 +596,7 @@ final class DependencyEntryMacroTests: BaseTestCase { } } } - """ + """# } } } From 0ae1c7c2636069055943c3f3bb5fa444cefa17a8 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Fri, 31 Jul 2026 18:53:26 -0700 Subject: [PATCH 2/4] Type check as well --- Sources/DependenciesMacros/Macros.swift | 22 ++++++++ .../DependencyEntryMacro.swift | 53 ++++++++++++++++--- .../DependencyEntryMacroTests.swift | 16 ++++++ 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/Sources/DependenciesMacros/Macros.swift b/Sources/DependenciesMacros/Macros.swift index f721ed47..7f590f04 100644 --- a/Sources/DependenciesMacros/Macros.swift +++ b/Sources/DependenciesMacros/Macros.swift @@ -304,6 +304,28 @@ public macro IsolationCheck(keyPath: KeyPath) = type: "DependencyEntrySendableCheckMacro" ) +@_documentation(visibility: private) +@freestanding(declaration) +public macro TypeCheck( + _: KeyPath, + liveValue: @autoclosure @MainActor () -> Value +) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryIsolationCheckMacro" + ) + +@_documentation(visibility: private) +@freestanding(declaration) +public macro TypeCheck( + _: KeyPath, + previewValue: @autoclosure @MainActor () -> Value +) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryIsolationCheckMacro" + ) + /// The error thrown by "unimplemented" closures produced by ``DependencyEndpoint(method:)`` public struct Unimplemented: Error { let endpoint: String diff --git a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift index ea2e3444..4a8c4fd3 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift @@ -24,7 +24,7 @@ extension DependencyEntryMacro: AccessorMacro { return [ """ get { - \(isolationCheck(for: node, in: context)) + \(entryChecks(for: node, identifier: identifier, in: context)) return self[\(keyName).self] } """, @@ -263,22 +263,61 @@ private func isInDependencyValuesExtension( private let isolationProbeName = "__dependencyEntryIsolationProbe" -private func isolationCheck( +private func entryValueArguments( + from node: AttributeSyntax +) -> (liveValue: ExprSyntax?, previewValue: ExprSyntax?) { + var liveValueExpr: ExprSyntax? + var previewValueExpr: ExprSyntax? + if let arguments = node.arguments?.as(LabeledExprListSyntax.self) { + for argument in arguments { + switch argument.label?.text { + case "liveValue": + liveValueExpr = argument.expression + case "previewValue": + previewValueExpr = argument.expression + default: + break + } + } + } + return (liveValueExpr, previewValueExpr) +} + +private func extendedType(in context: some MacroExpansionContext) -> TypeSyntax? { + context.lexicalContext.first?.as(ExtensionDeclSyntax.self)?.extendedType.trimmed +} + +private func entryChecks( for node: AttributeSyntax, + identifier: TokenSyntax, in context: some MacroExpansionContext ) -> CodeBlockItemListSyntax { + var checks = ["#IsolationCheck(\(isolationProbeName))"] + if let extendedType = extendedType(in: context) { + let (liveValueExpr, previewValueExpr) = entryValueArguments(from: node) + if let liveValueExpr { + checks.append( + "#TypeCheck(\\\(extendedType).\(identifier), liveValue: \(liveValueExpr.trimmed))" + ) + } + if let previewValueExpr { + checks.append( + "#TypeCheck(\\\(extendedType).\(identifier), previewValue: \(previewValueExpr.trimmed))" + ) + } + } guard let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath) else { return """ func \(raw: isolationProbeName)() {} - #IsolationCheck(\(raw: isolationProbeName)) + \(raw: checks.joined(separator: "\n")) """ } + let directive = "#sourceLocation(file: \(location.file), line: \(location.line))" return """ func \(raw: isolationProbeName)() {} - #sourceLocation(file: \(location.file), line: \(location.line)) - #IsolationCheck(\(raw: isolationProbeName)) + \(raw: checks.map { "\(directive)\n\($0)" }.joined(separator: "\n")) #sourceLocation() """ } @@ -288,9 +327,7 @@ private func sendableCheck( identifier: TokenSyntax, in context: some MacroExpansionContext ) -> [DeclSyntax] { - guard - let extendedType = context.lexicalContext.first?.as(ExtensionDeclSyntax.self)? - .extendedType.trimmed + guard let extendedType = extendedType(in: context) else { return [] } diff --git a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift index 0ac2cfb4..13c315d2 100644 --- a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift +++ b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift @@ -30,6 +30,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() return self[__Key_client.self] } @@ -73,6 +75,10 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, previewValue: Client.preview) #sourceLocation() return self[__Key_client.self] } @@ -117,6 +123,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, previewValue: Client.preview) #sourceLocation() return self[__Key_client.self] } @@ -202,6 +210,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() return self[__Key_client.self] } @@ -309,6 +319,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() return self[__Key_client.self] } @@ -354,6 +366,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() return self[APIClientKey.self] } @@ -439,6 +453,8 @@ final class DependencyEntryMacroTests: BaseTestCase { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) + #sourceLocation(file: "Test.swift", line: 2) + #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() return self[ClientKey.self] } From cfc0cbaa1f9535fefa230d3f6b5d5d04ff08b6cb Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 3 Aug 2026 13:26:31 -0700 Subject: [PATCH 3/4] Handle `@DependencyClient`, too --- Sources/DependenciesMacros/Macros.swift | 16 ++ .../DependencyClientMacro.swift | 38 ++++- .../DependencyEntryMacro.swift | 19 +++ .../DependenciesMacrosPlugin/Plugins.swift | 1 + .../DependencyClientMacroTests.swift | 150 ++++++++++++++++++ 5 files changed, 218 insertions(+), 6 deletions(-) diff --git a/Sources/DependenciesMacros/Macros.swift b/Sources/DependenciesMacros/Macros.swift index 7f590f04..7ffb3ad0 100644 --- a/Sources/DependenciesMacros/Macros.swift +++ b/Sources/DependenciesMacros/Macros.swift @@ -304,6 +304,22 @@ public macro IsolationCheck(keyPath: KeyPath) = type: "DependencyEntrySendableCheckMacro" ) +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(client: () -> Void) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyEntryIsolationCheckMacro" + ) + +@_documentation(visibility: private) +@freestanding(declaration) +public macro IsolationCheck(client: @MainActor () -> Void) = + #externalMacro( + module: "DependenciesMacrosPlugin", + type: "DependencyClientMainActorCheckMacro" + ) + @_documentation(visibility: private) @freestanding(declaration) public macro TypeCheck( diff --git a/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift index 28c0bbb6..e0a9169d 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift @@ -231,18 +231,44 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro { guard hasEndpoints else { return [] } let access = accesses.min().flatMap { $0.token?.with(\.trailingTrivia, .space) } // TODO: Don't define initializers if any single endpoint is invalid - return [properties, properties.filter { !$0.isEndpoint }].map { - $0.isEmpty - ? "\(access)init() {}" + return [(properties, isolationCheck(for: node, in: context)), (properties.filter { !$0.isEndpoint }, "")].map { + (properties, check) in + properties.isEmpty + ? """ + \(access)init() {\(raw: check)} + """ : """ \(access)init( - \(raw: $0.map { $0.declaration.bindings.trimmedDescription }.joined(separator: ",\n")) - ) { - \(raw: $0.map { "self.\($0.identifier) = \($0.identifier)" }.joined(separator: "\n")) + \(raw: properties.map { $0.declaration.bindings.trimmedDescription }.joined(separator: ",\n")) + ) {\(raw: check) + \(raw: properties.map { "self.\($0.identifier) = \($0.identifier)" }.joined(separator: "\n")) } """ } } + + private static func isolationCheck( + for node: AttributeSyntax, + in context: some MacroExpansionContext + ) -> String { + let probeName = "__dependencyClientIsolationProbe" + guard + let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath) + else { + return """ + + func \(probeName)() {} + #IsolationCheck(client: \(probeName)) + """ + } + return """ + + func \(probeName)() {} + #sourceLocation(file: \(location.file), line: \(location.line)) + #IsolationCheck(client: \(probeName)) + #sourceLocation() + """ + } } private enum Access: Comparable { diff --git a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift index 4a8c4fd3..09010f0f 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift @@ -376,6 +376,25 @@ extension DependencyEntryMainActorIsolationCheckMacro: DeclarationMacro { } } +public enum DependencyClientMainActorCheckMacro {} + +extension DependencyClientMainActorCheckMacro: DeclarationMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + context.diagnose( + Diagnostic( + node: node, + message: MacroExpansionErrorMessage( + "client must be 'nonisolated struct' when default isolation is '@MainActor'" + ) + ) + ) + return [] + } +} + public enum DependencyEntrySendableCheckMacro {} extension DependencyEntrySendableCheckMacro: DeclarationMacro { diff --git a/Sources/DependenciesMacrosPlugin/Plugins.swift b/Sources/DependenciesMacrosPlugin/Plugins.swift index a8771e6c..2ea89bfb 100644 --- a/Sources/DependenciesMacrosPlugin/Plugins.swift +++ b/Sources/DependenciesMacrosPlugin/Plugins.swift @@ -12,5 +12,6 @@ struct MacrosPlugin: CompilerPlugin { DependencyEntryIsolationCheckMacro.self, DependencyEntryMainActorIsolationCheckMacro.self, DependencyEntrySendableCheckMacro.self, + DependencyClientMainActorCheckMacro.self, ] } diff --git a/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift b/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift index 624a5381..caf066eb 100644 --- a/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift +++ b/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift @@ -33,6 +33,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool = false, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -63,6 +68,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -93,6 +103,11 @@ final class DependencyClientMacroTests: BaseTestCase { endpoint: @escaping () -> Void, config: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint self.config = config } @@ -127,6 +142,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Bool = false, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -161,6 +181,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Double = 1.0, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -195,6 +220,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Int = 1, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -229,6 +259,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.String = "Blob", endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -263,6 +298,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } @@ -296,6 +336,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( config: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config } @@ -323,6 +368,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Int ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -352,6 +402,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -381,6 +436,11 @@ final class DependencyClientMacroTests: BaseTestCase { public init( endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -410,6 +470,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -437,6 +502,11 @@ final class DependencyClientMacroTests: BaseTestCase { package init( endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -464,6 +534,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -494,6 +569,11 @@ final class DependencyClientMacroTests: BaseTestCase { name: String? = nil, endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.name = name self.endpoint = endpoint } @@ -533,6 +613,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -572,6 +657,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -607,6 +697,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () throws -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -644,6 +739,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -683,6 +783,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -712,6 +817,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -742,6 +852,11 @@ final class DependencyClientMacroTests: BaseTestCase { id: UUID, endpoint: @Sendable @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.id = id self.endpoint = endpoint } @@ -794,6 +909,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Int ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint } @@ -837,6 +957,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (_ id: Int) throws -> String ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.fetch = fetch } @@ -881,6 +1006,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (_ id: Int) throws -> String ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.fetch = fetch } @@ -919,6 +1049,11 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (Int) throws -> String ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.fetch = fetch } @@ -968,6 +1103,11 @@ final class DependencyClientMacroTests: BaseTestCase { endpoint: @escaping () -> Void, value: <#Type#> = Value() ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.endpoint = endpoint self.value = value } @@ -1050,6 +1190,11 @@ final class DependencyClientMacroTests: BaseTestCase { foo: @escaping () -> String, bar: @escaping () -> String ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.foo = foo self.bar = bar } @@ -1081,6 +1226,11 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool = false, endpoint: @escaping () -> Void ) { + func __dependencyClientIsolationProbe() { + } + #sourceLocation(file: "Test.swift", line: 1) + #IsolationCheck(client: __dependencyClientIsolationProbe) + #sourceLocation() self.config = config self.endpoint = endpoint } From e57d5c2eca06d5d72c7b2c7a712462b31dbfcf6a Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 3 Aug 2026 13:36:36 -0700 Subject: [PATCH 4/4] debug --- .../DependencyClientMacro.swift | 4 + .../DependencyEntryMacro.swift | 28 ++++-- .../DependencyClientMacroTests.swift | 60 ++++++++++++ .../DependencyEntryMacroTests.swift | 96 ++++++++++++------- 4 files changed, 144 insertions(+), 44 deletions(-) diff --git a/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift index e0a9169d..ed3033f5 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyClientMacro.swift @@ -257,16 +257,20 @@ public enum DependencyClientMacro: MemberAttributeMacro, MemberMacro { else { return """ + #if DEBUG func \(probeName)() {} #IsolationCheck(client: \(probeName)) + #endif """ } return """ + #if DEBUG func \(probeName)() {} #sourceLocation(file: \(location.file), line: \(location.line)) #IsolationCheck(client: \(probeName)) #sourceLocation() + #endif """ } } diff --git a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift index 09010f0f..4de7ee43 100644 --- a/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift +++ b/Sources/DependenciesMacrosPlugin/DependencyEntryMacro.swift @@ -310,15 +310,19 @@ private func entryChecks( let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath) else { return """ + #if DEBUG func \(raw: isolationProbeName)() {} \(raw: checks.joined(separator: "\n")) + #endif """ } let directive = "#sourceLocation(file: \(location.file), line: \(location.line))" return """ + #if DEBUG func \(raw: isolationProbeName)() {} \(raw: checks.map { "\(directive)\n\($0)" }.joined(separator: "\n")) #sourceLocation() + #endif """ } @@ -331,18 +335,26 @@ private func sendableCheck( else { return [] } - let check: DeclSyntax = "#IsolationCheck(keyPath: \\\(extendedType).\(identifier))" + let check = "#IsolationCheck(keyPath: \\\(extendedType).\(identifier))" guard - let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath), - let line = location.line.as(IntegerLiteralExprSyntax.self), - let lineValue = Int(line.literal.text) + let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .filePath) else { - return [check] + return [ + """ + #if DEBUG + \(raw: check) + #endif + """ + ] } return [ - "#sourceLocation(file: \(location.file), line: \(raw: lineValue - 1))", - check, - "#sourceLocation()", + """ + #if DEBUG + #sourceLocation(file: \(location.file), line: \(location.line)) + \(raw: check) + #sourceLocation() + #endif + """ ] } diff --git a/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift b/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift index caf066eb..91a1ba88 100644 --- a/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift +++ b/Tests/DependenciesMacrosPluginTests/DependencyClientMacroTests.swift @@ -33,11 +33,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool = false, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -68,11 +70,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -103,11 +107,13 @@ final class DependencyClientMacroTests: BaseTestCase { endpoint: @escaping () -> Void, config: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint self.config = config } @@ -142,11 +148,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Bool = false, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -181,11 +189,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Double = 1.0, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -220,11 +230,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.Int = 1, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -259,11 +271,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Swift.String = "Blob", endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -298,11 +312,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } @@ -336,11 +352,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( config: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config } @@ -368,11 +386,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Int ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -402,11 +422,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -436,11 +458,13 @@ final class DependencyClientMacroTests: BaseTestCase { public init( endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -470,11 +494,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -502,11 +528,13 @@ final class DependencyClientMacroTests: BaseTestCase { package init( endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -534,11 +562,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -569,11 +599,13 @@ final class DependencyClientMacroTests: BaseTestCase { name: String? = nil, endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.name = name self.endpoint = endpoint } @@ -613,11 +645,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -657,11 +691,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -697,11 +733,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () throws -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -739,11 +777,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -783,11 +823,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -817,11 +859,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -852,11 +896,13 @@ final class DependencyClientMacroTests: BaseTestCase { id: UUID, endpoint: @Sendable @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.id = id self.endpoint = endpoint } @@ -909,11 +955,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( endpoint: @Sendable @escaping () -> Int ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint } @@ -957,11 +1005,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (_ id: Int) throws -> String ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.fetch = fetch } @@ -1006,11 +1056,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (_ id: Int) throws -> String ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.fetch = fetch } @@ -1049,11 +1101,13 @@ final class DependencyClientMacroTests: BaseTestCase { init( fetch: @escaping (Int) throws -> String ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.fetch = fetch } @@ -1103,11 +1157,13 @@ final class DependencyClientMacroTests: BaseTestCase { endpoint: @escaping () -> Void, value: <#Type#> = Value() ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.endpoint = endpoint self.value = value } @@ -1190,11 +1246,13 @@ final class DependencyClientMacroTests: BaseTestCase { foo: @escaping () -> String, bar: @escaping () -> String ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.foo = foo self.bar = bar } @@ -1226,11 +1284,13 @@ final class DependencyClientMacroTests: BaseTestCase { config: Bool = false, endpoint: @escaping () -> Void ) { + #if DEBUG func __dependencyClientIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 1) #IsolationCheck(client: __dependencyClientIsolationProbe) #sourceLocation() + #endif self.config = config self.endpoint = endpoint } diff --git a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift index 13c315d2..ff75aec1 100644 --- a/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift +++ b/Tests/DependenciesMacrosPluginTests/DependencyEntryMacroTests.swift @@ -26,6 +26,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -33,6 +34,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -43,11 +45,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var liveValue = Client.live @@ -71,6 +73,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -80,6 +83,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, previewValue: Client.preview) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -90,11 +94,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var liveValue = Client.live @@ -119,6 +123,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -126,6 +131,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, previewValue: Client.preview) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -136,11 +142,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var previewValue = Client.preview @@ -164,11 +170,13 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -179,11 +187,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue static var testValue = Client.test @@ -206,6 +214,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client: Client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -213,6 +222,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -223,11 +233,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.DependencyKey { typealias Value = Client @@ -315,6 +325,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { var client: Client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -322,6 +333,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() + #endif return self[__Key_client.self] } set { @@ -332,11 +344,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif private nonisolated enum __Key_client: Dependencies.DependencyKey { typealias Value = Client @@ -362,6 +374,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { public var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -369,6 +382,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() + #endif return self[APIClientKey.self] } set { @@ -379,11 +393,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif public nonisolated enum APIClientKey: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue public static var liveValue = Client.live @@ -407,11 +421,13 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { package var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) #sourceLocation() + #endif return self[ClientKey.self] } set { @@ -422,11 +438,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif package nonisolated enum ClientKey: Dependencies.TestDependencyKey { @DependenciesMacros._DependencyEntryDefaultValue package static var testValue = Client.test @@ -449,6 +465,7 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { public var client { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) @@ -456,6 +473,7 @@ final class DependencyEntryMacroTests: BaseTestCase { #sourceLocation(file: "Test.swift", line: 2) #TypeCheck(\DependencyValues.client, liveValue: Client.live) #sourceLocation() + #endif return self[ClientKey.self] } set { @@ -466,11 +484,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif public nonisolated enum ClientKey: Dependencies.DependencyKey { @DependenciesMacros._DependencyEntryDefaultValue public static var liveValue = Client.live @@ -494,11 +512,13 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { public var client: any APIClient { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) #sourceLocation() + #endif return self[ExplicitAPIClientKey.self] } set { @@ -509,11 +529,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif public nonisolated enum ExplicitAPIClientKey: Dependencies.TestDependencyKey { public typealias Value = any APIClient @@ -539,11 +559,13 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { public var client: MockAPIClient { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) #sourceLocation() + #endif return self[MockAPIClientKey.self] } set { @@ -554,11 +576,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif public nonisolated enum MockAPIClientKey: Dependencies.TestDependencyKey { public typealias Value = MockAPIClient @@ -584,11 +606,13 @@ final class DependencyEntryMacroTests: BaseTestCase { extension DependencyValues { public var client: any APIClient { get { + #if DEBUG func __dependencyEntryIsolationProbe() { } #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(__dependencyEntryIsolationProbe) #sourceLocation() + #endif return self[APIClientKey.self] } set { @@ -599,11 +623,11 @@ final class DependencyEntryMacroTests: BaseTestCase { } } - #sourceLocation(file: "Test.swift", line: 1) - + #if DEBUG + #sourceLocation(file: "Test.swift", line: 2) #IsolationCheck(keyPath: \DependencyValues.client) - #sourceLocation() + #endif public nonisolated enum APIClientKey: Dependencies.TestDependencyKey { public typealias Value = any APIClient