@@ -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
}
@@ -702,13 +702,26 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
702
702
context. addDiagnostics ( from: MacroApplicationError . accessorMacroOnVariableWithMultipleBindings, node: node)
703
703
return DeclSyntax ( node)
704
704
}
705
- node. bindings [ node. bindings. startIndex] . accessorBlock = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
705
+
706
+ let expansion = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
707
+ if expansion. accessors != binding. accessorBlock {
708
+ if binding. initializer != nil , expansion. expandsGetSet {
709
+ // The accessor block will have a leading space, but there will already be a
710
+ // space between the variable and the to-be-removed initializer. Remove the
711
+ // leading trivia on the accessor block so we don't double up.
712
+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors? . with ( \. leadingTrivia, [ ] )
713
+ node. bindings [ node. bindings. startIndex] . initializer = nil
714
+ } else {
715
+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors
716
+ }
717
+ }
718
+
706
719
return DeclSyntax ( node)
707
720
}
708
721
709
722
override func visit( _ node: SubscriptDeclSyntax ) -> DeclSyntax {
710
723
var node = super. visit ( node) . cast ( SubscriptDeclSyntax . self)
711
- node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock)
724
+ node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock) . accessors
712
725
return DeclSyntax ( node)
713
726
}
714
727
}
@@ -869,14 +882,23 @@ extension MacroApplication {
869
882
}
870
883
}
871
884
872
- /// Expand all 'accessor' macros attached to `storage` and return the `storage`
873
- /// node.
885
+ /// Expand all 'accessor' macros attached to `storage`.
874
886
///
875
- /// - Returns: The storage node with all macro-synthesized accessors applied.
876
- private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> AccessorBlockSyntax ? {
887
+ /// - Returns: The final accessors block that includes both the existing
888
+ /// and expanded accessors, as well as whether any `get`/`set` were
889
+ /// expanded (in which case any initializer on `storage` should be
890
+ /// removed).
891
+ private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> (
892
+ accessors: AccessorBlockSyntax ? , expandsGetSet: Bool
893
+ ) {
877
894
let accessorMacros = macroAttributes ( attachedTo: DeclSyntax ( storage) , ofType: AccessorMacro . Type. self)
878
895
879
896
var newAccessorsBlock = existingAccessors
897
+ var expandsGetSet = false
898
+ func checkExpansions( _ accessors: AccessorDeclListSyntax ? ) {
899
+ guard let accessors else { return }
900
+ expandsGetSet = expandsGetSet || accessors. contains ( where: \. isGetOrSet)
901
+ }
880
902
881
903
for macro in accessorMacros {
882
904
do {
@@ -894,6 +916,8 @@ extension MacroApplication {
894
916
in: context,
895
917
indentationWidth: indentationWidth
896
918
) {
919
+ checkExpansions ( newAccessors)
920
+
897
921
// If existingAccessors is not `nil`, then we also set
898
922
// `newAccessorBlock` above to a a non-nil value, so
899
923
// `newAccessorsBlock` also isn’t `nil`.
@@ -902,31 +926,33 @@ extension MacroApplication {
902
926
indentationWidth: self . indentationWidth
903
927
)
904
928
}
905
- } else {
906
- let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
907
- definition : macro. definition ,
908
- attributeNode : macro . attributeNode ,
909
- attachedTo : DeclSyntax ( storage ) ,
910
- in : context ,
911
- indentationWidth : indentationWidth
912
- )
913
- if newAccessorsBlock == nil {
914
- newAccessorsBlock = newAccessors
915
- } else if let newAccessors = newAccessors {
916
- guard case . accessors ( let accessorList) = newAccessors . accessors else {
917
- throw MacroApplicationError . malformedAccessor
918
- }
919
- newAccessorsBlock = newAccessorsBlock! . addingAccessors (
929
+ } else if let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
930
+ definition : macro . definition ,
931
+ attributeNode : macro. attributeNode ,
932
+ attachedTo : DeclSyntax ( storage ) ,
933
+ in : context ,
934
+ indentationWidth : indentationWidth
935
+ ) {
936
+ guard case . accessors ( let accessorList ) = newAccessors . accessors else {
937
+ throw MacroApplicationError . malformedAccessor
938
+ }
939
+
940
+ checkExpansions ( accessorList)
941
+
942
+ if let oldBlock = newAccessorsBlock {
943
+ newAccessorsBlock = oldBlock . addingAccessors (
920
944
from: accessorList,
921
945
indentationWidth: self . indentationWidth
922
946
)
947
+ } else {
948
+ newAccessorsBlock = newAccessors
923
949
}
924
950
}
925
951
} catch {
926
952
context. addDiagnostics ( from: error, node: macro. attributeNode)
927
953
}
928
954
}
929
- return newAccessorsBlock
955
+ return ( newAccessorsBlock, expandsGetSet )
930
956
}
931
957
}
932
958
@@ -1130,3 +1156,9 @@ private extension AttributeSyntax {
1130
1156
return ( detach ( in: context, foldingWith: operatorTable) as Syntax ) . cast ( Self . self)
1131
1157
}
1132
1158
}
1159
+
1160
+ private extension AccessorDeclSyntax {
1161
+ var isGetOrSet : Bool {
1162
+ return accessorSpecifier. tokenKind == . keyword( . get) || accessorSpecifier. tokenKind == . keyword( . set)
1163
+ }
1164
+ }
0 commit comments