@@ -46,12 +46,12 @@ public enum FixItApplier {
46
46
return self . apply ( edits: edits, to: tree)
47
47
}
48
48
49
- /// Apply the given edits to the syntax tree.
49
+ /// Applies the given edits to the given syntax tree.
50
50
///
51
51
/// - 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.
55
55
public static func apply(
56
56
edits: [ SourceEdit ] ,
57
57
to tree: some SyntaxProtocol
@@ -62,17 +62,27 @@ public enum FixItApplier {
62
62
while let edit = edits. first {
63
63
edits = Array ( edits. dropFirst ( ) )
64
64
65
+ // Empty edits do nothing.
66
+ guard !edit. isEmpty else {
67
+ continue
68
+ }
69
+
65
70
let startIndex = source. utf8. index ( source. utf8. startIndex, offsetBy: edit. startUtf8Offset)
66
71
let endIndex = source. utf8. index ( source. utf8. startIndex, offsetBy: edit. endUtf8Offset)
67
72
68
73
source. replaceSubrange ( startIndex..< endIndex, with: edit. replacement)
69
74
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 {
72
81
// 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
76
86
}
77
87
78
88
// If the remaining edit starts after or at the end of the edit that we just applied,
@@ -82,10 +92,8 @@ public enum FixItApplier {
82
92
let startPosition = AbsolutePosition ( utf8Offset: remainingEdit. startUtf8Offset + shift)
83
93
let endPosition = AbsolutePosition ( utf8Offset: remainingEdit. endUtf8Offset + shift)
84
94
85
- return SourceEdit ( range: startPosition..< endPosition, replacement: remainingEdit. replacement)
95
+ edits [ i ] = SourceEdit ( range: startPosition..< endPosition, replacement: remainingEdit. replacement)
86
96
}
87
-
88
- return remainingEdit
89
97
}
90
98
}
91
99
@@ -101,4 +109,16 @@ private extension SourceEdit {
101
109
var endUtf8Offset : Int {
102
110
return range. upperBound. utf8Offset
103
111
}
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
+ }
104
124
}
0 commit comments