@@ -52,13 +52,39 @@ 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: [ Syntax ] ) -> 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 {
56- /// Replaced a present token with a missing node .
82+ /// Replaced a present token with a missing token .
5783 ///
5884 /// If `transferTrivia` is `true`, the leading and trailing trivia of the
59- /// removed node will be transferred to the trailing trivia of the previous token.
85+ /// removed token will be transferred to the trailing trivia of the previous token.
6086 static func makeMissing( _ token: TokenSyntax , transferTrivia: Bool = true ) -> Self {
61- return makeMissing ( [ token] , transferTrivia: transferTrivia)
87+ self . makeMissing ( [ token] , transferTrivia: transferTrivia)
6288 }
6389
6490 /// Replace present tokens with missing tokens.
@@ -68,57 +94,42 @@ extension FixIt.MultiNodeChange {
6894 /// tokens.
6995 static func makeMissing( _ tokens: [ TokenSyntax ] , transferTrivia: Bool = true ) -> Self {
7096 precondition ( tokens. allSatisfy ( \. isPresent) )
71- return . makeMissing( tokens. map ( Syntax . init) , transferTrivia: transferTrivia)
97+ return self . makeMissing ( tokens. map ( Syntax . init) , transferTrivia: transferTrivia)
7298 }
7399
74100 /// If `transferTrivia` is `true`, the leading and trailing trivia of the
75101 /// removed node will be transferred to the trailing trivia of the previous token.
76102 static func makeMissing( _ node: ( some SyntaxProtocol ) ? , transferTrivia: Bool = true ) -> Self {
77- guard let node = node else {
103+ guard let node else {
78104 return FixIt . MultiNodeChange ( primitiveChanges: [ ] )
79105 }
80- 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
83- }
84- return FixIt . MultiNodeChange ( primitiveChanges: changes)
106+ return self . makeMissing ( [ node] , transferTrivia: transferTrivia)
85107 }
86108
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- }
109+ /// Replace present nodes with missing nodes.
110+ ///
111+ /// If `transferTrivia` is `true`, the leading trivia of the first node and
112+ /// the trailing trivia of the last node will be transferred to their adjecent
113+ /// tokens.
114+ static func makeMissing( _ nodes: [ some SyntaxProtocol ] , transferTrivia: Bool = true ) -> Self {
115+ self . makeMissing ( nodes. map ( Syntax . init) , transferTrivia: transferTrivia)
105116 }
106117
107118 /// Replace present nodes with their missing equivalents.
108119 ///
109120 /// If `transferTrivia` is `true`, the leading trivia of the first node and
110121 /// the trailing trivia of the last node will be transferred to their adjecent
111122 /// tokens.
112- static func makeMissing( _ nodes: [ Syntax ] , transferTrivia: Bool = true ) -> Self {
123+ private static func makeMissing( _ nodes: [ Syntax ] , transferTrivia: Bool = true ) -> Self {
113124 precondition ( !nodes. isEmpty)
114125 var changes = nodes. map {
115126 FixIt . Change. replace (
116127 oldNode: $0,
117128 newNode: MissingMaker ( ) . rewrite ( $0, detach: true )
118129 )
119130 }
120- if transferTrivia {
121- changes += FixIt . MultiNodeChange . transferTriviaAtSides ( from : nodes ) . primitiveChanges
131+ if transferTrivia, let transferredTrivia = FixIt . Change . transferTriviaAtSides ( from : nodes ) {
132+ changes. append ( transferredTrivia )
122133 }
123134 return FixIt . MultiNodeChange ( primitiveChanges: changes)
124135 }
0 commit comments