Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 13770a2

Browse files
committed
Track hashes for file contents
1 parent 5fa2b06 commit 13770a2

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

src/tools/rust-analyzer/crates/stdx/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ pub fn is_ci() -> bool {
2222
option_env!("CI").is_some()
2323
}
2424

25+
pub fn hash_once<Hasher: std::hash::Hasher + Default>(thing: impl std::hash::Hash) -> u64 {
26+
std::hash::BuildHasher::hash_one(&std::hash::BuildHasherDefault::<Hasher>::default(), thing)
27+
}
28+
2529
#[must_use]
2630
#[allow(clippy::print_stderr)]
2731
pub fn timeit(label: &'static str) -> impl Drop {

src/tools/rust-analyzer/crates/vfs/src/lib.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ pub use crate::{
5656
};
5757
pub use paths::{AbsPath, AbsPathBuf};
5858

59+
use rustc_hash::FxHasher;
60+
use stdx::hash_once;
5961
use tracing::{span, Level};
6062

6163
/// Handle to a file in [`Vfs`]
@@ -106,7 +108,7 @@ pub enum FileState {
106108
/// The file has been created this cycle.
107109
Created,
108110
/// The file exists.
109-
Exists,
111+
Exists(u64),
110112
/// The file is deleted.
111113
Deleted,
112114
}
@@ -139,13 +141,13 @@ impl ChangedFile {
139141

140142
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
141143
pub fn is_modified(&self) -> bool {
142-
matches!(self.change, Change::Modify(_))
144+
matches!(self.change, Change::Modify(_, _))
143145
}
144146

145147
pub fn kind(&self) -> ChangeKind {
146148
match self.change {
147149
Change::Create(_) => ChangeKind::Create,
148-
Change::Modify(_) => ChangeKind::Modify,
150+
Change::Modify(_, _) => ChangeKind::Modify,
149151
Change::Delete => ChangeKind::Delete,
150152
}
151153
}
@@ -157,7 +159,7 @@ pub enum Change {
157159
/// The file was (re-)created
158160
Create(Vec<u8>),
159161
/// The file was modified
160-
Modify(Vec<u8>),
162+
Modify(Vec<u8>, u64),
161163
/// The file was deleted
162164
Delete,
163165
}
@@ -178,7 +180,7 @@ impl Vfs {
178180
pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
179181
self.interner
180182
.get(path)
181-
.filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
183+
.filter(|&it| matches!(self.get(it), FileState::Exists(_) | FileState::Created))
182184
}
183185

184186
/// File path corresponding to the given `file_id`.
@@ -197,7 +199,7 @@ impl Vfs {
197199
(0..self.data.len())
198200
.map(|it| FileId(it as u32))
199201
.filter(move |&file_id| {
200-
matches!(self.get(file_id), FileState::Exists | FileState::Created)
202+
matches!(self.get(file_id), FileState::Exists(_) | FileState::Created)
201203
})
202204
.map(move |file_id| {
203205
let path = self.interner.lookup(file_id);
@@ -218,8 +220,18 @@ impl Vfs {
218220
let change_kind = match (state, contents) {
219221
(FileState::Deleted, None) => return false,
220222
(FileState::Deleted, Some(v)) => Change::Create(v),
221-
(FileState::Exists | FileState::Created, None) => Change::Delete,
222-
(FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
223+
(FileState::Exists(_) | FileState::Created, None) => Change::Delete,
224+
(FileState::Created, Some(v)) => {
225+
let hash = hash_once::<FxHasher>(&*v);
226+
Change::Modify(v, hash)
227+
}
228+
(FileState::Exists(hash), Some(v)) => {
229+
let new_hash = hash_once::<FxHasher>(&*v);
230+
if new_hash == hash {
231+
return false;
232+
}
233+
Change::Modify(v, new_hash)
234+
}
223235
};
224236
self.data[file_id.0 as usize] = match change_kind {
225237
Change::Create(_) => {
@@ -228,8 +240,8 @@ impl Vfs {
228240
}
229241
// If the file got created this cycle, make sure we keep it that way even
230242
// if a modify comes in
231-
Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
232-
Change::Modify(_) => FileState::Exists,
243+
Change::Modify(_, _) if matches!(state, FileState::Created) => FileState::Created,
244+
Change::Modify(_, hash) => FileState::Exists(hash),
233245
Change::Delete => FileState::Deleted,
234246
};
235247
let changed_file = ChangedFile { file_id, change: change_kind };
@@ -243,15 +255,15 @@ impl Vfs {
243255
for file_id in self.created_this_cycle.drain(..) {
244256
if self.data[file_id.0 as usize] == FileState::Created {
245257
// downgrade the file from `Created` to `Exists` as the cycle is done
246-
self.data[file_id.0 as usize] = FileState::Exists;
258+
self.data[file_id.0 as usize] = FileState::Exists(todo!());
247259
}
248260
}
249261
mem::take(&mut self.changes)
250262
}
251263

252264
/// Provides a panic-less way to verify file_id validity.
253265
pub fn exists(&self, file_id: FileId) -> bool {
254-
matches!(self.get(file_id), FileState::Exists | FileState::Created)
266+
matches!(self.get(file_id), FileState::Exists(_) | FileState::Created)
255267
}
256268

257269
/// Returns the id associated with `path`

0 commit comments

Comments
 (0)