diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7743a45..c5f1370c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,13 +8,13 @@ on: jobs: xcodebuild-15: - name: Build with xcodebuild on Xcode 15 + name: Build with xcodebuild on Xcode 16 runs-on: macos-14 strategy: matrix: platforms: [ 'generic/platform=ios', - 'platform=macos', + 'platform=macOS', 'generic/platform=tvos', 'generic/platform=watchos', 'generic/platform=visionos' @@ -24,32 +24,36 @@ jobs: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Download visionOS if: matrix.platforms == 'generic/platform=visionos' - run: xcodebuild -downloadPlatform visionOS + run: | + sudo xcodebuild -runFirstLaunch + sudo xcrun simctl list + sudo xcodebuild -downloadPlatform visionOS + sudo xcodebuild -runFirstLaunch - name: Build Framework run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme SafeDI-Package -destination ${{ matrix.platforms }} spm-package-integration-15: - name: Build Package Integration on Xcode 15 + name: Build Package Integration on Xcode 16 runs-on: macos-14 steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Build Package Integration run: xcrun swift build --package-path Examples/ExamplePackageIntegration spm-project-integration-15: - name: Build Project Integration on Xcode 15 + name: Build Project Integration on Xcode 16 runs-on: macos-14 steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Replace 'main' branch with the current branch if: github.event.pull_request.head.repo.full_name == github.repository # Only do this if the branch is from our repo. run: sed -i '' "s#branch = main;#branch = ${{ github.head_ref || github.ref_name }};#" "Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/project.pbxproj" @@ -57,13 +61,13 @@ jobs: run: pushd Examples/ExampleProjectIntegration; xcrun xcodebuild build -skipPackagePluginValidation -skipMacroValidation -scheme ExampleProjectIntegration; popd spm-multi-project-integration-15: - name: Build Multi Project Integration on Xcode 15 + name: Build Multi Project Integration on Xcode 16 runs-on: macos-14 steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Replace 'main' branch with the current branch if: github.event.pull_request.head.repo.full_name == github.repository # Only do this if the branch is from our repo. run: sed -i '' "s#branch = main;#branch = ${{ github.head_ref || github.ref_name }};#" "Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/project.pbxproj" @@ -71,13 +75,13 @@ jobs: run: pushd Examples/ExampleMultiProjectIntegration; xcrun xcodebuild build -skipPackagePluginValidation -skipMacroValidation -scheme ExampleMultiProjectIntegration; popd spm-15: - name: Build and Test on Xcode 15 + name: Build and Test on Xcode 16 runs-on: macos-14 steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Build and Test Framework run: | for i in {1..5}; do # Run tests a few times to ensure code-gen is stable. @@ -98,7 +102,7 @@ jobs: linux: name: Build and Test on Linux runs-on: ubuntu-latest - container: swift:5.10 + container: swift:6.0 steps: - name: Checkout Repo uses: actions/checkout@v4 @@ -129,9 +133,9 @@ jobs: lint-swift: name: Lint Swift runs-on: ubuntu-latest - container: swift:5.10 + container: swift:6.0 steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Lint Swift - run: swift run --package-path CLI swiftformat --swiftversion 5.10 . --lint + run: swift run --package-path CLI swiftformat --swiftversion 6.0 . --lint diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e3a98fb3..3f41ed10 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: - name: Checkout Repo uses: actions/checkout@v4 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_15.3.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer - name: Build SafeDITool run: xcrun swift build -c release --product SafeDITool --arch ${{ matrix.architecture }} - name: Give SafeDITool executable permissions diff --git a/CLI/Package.resolved b/CLI/Package.resolved index db1d8545..8226112d 100644 --- a/CLI/Package.resolved +++ b/CLI/Package.resolved @@ -1,14 +1,15 @@ { + "originHash" : "b043e9190ddd3045375d40ccb608edf659c48e3b9f8e2ee40cc489c8ec3f496d", "pins" : [ { "identity" : "swiftformat", "kind" : "remoteSourceControl", "location" : "https://github.com/nicklockwood/SwiftFormat", "state" : { - "revision" : "d6309f7440889427426143b4a0b100b959d3f3e6", - "version" : "0.54.3" + "revision" : "ab6844edb79a7b88dc6320e6cee0a0db7674dac3", + "version" : "0.54.5" } } ], - "version" : 2 + "version" : 3 } diff --git a/CLI/Package.swift b/CLI/Package.swift index e7679490..dbf2c6e4 100644 --- a/CLI/Package.swift +++ b/CLI/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/project.pbxproj b/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/project.pbxproj index 68962cdc..06ba237d 100644 --- a/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/project.pbxproj +++ b/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/project.pbxproj @@ -217,7 +217,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1500; - LastUpgradeCheck = 1510; + LastUpgradeCheck = 1600; TargetAttributes = { 32756FE12B24C042006BDD24 = { CreatedOnToolsVersion = 15.0.1; @@ -383,6 +383,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 6.0; }; name = Debug; }; @@ -438,13 +439,13 @@ MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 6.0; }; name = Release; }; 32756FF22B24C044006BDD24 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.entitlements; @@ -475,7 +476,6 @@ SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -483,7 +483,6 @@ 32756FF32B24C044006BDD24 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.entitlements; @@ -514,7 +513,6 @@ SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleMultiProjectIntegration.xcscheme b/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleMultiProjectIntegration.xcscheme index ead3ce6f..bcdcc9ec 100644 --- a/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleMultiProjectIntegration.xcscheme +++ b/Examples/ExampleMultiProjectIntegration/ExampleMultiProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleMultiProjectIntegration.xcscheme @@ -1,6 +1,6 @@ UserDefaults { .standard } diff --git a/Examples/ExamplePackageIntegration/Package.resolved b/Examples/ExamplePackageIntegration/Package.resolved index ab8b8de0..9378e4bc 100644 --- a/Examples/ExamplePackageIntegration/Package.resolved +++ b/Examples/ExamplePackageIntegration/Package.resolved @@ -33,8 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "fa8f95c2d536d6620cc2f504ebe8a6167c9fc2dd", - "version" : "510.0.1" + "revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25", + "version" : "600.0.0" } }, { diff --git a/Examples/ExamplePackageIntegration/Package.swift b/Examples/ExamplePackageIntegration/Package.swift index 64a2cfb5..8495e2c7 100644 --- a/Examples/ExamplePackageIntegration/Package.swift +++ b/Examples/ExamplePackageIntegration/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.10 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -34,6 +34,9 @@ let package = Package( "ChildBModule", "ChildCModule", ], + swiftSettings: [ + .swiftLanguageMode(.v6), + ], plugins: [ .plugin(name: "SafeDIGenerator", package: "SafeDI"), ] @@ -44,6 +47,9 @@ let package = Package( "SafeDI", "SharedModule", "GrandchildrenModule", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .target( @@ -52,6 +58,9 @@ let package = Package( "SafeDI", "SharedModule", "GrandchildrenModule", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .target( @@ -60,6 +69,9 @@ let package = Package( "SafeDI", "SharedModule", "GrandchildrenModule", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .target( @@ -67,11 +79,17 @@ let package = Package( dependencies: [ "SafeDI", "SharedModule", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .target( name: "SharedModule", - dependencies: ["SafeDI"] + dependencies: ["SafeDI"], + swiftSettings: [ + .swiftLanguageMode(.v6), + ] ), ] ) diff --git a/Examples/ExamplePackageIntegration/Sources/RootModule/Root.swift b/Examples/ExamplePackageIntegration/Sources/RootModule/Root.swift index 7addb5c8..3393883e 100644 --- a/Examples/ExamplePackageIntegration/Sources/RootModule/Root.swift +++ b/Examples/ExamplePackageIntegration/Sources/RootModule/Root.swift @@ -25,7 +25,7 @@ import Foundation import SafeDI import SharedModule -@Instantiable +@Instantiable @MainActor public final class Root: Instantiable { public init(childA: ChildA, childB: ChildB, childC: ChildC, shared: SharedThing, userDefaults: UserDefaults) { self.childA = childA diff --git a/Examples/ExamplePackageIntegration/Sources/SharedModule/SharedThing.swift b/Examples/ExamplePackageIntegration/Sources/SharedModule/SharedThing.swift index 6a47b4a1..f05e862d 100644 --- a/Examples/ExamplePackageIntegration/Sources/SharedModule/SharedThing.swift +++ b/Examples/ExamplePackageIntegration/Sources/SharedModule/SharedThing.swift @@ -21,6 +21,6 @@ import SafeDI @Instantiable -public final class SharedThing: Instantiable { +public final class SharedThing: Instantiable, Sendable { public init() {} } diff --git a/Examples/ExamplePackageIntegration/Sources/SharedModule/UserDefaults.swift b/Examples/ExamplePackageIntegration/Sources/SharedModule/UserDefaults.swift index 8c282484..7d5a9bfc 100644 --- a/Examples/ExamplePackageIntegration/Sources/SharedModule/UserDefaults.swift +++ b/Examples/ExamplePackageIntegration/Sources/SharedModule/UserDefaults.swift @@ -22,7 +22,7 @@ import Foundation import SafeDI @Instantiable -extension UserDefaults: Instantiable { +extension UserDefaults: @retroactive Instantiable { public static func instantiate() -> UserDefaults { .standard } diff --git a/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/project.pbxproj b/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/project.pbxproj index c6f12098..bfc24720 100644 --- a/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/project.pbxproj +++ b/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/project.pbxproj @@ -263,6 +263,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 6.0; }; name = Debug; }; @@ -318,6 +319,7 @@ MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 6.0; }; name = Release; }; @@ -353,7 +355,6 @@ SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -390,7 +391,6 @@ SDKROOT = auto; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleProjectIntegration.xcscheme b/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleProjectIntegration.xcscheme new file mode 100644 index 00000000..2c520f45 --- /dev/null +++ b/Examples/ExampleProjectIntegration/ExampleProjectIntegration.xcodeproj/xcshareddata/xcschemes/ExampleProjectIntegration.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/ExampleProjectIntegration/ExampleProjectIntegration/Models/StringStorage.swift b/Examples/ExampleProjectIntegration/ExampleProjectIntegration/Models/StringStorage.swift index d67c71e6..e16d0c65 100644 --- a/Examples/ExampleProjectIntegration/ExampleProjectIntegration/Models/StringStorage.swift +++ b/Examples/ExampleProjectIntegration/ExampleProjectIntegration/Models/StringStorage.swift @@ -27,7 +27,7 @@ public protocol StringStorage { } @Instantiable(fulfillingAdditionalTypes: [StringStorage.self]) -extension UserDefaults: Instantiable, StringStorage { +extension UserDefaults: @retroactive Instantiable, StringStorage { public static func instantiate() -> UserDefaults { .standard } diff --git a/Examples/ExampleProjectIntegration/Package.swift b/Examples/ExampleProjectIntegration/Package.swift index f06ad403..fc7ee9f8 100644 --- a/Examples/ExampleProjectIntegration/Package.swift +++ b/Examples/ExampleProjectIntegration/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Package.resolved b/Package.resolved index 0a1a3272..2504cf58 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "510f944249fe47ef5eb47a3895fae01d320996b28ac46f0f9c27a513878af17f", + "originHash" : "b243abcc717034a6320fa64413f1b1d699f25995bf795e1723ae1e64e70cd2b2", "pins" : [ { "identity" : "jjliso8601dateformatter", @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d", - "version" : "1.1.2" + "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", + "version" : "1.1.3" } }, { @@ -42,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "6d932a79e7173b275b96c600c86c603cf84f153c", - "version" : "1.17.4" + "revision" : "7b0bbbae90c41f848f90ac7b4df6c4f50068256d", + "version" : "1.17.5" } }, { @@ -51,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", - "version" : "510.0.3" + "revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25", + "version" : "600.0.0" } }, { diff --git a/Package.swift b/Package.swift index 8e2e9087..0157ddf7 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.10 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import CompilerPluginSupport @@ -25,11 +25,15 @@ let package = Package( name: "SafeDIGenerator", targets: ["SafeDIGenerator"] ), + .plugin( + name: "InstallSafeDITool", + targets: ["InstallSafeDITool"] + ), ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"), .package(url: "https://github.com/apple/swift-collections.git", from: "1.0.0"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "510.0.0"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0"), .package(url: "https://github.com/michaeleisel/ZippyJSON.git", from: "1.2.0"), .package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.5.0"), ], @@ -37,13 +41,19 @@ let package = Package( // Macros .target( name: "SafeDI", - dependencies: ["SafeDIMacros"] + dependencies: ["SafeDIMacros"], + swiftSettings: [ + .swiftLanguageMode(.v6), + ] ), .testTarget( name: "SafeDITests", dependencies: [ "SafeDI", "SafeDICore", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .macro( @@ -55,6 +65,9 @@ let package = Package( .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .testTarget( @@ -64,6 +77,9 @@ let package = Package( "SafeDICore", .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), .product(name: "MacroTesting", package: "swift-macro-testing"), + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), @@ -81,6 +97,9 @@ let package = Package( .product(name: "SwiftParser", package: "swift-syntax"), .byNameItem(name: "ZippyJSON", condition: .when(platforms: [.iOS, .tvOS, .macOS])), "SafeDICore", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .testTarget( @@ -89,8 +108,25 @@ let package = Package( .product(name: "ArgumentParser", package: "swift-argument-parser"), .byNameItem(name: "ZippyJSON", condition: .when(platforms: [.iOS, .tvOS, .macOS])), "SafeDITool", + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), + .plugin( + name: "InstallSafeDITool", + capability: .command( + intent: .custom( + verb: "safedi-release-install", + description: "Installs a release version of the SafeDITool build plugin executable." + ), + permissions: [ + .writeToPackageDirectory(reason: "Downloads the SafeDI release build plugin executable into your project directory."), + .allowNetworkConnections(scope: .all(ports: []), reason: "Downloads the SafeDI release build plugin executable from GitHub."), + ] + ), + dependencies: [] + ), // Core .target( @@ -100,11 +136,17 @@ let package = Package( .product(name: "SwiftDiagnostics", package: "swift-syntax"), .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), + ], + swiftSettings: [ + .swiftLanguageMode(.v6), ] ), .testTarget( name: "SafeDICoreTests", - dependencies: ["SafeDICore"] + dependencies: ["SafeDICore"], + swiftSettings: [ + .swiftLanguageMode(.v6), + ] ), ] ) diff --git a/Package@swift-6.0.swift b/Package@swift-6.0.swift deleted file mode 100644 index 0157ddf7..00000000 --- a/Package@swift-6.0.swift +++ /dev/null @@ -1,152 +0,0 @@ -// swift-tools-version: 6.0 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import CompilerPluginSupport -import PackageDescription - -let package = Package( - name: "SafeDI", - platforms: [ - .macOS(.v10_15), - .iOS(.v13), - .tvOS(.v13), - .watchOS(.v6), - .macCatalyst(.v13), - .visionOS(.v1), - ], - products: [ - /// A library containing SafeDI macros, property wrappers, and types. - .library( - name: "SafeDI", - targets: ["SafeDI"] - ), - /// A SafeDI plugin that must be run on the root source module in a project. - .plugin( - name: "SafeDIGenerator", - targets: ["SafeDIGenerator"] - ), - .plugin( - name: "InstallSafeDITool", - targets: ["InstallSafeDITool"] - ), - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"), - .package(url: "https://github.com/apple/swift-collections.git", from: "1.0.0"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0"), - .package(url: "https://github.com/michaeleisel/ZippyJSON.git", from: "1.2.0"), - .package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.5.0"), - ], - targets: [ - // Macros - .target( - name: "SafeDI", - dependencies: ["SafeDIMacros"], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .testTarget( - name: "SafeDITests", - dependencies: [ - "SafeDI", - "SafeDICore", - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .macro( - name: "SafeDIMacros", - dependencies: [ - "SafeDICore", - .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), - .product(name: "SwiftDiagnostics", package: "swift-syntax"), - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), - .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .testTarget( - name: "SafeDIMacrosTests", - dependencies: [ - "SafeDIMacros", - "SafeDICore", - .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), - .product(name: "MacroTesting", package: "swift-macro-testing"), - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - - // Plugins - .plugin( - name: "SafeDIGenerator", - capability: .buildTool(), - dependencies: ["SafeDITool"] - ), - .executableTarget( - name: "SafeDITool", - dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser"), - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftParser", package: "swift-syntax"), - .byNameItem(name: "ZippyJSON", condition: .when(platforms: [.iOS, .tvOS, .macOS])), - "SafeDICore", - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .testTarget( - name: "SafeDIToolTests", - dependencies: [ - .product(name: "ArgumentParser", package: "swift-argument-parser"), - .byNameItem(name: "ZippyJSON", condition: .when(platforms: [.iOS, .tvOS, .macOS])), - "SafeDITool", - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .plugin( - name: "InstallSafeDITool", - capability: .command( - intent: .custom( - verb: "safedi-release-install", - description: "Installs a release version of the SafeDITool build plugin executable." - ), - permissions: [ - .writeToPackageDirectory(reason: "Downloads the SafeDI release build plugin executable into your project directory."), - .allowNetworkConnections(scope: .all(ports: []), reason: "Downloads the SafeDI release build plugin executable from GitHub."), - ] - ), - dependencies: [] - ), - - // Core - .target( - name: "SafeDICore", - dependencies: [ - .product(name: "Collections", package: "swift-collections"), - .product(name: "SwiftDiagnostics", package: "swift-syntax"), - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), - ], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - .testTarget( - name: "SafeDICoreTests", - dependencies: ["SafeDICore"], - swiftSettings: [ - .swiftLanguageMode(.v6), - ] - ), - ] -) diff --git a/Plugins/InstallSafeDITool/InstallCLIPluginCommand.swift b/Plugins/InstallSafeDITool/InstallCLIPluginCommand.swift index 2db731da..22aafffc 100644 --- a/Plugins/InstallSafeDITool/InstallCLIPluginCommand.swift +++ b/Plugins/InstallSafeDITool/InstallCLIPluginCommand.swift @@ -19,6 +19,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import PackagePlugin @main diff --git a/Plugins/SafeDIGenerator/SafeDIGenerateDependencyTree.swift b/Plugins/SafeDIGenerator/SafeDIGenerateDependencyTree.swift index 0ea10d6d..a72eeae9 100644 --- a/Plugins/SafeDIGenerator/SafeDIGenerateDependencyTree.swift +++ b/Plugins/SafeDIGenerator/SafeDIGenerateDependencyTree.swift @@ -31,104 +31,60 @@ struct SafeDIGenerateDependencyTree: BuildToolPlugin { return [] } - #if compiler(>=6.0) - let outputSwiftFile = context.pluginWorkDirectoryURL.appending(path: "SafeDI.swift") - // Swift Package Plugins do not (as of Swift 5.9) allow for - // creating dependencies between plugin output. Since our - // current build system does not support depending on the - // output of other plugins, we must forgo searching for - // `.safeDI` files and instead parse the entire project at once. - let targetSwiftFiles = sourceTarget.sourceFiles(withSuffix: ".swift").map(\.url) - let dependenciesSourceFiles = sourceTarget - .sourceModuleRecursiveDependencies - .flatMap { - $0 - .sourceFiles(withSuffix: ".swift") - .map(\.url) - } - let inputSourcesFilePath = context.pluginWorkDirectoryURL.appending(path: "InputSwiftFiles.csv").path() - try Data( - (targetSwiftFiles.map { $0.path() } + dependenciesSourceFiles.map { $0.path() }) - .joined(separator: ",") - .utf8 - ) - .write(toPath: inputSourcesFilePath) - let arguments = [ - inputSourcesFilePath, - "--dependency-tree-output", - outputSwiftFile.path(), - ] - - let downloadedToolLocation = context.downloadedToolLocation - let safeDIVersion = context.safeDIVersion - if context.hasSafeDIFolder, let safeDIVersion, downloadedToolLocation == nil { - Diagnostics.error(""" - \(context.safediFolder.path()) exists, but contains no SafeDITool binary for version \(safeDIVersion). - - To download the release SafeDITool binary for version \(safeDIVersion), run: - \tswift package --package-path \(context.package.directoryURL.path()) --allow-network-connections all --allow-writing-to-package-directory safedi-release-install - - To use a debug SafeDITool binary instead, remove the `.safedi` directory by running: - \trm -rf \(context.safediFolder.path()) - """) - } else if downloadedToolLocation == nil, let safeDIVersion { - Diagnostics.warning(""" - Using a debug SafeDITool binary, which is 15x slower than a release SafeDITool binary. - - To download the release SafeDITool binary for version \(safeDIVersion), run: - \tswift package --package-path \(context.package.directoryURL.path()) --allow-network-connections all --allow-writing-to-package-directory safedi-release-install - """) - } - - let toolLocation = if let downloadedToolLocation { - downloadedToolLocation - } else { - try context.tool(named: "SafeDITool").url + let outputSwiftFile = context.pluginWorkDirectoryURL.appending(path: "SafeDI.swift") + // Swift Package Plugins did not (as of Swift 5.9) allow for + // creating dependencies between plugin output at the time of writing. + // Since our current build system didnot support depending on the + // output of other plugins, we must forgo searching for `.safeDI` files + // and instead parse the entire project at once. + // TODO: https://github.com/dfed/SafeDI/issues/92 + let targetSwiftFiles = sourceTarget.sourceFiles(withSuffix: ".swift").map(\.url) + let dependenciesSourceFiles = sourceTarget + .sourceModuleRecursiveDependencies + .flatMap { + $0 + .sourceFiles(withSuffix: ".swift") + .map(\.url) } + let inputSourcesFilePath = context.pluginWorkDirectoryURL.appending(path: "InputSwiftFiles.csv").path() + try Data( + (targetSwiftFiles.map { $0.path() } + dependenciesSourceFiles.map { $0.path() }) + .joined(separator: ",") + .utf8 + ) + .write(toPath: inputSourcesFilePath) + let arguments = [ + inputSourcesFilePath, + "--dependency-tree-output", + outputSwiftFile.path(), + ] - #else - let outputSwiftFile = context.pluginWorkDirectory.appending(subpath: "SafeDI.swift") - // Swift Package Plugins do not (as of Swift 5.9) allow for - // creating dependencies between plugin output. Since our - // current build system does not support depending on the - // output of other plugins, we must forgo searching for - // `.safeDI` files and instead parse the entire project at once. - let targetSwiftFiles = sourceTarget.sourceFiles(withSuffix: ".swift").map(\.path) - let dependenciesSourceFiles = sourceTarget - .sourceModuleRecursiveDependencies - .flatMap { - $0 - .sourceFiles(withSuffix: ".swift") - .map(\.path) - } - - let inputSourcesFilePath = context.pluginWorkDirectory.appending(subpath: "InputSwiftFiles.csv").string - try Data( - (targetSwiftFiles + dependenciesSourceFiles) - .map(\.string) - .joined(separator: ",") - .utf8 - ) - .write(toPath: inputSourcesFilePath) - let arguments = [ - inputSourcesFilePath, - "--dependency-tree-output", - outputSwiftFile.string, - ] + let downloadedToolLocation = context.downloadedToolLocation + let safeDIVersion = context.safeDIVersion + if context.hasSafeDIFolder, let safeDIVersion, downloadedToolLocation == nil { + Diagnostics.error(""" + \(context.safediFolder.path()) exists, but contains no SafeDITool binary for version \(safeDIVersion). + + To download the release SafeDITool binary for version \(safeDIVersion), run: + \tswift package --package-path \(context.package.directoryURL.path()) --allow-network-connections all --allow-writing-to-package-directory safedi-release-install + + To use a debug SafeDITool binary instead, remove the `.safedi` directory by running: + \trm -rf \(context.safediFolder.path()) + """) + } else if downloadedToolLocation == nil, let safeDIVersion { + Diagnostics.warning(""" + Using a debug SafeDITool binary, which is 15x slower than a release SafeDITool binary. + + To download the release SafeDITool binary for version \(safeDIVersion), run: + \tswift package --package-path \(context.package.directoryURL.path()) --allow-network-connections all --allow-writing-to-package-directory safedi-release-install + """) + } - let armMacBrewInstallLocation = "/opt/homebrew/bin/safeditool" - let intelMacBrewInstallLocation = "/usr/local/bin/safeditool" - let toolLocation: PackagePlugin.Path = if FileManager.default.fileExists(atPath: armMacBrewInstallLocation) { - // SafeDITool has been installed via homebrew on an ARM Mac. - PackagePlugin.Path(armMacBrewInstallLocation) - } else if FileManager.default.fileExists(atPath: intelMacBrewInstallLocation) { - // SafeDITool has been installed via homebrew on an Intel Mac. - PackagePlugin.Path(intelMacBrewInstallLocation) - } else { - // Fall back to the just-in-time built tool. - try context.tool(named: "SafeDITool").path - } - #endif + let toolLocation = if let downloadedToolLocation { + downloadedToolLocation + } else { + try context.tool(named: "SafeDITool").url + } return [ .buildCommand( @@ -152,36 +108,20 @@ extension Target { } // We only care about first-party code. Ignore third-party dependencies. - #if compiler(>=6.0) - guard - swiftModule - .directoryURL - .pathComponents - // Removing the module name. - .dropLast() - // Removing 'Sources'. - .dropLast() - // Removing the package name. - .dropLast() - .last != "checkouts" - else { - return nil - } - #else - guard - swiftModule - .directory - // Removing the module name. - .removingLastComponent() - // Removing 'Sources'. - .removingLastComponent() - // Removing the package name. - .removingLastComponent() - .lastComponent != "checkouts" - else { - return nil - } - #endif + guard + swiftModule + .directoryURL + .pathComponents + // Removing the module name. + .dropLast() + // Removing 'Sources'. + .dropLast() + // Removing the package name. + .dropLast() + .last != "checkouts" + else { + return nil + } return swiftModule } } @@ -195,87 +135,45 @@ extension Target { context: XcodeProjectPlugin.XcodePluginContext, target: XcodeProjectPlugin.XcodeTarget ) throws -> [PackagePlugin.Command] { - #if compiler(>=6.0) - // As of Xcode 15.0.1, Swift Package Plugins in Xcode are unable - // to inspect target dependencies. As a result, this Xcode plugin - // only works if it is running on a single-module project, or if - // all `@Instantiable`-decorated types are in the target module. - // https://github.com/apple/swift-package-manager/issues/6003 - let inputSwiftFiles = target - .inputFiles - .filter { $0.url.pathExtension == "swift" } - .map(\.url) - guard !inputSwiftFiles.isEmpty else { - // There are no Swift files in this module! - return [] - } - - let outputSwiftFile = context.pluginWorkDirectoryURL.appending(path: "SafeDI.swift") - let inputSourcesFilePath = context.pluginWorkDirectoryURL.appending(path: "InputSwiftFiles.csv").path() - try Data( - inputSwiftFiles - .map { $0.path() } - .joined(separator: ",") - .utf8 - ) - .write(toPath: inputSourcesFilePath) - let arguments = [ - inputSourcesFilePath, - "--dependency-tree-output", - outputSwiftFile.path(), - ] - - return try [ - .buildCommand( - displayName: "SafeDIGenerateDependencyTree", - executable: context.tool(named: "SafeDITool").url, - arguments: arguments, - environment: [:], - inputFiles: inputSwiftFiles, - outputFiles: [outputSwiftFile] - ), - ] - #else - // As of Xcode 15.0.1, Swift Package Plugins in Xcode are unable - // to inspect target dependencies. As a result, this Xcode plugin - // only works if it is running on a single-module project, or if - // all `@Instantiable`-decorated types are in the target module. - // https://github.com/apple/swift-package-manager/issues/6003 - let inputSwiftFiles = target - .inputFiles - .filter { $0.path.extension == "swift" } - .map(\.path) - guard !inputSwiftFiles.isEmpty else { - // There are no Swift files in this module! - return [] - } + // As of Xcode 15.0.1, Swift Package Plugins in Xcode are unable + // to inspect target dependencies. As a result, this Xcode plugin + // only works if it is running on a single-module project, or if + // all `@Instantiable`-decorated types are in the target module. + // https://github.com/apple/swift-package-manager/issues/6003 + let inputSwiftFiles = target + .inputFiles + .filter { $0.url.pathExtension == "swift" } + .map(\.url) + guard !inputSwiftFiles.isEmpty else { + // There are no Swift files in this module! + return [] + } - let outputSwiftFile = context.pluginWorkDirectory.appending(subpath: "SafeDI.swift") - let inputSourcesFilePath = context.pluginWorkDirectory.appending(subpath: "InputSwiftFiles.csv").string - try Data( - inputSwiftFiles - .map(\.string) - .joined(separator: ",") - .utf8 - ) - .write(toPath: inputSourcesFilePath) - let arguments = [ - inputSourcesFilePath, - "--dependency-tree-output", - outputSwiftFile.string, - ] + let outputSwiftFile = context.pluginWorkDirectoryURL.appending(path: "SafeDI.swift") + let inputSourcesFilePath = context.pluginWorkDirectoryURL.appending(path: "InputSwiftFiles.csv").path() + try Data( + inputSwiftFiles + .map { $0.path() } + .joined(separator: ",") + .utf8 + ) + .write(toPath: inputSourcesFilePath) + let arguments = [ + inputSourcesFilePath, + "--dependency-tree-output", + outputSwiftFile.path(), + ] - return try [ - .buildCommand( - displayName: "SafeDIGenerateDependencyTree", - executable: context.tool(named: "SafeDITool").path, - arguments: arguments, - environment: [:], - inputFiles: inputSwiftFiles, - outputFiles: [outputSwiftFile] - ), - ] - #endif + return try [ + .buildCommand( + displayName: "SafeDIGenerateDependencyTree", + executable: context.tool(named: "SafeDITool").url, + arguments: arguments, + environment: [:], + inputFiles: inputSwiftFiles, + outputFiles: [outputSwiftFile] + ), + ] } } #endif @@ -294,46 +192,44 @@ extension Data { } } -#if compiler(>=6.0) - extension PackagePlugin.PluginContext { - var safeDIVersion: String? { - guard let safeDIOrigin = package.dependencies.first(where: { $0.package.displayName == "SafeDI" })?.package.origin else { - return nil - } - switch safeDIOrigin { - case let .repository(_, displayVersion, _): - // This regular expression is duplicated by InstallSafeDITool since plugins can not share code. - guard let versionMatch = try? /Optional\((.*?)\)|^(.*?)$/.firstMatch(in: displayVersion), - let version = versionMatch.output.1 ?? versionMatch.output.2 - else { - return nil - } - return String(version) - case .registry, .root, .local: - fallthrough - @unknown default: +extension PackagePlugin.PluginContext { + var safeDIVersion: String? { + guard let safeDIOrigin = package.dependencies.first(where: { $0.package.displayName == "SafeDI" })?.package.origin else { + return nil + } + switch safeDIOrigin { + case let .repository(_, displayVersion, _): + // This regular expression is duplicated by InstallSafeDITool since plugins can not share code. + guard let versionMatch = try? /Optional\((.*?)\)|^(.*?)$/.firstMatch(in: displayVersion), + let version = versionMatch.output.1 ?? versionMatch.output.2 + else { return nil } + return String(version) + case .registry, .root, .local: + fallthrough + @unknown default: + return nil } + } - var hasSafeDIFolder: Bool { - FileManager.default.fileExists(atPath: safediFolder.path()) - } + var hasSafeDIFolder: Bool { + FileManager.default.fileExists(atPath: safediFolder.path()) + } - var safediFolder: URL { - package.directoryURL.appending( - component: ".safedi" - ) - } + var safediFolder: URL { + package.directoryURL.appending( + component: ".safedi" + ) + } - var downloadedToolLocation: URL? { - guard let safeDIVersion else { return nil } - let location = safediFolder.appending( - components: safeDIVersion, - "safeditool" - ) - guard FileManager.default.fileExists(atPath: location.path()) else { return nil } - return location - } + var downloadedToolLocation: URL? { + guard let safeDIVersion else { return nil } + let location = safediFolder.appending( + components: safeDIVersion, + "safeditool" + ) + guard FileManager.default.fileExists(atPath: location.path()) else { return nil } + return location } -#endif +} diff --git a/README.md b/README.md index 0bd4cd23..a9729a69 100644 --- a/README.md +++ b/README.md @@ -411,7 +411,7 @@ To install the SafeDI framework into your package with [Swift Package Manager](h ```swift dependencies: [ - .package(url: "https://github.com/dfed/SafeDI", from: "0.8.0"), + .package(url: "https://github.com/dfed/SafeDI", from: "0.9.0"), ] ``` @@ -437,16 +437,6 @@ If your first-party code is entirely contained in a Swift Package with one or mo You can see this in integration in practice in the [ExamplePackageIntegration](Examples/ExamplePackageIntegration) package. -##### Xcode 15 - -For faster builds, you can install a release version of `SafeDITool` [rather than a debug version](https://github.com/apple/swift-package-manager/issues/7233) via `brew`: - -```zsh -brew install dfed/safedi/safeditool -``` - -##### Xcode 16 - for faster builds, you can install a release version of `SafeDITool` [rather than a debug version](https://github.com/apple/swift-package-manager/issues/7233) via `swift`: ```zsh @@ -496,7 +486,7 @@ The `SafeDITool` can parse all of your Swift files at once, or for even better p ### Requirements -* Xcode 15.3 or later +* Xcode 16.0 or later * iOS 13 or later * tvOS 13 or later * watchOS 6 or later diff --git a/Sources/SafeDICore/Models/Initializer.swift b/Sources/SafeDICore/Models/Initializer.swift index b2128973..8acbfa09 100644 --- a/Sources/SafeDICore/Models/Initializer.swift +++ b/Sources/SafeDICore/Models/Initializer.swift @@ -18,11 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#if compiler(>=6.0) - @preconcurrency import SwiftSyntax -#else - import SwiftSyntax -#endif +@preconcurrency import SwiftSyntax import SwiftSyntaxBuilder public struct Initializer: Codable, Hashable, Sendable { @@ -32,11 +28,7 @@ public struct Initializer: Codable, Hashable, Sendable { isPublicOrOpen = node.modifiers.containsPublicOrOpen isOptional = node.optionalMark != nil isAsync = node.signature.effectSpecifiers?.asyncSpecifier != nil - #if compiler(>=6.0) - doesThrow = node.signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil - #else - doesThrow = node.signature.effectSpecifiers?.throwsSpecifier != nil - #endif + doesThrow = node.signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil hasGenericParameter = node.genericParameterClause != nil hasGenericWhereClause = node.genericWhereClause != nil arguments = node @@ -50,11 +42,7 @@ public struct Initializer: Codable, Hashable, Sendable { isPublicOrOpen = node.modifiers.containsPublicOrOpen isOptional = false isAsync = node.signature.effectSpecifiers?.asyncSpecifier != nil - #if compiler(>=6.0) - doesThrow = node.signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil - #else - doesThrow = node.signature.effectSpecifiers?.throwsSpecifier != nil - #endif + doesThrow = node.signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil hasGenericParameter = node.genericParameterClause != nil hasGenericWhereClause = node.genericWhereClause != nil arguments = node diff --git a/Sources/SafeDICore/Models/Property.swift b/Sources/SafeDICore/Models/Property.swift index 5a135104..cc9c4786 100644 --- a/Sources/SafeDICore/Models/Property.swift +++ b/Sources/SafeDICore/Models/Property.swift @@ -56,87 +56,44 @@ public struct Property: Codable, Hashable, Comparable, Sendable { var asFunctionParamter: FunctionParameterSyntax { switch typeDescription { case .closure: - #if compiler(>=6.0) - FunctionParameterSyntax( - firstName: .identifier(label), - colon: .colonToken(trailingTrivia: .space), - type: AttributedTypeSyntax( - specifiers: [], - attributes: AttributeListSyntax { - AttributeSyntax(attributeName: IdentifierTypeSyntax( - name: "escaping", - trailingTrivia: .space - )) - }, - baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) - ) - ) - #else - FunctionParameterSyntax( - firstName: .identifier(label), - colon: .colonToken(trailingTrivia: .space), - type: AttributedTypeSyntax( - specifier: nil, - attributes: AttributeListSyntax { - AttributeSyntax(attributeName: IdentifierTypeSyntax( - name: "escaping", - trailingTrivia: .space - )) - }, - baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) - ) + FunctionParameterSyntax( + firstName: .identifier(label), + colon: .colonToken(trailingTrivia: .space), + type: AttributedTypeSyntax( + specifiers: [], + attributes: AttributeListSyntax { + AttributeSyntax(attributeName: IdentifierTypeSyntax( + name: "escaping", + trailingTrivia: .space + )) + }, + baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) ) - #endif + ) case let .attributed(typeDescription, _, attributes): - #if compiler(>=6.0) - FunctionParameterSyntax( - firstName: .identifier(label), - colon: .colonToken(trailingTrivia: .space), - type: AttributedTypeSyntax( - // It is not possible for a property declaration to have specifiers today. - specifiers: [], - attributes: AttributeListSyntax { - AttributeSyntax(attributeName: IdentifierTypeSyntax( - name: "escaping", - trailingTrivia: .space - )) - if let attributes { - for attribute in attributes { - AttributeSyntax( - attributeName: IdentifierTypeSyntax(name: .identifier(attribute)), - trailingTrivia: .space - ) - } - } - }, - baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) - ) - ) - #else - FunctionParameterSyntax( - firstName: .identifier(label), - colon: .colonToken(trailingTrivia: .space), - type: AttributedTypeSyntax( - // It is not possible for a property declaration to have specifiers today. - specifier: nil, - attributes: AttributeListSyntax { - AttributeSyntax(attributeName: IdentifierTypeSyntax( - name: "escaping", - trailingTrivia: .space - )) - if let attributes { - for attribute in attributes { - AttributeSyntax( - attributeName: IdentifierTypeSyntax(name: .identifier(attribute)), - trailingTrivia: .space - ) - } + FunctionParameterSyntax( + firstName: .identifier(label), + colon: .colonToken(trailingTrivia: .space), + type: AttributedTypeSyntax( + // It is not possible for a property declaration to have specifiers today. + specifiers: [], + attributes: AttributeListSyntax { + AttributeSyntax(attributeName: IdentifierTypeSyntax( + name: "escaping", + trailingTrivia: .space + )) + if let attributes { + for attribute in attributes { + AttributeSyntax( + attributeName: IdentifierTypeSyntax(name: .identifier(attribute)), + trailingTrivia: .space + ) } - }, - baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) - ) + } + }, + baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)) ) - #endif + ) case .simple, .nested, .composition, diff --git a/Sources/SafeDICore/Models/TypeDescription.swift b/Sources/SafeDICore/Models/TypeDescription.swift index 23e846e5..ec3527f1 100644 --- a/Sources/SafeDICore/Models/TypeDescription.swift +++ b/Sources/SafeDICore/Models/TypeDescription.swift @@ -331,18 +331,9 @@ extension TypeSyntax { let attributes: [String] = typeIdentifier.attributes.compactMap { AttributeSyntax($0)?.attributeName.as(IdentifierTypeSyntax.self)?.name.text } - #if compiler(>=6.0) - let specifiers = typeIdentifier.specifiers.textRepresentation - #else - let specifiers: [String]? = if let specifier = typeIdentifier.specifier?.text { - [specifier] - } else { - nil - } - #endif return .attributed( typeIdentifier.baseType.typeDescription, - specifiers: specifiers, + specifiers: typeIdentifier.specifiers.textRepresentation, attributes: attributes.isEmpty ? nil : attributes ) @@ -378,15 +369,10 @@ extension TypeSyntax { return .simple(name: "AnyObject") } else if let typeIdentifier = FunctionTypeSyntax(self) { - #if compiler(>=6.0) - let doesThrow = typeIdentifier.effectSpecifiers?.throwsClause?.throwsSpecifier != nil - #else - let doesThrow = typeIdentifier.effectSpecifiers?.throwsSpecifier != nil - #endif return .closure( arguments: typeIdentifier.parameters.map(\.type.typeDescription), isAsync: typeIdentifier.effectSpecifiers?.asyncSpecifier != nil, - doesThrow: doesThrow, + doesThrow: typeIdentifier.effectSpecifiers?.throwsClause?.throwsSpecifier != nil, returnType: typeIdentifier.returnClause.type.typeDescription ) @@ -490,15 +476,10 @@ extension ExprSyntax { ]), let returnType = sequenceExpr.elements.last { - #if compiler(>=6.0) - let doesThrow = arrow.effectSpecifiers?.throwsClause?.throwsSpecifier != nil - #else - let doesThrow = arrow.effectSpecifiers?.throwsSpecifier != nil - #endif return .closure( arguments: arguments.elements.map(\.expression.typeDescription), isAsync: arrow.effectSpecifiers?.asyncSpecifier != nil, - doesThrow: doesThrow, + doesThrow: arrow.effectSpecifiers?.throwsClause?.throwsSpecifier != nil, returnType: returnType.typeDescription ) } @@ -536,22 +517,20 @@ private final class GenericArgumentVisitor: SyntaxVisitor { } } -#if compiler(>=6.0) - extension TypeSpecifierListSyntax { - fileprivate var textRepresentation: [String]? { - let specifiers = compactMap { specifier in - if case let .simpleTypeSpecifier(simpleTypeSpecifierSyntax) = specifier { - simpleTypeSpecifierSyntax.specifier.text - } else { - // lifetimeTypeSpecifier is SPI, so we ignore it. - nil - } - } - if specifiers.isEmpty { - return nil +extension TypeSpecifierListSyntax { + fileprivate var textRepresentation: [String]? { + let specifiers = compactMap { specifier in + if case let .simpleTypeSpecifier(simpleTypeSpecifierSyntax) = specifier { + simpleTypeSpecifierSyntax.specifier.text } else { - return specifiers + // lifetimeTypeSpecifier is SPI, so we ignore it. + nil } } + if specifiers.isEmpty { + return nil + } else { + return specifiers + } } -#endif +} diff --git a/Tests/SafeDICoreTests/TypeDescriptionTests.swift b/Tests/SafeDICoreTests/TypeDescriptionTests.swift index 8b535fc5..3572094d 100644 --- a/Tests/SafeDICoreTests/TypeDescriptionTests.swift +++ b/Tests/SafeDICoreTests/TypeDescriptionTests.swift @@ -247,20 +247,18 @@ final class TypeDescriptionTests: XCTestCase { XCTAssertEqual(typeDescription.asSource, "inout @autoclosure () -> Void") } - #if compiler(>=6.0) - func test_typeDescription_whenCalledOnATypeSyntaxNodeRepresentingAnAttributedTypeSyntax_withMultipleSpecifiers_findsTheType() throws { - let content = """ - func test(parameter: sending @autoclosure () -> Void) {} - """ - - let visitor = AttributedTypeSyntaxVisitor(viewMode: .sourceAccurate) - visitor.walk(Parser.parse(source: content)) - - let typeDescription = try XCTUnwrap(visitor.attributedTypeIdentifier) - XCTAssertFalse(typeDescription.isUnknown, "Type description is not of known type!") - XCTAssertEqual(typeDescription.asSource, "sending @autoclosure () -> Void") - } - #endif + func test_typeDescription_whenCalledOnATypeSyntaxNodeRepresentingAnAttributedTypeSyntax_withMultipleSpecifiers_findsTheType() throws { + let content = """ + func test(parameter: sending @autoclosure () -> Void) {} + """ + + let visitor = AttributedTypeSyntaxVisitor(viewMode: .sourceAccurate) + visitor.walk(Parser.parse(source: content)) + + let typeDescription = try XCTUnwrap(visitor.attributedTypeIdentifier) + XCTAssertFalse(typeDescription.isUnknown, "Type description is not of known type!") + XCTAssertEqual(typeDescription.asSource, "sending @autoclosure () -> Void") + } func test_typeDescription_whenCalledOnATypeSyntaxNodeRepresentingAnArrayTypeSyntax_findsTheType() throws { let content = """ diff --git a/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift b/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift index aa9d18c0..1a107f7a 100644 --- a/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift +++ b/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift @@ -429,27 +429,15 @@ import SafeDICore } """ } expansion: { - #if compiler(>=6.0) - """ - public struct ExampleService: Instantiable { - public init(instantiatedA: InstantiatedA) { - self.instantiatedA = instantiatedA - } - - @Unknown let instantiatedA: InstantiatedA - } - """ - #else - """ - public struct ExampleService: Instantiable { - public init(instantiatedA: InstantiatedA) { - self.instantiatedA = instantiatedA - }@Unknown + """ + public struct ExampleService: Instantiable { + public init(instantiatedA: InstantiatedA) { + self.instantiatedA = instantiatedA + } - let instantiatedA: InstantiatedA - } - """ - #endif + @Unknown let instantiatedA: InstantiatedA + } + """ } } diff --git a/lint.sh b/lint.sh index 923a5d66..d3f20acc 100755 --- a/lint.sh +++ b/lint.sh @@ -4,7 +4,7 @@ set -e pushd $(git rev-parse --show-toplevel) -swift run --package-path CLI -c release swiftformat --swiftversion 5.10 . +swift run --package-path CLI -c release swiftformat --swiftversion 6.0 . popd