mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-30 19:47:52 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			203 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::lint::{LintRegistry, RuleSelection};
 | |
| use ruff_db::Db as SourceDb;
 | |
| use ruff_db::files::File;
 | |
| 
 | |
| /// Database giving access to semantic information about a Python program.
 | |
| #[salsa::db]
 | |
| pub trait Db: SourceDb {
 | |
|     /// Returns `true` if the file should be checked.
 | |
|     fn should_check_file(&self, file: File) -> bool;
 | |
| 
 | |
|     /// Resolves the rule selection for a given file.
 | |
|     fn rule_selection(&self, file: File) -> &RuleSelection;
 | |
| 
 | |
|     fn lint_registry(&self) -> &LintRegistry;
 | |
| 
 | |
|     /// Whether ty is running with logging verbosity INFO or higher (`-v` or more).
 | |
|     fn verbose(&self) -> bool;
 | |
| }
 | |
| 
 | |
| #[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::Db as SourceDb;
 | |
|     use ruff_db::files::{File, Files};
 | |
|     use ruff_db::system::{
 | |
|         DbWithTestSystem, DbWithWritableSystem as _, System, SystemPath, SystemPathBuf, TestSystem,
 | |
|     };
 | |
|     use ruff_db::vendored::VendoredFileSystem;
 | |
|     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)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[salsa::db]
 | |
|     impl Db for TestDb {
 | |
|         fn should_check_file(&self, file: File) -> bool {
 | |
|             !file.path(self).is_vendored_path()
 | |
|         }
 | |
| 
 | |
|         fn rule_selection(&self, _file: File) -> &RuleSelection {
 | |
|             &self.rule_selection
 | |
|         }
 | |
| 
 | |
|         fn lint_registry(&self) -> &LintRegistry {
 | |
|             default_lint_registry()
 | |
|         }
 | |
| 
 | |
|         fn verbose(&self) -> bool {
 | |
|             false
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[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: PythonVersionWithSource {
 | |
|                         version: self.python_version,
 | |
|                         source: PythonVersionSource::default(),
 | |
|                     },
 | |
|                     python_platform: self.python_platform,
 | |
|                     search_paths: SearchPathSettings::new(vec![src_root])
 | |
|                         .to_search_paths(db.system(), db.vendored())
 | |
|                         .context("Invalid search path settings")?,
 | |
|                 },
 | |
|             );
 | |
| 
 | |
|             Ok(db)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn setup_db() -> TestDb {
 | |
|         TestDbBuilder::new().build().expect("valid TestDb setup")
 | |
|     }
 | |
| }
 | 
