mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Track hashes for file contents
This commit is contained in:
parent
580b8dab1a
commit
793396c624
2 changed files with 28 additions and 12 deletions
|
@ -22,6 +22,10 @@ pub fn is_ci() -> bool {
|
||||||
option_env!("CI").is_some()
|
option_env!("CI").is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hash_once<Hasher: std::hash::Hasher + Default>(thing: impl std::hash::Hash) -> u64 {
|
||||||
|
std::hash::BuildHasher::hash_one(&std::hash::BuildHasherDefault::<Hasher>::default(), thing)
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::print_stderr)]
|
#[allow(clippy::print_stderr)]
|
||||||
pub fn timeit(label: &'static str) -> impl Drop {
|
pub fn timeit(label: &'static str) -> impl Drop {
|
||||||
|
|
|
@ -56,6 +56,8 @@ pub use crate::{
|
||||||
};
|
};
|
||||||
pub use paths::{AbsPath, AbsPathBuf};
|
pub use paths::{AbsPath, AbsPathBuf};
|
||||||
|
|
||||||
|
use rustc_hash::FxHasher;
|
||||||
|
use stdx::hash_once;
|
||||||
use tracing::{span, Level};
|
use tracing::{span, Level};
|
||||||
|
|
||||||
/// Handle to a file in [`Vfs`]
|
/// Handle to a file in [`Vfs`]
|
||||||
|
@ -106,7 +108,7 @@ pub enum FileState {
|
||||||
/// The file has been created this cycle.
|
/// The file has been created this cycle.
|
||||||
Created,
|
Created,
|
||||||
/// The file exists.
|
/// The file exists.
|
||||||
Exists,
|
Exists(u64),
|
||||||
/// The file is deleted.
|
/// The file is deleted.
|
||||||
Deleted,
|
Deleted,
|
||||||
}
|
}
|
||||||
|
@ -139,13 +141,13 @@ impl ChangedFile {
|
||||||
|
|
||||||
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
|
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
|
||||||
pub fn is_modified(&self) -> bool {
|
pub fn is_modified(&self) -> bool {
|
||||||
matches!(self.change, Change::Modify(_))
|
matches!(self.change, Change::Modify(_, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> ChangeKind {
|
pub fn kind(&self) -> ChangeKind {
|
||||||
match self.change {
|
match self.change {
|
||||||
Change::Create(_) => ChangeKind::Create,
|
Change::Create(_) => ChangeKind::Create,
|
||||||
Change::Modify(_) => ChangeKind::Modify,
|
Change::Modify(_, _) => ChangeKind::Modify,
|
||||||
Change::Delete => ChangeKind::Delete,
|
Change::Delete => ChangeKind::Delete,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +159,7 @@ pub enum Change {
|
||||||
/// The file was (re-)created
|
/// The file was (re-)created
|
||||||
Create(Vec<u8>),
|
Create(Vec<u8>),
|
||||||
/// The file was modified
|
/// The file was modified
|
||||||
Modify(Vec<u8>),
|
Modify(Vec<u8>, u64),
|
||||||
/// The file was deleted
|
/// The file was deleted
|
||||||
Delete,
|
Delete,
|
||||||
}
|
}
|
||||||
|
@ -178,7 +180,7 @@ impl Vfs {
|
||||||
pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
|
pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
|
||||||
self.interner
|
self.interner
|
||||||
.get(path)
|
.get(path)
|
||||||
.filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
|
.filter(|&it| matches!(self.get(it), FileState::Exists(_) | FileState::Created))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// File path corresponding to the given `file_id`.
|
/// File path corresponding to the given `file_id`.
|
||||||
|
@ -197,7 +199,7 @@ impl Vfs {
|
||||||
(0..self.data.len())
|
(0..self.data.len())
|
||||||
.map(|it| FileId(it as u32))
|
.map(|it| FileId(it as u32))
|
||||||
.filter(move |&file_id| {
|
.filter(move |&file_id| {
|
||||||
matches!(self.get(file_id), FileState::Exists | FileState::Created)
|
matches!(self.get(file_id), FileState::Exists(_) | FileState::Created)
|
||||||
})
|
})
|
||||||
.map(move |file_id| {
|
.map(move |file_id| {
|
||||||
let path = self.interner.lookup(file_id);
|
let path = self.interner.lookup(file_id);
|
||||||
|
@ -218,8 +220,18 @@ impl Vfs {
|
||||||
let change_kind = match (state, contents) {
|
let change_kind = match (state, contents) {
|
||||||
(FileState::Deleted, None) => return false,
|
(FileState::Deleted, None) => return false,
|
||||||
(FileState::Deleted, Some(v)) => Change::Create(v),
|
(FileState::Deleted, Some(v)) => Change::Create(v),
|
||||||
(FileState::Exists | FileState::Created, None) => Change::Delete,
|
(FileState::Exists(_) | FileState::Created, None) => Change::Delete,
|
||||||
(FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
|
(FileState::Created, Some(v)) => {
|
||||||
|
let hash = hash_once::<FxHasher>(&*v);
|
||||||
|
Change::Modify(v, hash)
|
||||||
|
}
|
||||||
|
(FileState::Exists(hash), Some(v)) => {
|
||||||
|
let new_hash = hash_once::<FxHasher>(&*v);
|
||||||
|
if new_hash == hash {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Change::Modify(v, new_hash)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.data[file_id.0 as usize] = match change_kind {
|
self.data[file_id.0 as usize] = match change_kind {
|
||||||
Change::Create(_) => {
|
Change::Create(_) => {
|
||||||
|
@ -228,8 +240,8 @@ impl Vfs {
|
||||||
}
|
}
|
||||||
// If the file got created this cycle, make sure we keep it that way even
|
// If the file got created this cycle, make sure we keep it that way even
|
||||||
// if a modify comes in
|
// if a modify comes in
|
||||||
Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
|
Change::Modify(_, _) if matches!(state, FileState::Created) => FileState::Created,
|
||||||
Change::Modify(_) => FileState::Exists,
|
Change::Modify(_, hash) => FileState::Exists(hash),
|
||||||
Change::Delete => FileState::Deleted,
|
Change::Delete => FileState::Deleted,
|
||||||
};
|
};
|
||||||
let changed_file = ChangedFile { file_id, change: change_kind };
|
let changed_file = ChangedFile { file_id, change: change_kind };
|
||||||
|
@ -243,7 +255,7 @@ impl Vfs {
|
||||||
for file_id in self.created_this_cycle.drain(..) {
|
for file_id in self.created_this_cycle.drain(..) {
|
||||||
if self.data[file_id.0 as usize] == FileState::Created {
|
if self.data[file_id.0 as usize] == FileState::Created {
|
||||||
// downgrade the file from `Created` to `Exists` as the cycle is done
|
// downgrade the file from `Created` to `Exists` as the cycle is done
|
||||||
self.data[file_id.0 as usize] = FileState::Exists;
|
self.data[file_id.0 as usize] = FileState::Exists(todo!());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mem::take(&mut self.changes)
|
mem::take(&mut self.changes)
|
||||||
|
@ -251,7 +263,7 @@ impl Vfs {
|
||||||
|
|
||||||
/// Provides a panic-less way to verify file_id validity.
|
/// Provides a panic-less way to verify file_id validity.
|
||||||
pub fn exists(&self, file_id: FileId) -> bool {
|
pub fn exists(&self, file_id: FileId) -> bool {
|
||||||
matches!(self.get(file_id), FileState::Exists | FileState::Created)
|
matches!(self.get(file_id), FileState::Exists(_) | FileState::Created)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the id associated with `path`
|
/// Returns the id associated with `path`
|
||||||
|
|
Loading…
Reference in a new issue