@@ -52,6 +52,32 @@ extension FixIt {
5252
5353// MARK: - Make missing
5454
55+ private extension FixIt . Change {
56+ /// Transfers the leading and trailing trivia of `nodes` to the previous token
57+ /// While doing this, it tries to be smart, merging trivia where it makes sense
58+ /// and refusing to add e.g. a space after punctuation, where it usually
59+ /// doesn't make sense.
60+ static func transferTriviaAtSides( from nodes: [ some SyntaxProtocol ] ) -> Self ? {
61+ guard let first = nodes. first, let last = nodes. last else {
62+ preconditionFailure ( )
63+ }
64+ let removedTriviaAtSides = first. leadingTrivia. mergingCommonSuffix ( last. trailingTrivia)
65+ guard !removedTriviaAtSides. isEmpty, let previousToken = first. previousToken ( viewMode: . sourceAccurate) else {
66+ return nil
67+ }
68+ let mergedTrivia = previousToken. trailingTrivia. mergingCommonPrefix ( removedTriviaAtSides)
69+ // We merge with the common prefix instead of the common suffix to preserve the original shape of the previous
70+ // token's trailing trivia after merging.
71+ guard !previousToken. tokenKind. isPunctuation || !mergedTrivia. allSatisfy ( \. isSpaceOrTab) else {
72+ // Punctuation is generally not followed by spaces in Swift.
73+ // If this action would only add spaces to the punctuation, drop it.
74+ // This generally yields better results.
75+ return nil
76+ }
77+ return . replaceTrailingTrivia( token: previousToken, newTrivia: mergedTrivia)
78+ }
79+ }
80+
5581extension FixIt . MultiNodeChange {
5682 /// Replaced a present token with a missing node.
5783 ///
@@ -78,32 +104,12 @@ extension FixIt.MultiNodeChange {
78104 return FixIt . MultiNodeChange ( primitiveChanges: [ ] )
79105 }
80106 var changes = [ FixIt . Change. replace ( oldNode: Syntax ( node) , newNode: MissingMaker ( ) . rewrite ( node, detach: true ) ) ]
81- if transferTrivia {
82- changes += FixIt . MultiNodeChange . transferTriviaAtSides ( from : [ node ] ) . primitiveChanges
107+ if transferTrivia, let transferredTrivia = FixIt . Change . transferTriviaAtSides ( from : [ node ] ) {
108+ changes. append ( transferredTrivia )
83109 }
84110 return FixIt . MultiNodeChange ( primitiveChanges: changes)
85111 }
86112
87- /// Transfers the leading and trailing trivia of `nodes` to the previous token
88- /// While doing this, it tries to be smart, merging trivia where it makes sense
89- /// and refusing to add e.g. a space after punctuation, where it usually
90- /// doesn't make sense.
91- private static func transferTriviaAtSides( from nodes: [ some SyntaxProtocol ] ) -> Self {
92- let removedTriviaAtSides = ( nodes. first? . leadingTrivia ?? [ ] ) . merging ( nodes. last? . trailingTrivia ?? [ ] )
93- if !removedTriviaAtSides. isEmpty, let previousToken = nodes. first? . previousToken ( viewMode: . sourceAccurate) {
94- let mergedTrivia = previousToken. trailingTrivia. merging ( removedTriviaAtSides)
95- if previousToken. tokenKind. isPunctuation, mergedTrivia. allSatisfy ( { $0. isSpaceOrTab } ) {
96- // Punctuation is generally not followed by spaces in Swift.
97- // If this action would only add spaces to the punctuation, drop it.
98- // This generally yields better results.
99- return FixIt . MultiNodeChange ( )
100- }
101- return FixIt . MultiNodeChange ( . replaceTrailingTrivia( token: previousToken, newTrivia: mergedTrivia) )
102- } else {
103- return FixIt . MultiNodeChange ( )
104- }
105- }
106-
107113 /// Replace present nodes with their missing equivalents.
108114 ///
109115 /// If `transferTrivia` is `true`, the leading trivia of the first node and
@@ -117,8 +123,8 @@ extension FixIt.MultiNodeChange {
117123 newNode: MissingMaker ( ) . rewrite ( $0, detach: true )
118124 )
119125 }
120- if transferTrivia {
121- changes += FixIt . MultiNodeChange . transferTriviaAtSides ( from : nodes ) . primitiveChanges
126+ if transferTrivia, let transferredTrivia = FixIt . Change . transferTriviaAtSides ( from : nodes ) {
127+ changes. append ( transferredTrivia )
122128 }
123129 return FixIt . MultiNodeChange ( primitiveChanges: changes)
124130 }
0 commit comments