@@ -307,7 +307,7 @@ private func expandAccessorMacroWithExistingAccessors(
307
307
return nil
308
308
}
309
309
310
- // Separate the accessor from any existing accessors by two spaces
310
+ // Separate the accessor from any existing accessors by an empty line
311
311
let indentedSource = " \n " + expanded. indented ( by: attachedTo. indentationOfFirstLine + indentationWidth)
312
312
return " \( raw: indentedSource) "
313
313
}
@@ -636,13 +636,26 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
636
636
context. addDiagnostics ( from: MacroApplicationError . accessorMacroOnVariableWithMultipleBindings, node: node)
637
637
return DeclSyntax ( node)
638
638
}
639
- node. bindings [ node. bindings. startIndex] . accessorBlock = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
639
+
640
+ let expansion = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
641
+ if expansion. accessors != binding. accessorBlock {
642
+ if binding. initializer != nil , expansion. expandsGetSet {
643
+ // The accessor block will have a leading space, but there will already be a
644
+ // space between the variable and the to-be-removed initializer. Remove the
645
+ // leading trivia on the accessor block so we don't double up.
646
+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors? . with ( \. leadingTrivia, [ ] )
647
+ node. bindings [ node. bindings. startIndex] . initializer = nil
648
+ } else {
649
+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors
650
+ }
651
+ }
652
+
640
653
return DeclSyntax ( node)
641
654
}
642
655
643
656
override func visit( _ node: SubscriptDeclSyntax ) -> DeclSyntax {
644
657
var node = super. visit ( node) . cast ( SubscriptDeclSyntax . self)
645
- node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock)
658
+ node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock) . accessors
646
659
return DeclSyntax ( node)
647
660
}
648
661
}
@@ -803,14 +816,23 @@ extension MacroApplication {
803
816
}
804
817
}
805
818
806
- /// Expand all 'accessor' macros attached to `storage` and return the `storage`
807
- /// node.
819
+ /// Expand all 'accessor' macros attached to `storage`.
808
820
///
809
- /// - Returns: The storage node with all macro-synthesized accessors applied.
810
- private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> AccessorBlockSyntax ? {
821
+ /// - Returns: The final accessors block that includes both the existing
822
+ /// and expanded accessors, as well as whether any `get`/`set` were
823
+ /// expanded (in which case any initializer on `storage` should be
824
+ /// removed).
825
+ private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> (
826
+ accessors: AccessorBlockSyntax ? , expandsGetSet: Bool
827
+ ) {
811
828
let accessorMacros = macroAttributes ( attachedTo: DeclSyntax ( storage) , ofType: AccessorMacro . Type. self)
812
829
813
830
var newAccessorsBlock = existingAccessors
831
+ var expandsGetSet = false
832
+ func checkExpansions( _ accessors: AccessorDeclListSyntax ? ) {
833
+ guard let accessors else { return }
834
+ expandsGetSet = expandsGetSet || accessors. contains ( where: \. isGetOrSet)
835
+ }
814
836
815
837
for macro in accessorMacros {
816
838
do {
@@ -828,6 +850,8 @@ extension MacroApplication {
828
850
in: context,
829
851
indentationWidth: indentationWidth
830
852
) {
853
+ checkExpansions ( newAccessors)
854
+
831
855
// If existingAccessors is not `nil`, then we also set
832
856
// `newAccessorBlock` above to a a non-nil value, so
833
857
// `newAccessorsBlock` also isn’t `nil`.
@@ -836,31 +860,33 @@ extension MacroApplication {
836
860
indentationWidth: self . indentationWidth
837
861
)
838
862
}
839
- } else {
840
- let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
841
- definition : macro. definition ,
842
- attributeNode : macro . attributeNode ,
843
- attachedTo : DeclSyntax ( storage ) ,
844
- in : context ,
845
- indentationWidth : indentationWidth
846
- )
847
- if newAccessorsBlock == nil {
848
- newAccessorsBlock = newAccessors
849
- } else if let newAccessors = newAccessors {
850
- guard case . accessors ( let accessorList) = newAccessors . accessors else {
851
- throw MacroApplicationError . malformedAccessor
852
- }
853
- newAccessorsBlock = newAccessorsBlock! . addingAccessors (
863
+ } else if let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
864
+ definition : macro . definition ,
865
+ attributeNode : macro. attributeNode ,
866
+ attachedTo : DeclSyntax ( storage ) ,
867
+ in : context ,
868
+ indentationWidth : indentationWidth
869
+ ) {
870
+ guard case . accessors ( let accessorList ) = newAccessors . accessors else {
871
+ throw MacroApplicationError . malformedAccessor
872
+ }
873
+
874
+ checkExpansions ( accessorList)
875
+
876
+ if let oldBlock = newAccessorsBlock {
877
+ newAccessorsBlock = oldBlock . addingAccessors (
854
878
from: accessorList,
855
879
indentationWidth: self . indentationWidth
856
880
)
881
+ } else {
882
+ newAccessorsBlock = newAccessors
857
883
}
858
884
}
859
885
} catch {
860
886
context. addDiagnostics ( from: error, node: macro. attributeNode)
861
887
}
862
888
}
863
- return newAccessorsBlock
889
+ return ( newAccessorsBlock, expandsGetSet )
864
890
}
865
891
}
866
892
@@ -1064,3 +1090,9 @@ private extension AttributeSyntax {
1064
1090
return ( detach ( in: context, foldingWith: operatorTable) as Syntax ) . cast ( Self . self)
1065
1091
}
1066
1092
}
1093
+
1094
+ private extension AccessorDeclSyntax {
1095
+ var isGetOrSet : Bool {
1096
+ return accessorSpecifier. tokenKind == . keyword( . get) || accessorSpecifier. tokenKind == . keyword( . set)
1097
+ }
1098
+ }
0 commit comments