@@ -15,24 +15,51 @@ import SwiftBasicFormat
1515import SwiftSyntax
1616
1717extension FixIt {
18- public init ( message: FixItMessage , changes: [ Changes ] ) {
19- self . init ( message: message, changes: FixIt . Changes ( combining: changes) )
18+ /// A more complex set of changes that affects multiple syntax nodes and thus
19+ /// produces multiple `FixIt.Change`s. This allows us to e.g. mark a node as
20+ /// missing but keep the trivia by transferring it to the previous or next
21+ /// token.
22+ struct MultiNodeChange {
23+ var primitiveChanges : [ Change ]
24+
25+ init ( primitiveChanges: [ Change ] ) {
26+ self . primitiveChanges = primitiveChanges
27+ }
28+
29+ init ( _ primitiveChanges: Change ... ) {
30+ self . init ( primitiveChanges: primitiveChanges)
31+ }
32+
33+ init ( combining: [ MultiNodeChange ] ) {
34+ self . init ( primitiveChanges: combining. flatMap ( \. primitiveChanges) )
35+ }
36+ }
37+
38+ init ( message: FixItMessage , changes: [ MultiNodeChange ] ) {
39+ self . init ( message: message, changes: MultiNodeChange ( combining: changes) )
40+ }
41+
42+ init ( message: FixItMessage , changes: MultiNodeChange ) {
43+ self . init ( message: message, changes: changes. primitiveChanges)
2044 }
2145
2246 // These overloads shouldn't be needed, but are currently required for the
2347 // Swift 5.5 compiler to handle non-trivial FixIt initializations using
2448 // leading-dot syntax.
2549 // TODO: These can be dropped once we require a minimum of Swift 5.6 to
2650 // compile the library.
27- init ( message: StaticParserFixIt , changes: Changes ) {
28- self . init ( message: message as FixItMessage , changes: changes)
51+ init ( message: StaticParserFixIt , changes: MultiNodeChange ) {
52+ self . init ( message: message as FixItMessage , changes: changes. primitiveChanges )
2953 }
30- init ( message: StaticParserFixIt , changes: [ Changes ] ) {
31- self . init ( message: message as FixItMessage , changes: FixIt . Changes ( combining: changes) )
54+ init ( message: StaticParserFixIt , changes: [ MultiNodeChange ] ) {
55+ self . init ( message: message as FixItMessage , changes: MultiNodeChange ( combining: changes) . primitiveChanges)
56+ }
57+ public init ( message: StaticParserFixIt , changes: [ Change ] ) {
58+ self . init ( message: message as FixItMessage , changes: changes)
3259 }
3360}
3461
35- extension FixIt . Changes {
62+ extension FixIt . MultiNodeChange {
3663 /// Replaced a present token with a missing node.
3764 /// If `transferTrivia` is `true`, the leading and trailing trivia of the
3865 /// removed node will be transferred to the trailing trivia of the previous token.
@@ -49,26 +76,26 @@ extension FixIt.Changes {
4976 var changes = tokens. map {
5077 FixIt . Change. replace (
5178 oldNode: Syntax ( $0) ,
52- newNode: Syntax ( TokenSyntax ( $0. tokenKind , leadingTrivia : [ ] , trailingTrivia : [ ] , presence: . missing) )
79+ newNode: Syntax ( $0. with ( \ . presence, . missing) )
5380 )
5481 }
5582 if transferTrivia {
56- changes += FixIt . Changes . transferTriviaAtSides ( from: tokens) . changes
83+ changes += FixIt . MultiNodeChange . transferTriviaAtSides ( from: tokens) . primitiveChanges
5784 }
58- return FixIt . Changes ( changes : changes)
85+ return FixIt . MultiNodeChange ( primitiveChanges : changes)
5986 }
6087
6188 /// If `transferTrivia` is `true`, the leading and trailing trivia of the
6289 /// removed node will be transferred to the trailing trivia of the previous token.
6390 static func makeMissing< SyntaxType: SyntaxProtocol > ( _ node: SyntaxType ? , transferTrivia: Bool = true ) -> Self {
6491 guard let node = node else {
65- return FixIt . Changes ( changes : [ ] )
92+ return FixIt . MultiNodeChange ( primitiveChanges : [ ] )
6693 }
6794 var changes = [ FixIt . Change. replace ( oldNode: Syntax ( node) , newNode: MissingMaker ( ) . visit ( Syntax ( node) ) ) ]
6895 if transferTrivia {
69- changes += FixIt . Changes . transferTriviaAtSides ( from: [ node] ) . changes
96+ changes += FixIt . MultiNodeChange . transferTriviaAtSides ( from: [ node] ) . primitiveChanges
7097 }
71- return FixIt . Changes ( changes : changes)
98+ return FixIt . MultiNodeChange ( primitiveChanges : changes)
7299 }
73100
74101 /// Make a node present. If `leadingTrivia` or `trailingTrivia` is specified,
@@ -89,13 +116,13 @@ extension FixIt.Changes {
89116 let nextToken = node. nextToken ( viewMode: . sourceAccurate) ,
90117 leadingTrivia == nil
91118 {
92- return [
119+ return FixIt . MultiNodeChange (
93120 . replace(
94121 oldNode: Syntax ( node) ,
95122 newNode: Syntax ( presentNode) . with ( \. leadingTrivia, nextToken. leadingTrivia)
96123 ) ,
97- . replaceLeadingTrivia( token: nextToken, newTrivia: [ ] ) ,
98- ]
124+ . replaceLeadingTrivia( token: nextToken, newTrivia: [ ] )
125+ )
99126 } else if node. leadingTrivia. isEmpty,
100127 let previousToken = node. previousToken ( viewMode: . fixedUp) ,
101128 previousToken. presence == . present,
@@ -105,19 +132,19 @@ extension FixIt.Changes {
105132 {
106133 /// If neither this nor the previous token are punctionation make sure they
107134 /// are separated by a space.
108- return [
135+ return FixIt . MultiNodeChange (
109136 . replace(
110137 oldNode: Syntax ( node) ,
111138 newNode: Syntax ( presentNode) . with ( \. leadingTrivia, . space)
112139 )
113- ]
140+ )
114141 } else {
115- return [
142+ return FixIt . MultiNodeChange (
116143 . replace(
117144 oldNode: Syntax ( node) ,
118145 newNode: Syntax ( presentNode)
119146 )
120- ]
147+ )
121148 }
122149 }
123150
@@ -128,10 +155,10 @@ extension FixIt.Changes {
128155 if !previousToken. trailingTrivia. isEmpty {
129156 presentToken = presentToken. with ( \. trailingTrivia, previousToken. trailingTrivia)
130157 }
131- return [
158+ return FixIt . MultiNodeChange (
132159 . replaceTrailingTrivia( token: previousToken, newTrivia: [ ] ) ,
133- . replace( oldNode: Syntax ( token) , newNode: Syntax ( presentToken) ) ,
134- ]
160+ . replace( oldNode: Syntax ( token) , newNode: Syntax ( presentToken) )
161+ )
135162 } else {
136163 return . makePresent( token)
137164 }
@@ -149,11 +176,11 @@ extension FixIt.Changes {
149176 // Punctuation is generally not followed by spaces in Swift.
150177 // If this action would only add spaces to the punctuation, drop it.
151178 // This generally yields better results.
152- return [ ]
179+ return FixIt . MultiNodeChange ( )
153180 }
154- return [ . replaceTrailingTrivia( token: previousToken, newTrivia: mergedTrivia) ]
181+ return FixIt . MultiNodeChange ( . replaceTrailingTrivia( token: previousToken, newTrivia: mergedTrivia) )
155182 } else {
156- return [ ]
183+ return FixIt . MultiNodeChange ( )
157184 }
158185 }
159186}
0 commit comments