Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration to Swift 6 #2

Merged
merged 2 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# This workflow will build a Swift project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift

name: Swift
name: test

on:
push:
Expand All @@ -10,13 +7,17 @@ on:
branches: [ "main" ]

jobs:
build:
runs-on: macos-latest
run-tests:
runs-on: ${{ matrix.runner }}
strategy:
matrix:
runner: [ ubuntu-22.04, macos-latest ]
steps:
- uses: swift-actions/setup-swift@v1
with:
swift-version: "5.9"
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v
- uses: actions/checkout@v4
- uses: khlopko/setup-swift@bfd61cbd14eeef55a27afc45138b61ced7174839
with:
swift-version: "main-snapshot"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: swift test

7 changes: 4 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"originHash" : "ac7a8b3c89189306fafff79842be1c9addc0a3faf5b97bab411a81122122615a",
"pins" : [
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "f1e9245226002bb134884345d4809b9543da3666",
"version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-17-a"
"revision" : "06b5cdc432e93b60e3bdf53aff2857c6b312991a",
"version" : "600.0.0-prerelease-2024-07-30"
}
}
],
"version" : 2
"version" : 3
}
45 changes: 26 additions & 19 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
// swift-tools-version: 5.9
// swift-tools-version: 6.0

import PackageDescription
import CompilerPluginSupport
import PackageDescription

let package = Package(
name: "SweetDeclarations",
name: "swift-util-macros",
platforms: [
.macOS(.v10_15),
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6),
.macCatalyst(.v13)
.macCatalyst(.v13),
],
products: [
.library(
name: "SweetDeclarationsLib",
targets: ["SweetDeclarationsLib"]
name: "SwiftUtilMacros",
targets: ["SwiftUtilMacros"]
),
.executable(
name: "SweetDeclarationsClient",
targets: ["SweetDeclarationsClient"]
name: "SwiftUtilMacrosClient",
targets: ["SwiftUtilMacrosClient"]
),
],
dependencies: [
.package(
url: "https://github.com/apple/swift-syntax.git",
from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b"
),
.package(url: "https://github.com/apple/swift-syntax.git", from: "600.0.0-latest")
],
targets: [
.macro(
name: "SweetDeclarationsPlugin",
name: "SwiftUtilMacrosPlugin",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
]
),
.target(
name: "SwiftUtilMacros",
dependencies: [
.target(name: "SwiftUtilMacrosPlugin")
]
),
.executableTarget(
name: "SwiftUtilMacrosClient",
dependencies: [
.target(name: "SwiftUtilMacros")
]
),
.target(name: "SweetDeclarationsLib", dependencies: ["SweetDeclarationsPlugin"]),
.executableTarget(name: "SweetDeclarationsClient", dependencies: ["SweetDeclarationsLib"]),
.testTarget(
name: "SweetDeclarationsLibTests",
name: "SwiftUtilMacrosPluginTests",
dependencies: [
"SweetDeclarationsLib",
.target(name: "SwiftUtilMacrosPlugin"),
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
]
)
),
]
)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SweetDeclarations
# swift-util-macros

A set of Swift macros to provide convenient initialization / modification over structs and classes
declarations.
Expand Down
15 changes: 0 additions & 15 deletions Sources/SweetDeclarationsLib/Macros.swift

This file was deleted.

20 changes: 20 additions & 0 deletions Sources/SwiftUtilMacros/Macros.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Macros.swift
//

@attached(member, names: arbitrary)
public macro PublicInit() = #externalMacro(module: "SwiftUtilMacrosPlugin", type: "PublicInitMacro")

@attached(member, names: arbitrary)
public macro PublicInit(escaping: [Any.Type]) = #externalMacro(module: "SwiftUtilMacrosPlugin", type: "PublicInitMacro")

@attached(member, names: arbitrary)
public macro GranularUpdate() = #externalMacro(module: "SwiftUtilMacrosPlugin", type: "GranularUpdateMacro")

@attached(member, names: arbitrary)
public macro TestStub() = #externalMacro(module: "SwiftUtilMacrosPlugin", type: "TestStubMacro")

@attached(member)
@attached(extension, conformances: OptionSet)
public macro BitMask() = #externalMacro(module: "SwiftUtilMacrosPlugin", type: "BitMaskOptionSetMacro")

Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@

import Foundation

import SweetDeclarationsLib
import SwiftUtilMacros

public typealias GetConnections = () -> [User]

@PublicInit(escaping: [GetConnections.self])
@PublicInit
@GranularUpdate
public struct User {
var desc: String { "\(id)+\(name)" }
public let id: String
public let name: Name
public let getConnections: GetConnections
public let getConnections: () -> [User]
public let getPublications: (_ startDate: Date) -> [String]
}

