Skip to content

Commit

Permalink
Add swift-syntax 510 support; matrix testing for swift-syntax versions
Browse files Browse the repository at this point in the history
- Implement matrix strategy for macOS job to test against multiple
  versions of swift-syntax
- Use SWIFT_SYNTAX_VERSION environment variable to dictate
  swift-syntax version per test run
- Maintain existing setup for Linux CI (only test "natural"
  `Package.swift` swift-syntax version), but update to use
  `swift-actions/setup-swift` and Swift 5.10.
  • Loading branch information
gohanlon committed Apr 17, 2024
1 parent 84f14bc commit 334d6d2
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 101 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ jobs:
macos:
name: macOS
runs-on: macos-13
strategy:
matrix:
swift-syntax-version: ['509.0.0..<510.0.0', '510.0.0..<511.0.0']

steps:
- uses: actions/checkout@v4
- name: Select Xcode 15
run: sudo xcode-select -s /Applications/Xcode_15.0.app
- name: Set SWIFT_SYNTAX_VERSION environment variable
run: echo "SWIFT_SYNTAX_VERSION=${{ matrix.swift-syntax-version }}" >> $GITHUB_ENV
- name: Resolve Dependencies
run: swift package resolve
- name: Run tests
run: swift test

Expand All @@ -29,9 +37,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install Swift
uses: slashmo/install-swift@v0.4.0
uses: swift-actions/setup-swift@v2
with:
version: 5.9
swift-version: "5.10"
- uses: actions/checkout@v4
- name: Run tests
run: swift test
Expand Down
10 changes: 5 additions & 5 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
"state" : {
"revision" : "59b663f68e69f27a87b45de48cb63264b8194605",
"version" : "1.15.1"
"revision" : "625ccca8570773dd84a34ee51a81aa2bc5a4f97a",
"version" : "1.16.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"location" : "https://github.com/apple/swift-syntax",
"state" : {
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
"revision" : "fa8f95c2d536d6620cc2f504ebe8a6167c9fc2dd",
"version" : "510.0.1"
}
}
],
Expand Down
61 changes: 60 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// swift-tools-version: 5.9

import CompilerPluginSupport
import Foundation
import PackageDescription

let package = Package(
Expand All @@ -23,7 +24,13 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.15.0"),
.package(url: "https://github.com/apple/swift-syntax", from: "509.0.0"),
//.conditionalPackage(url: "https://github.com/apple/swift-syntax", envVar: "SWIFT_SYNTAX_VERSION", default: "509.0.0..<510.0.0")
//.conditionalPackage(url: "https://github.com/apple/swift-syntax", envVar: "SWIFT_SYNTAX_VERSION", default: "510.0.0..<511.0.0")
.conditionalPackage(
url: "https://github.com/apple/swift-syntax",
envVar: "SWIFT_SYNTAX_VERSION",
default: "509.0.0..<511.0.0"
),
],
targets: [
.macro(
Expand Down Expand Up @@ -68,3 +75,55 @@ let package = Package(
),
]
)

extension Package.Dependency {
/// Creates a dependency based on an environment variable or a default version range.
///
/// This function allows dynamically setting the version range of a package dependency via an environment variable.
/// If the environment variable is not set, it falls back to a specified default version range.
///
/// - Parameters:
/// - url: The URL of the package repository.
/// - envVar: The name of the environment variable that contains the version range.
/// - versionExpression: The default version range in case the environment variable is not set.
/// Example format: `"509.0.0..<511.0.0"` or `"509.0.0...510.0.0"`.
/// - Returns: A `Package.Dependency` configured with the specified or default version range.
/// - Throws: A fatal error if the version expression format is invalid or the range operator is unsupported.
///
static func conditionalPackage(
url: String,
envVar: String,
default versionExpression: String
) -> Package.Dependency {
let versionRangeString = ProcessInfo.processInfo.environment[envVar] ?? versionExpression
let (lower, op, upper) = parseVersionExpression(from: versionRangeString)
if op == "..<" {
return .package(url: url, lower..<upper)
} else if op == "..." {
return .package(url: url, lower...upper)
} else {
fatalError("Unsupported version range operator: \(op)")
}
}

private static func parseVersionExpression(
from expression: String
) -> (Version, String, Version) {
let rangeOperators = ["..<", "..."]
for op in rangeOperators {
if expression.contains(op) {
let parts = expression.split(separator: op, maxSplits: 1, omittingEmptySubsequences: true)
.map(String.init)
guard
parts.count == 2,
let lower = Version(parts[0]),
let upper = Version(parts[1])
else {
fatalError("Invalid version expression format: \(expression)")
}
return (lower, op, upper)
}
}
fatalError("No valid range operator found in expression: \(expression)")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ extension ExprSyntax {
else { return nil }
return .tuple(elementTypes)

#if canImport(SwiftSyntax510)
case .thenStmt:
return nil
#endif

case .token, .accessorBlock, .accessorDeclList, .accessorDecl, .accessorEffectSpecifiers,
.accessorParameters, .actorDecl, .arrayElementList, .arrayElement, .arrayType, .arrowExpr,
.assignmentExpr, .associatedTypeDecl, .attributeList, .attribute, .attributedType,
Expand Down
85 changes: 60 additions & 25 deletions Tests/MacroTestingTests/DictionaryStorageMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,73 @@ final class DictionaryStorageMacroTests: BaseTestCase {
}

func testExpansionConvertsStoredProperties() {
assertMacro {
"""
@DictionaryStorage
struct Point {
var x: Int = 1
var y: Int = 2
}
"""
} expansion: {
"""
struct Point {
var x: Int = 1 {
get {
_storage["x", default: 1] as! Int
#if canImport(SwiftSyntax510)
assertMacro {
"""
@DictionaryStorage
struct Point {
var x: Int = 1
var y: Int = 2
}
"""
} expansion: {
"""
struct Point {
var x: Int {
get {
_storage["x", default: 1] as! Int
}
set {
_storage["x"] = newValue
}
}
set {
_storage["x"] = newValue
var y: Int {
get {
_storage["y", default: 2] as! Int
}
set {
_storage["y"] = newValue
}
}
var _storage: [String: Any] = [:]
}
"""
}
#elseif canImport(SwiftSyntax509)
assertMacro {
"""
@DictionaryStorage
struct Point {
var x: Int = 1
var y: Int = 2
}
var y: Int = 2 {
get {
_storage["y", default: 2] as! Int
"""
} expansion: {
"""
struct Point {
var x: Int = 1 {
get {
_storage["x", default: 1] as! Int
}
set {
_storage["x"] = newValue
}
}
set {
_storage["y"] = newValue
var y: Int = 2 {
get {
_storage["y", default: 2] as! Int
}
set {
_storage["y"] = newValue
}
}
}
var _storage: [String: Any] = [:]
var _storage: [String: Any] = [:]
}
"""
}
"""
}
#endif
}

func testExpansionWithoutInitializersEmitsError() {
Expand Down
2 changes: 1 addition & 1 deletion Tests/MacroTestingTests/MacroExamples/AddBlocker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,6 @@ public struct AddBlocker: ExpressionMacro {
context.diagnose(diag)
}

return result.asProtocol(FreestandingMacroExpansionSyntax.self)!.argumentList.first!.expression
return result.asProtocol(FreestandingMacroExpansionSyntax.self)!.arguments.first!.expression
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum FontLiteralMacro: ExpressionMacro {
in context: some MacroExpansionContext
) throws -> ExprSyntax {
let argList = replaceFirstLabel(
of: node.argumentList,
of: node.arguments,
with: "fontLiteralName"
)
return ".init(\(argList))"
Expand Down
2 changes: 1 addition & 1 deletion Tests/MacroTestingTests/MacroExamples/StringifyMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public enum StringifyMacro: ExpressionMacro {
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let argument = node.argumentList.first?.expression else {
guard let argument = node.arguments.first?.expression else {
fatalError("compiler bug: the macro does not have any arguments")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import SwiftSyntax
import SwiftSyntaxMacros

#if !canImport(SwiftSyntax510) && canImport(SwiftSyntax509)
extension FreestandingMacroExpansionSyntax {
var arguments: LabeledExprListSyntax {
get { self.argumentList }
set { self.argumentList = newValue }
}
}
#endif
2 changes: 1 addition & 1 deletion Tests/MacroTestingTests/MacroExamples/URLMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum URLMacro: ExpressionMacro {
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
guard let argument = node.argumentList.first?.expression,
guard let argument = node.arguments.first?.expression,
let segments = argument.as(StringLiteralExprSyntax.self)?.segments,
segments.count == 1,
case .stringSegment(let literalSegment)? = segments.first
Expand Down
2 changes: 1 addition & 1 deletion Tests/MacroTestingTests/MacroExamples/WarningMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum WarningMacro: ExpressionMacro {
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
guard let firstElement = node.argumentList.first,
guard let firstElement = node.arguments.first,
let stringLiteral = firstElement.expression
.as(StringLiteralExprSyntax.self),
stringLiteral.segments.count == 1,
Expand Down
Loading

0 comments on commit 334d6d2

Please sign in to comment.