Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,17 @@ extension WithAttributesSyntax {
}.first

var lastPlatformName: TokenSyntax? = nil
var asteriskEncountered = false
var wildcardEncountered = false
let hasWildcard = entries.contains(where: \.isWildcard)
return entries.compactMap { entry in
switch entry {
case let .availabilityVersionRestriction(restriction) where whenKeyword == .introduced:
return Availability(attribute: attribute, platformName: restriction.platform, version: restriction.version, message: message)
return Availability(attribute: attribute, platformName: restriction.platform, version: restriction.version, mayNeedTrailingWildcard: hasWildcard, message: message)
case let .token(token):
if case .identifier = token.tokenKind {
lastPlatformName = token
} else if case let .binaryOperator(op) = token.tokenKind, op == "*" {
asteriskEncountered = true
} else if entry.isWildcard {
wildcardEncountered = true
// It is syntactically valid to specify a platform name without a
// version in an availability declaration, and it's used to resolve
// a custom availability definition specified via the
Expand All @@ -81,7 +82,7 @@ extension WithAttributesSyntax {
return Availability(attribute: attribute, platformName: lastPlatformName, version: nil, message: message)
}
} else if case let .keyword(keyword) = token.tokenKind, keyword == whenKeyword {
if asteriskEncountered {
if wildcardEncountered {
// Match the "always this availability" construct, i.e.
// `@available(*, deprecated)` and `@available(*, unavailable)`.
return Availability(attribute: attribute, platformName: lastPlatformName, version: nil, message: message)
Expand Down Expand Up @@ -144,3 +145,13 @@ extension AttributeSyntax {
.joined()
}
}

extension AvailabilityArgumentSyntax.Argument {
var isWildcard: Bool {
if case let .token(token) = self,
case let .binaryOperator(op) = token.tokenKind, op == "*" {
return true
}
return false
}
}
11 changes: 8 additions & 3 deletions Sources/TestingMacros/Support/AvailabilityGuards.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ struct Availability {
/// The platform version, such as 1.2.3, if any.
var version: VersionTupleSyntax?

/// Whether or not this availability attribute may need a trailing wildcard
/// (`*`) when it is expanded into `@available()` or `#available()`.
var mayNeedTrailingWildcard = true

/// The `message` argument to the attribute, if any.
var message: SimpleStringLiteralExprSyntax?

Expand Down Expand Up @@ -70,13 +74,14 @@ private func _createAvailabilityTraitExpr(
"(\(literal: components.major), \(literal: components.minor), \(literal: components.patch))"
} ?? "nil"
let message = availability.message.map(\.trimmed).map(ExprSyntax.init) ?? "nil"
let trailingWildcard = availability.mayNeedTrailingWildcard ? ", *" : ""
let sourceLocationExpr = createSourceLocationExpr(of: availability.attribute, context: context)

switch (whenKeyword, availability.isSwift) {
case (.introduced, false):
return """
.__available(\(literal: availability.platformName!.textWithoutBackticks), introduced: \(version), message: \(message), sourceLocation: \(sourceLocationExpr)) {
if #available(\(availability.platformVersion!), *) {
if #available(\(availability.platformVersion!)\(raw: trailingWildcard)) {
return true
}
return false
Expand Down Expand Up @@ -207,8 +212,8 @@ func createSyntaxNode(
do {
let availableExprs: [ExprSyntax] = decl.availability(when: .introduced).lazy
.filter { !$0.isSwift }
.compactMap(\.platformVersion)
.map { "#available(\($0), *)" }
.compactMap { ($0.platformVersion, $0.mayNeedTrailingWildcard ? ", *" : "") }
.map { "#available(\($0.0)\(raw: $0.1))" }
if !availableExprs.isEmpty {
let conditionList = ConditionElementListSyntax {
for availableExpr in availableExprs {
Expand Down
7 changes: 6 additions & 1 deletion Tests/TestingMacrosTests/TestDeclarationMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,12 @@ struct TestDeclarationMacroTests {
[
#"#if os(moofOS)"#,
#".__available("moofOS", obsoleted: nil, message: "Moof!", "#,
]
],
#"@available(customAvailabilityDomain) @Test func f() {}"#:
[
#".__available("customAvailabilityDomain", introduced: nil, "#,
#"guard #available (customAvailabilityDomain) else"#,
],
]
)
func availabilityAttributeCapture(input: String, expectedOutputs: [String]) throws {
Expand Down
Loading