mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
202 lines
5.7 KiB
Rust
202 lines
5.7 KiB
Rust
use crate::lint::{LintRegistry, RuleSelection};
|
|
use ruff_db::files::File;
|
|
use ruff_db::{Db as SourceDb, Upcast};
|
|
|
|
/// Database giving access to semantic information about a Python program.
|
|
#[salsa::db]
|
|
pub trait Db: SourceDb + Upcast<dyn SourceDb> {
|
|
fn is_file_open(&self, file: File) -> bool;
|
|
|
|
fn rule_selection(&self) -> &RuleSelection;
|
|
|
|
fn lint_registry(&self) -> &LintRegistry;
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub(crate) mod tests {
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use crate::program::{Program, SearchPathSettings};
|
|
use crate::{
|
|
ProgramSettings, PythonPlatform, PythonVersionSource, PythonVersionWithSource,
|
|
default_lint_registry,
|
|
};
|
|
|
|
use super::Db;
|
|
use crate::lint::{LintRegistry, RuleSelection};
|
|
use anyhow::Context;
|
|
use ruff_db::files::{File, Files};
|
|
use ruff_db::system::{
|
|
DbWithTestSystem, DbWithWritableSystem as _, System, SystemPath, SystemPathBuf, TestSystem,
|
|
};
|
|
use ruff_db::vendored::VendoredFileSystem;
|
|
use ruff_db::{Db as SourceDb, Upcast};
|
|
use ruff_python_ast::PythonVersion;
|
|
|
|
type Events = Arc<Mutex<Vec<salsa::Event>>>;
|
|
|
|
#[salsa::db]
|
|
#[derive(Clone)]
|
|
pub(crate) struct TestDb {
|
|
storage: salsa::Storage<Self>,
|
|
files: Files,
|
|
system: TestSystem,
|
|
vendored: VendoredFileSystem,
|
|
events: Events,
|
|
rule_selection: Arc<RuleSelection>,
|
|
}
|
|
|
|
impl TestDb {
|
|
pub(crate) fn new() -> Self {
|
|
let events = Events::default();
|
|
Self {
|
|
storage: salsa::Storage::new(Some(Box::new({
|
|
let events = events.clone();
|
|
move |event| {
|
|
tracing::trace!("event: {event:?}");
|
|
let mut events = events.lock().unwrap();
|
|
events.push(event);
|
|
}
|
|
}))),
|
|
system: TestSystem::default(),
|
|
vendored: ty_vendored::file_system().clone(),
|
|
events,
|
|
files: Files::default(),
|
|
rule_selection: Arc::new(RuleSelection::from_registry(default_lint_registry())),
|
|
}
|
|
}
|
|
|
|
/// Takes the salsa events.
|
|
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
|
let mut events = self.events.lock().unwrap();
|
|
|
|
std::mem::take(&mut *events)
|
|
}
|
|
|
|
/// Clears the salsa events.
|
|
///
|
|
/// ## Panics
|
|
/// If there are any pending salsa snapshots.
|
|
pub(crate) fn clear_salsa_events(&mut self) {
|
|
self.take_salsa_events();
|
|
}
|
|
}
|
|
|
|
impl DbWithTestSystem for TestDb {
|
|
fn test_system(&self) -> &TestSystem {
|
|
&self.system
|
|
}
|
|
|
|
fn test_system_mut(&mut self) -> &mut TestSystem {
|
|
&mut self.system
|
|
}
|
|
}
|
|
|
|
#[salsa::db]
|
|
impl SourceDb for TestDb {
|
|
fn vendored(&self) -> &VendoredFileSystem {
|
|
&self.vendored
|
|
}
|
|
|
|
fn system(&self) -> &dyn System {
|
|
&self.system
|
|
}
|
|
|
|
fn files(&self) -> &Files {
|
|
&self.files
|
|
}
|
|
|
|
fn python_version(&self) -> PythonVersion {
|
|
Program::get(self).python_version(self)
|
|
}
|
|
}
|
|
|
|
impl Upcast<dyn SourceDb> for TestDb {
|
|
fn upcast(&self) -> &(dyn SourceDb + 'static) {
|
|
self
|
|
}
|
|
fn upcast_mut(&mut self) -> &mut (dyn SourceDb + 'static) {
|
|
self
|
|
}
|
|
}
|
|
|
|
#[salsa::db]
|
|
impl Db for TestDb {
|
|
fn is_file_open(&self, file: File) -> bool {
|
|
!file.path(self).is_vendored_path()
|
|
}
|
|
|
|
fn rule_selection(&self) -> &RuleSelection {
|
|
&self.rule_selection
|
|
}
|
|
|
|
fn lint_registry(&self) -> &LintRegistry {
|
|
default_lint_registry()
|
|
}
|
|
}
|
|
|
|
#[salsa::db]
|
|
impl salsa::Database for TestDb {}
|
|
|
|
pub(crate) struct TestDbBuilder<'a> {
|
|
/// Target Python version
|
|
python_version: PythonVersion,
|
|
/// Target Python platform
|
|
python_platform: PythonPlatform,
|
|
/// Path and content pairs for files that should be present
|
|
files: Vec<(&'a str, &'a str)>,
|
|
}
|
|
|
|
impl<'a> TestDbBuilder<'a> {
|
|
pub(crate) fn new() -> Self {
|
|
Self {
|
|
python_version: PythonVersion::default(),
|
|
python_platform: PythonPlatform::default(),
|
|
files: vec![],
|
|
}
|
|
}
|
|
|
|
pub(crate) fn with_python_version(mut self, version: PythonVersion) -> Self {
|
|
self.python_version = version;
|
|
self
|
|
}
|
|
|
|
pub(crate) fn with_file(
|
|
mut self,
|
|
path: &'a (impl AsRef<SystemPath> + ?Sized),
|
|
content: &'a str,
|
|
) -> Self {
|
|
self.files.push((path.as_ref().as_str(), content));
|
|
self
|
|
}
|
|
|
|
pub(crate) fn build(self) -> anyhow::Result<TestDb> {
|
|
let mut db = TestDb::new();
|
|
|
|
let src_root = SystemPathBuf::from("/src");
|
|
db.memory_file_system().create_directory_all(&src_root)?;
|
|
|
|
db.write_files(self.files)
|
|
.context("Failed to write test files")?;
|
|
|
|
Program::from_settings(
|
|
&db,
|
|
ProgramSettings {
|
|
python_version: Some(PythonVersionWithSource {
|
|
version: self.python_version,
|
|
source: PythonVersionSource::default(),
|
|
}),
|
|
python_platform: self.python_platform,
|
|
search_paths: SearchPathSettings::new(vec![src_root]),
|
|
},
|
|
)
|
|
.context("Failed to configure Program settings")?;
|
|
|
|
Ok(db)
|
|
}
|
|
}
|
|
|
|
pub(crate) fn setup_db() -> TestDb {
|
|
TestDbBuilder::new().build().expect("valid TestDb setup")
|
|
}
|
|
}
|