mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-30 19:49:52 +00:00
Remove salsa::report_untracked_read when finding the dynamic module resolution paths (#12509)
This commit is contained in:
parent
e18b4e42d3
commit
2f54d05d97
7 changed files with 242 additions and 67 deletions
125
crates/ruff_db/src/files/file_root.rs
Normal file
125
crates/ruff_db/src/files/file_root.rs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
use std::fmt::Formatter;
|
||||
|
||||
use path_slash::PathExt;
|
||||
|
||||
use crate::file_revision::FileRevision;
|
||||
use crate::system::{SystemPath, SystemPathBuf};
|
||||
use crate::Db;
|
||||
|
||||
/// A root path for files tracked by the database.
|
||||
///
|
||||
/// We currently create roots for:
|
||||
/// * static module resolution paths
|
||||
/// * the workspace root
|
||||
///
|
||||
/// The main usage of file roots is to determine a file's durability. But it can also be used
|
||||
/// to make a salsa query dependent on whether a file in a root has changed without writing any
|
||||
/// manual invalidation logic.
|
||||
#[salsa::input]
|
||||
pub struct FileRoot {
|
||||
/// The path of a root is guaranteed to never change.
|
||||
#[return_ref]
|
||||
path_buf: SystemPathBuf,
|
||||
|
||||
/// The kind of the root at the time of its creation.
|
||||
kind_at_time_of_creation: FileRootKind,
|
||||
|
||||
/// A revision that changes when the contents of the source root change.
|
||||
///
|
||||
/// The revision changes when a new file was added, removed, or changed inside this source root.
|
||||
pub revision: FileRevision,
|
||||
}
|
||||
|
||||
impl FileRoot {
|
||||
pub fn path(self, db: &dyn Db) -> &SystemPath {
|
||||
self.path_buf(db)
|
||||
}
|
||||
|
||||
pub fn durability(self, db: &dyn Db) -> salsa::Durability {
|
||||
match self.kind_at_time_of_creation(db) {
|
||||
FileRootKind::Workspace => salsa::Durability::LOW,
|
||||
FileRootKind::LibrarySearchPath => salsa::Durability::HIGH,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FileRootKind {
|
||||
/// The root of a workspace.
|
||||
Workspace,
|
||||
|
||||
/// A non-workspace module resolution search path.
|
||||
LibrarySearchPath,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct FileRoots {
|
||||
by_path: matchit::Router<FileRoot>,
|
||||
roots: Vec<FileRoot>,
|
||||
}
|
||||
|
||||
impl FileRoots {
|
||||
/// Tries to add a new root for `path` and returns the root.
|
||||
///
|
||||
/// The root isn't added nor is the file root's kind updated if a root for `path` already exists.
|
||||
pub(super) fn try_add(
|
||||
&mut self,
|
||||
db: &dyn Db,
|
||||
path: SystemPathBuf,
|
||||
kind: FileRootKind,
|
||||
) -> FileRoot {
|
||||
// SAFETY: Guaranteed to succeed because `path` is a UTF-8 that only contains Unicode characters.
|
||||
let normalized_path = path.as_std_path().to_slash().unwrap();
|
||||
|
||||
if let Ok(existing) = self.by_path.at(&normalized_path) {
|
||||
// Only if it is an exact match
|
||||
if existing.value.path(db) == &*path {
|
||||
return *existing.value;
|
||||
}
|
||||
}
|
||||
|
||||
// normalize the path to use `/` separators and escape the '{' and '}' characters,
|
||||
// which matchit uses for routing parameters
|
||||
let mut route = normalized_path.replace('{', "{{").replace('}', "}}");
|
||||
|
||||
// Insert a new source root
|
||||
let root = FileRoot::new(db, path, kind, FileRevision::now());
|
||||
|
||||
// Insert a path that matches the root itself
|
||||
self.by_path.insert(route.clone(), root).unwrap();
|
||||
|
||||
// Insert a path that matches all subdirectories and files
|
||||
route.push_str("/{*filepath}");
|
||||
|
||||
self.by_path.insert(route, root).unwrap();
|
||||
self.roots.push(root);
|
||||
|
||||
root
|
||||
}
|
||||
|
||||
/// Returns the closest root for `path` or `None` if no root contains `path`.
|
||||
pub(super) fn at(&self, path: &SystemPath) -> Option<FileRoot> {
|
||||
// SAFETY: Guaranteed to succeed because `path` is a UTF-8 that only contains Unicode characters.
|
||||
let normalized_path = path.as_std_path().to_slash().unwrap();
|
||||
dbg!(&normalized_path);
|
||||
dbg!(&self.roots);
|
||||
let entry = self.by_path.at(&normalized_path).ok()?;
|
||||
Some(*entry.value)
|
||||
}
|
||||
|
||||
pub(super) fn all(&self) -> impl Iterator<Item = FileRoot> + '_ {
|
||||
self.roots.iter().copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for FileRoots {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("FileRoots").field(&self.roots).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FileRoots {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.roots.eq(&other.roots)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue