Skip to content

Commit 8a122ba

Browse files
authored
🍒[Observation] Forward availability and defines to extensions (#67432)
* [Observation] Forward availability and defines to extensions (#67412) * [Observation] Forward availability and defines to extensions * Simplify availability slightly from review feedback * Simplify availability for extensions to use `.with` * Use older name for detaching nodes * Force a newline for the trailing trivia of the replicated availability
1 parent 73c7ebb commit 8a122ba

File tree

5 files changed

+146
-14
lines changed

5 files changed

+146
-14
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import SwiftSyntax
13+
import SwiftSyntaxMacros
14+
import SwiftDiagnostics
15+
import SwiftOperators
16+
import SwiftSyntaxBuilder
17+
18+
19+
extension AttributeSyntax {
20+
var availability: AttributeSyntax? {
21+
if attributeName.identifier == "available" {
22+
return self
23+
} else {
24+
return nil
25+
}
26+
}
27+
}
28+
29+
extension IfConfigClauseSyntax.Elements {
30+
var availability: IfConfigClauseSyntax.Elements? {
31+
switch self {
32+
case .attributes(let attributes):
33+
if let availability = attributes.availability {
34+
return .attributes(availability)
35+
} else {
36+
return nil
37+
}
38+
default:
39+
return nil
40+
}
41+
}
42+
}
43+
44+
extension IfConfigClauseSyntax {
45+
var availability: IfConfigClauseSyntax? {
46+
if let availability = elements?.availability {
47+
return with(\.elements, availability)
48+
} else {
49+
return nil
50+
}
51+
}
52+
53+
var clonedAsIf: IfConfigClauseSyntax {
54+
detach().with(\.poundKeyword, .poundIfKeyword())
55+
}
56+
}
57+
58+
extension IfConfigDeclSyntax {
59+
var availability: IfConfigDeclSyntax? {
60+
var elements = [IfConfigClauseListSyntax.Element]()
61+
for clause in clauses {
62+
if let availability = clause.availability {
63+
if elements.isEmpty {
64+
elements.append(availability.clonedAsIf)
65+
} else {
66+
elements.append(availability)
67+
}
68+
}
69+
}
70+
if elements.isEmpty {
71+
return nil
72+
} else {
73+
return with(\.clauses, IfConfigClauseListSyntax(elements))
74+
}
75+
76+
}
77+
}
78+
79+
extension AttributeListSyntax.Element {
80+
var availability: AttributeListSyntax.Element? {
81+
switch self {
82+
case .attribute(let attribute):
83+
if let availability = attribute.availability {
84+
return .attribute(availability)
85+
}
86+
case .ifConfigDecl(let ifConfig):
87+
if let availability = ifConfig.availability {
88+
return .ifConfigDecl(availability)
89+
}
90+
default:
91+
break
92+
}
93+
return nil
94+
}
95+
}
96+
97+
extension AttributeListSyntax {
98+
var availability: AttributeListSyntax? {
99+
var elements = [AttributeListSyntax.Element]()
100+
for element in self {
101+
if let availability = element.availability {
102+
elements.append(availability)
103+
}
104+
}
105+
if elements.isEmpty {
106+
return nil
107+
}
108+
return AttributeListSyntax(elements)
109+
}
110+
}
111+
112+
extension DeclGroupSyntax {
113+
var availability: AttributeListSyntax? {
114+
if let attributes {
115+
return attributes.availability
116+
} else {
117+
return nil
118+
}
119+
}
120+
}

lib/Macros/Sources/ObservationMacros/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
#===----------------------------------------------------------------------===#
1212

1313
add_swift_macro_library(ObservationMacros
14-
ObservableMacro.swift
14+
Availability.swift
1515
Extensions.swift
16+
ObservableMacro.swift
1617
SWIFT_DEPENDENCIES
1718
SwiftSyntax::SwiftDiagnostics
1819
SwiftSyntax::SwiftOperators

lib/Macros/Sources/ObservationMacros/Extensions.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
import SwiftSyntax
1313
import SwiftSyntaxMacros
14-
15-
@_implementationOnly import SwiftDiagnostics
16-
@_implementationOnly import SwiftOperators
17-
@_implementationOnly import SwiftSyntaxBuilder
14+
import SwiftDiagnostics
15+
import SwiftOperators
16+
import SwiftSyntaxBuilder
1817

1918
extension VariableDeclSyntax {
2019
var identifierPattern: IdentifierPatternSyntax? {

lib/Macros/Sources/ObservationMacros/ObservableMacro.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111

1212
import SwiftSyntax
1313
import SwiftSyntaxMacros
14-
15-
@_implementationOnly import SwiftDiagnostics
16-
@_implementationOnly import SwiftOperators
17-
@_implementationOnly import SwiftSyntaxBuilder
14+
import SwiftDiagnostics
15+
import SwiftOperators
16+
import SwiftSyntaxBuilder
1817

1918
public struct ObservableMacro {
2019
static let moduleName = "Observation"
@@ -273,12 +272,15 @@ extension ObservableMacro: ExtensionMacro {
273272
}
274273

275274
let decl: DeclSyntax = """
276-
extension \(raw: type.trimmedDescription): \(raw: qualifiedConformanceName) {}
277-
"""
275+
extension \(raw: type.trimmedDescription): \(raw: qualifiedConformanceName) {}
276+
"""
277+
let ext = decl.cast(ExtensionDeclSyntax.self)
278278

279-
return [
280-
decl.cast(ExtensionDeclSyntax.self)
281-
]
279+
if let availability = declaration.availability {
280+
return [ext.with(\.attributes, availability.with(\.trailingTrivia, .newline))]
281+
} else {
282+
return [ext]
283+
}
282284
}
283285
}
284286

test/stdlib/Observation/Observable.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,16 @@ class RecursiveOuter {
200200
}
201201
}
202202

203+
@Observable
204+
#if FOO
205+
@available(SwiftStdlib 5.9, *)
206+
#elseif BAR
207+
@available(SwiftStdlib 5.9, *)
208+
#else
209+
#endif
210+
class GuardedAvailability {
211+
}
212+
203213
@main
204214
struct Validator {
205215
@MainActor

0 commit comments

Comments
 (0)