Skip to content

Commit 093de32

Browse files
committed
Auto merge of #13237 - Veykril:process-changes, r=Veykril
Amalgamate file changes for the same file ids in process_changes When receiving multiple change events for a single file id where the last change is a delete the server panics, as it tries to access the file contents of a deleted file. This occurs due to the VFS changes and the in memory file contents being updated immediately, while `process_changes` processes the events afterwards in sequence which no longer works as it will only observe the final file contents. By folding these events together, we will no longer try to process these intermediate changes, as they aren't relevant anyways. Potentially fixes #13236
2 parents bd8c5b6 + c3a6c96 commit 093de32

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

Diff for: crates/rust-analyzer/src/global_state.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,48 @@ impl GlobalState {
185185
let (change, changed_files) = {
186186
let mut change = Change::new();
187187
let (vfs, line_endings_map) = &mut *self.vfs.write();
188-
let changed_files = vfs.take_changes();
188+
let mut changed_files = vfs.take_changes();
189189
if changed_files.is_empty() {
190190
return false;
191191
}
192192

193+
// important: this needs to be a stable sort, the order between changes is relevant
194+
// for the same file ids
195+
changed_files.sort_by_key(|file| file.file_id);
196+
// We need to fix up the changed events a bit, if we have a create or modify for a file
197+
// id that is followed by a delete we actually no longer observe the file text from the
198+
// create or modify which may cause problems later on
199+
changed_files.dedup_by(|a, b| {
200+
use vfs::ChangeKind::*;
201+
202+
if a.file_id != b.file_id {
203+
return false;
204+
}
205+
206+
match (a.change_kind, b.change_kind) {
207+
// duplicate can be merged
208+
(Create, Create) | (Modify, Modify) | (Delete, Delete) => true,
209+
// just leave the create, modify is irrelevant
210+
(Create, Modify) => {
211+
std::mem::swap(a, b);
212+
true
213+
}
214+
// modify becomes irrelevant if the file is deleted
215+
(Modify, Delete) => true,
216+
// we should fully remove this occurrence,
217+
// but leaving just a delete works as well
218+
(Create, Delete) => true,
219+
// this is equivalent to a modify
220+
(Delete, Create) => {
221+
a.change_kind = Modify;
222+
true
223+
}
224+
// can't really occur
225+
(Modify, Create) => false,
226+
(Delete, Modify) => false,
227+
}
228+
});
229+
193230
for file in &changed_files {
194231
if let Some(path) = vfs.file_path(file.file_id).as_path() {
195232
let path = path.to_path_buf();

0 commit comments

Comments
 (0)