11import SwiftCompilerPlugin
22import SwiftSyntax
33import SwiftSyntaxBuilder
4- import SwiftSyntaxMacros
54import SwiftSyntaxMacroExpansion
5+ import SwiftSyntaxMacros
66
77public struct COWTrackingPropertyMacro {
88
@@ -44,15 +44,34 @@ extension COWTrackingPropertyMacro: PeerMacro {
4444 var _variableDecl = variableDecl. trimmed
4545 _variableDecl. attributes = [ . init( . init( stringLiteral: " @TrackingIgnored " ) ) ]
4646
47- _variableDecl = _variableDecl
48- . renamingIdentifier ( with: " _backing_ " )
49- . modifyingTypeAnnotation ( { type in
50- return " _BackingStorage< \( type. trimmed) > "
51- } )
52- . modifyingInit ( { initializer in
53- return . init( value: " _BackingStorage.init( \( initializer. value) ) " as ExprSyntax )
54- } )
55-
47+ if variableDecl. isOptional {
48+ _variableDecl =
49+ _variableDecl
50+ . renamingIdentifier ( with: " _backing_ " )
51+ . modifyingTypeAnnotation ( { type in
52+ return " _BackingStorage< \( type. trimmed) > "
53+ } )
54+
55+ _variableDecl = _variableDecl. with (
56+ \. bindings,
57+ . init(
58+ _variableDecl. bindings. map { binding in
59+ binding. with ( \. initializer, . init( value: " _BackingStorage.init(nil) " as ExprSyntax ) )
60+ } )
61+ )
62+
63+ } else {
64+ _variableDecl =
65+ _variableDecl
66+ . renamingIdentifier ( with: " _backing_ " )
67+ . modifyingTypeAnnotation ( { type in
68+ return " _BackingStorage< \( type. trimmed) > "
69+ } )
70+ . modifyingInit ( { initializer in
71+ return . init( value: " _BackingStorage.init( \( initializer. value) ) " as ExprSyntax )
72+ } )
73+ }
74+
5675 newMembers. append ( DeclSyntax ( _variableDecl) )
5776
5877 return newMembers
@@ -88,7 +107,7 @@ extension COWTrackingPropertyMacro: AccessorMacro {
88107 }
89108 """
90109 )
91-
110+
92111 let readAccessor = AccessorDeclSyntax (
93112 """
94113 _read {
@@ -113,7 +132,7 @@ extension COWTrackingPropertyMacro: AccessorMacro {
113132 } else {
114133 \( raw: backingName) .value = newValue
115134 }
116-
135+
117136 }
118137 """
119138 )
@@ -132,17 +151,19 @@ extension COWTrackingPropertyMacro: AccessorMacro {
132151 }
133152 """
134153 )
135-
154+
136155 var accessors : [ AccessorDeclSyntax ] = [ ]
137-
156+
157+ if binding. initializer == nil {
158+ accessors. append ( initAccessor)
159+ }
160+
138161 accessors. append ( readAccessor)
162+
139163 if !isConstant {
140- accessors. append ( setAccessor)
164+ accessors. append ( setAccessor)
141165 accessors. append ( modifyAccessor)
142166 }
143- if binding. initializer == nil {
144- accessors. append ( initAccessor)
145- }
146167
147168 return accessors
148169
@@ -153,28 +174,28 @@ extension COWTrackingPropertyMacro: AccessorMacro {
153174extension VariableDeclSyntax {
154175 func renamingIdentifier( with newName: String ) -> VariableDeclSyntax {
155176 let newBindings = self . bindings. map { binding -> PatternBindingSyntax in
156-
177+
157178 if let identifierPattern = binding. pattern. as ( IdentifierPatternSyntax . self) {
158-
179+
159180 let propertyName = identifierPattern. identifier. text
160-
181+
161182 let newIdentifierPattern = identifierPattern. with (
162183 \. identifier, " \( raw: newName) \( raw: propertyName) " )
163184 return binding. with ( \. pattern, . init( newIdentifierPattern) )
164185 }
165186 return binding
166187 }
167-
188+
168189 return self . with ( \. bindings, . init( newBindings) )
169190 }
170191}
171192
172193extension VariableDeclSyntax {
173194 func withPrivateModifier( ) -> VariableDeclSyntax {
174-
195+
175196 let privateModifier = DeclModifierSyntax . init (
176197 name: . keyword( . private) , trailingTrivia: . spaces( 1 ) )
177-
198+
178199 var modifiers = self . modifiers
179200 if modifiers. contains ( where: { $0. name. tokenKind == . keyword( . private) } ) {
180201 return self
@@ -185,7 +206,15 @@ extension VariableDeclSyntax {
185206}
186207
187208extension VariableDeclSyntax {
188-
209+
210+ var isOptional : Bool {
211+
212+ return self . bindings. contains ( where: {
213+ $0. typeAnnotation? . type. is ( OptionalTypeSyntax . self) ?? false
214+ } )
215+
216+ }
217+
189218 func modifyingTypeAnnotation( _ modifier: ( TypeSyntax ) -> TypeSyntax ) -> VariableDeclSyntax {
190219 let newBindings = self . bindings. map { binding -> PatternBindingSyntax in
191220 if let typeAnnotation = binding. typeAnnotation {
@@ -195,21 +224,23 @@ extension VariableDeclSyntax {
195224 }
196225 return binding
197226 }
198-
227+
199228 return self . with ( \. bindings, . init( newBindings) )
200229 }
201-
202- func modifyingInit( _ modifier: ( InitializerClauseSyntax ) -> InitializerClauseSyntax ) -> VariableDeclSyntax {
203-
204- let newBindings = self . bindings. map { binding -> PatternBindingSyntax in
230+
231+ func modifyingInit( _ modifier: ( InitializerClauseSyntax ) -> InitializerClauseSyntax )
232+ -> VariableDeclSyntax
233+ {
234+
235+ let newBindings = self . bindings. map { binding -> PatternBindingSyntax in
205236 if let initializer = binding. initializer {
206237 let newInitializer = modifier ( initializer)
207238 return binding. with ( \. initializer, newInitializer)
208239 }
209240 return binding
210241 }
211-
242+
212243 return self . with ( \. bindings, . init( newBindings) )
213244 }
214-
245+
215246}
0 commit comments