From cc38b100ecf9f23fb9a935f9f26548546b58e97d Mon Sep 17 00:00:00 2001 From: Kamil Strzelecki Date: Mon, 18 Aug 2025 23:10:21 +0200 Subject: [PATCH 1/5] Refactored `GlobalActorIsolation` type --- .../Declarations/Common/DeclBuilder.swift | 16 +++++----- .../Common/DeclBuilderSettings.swift | 6 ++-- .../Parameters/ParameterExtractor.swift | 8 ++--- .../Syntax/Helpers/GlobalActorIsolation.swift | 31 +++++++++++++++++++ .../GlobalActorIsolationPreference.swift | 15 --------- .../Parameters/ParameterExtractorTests.swift | 30 +++++++----------- 6 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift delete mode 100644 Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift diff --git a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift index 5b1d20e..af0b4ae 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift @@ -26,15 +26,13 @@ extension DeclBuilder { ) } - public var inheritedGlobalActorIsolation: AttributeSyntax? { - let globalActor: AttributeSyntax? = switch settings.globalActorIsolationPreference { - case .nonisolated: - nil - case let .isolated(globalActor): - "@\(globalActor)" - case .none: - basicDeclaration.globalActor?.trimmed + public var inheritedGlobalActorIsolation: GlobalActorIsolation? { + if let preferred = settings.preferredGlobalActorIsolation { + return preferred } - return globalActor?.withTrailingSpace + if let inferred = basicDeclaration.globalActor?.attributeName { + return .isolated(inferred) + } + return .nonisolated } } diff --git a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift index c157be7..1c81b02 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift @@ -11,14 +11,14 @@ import SwiftSyntax public struct DeclBuilderSettings { public var accessControlLevel: AccessControlLevel - public var globalActorIsolationPreference: GlobalActorIsolationPreference? + public var preferredGlobalActorIsolation: GlobalActorIsolation? public init( accessControlLevel: AccessControlLevel, - globalActorIsolationPreference: GlobalActorIsolationPreference? = nil + preferredGlobalActorIsolation: GlobalActorIsolation? = nil ) { self.accessControlLevel = accessControlLevel - self.globalActorIsolationPreference = globalActorIsolationPreference + self.preferredGlobalActorIsolation = preferredGlobalActorIsolation } } diff --git a/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift b/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift index f86a826..71249e5 100644 --- a/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift +++ b/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift @@ -64,9 +64,9 @@ public struct ParameterExtractor { return rawString } - public func globalActorIsolationPreference( + public func preferredGlobalActorIsolation( withLabel label: TokenSyntax? - ) throws -> GlobalActorIsolationPreference? { + ) throws -> GlobalActorIsolation? { guard let expression = expression(withLabel: label) else { return nil } @@ -77,8 +77,8 @@ public struct ParameterExtractor { if let memberAccessExpression = MemberAccessExprSyntax(expression), memberAccessExpression.declName.baseName.tokenKind == .keyword(.self), - let baseType = memberAccessExpression.base { - return .isolated("\(baseType)") + let globalActor = memberAccessExpression.base?.trimmed { + return .isolated("\(globalActor)") } throw ParameterExtractionError.unexpectedSyntaxType diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift new file mode 100644 index 0000000..bbbc7a4 --- /dev/null +++ b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift @@ -0,0 +1,31 @@ +// +// GlobalActorIsolationPreference.swift +// PrincipleMacros +// +// Created by Kamil Strzelecki on 18/08/2025. +// Copyright © 2025 Kamil Strzelecki. All rights reserved. +// + +import SwiftSyntax + +public enum GlobalActorIsolation: Hashable { + + case nonisolated + case isolated(TypeSyntax) + + public var type: TypeSyntax? { + switch self { + case .isolated(let type): + type + case .nonisolated: + nil + } + } + + public var attribute: AttributeSyntax? { + guard let type else { + return nil + } + return AttributeSyntax(attributeName: type) + } +} diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift deleted file mode 100644 index d5ea051..0000000 --- a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolationPreference.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// GlobalActorIsolationPreference.swift -// PrincipleMacros -// -// Created by Kamil Strzelecki on 18/08/2025. -// Copyright © 2025 Kamil Strzelecki. All rights reserved. -// - -import SwiftSyntax - -public enum GlobalActorIsolationPreference: Hashable { - - case nonisolated - case isolated(TypeSyntax) -} diff --git a/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift b/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift index db266df..61dd125 100644 --- a/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift +++ b/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift @@ -46,16 +46,14 @@ extension ParameterExtractorTests { func testTrailingClosureExtraction() throws { let extractor = try makeExtractor(from: "#MyMacro { _ in }") let extracted = try extractor.trailingClosure(withLabel: "operation") - let expected: ExprSyntax = "{ _ in }" - #expect(extracted?.description == expected.description) + #expect(extracted?.description == "{ _ in }") } @Test func testTrailingClosureReferenceExtraction() throws { let extractor = try makeExtractor(from: "#MyMacro(operation: perform)") let extracted = try extractor.trailingClosure(withLabel: "operation") - let expected: ExprSyntax = "perform" - #expect(extracted?.description == expected.description) + #expect(extracted?.description == "perform") } } @@ -80,16 +78,16 @@ extension ParameterExtractorTests { extension ParameterExtractorTests { @Test - func testMissingGlobalActorPreferenceExtraction() throws { + func testMissingPreferredGlobalActorExtraction() throws { let extractor = try makeExtractor(from: "#MyMacro()") - let extracted = try extractor.globalActorIsolationPreference(withLabel: "isolation") + let extracted = try extractor.preferredGlobalActorIsolation(withLabel: "isolation") #expect(extracted == nil) } @Test - func testNonisolatedGlobalActorPreferenceExtraction() throws { + func testNonisolatedPreferredGlobalActorExtraction() throws { let extractor = try makeExtractor(from: "#MyMacro(isolation: nil)") - let extracted = try extractor.globalActorIsolationPreference(withLabel: "isolation") + let extracted = try extractor.preferredGlobalActorIsolation(withLabel: "isolation") #expect(extracted == .nonisolated) } @@ -99,23 +97,17 @@ extension ParameterExtractorTests { "SomeType.SomeActor" ] ) - func testIsolatedGlobalActorPreferenceExtraction(isolation: String) throws { + func testIsolatedPreferredGlobalActorExtraction(isolation: String) throws { let extractor = try makeExtractor(from: "#MyMacro(isolation: \(raw: isolation).self)") - let extracted = try extractor.globalActorIsolationPreference(withLabel: "isolation") - - switch extracted { - case let .isolated(globalActor): - #expect(globalActor.description == isolation) - default: - Issue.record() - } + let extracted = try extractor.preferredGlobalActorIsolation(withLabel: "isolation") + #expect(extracted?.attribute?.description == "@\(isolation)") } @Test - func testUnexpectedSyntaxWhenPerformingGlobalActorPreferenceExtraction() throws { + func testUnexpectedSyntaxWhenPerformingPreferredGlobalActorExtraction() throws { let extractor = try makeExtractor(from: #"#MyMacro(isolation: MainActor.Type)"#) #expect(throws: ParameterExtractionError.unexpectedSyntaxType) { - try extractor.globalActorIsolationPreference(withLabel: "isolation") + try extractor.preferredGlobalActorIsolation(withLabel: "isolation") } } } From b370c0c10769f6444190a282c876ac0116acbdbc Mon Sep 17 00:00:00 2001 From: Kamil Strzelecki Date: Mon, 18 Aug 2025 23:10:21 +0200 Subject: [PATCH 2/5] [SwiftFormat] Applied formatting --- .../PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift index bbbc7a4..28b55cb 100644 --- a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift +++ b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift @@ -15,7 +15,7 @@ public enum GlobalActorIsolation: Hashable { public var type: TypeSyntax? { switch self { - case .isolated(let type): + case let .isolated(type): type case .nonisolated: nil From 8ccc03f5c14e8fbe9d6d2137f95e8f91ee791f87 Mon Sep 17 00:00:00 2001 From: Kamil Strzelecki Date: Mon, 18 Aug 2025 23:11:03 +0200 Subject: [PATCH 3/5] - --- .../PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift index 28b55cb..b42a43b 100644 --- a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift +++ b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift @@ -1,5 +1,5 @@ // -// GlobalActorIsolationPreference.swift +// GlobalActorIsolation.swift // PrincipleMacros // // Created by Kamil Strzelecki on 18/08/2025. From ba58f2d910e362f964fea7093ac664de819eefa0 Mon Sep 17 00:00:00 2001 From: Kamil Strzelecki Date: Mon, 18 Aug 2025 23:20:09 +0200 Subject: [PATCH 4/5] - --- .../Builders/Declarations/Common/DeclBuilder.swift | 4 ++-- .../Parameters/ParameterExtractor.swift | 4 ++-- .../Syntax/Helpers/GlobalActorIsolation.swift | 12 +++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift index af0b4ae..18710c0 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift @@ -30,8 +30,8 @@ extension DeclBuilder { if let preferred = settings.preferredGlobalActorIsolation { return preferred } - if let inferred = basicDeclaration.globalActor?.attributeName { - return .isolated(inferred) + if let inferredType = basicDeclaration.globalActor?.attributeName.trimmed { + return .isolated(trimmedType: inferredType) } return .nonisolated } diff --git a/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift b/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift index 71249e5..e17ad0a 100644 --- a/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift +++ b/Sources/PrincipleMacros/Parameters/ParameterExtractor.swift @@ -77,8 +77,8 @@ public struct ParameterExtractor { if let memberAccessExpression = MemberAccessExprSyntax(expression), memberAccessExpression.declName.baseName.tokenKind == .keyword(.self), - let globalActor = memberAccessExpression.base?.trimmed { - return .isolated("\(globalActor)") + let explicitType = memberAccessExpression.base?.trimmed { + return .isolated(trimmedType: "\(explicitType)") } throw ParameterExtractionError.unexpectedSyntaxType diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift index b42a43b..6c116a8 100644 --- a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift +++ b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift @@ -11,9 +11,9 @@ import SwiftSyntax public enum GlobalActorIsolation: Hashable { case nonisolated - case isolated(TypeSyntax) + case isolated(trimmedType: TypeSyntax) - public var type: TypeSyntax? { + public var trimmedType: TypeSyntax? { switch self { case let .isolated(type): type @@ -22,10 +22,12 @@ public enum GlobalActorIsolation: Hashable { } } - public var attribute: AttributeSyntax? { - guard let type else { + public var trimmedAttribute: AttributeSyntax? { + guard let trimmedType else { return nil } - return AttributeSyntax(attributeName: type) + return AttributeSyntax( + attributeName: trimmedType + ) } } From 0f95a59e3b2257ac5ba4344266ceaf04ed3b58ea Mon Sep 17 00:00:00 2001 From: Kamil Strzelecki Date: Mon, 18 Aug 2025 23:52:45 +0200 Subject: [PATCH 5/5] Refactored `GlobalActorIsolation` type --- .../Declarations/Common/DeclBuilder.swift | 17 ++++++++++++----- .../Common/DeclBuilderSettings.swift | 6 +++--- .../Declarations/Types/TypeDeclBuilder.swift | 8 ++++---- .../Types/TypeDeclBuilderContext.swift | 2 +- .../Syntax/Extensions/WithModifiersSyntax.swift | 2 +- .../Syntax/Helpers/GlobalActorIsolation.swift | 11 +++++------ .../Parameters/ParameterExtractorTests.swift | 2 +- 7 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift index 18710c0..a836cf0 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilder.swift @@ -20,19 +20,26 @@ extension DeclBuilder { public var inheritedAccessControlLevel: TokenSyntax? { let settings = settings.accessControlLevel - return basicDeclaration.accessControlLevel( + return basicDeclaration.inlinableAccessControlLevel( inheritedBy: settings.inheritingDeclaration, maxAllowed: settings.maxAllowed ) } +} + +extension DeclBuilder { public var inheritedGlobalActorIsolation: GlobalActorIsolation? { - if let preferred = settings.preferredGlobalActorIsolation { - return preferred + if let explicit = settings.explicitGlobalActorIsolation { + return explicit } - if let inferredType = basicDeclaration.globalActor?.attributeName.trimmed { - return .isolated(trimmedType: inferredType) + if let inherited = basicDeclaration.globalActor?.attributeName { + return .isolated(trimmedType: inherited.trimmed) } return .nonisolated } + + public var inheritedGlobalActorAttribute: AttributeSyntax? { + inheritedGlobalActorIsolation?.inlinableAttribute + } } diff --git a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift index 1c81b02..bc48e4a 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Common/DeclBuilderSettings.swift @@ -11,14 +11,14 @@ import SwiftSyntax public struct DeclBuilderSettings { public var accessControlLevel: AccessControlLevel - public var preferredGlobalActorIsolation: GlobalActorIsolation? + public var explicitGlobalActorIsolation: GlobalActorIsolation? public init( accessControlLevel: AccessControlLevel, - preferredGlobalActorIsolation: GlobalActorIsolation? = nil + explicitGlobalActorIsolation: GlobalActorIsolation? = nil ) { self.accessControlLevel = accessControlLevel - self.preferredGlobalActorIsolation = preferredGlobalActorIsolation + self.explicitGlobalActorIsolation = explicitGlobalActorIsolation } } diff --git a/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilder.swift b/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilder.swift index 36e81bb..10bf2ba 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilder.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilder.swift @@ -22,10 +22,10 @@ extension TypeDeclBuilder { extension TypeDeclBuilder { - public var trimmedTypeName: TypeSyntax { + public var trimmedType: TypeSyntax { switch TypeDeclBuilderContext.current { - case let .extension(extendedType): - extendedType.trimmed + case let .extension(trimmedType): + trimmedType case .declaration: "\(typeDeclaration.name.trimmed)" } @@ -33,7 +33,7 @@ extension TypeDeclBuilder { public func buildExtension(of extendedType: some TypeSyntaxProtocol) throws -> MemberBlockSyntax { try TypeDeclBuilderContext.$current.withValue( - .extension(TypeSyntax(extendedType)), + .extension(trimmedType: TypeSyntax(extendedType.trimmed)), operation: { try MemberBlockSyntax( members: MemberBlockItemListSyntax( diff --git a/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilderContext.swift b/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilderContext.swift index fa57d6e..19fa5d3 100644 --- a/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilderContext.swift +++ b/Sources/PrincipleMacros/Builders/Declarations/Types/TypeDeclBuilderContext.swift @@ -11,7 +11,7 @@ import SwiftSyntax internal enum TypeDeclBuilderContext { case declaration - case `extension`(TypeSyntax) + case `extension`(trimmedType: TypeSyntax) } extension TypeDeclBuilderContext { diff --git a/Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift b/Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift index 8157f6a..a0779cf 100644 --- a/Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift +++ b/Sources/PrincipleMacros/Syntax/Extensions/WithModifiersSyntax.swift @@ -43,7 +43,7 @@ extension WithModifiersSyntax { extension WithModifiersSyntax { - public func accessControlLevel( + public func inlinableAccessControlLevel( inheritedBy inheritingDeclaration: InheritingDeclaration, maxAllowed: Keyword ) -> TokenSyntax? { diff --git a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift index 6c116a8..e8a60fa 100644 --- a/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift +++ b/Sources/PrincipleMacros/Syntax/Helpers/GlobalActorIsolation.swift @@ -15,19 +15,18 @@ public enum GlobalActorIsolation: Hashable { public var trimmedType: TypeSyntax? { switch self { - case let .isolated(type): - type + case let .isolated(trimmedType): + trimmedType case .nonisolated: nil } } - public var trimmedAttribute: AttributeSyntax? { + public var inlinableAttribute: AttributeSyntax? { guard let trimmedType else { return nil } - return AttributeSyntax( - attributeName: trimmedType - ) + let attribute = AttributeSyntax(attributeName: trimmedType) + return attribute.withTrailingSpace } } diff --git a/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift b/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift index 61dd125..06d205f 100644 --- a/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift +++ b/Tests/PrincipleMacrosTests/Parameters/ParameterExtractorTests.swift @@ -100,7 +100,7 @@ extension ParameterExtractorTests { func testIsolatedPreferredGlobalActorExtraction(isolation: String) throws { let extractor = try makeExtractor(from: "#MyMacro(isolation: \(raw: isolation).self)") let extracted = try extractor.preferredGlobalActorIsolation(withLabel: "isolation") - #expect(extracted?.attribute?.description == "@\(isolation)") + #expect(extracted?.trimmedType?.description == isolation) } @Test