@@ -46,12 +46,12 @@ public enum FixItApplier {
4646 return self . apply ( edits: edits, to: tree)
4747 }
4848
49- /// Apply the given edits to the syntax tree.
49+ /// Applies the given edits to the given syntax tree.
5050 ///
5151 /// - Parameters:
52- /// - edits: The edits to apply to the syntax tree
53- /// - tree: he syntax tree to which the edits should be applied.
54- /// - Returns: A `String` representation of the modified syntax tree after applying the edits .
52+ /// - edits: The edits to apply.
53+ /// - tree: The syntax tree to which the edits should be applied.
54+ /// - Returns: A `String` representation of the modified syntax tree.
5555 public static func apply(
5656 edits: [ SourceEdit ] ,
5757 to tree: some SyntaxProtocol
@@ -62,17 +62,27 @@ public enum FixItApplier {
6262 while let edit = edits. first {
6363 edits = Array ( edits. dropFirst ( ) )
6464
65+ // Empty edits do nothing.
66+ guard !edit. isEmpty else {
67+ continue
68+ }
69+
6570 let startIndex = source. utf8. index ( source. utf8. startIndex, offsetBy: edit. startUtf8Offset)
6671 let endIndex = source. utf8. index ( source. utf8. startIndex, offsetBy: edit. endUtf8Offset)
6772
6873 source. replaceSubrange ( startIndex..< endIndex, with: edit. replacement)
6974
70- edits = edits. compactMap { remainingEdit -> SourceEdit ? in
71- if remainingEdit. range. overlaps ( edit. range) {
75+ // Drop any subsequent edits that conflict with one we just applied, and
76+ // adjust the range of the rest.
77+ for i in edits. indices {
78+ let remainingEdit = edits [ i]
79+
80+ guard !remainingEdit. range. overlaps ( edit. range) else {
7281 // The edit overlaps with the previous edit. We can't apply both
73- // without conflicts. Apply the one that's listed first and drop the
74- // later edit.
75- return nil
82+ // without conflicts. Drop this one by swapping it for a no-op
83+ // edit.
84+ edits [ i] = SourceEdit ( )
85+ continue
7686 }
7787
7888 // If the remaining edit starts after or at the end of the edit that we just applied,
@@ -82,10 +92,8 @@ public enum FixItApplier {
8292 let startPosition = AbsolutePosition ( utf8Offset: remainingEdit. startUtf8Offset + shift)
8393 let endPosition = AbsolutePosition ( utf8Offset: remainingEdit. endUtf8Offset + shift)
8494
85- return SourceEdit ( range: startPosition..< endPosition, replacement: remainingEdit. replacement)
95+ edits [ i ] = SourceEdit ( range: startPosition..< endPosition, replacement: remainingEdit. replacement)
8696 }
87-
88- return remainingEdit
8997 }
9098 }
9199
@@ -101,4 +109,16 @@ private extension SourceEdit {
101109 var endUtf8Offset : Int {
102110 return range. upperBound. utf8Offset
103111 }
112+
113+ var isEmpty : Bool {
114+ self . range. isEmpty && self . replacement. isEmpty
115+ }
116+
117+ init ( ) {
118+ self = SourceEdit (
119+ range: AbsolutePosition ( utf8Offset: 0 ) ..< AbsolutePosition ( utf8Offset: 0 ) ,
120+ replacement: [ ]
121+ )
122+ precondition ( self . isEmpty)
123+ }
104124}
0 commit comments