Expand Down Expand Up @@ -52,3 +51,4 @@ final class SomeProtocolStub {
return method3Result!
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@
import SwiftSyntax

extension SwiftSyntax.AttributeSyntax {

internal func macrosEscapingArgs() -> [String] {
let tupleElement = argument?
.as(TupleExprElementListSyntax.self)?.first?
.as(TupleExprElementSyntax.self)
let tupleElement = arguments?.as(LabeledExprListSyntax.self)?.first
guard tupleElement?.label?.text == "escaping" else {
return []
}
return tupleElement?.expression.as(ArrayExprSyntax.self)?.elements.compactMap {
$0
.as(ArrayElementSyntax.self)?.expression
return tupleElement?.expression.as(ArrayExprSyntax.self)?.elements.compactMap { element in
element.expression
.as(MemberAccessExprSyntax.self)?.base?
.as(IdentifierExprSyntax.self)?.identifier.text
.as(DeclReferenceExprSyntax.self)?.baseName.text
} ?? []
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,50 @@
// DeclarationProperty.swift
//

import SwiftDiagnostics
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
import SwiftDiagnostics

internal struct DeclarationProperty {
let propertyName: String
let propertyType: String
let isClosure: Bool
let explicitlyEscaping: Bool
}

extension DeclarationProperty {
func asInitParam(nillable: Bool) -> String {
let propertyType = decoratedType(
for: self,
nillable: nillable,
isExplicitlyEscaping: { _ in explicitlyEscaping }
)
return " \(propertyName): \(propertyType)"
}

private func decoratedType(
for property: DeclarationProperty,
nillable: Bool,
isExplicitlyEscaping: (String) -> Bool
) -> String {
var propertyType: String = property.propertyType
let isExplicitlyEscaping = isExplicitlyEscaping(propertyType)
if nillable {
if property.isClosure {
propertyType = "(\(propertyType))"
}
propertyType = "\(propertyType)? = nil"
}
if !nillable && isExplicitlyEscaping {
propertyType = "@escaping \(propertyType)"
}
return propertyType
}
}

internal static func gather(
extension DeclarationProperty {
static func gather(
from declaration: some SwiftSyntax.DeclGroupSyntax,
in context: some SwiftSyntaxMacros.MacroExpansionContext
) -> [DeclarationProperty] {
Expand All @@ -24,85 +60,73 @@ internal struct DeclarationProperty {
else {
return nil
}
let isComputed = varDecl.bindings.contains { $0.accessorBlock != nil }
guard !isComputed else {
return nil
}
let typeSyntax = patternBindingSyntax?.typeAnnotation?.type
let propertyType: String
let isClosure: Bool
let explicitlyEscaping: Bool
if let optionalType = typeSyntax?.as(OptionalTypeSyntax.self) {
propertyType = optionalType.description
isClosure = optionalType.wrappedType
.as(TupleTypeSyntax.self)?.elements.first?
isClosure =
optionalType.wrappedType
.as(TupleTypeSyntax.self)?.elements.first?.type
.is(FunctionTypeSyntax.self) == true
} else if let simpleType = typeSyntax?.as(SimpleTypeIdentifierSyntax.self)?.name.text {
explicitlyEscaping = false
} else if let simpleType = typeSyntax?.as(IdentifierTypeSyntax.self)?.name.text {
propertyType = simpleType
isClosure = false
explicitlyEscaping = false
} else if let closureType = typeSyntax?.as(FunctionTypeSyntax.self) {
propertyType = closureType.description
isClosure = true
explicitlyEscaping = true
} else {
context.diagnose(
Diagnostic(node: varDecl._syntaxNode, message: TypeNotFoundMessage()))
return nil
}
return DeclarationProperty(
propertyName: propertyName,
propertyType: propertyType,
isClosure: isClosure
isClosure: isClosure,
explicitlyEscaping: explicitlyEscaping
)
}
}

let propertyName: String
let propertyType: String
let isClosure: Bool

func asInitParam(nillable: Bool, escapingPropertyTypes: [String]) -> String {
let propertyType = decoratedType(
for: self,
nillable: nillable,
isExplicitlyEscaping: { escapingPropertyTypes.contains($0) }
)
return " \(propertyName): \(propertyType)"
}

private func decoratedType(
for property: DeclarationProperty,
nillable: Bool,
isExplicitlyEscaping: (String) -> Bool
) -> String {
var propertyType: String = property.propertyType
let isExplicitlyEscaping = isExplicitlyEscaping(propertyType)
if nillable {
if property.isClosure {
propertyType = "(\(propertyType))"
}
propertyType = "\(propertyType)? = nil"
}
let isNotNilClosure = property.isClosure && !nillable
if isNotNilClosure || isExplicitlyEscaping {
propertyType = "@escaping \(propertyType)"
}
return propertyType
}

}

extension [DeclarationProperty] {

internal func asInitParams(
escapingPropertyTypes: [String],
nillable: Bool
) -> SwiftSyntax.DeclSyntax {
SwiftSyntax.DeclSyntax(stringLiteral: map {
$0.asInitParam(nillable: nillable, escapingPropertyTypes: escapingPropertyTypes)
}
.joined(separator: ",\n"))
SwiftSyntax.DeclSyntax(
stringLiteral: map {
$0.asInitParam(nillable: nillable)
}
.joined(separator: ",\n")
)
}

internal func asInitBody(
decorateAssignment: (_ propertyName: String) -> String = { $0 }
) -> SwiftSyntax.DeclSyntax {
SwiftSyntax.DeclSyntax(stringLiteral: map {
"self.\($0.propertyName) = \(decorateAssignment($0.propertyName))"
}
.joined(separator: "\n"))
SwiftSyntax.DeclSyntax(
stringLiteral: map {
"self.\($0.propertyName) = \(decorateAssignment($0.propertyName))"
}
.joined(separator: "\n")
)
}
}

extension DeclarationProperty {
struct TypeNotFoundMessage: DiagnosticMessage {
let message =
"Property type not found or not supported. Specify type explicitly if its missing to fix this error"
let diagnosticID = SwiftDiagnostics.MessageID(domain: "PublicInitMacro", id: "TypeNotFound")
let severity: SwiftDiagnostics.DiagnosticSeverity = .error
}
}
Loading