mirror of
https://github.com/astral-sh/ruff
synced 2026-01-22 22:10:48 -05:00
## Summary This PR extends version-related syntax error detection to red-knot. The main changes here are: 1. Passing `ParseOptions` specifying a `PythonVersion` to parser calls 2. Adding a `python_version` method to the `Db` trait to make this possible 3. Converting `UnsupportedSyntaxError`s to `Diagnostic`s 4. Updating existing mdtests to avoid unrelated syntax errors My initial draft of (1) and (2) in #16090 instead tried passing a `PythonVersion` down to every parser call, but @MichaReiser suggested the `Db` approach instead [here](https://github.com/astral-sh/ruff/pull/16090#discussion_r1969198407), and I think it turned out much nicer. All of the new `python_version` methods look like this: ```rust fn python_version(&self) -> ruff_python_ast::PythonVersion { Program::get(self).python_version(self) } ``` with the exception of the `TestDb` in `ruff_db`, which hard-codes `PythonVersion::latest()`. ## Test Plan Existing mdtests, plus a new mdtest to see at least one of the new diagnostics.
138 lines
3.8 KiB
Rust
138 lines
3.8 KiB
Rust
use std::hash::BuildHasherDefault;
|
|
|
|
use ruff_python_ast::PythonVersion;
|
|
use rustc_hash::FxHasher;
|
|
|
|
use crate::files::Files;
|
|
use crate::system::System;
|
|
use crate::vendored::VendoredFileSystem;
|
|
|
|
pub mod diagnostic;
|
|
pub mod display;
|
|
pub mod file_revision;
|
|
pub mod files;
|
|
pub mod panic;
|
|
pub mod parsed;
|
|
pub mod source;
|
|
pub mod system;
|
|
#[cfg(feature = "testing")]
|
|
pub mod testing;
|
|
pub mod vendored;
|
|
|
|
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
|
pub type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
|
|
|
|
/// Most basic database that gives access to files, the host system, source code, and parsed AST.
|
|
#[salsa::db]
|
|
pub trait Db: salsa::Database {
|
|
fn vendored(&self) -> &VendoredFileSystem;
|
|
fn system(&self) -> &dyn System;
|
|
fn files(&self) -> &Files;
|
|
fn python_version(&self) -> PythonVersion;
|
|
}
|
|
|
|
/// Trait for upcasting a reference to a base trait object.
|
|
pub trait Upcast<T: ?Sized> {
|
|
fn upcast(&self) -> &T;
|
|
fn upcast_mut(&mut self) -> &mut T;
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::sync::Arc;
|
|
|
|
use crate::files::Files;
|
|
use crate::system::TestSystem;
|
|
use crate::system::{DbWithTestSystem, System};
|
|
use crate::vendored::VendoredFileSystem;
|
|
use crate::Db;
|
|
|
|
/// Database that can be used for testing.
|
|
///
|
|
/// Uses an in memory filesystem and it stubs out the vendored files by default.
|
|
#[salsa::db]
|
|
#[derive(Default, Clone)]
|
|
pub(crate) struct TestDb {
|
|
storage: salsa::Storage<Self>,
|
|
files: Files,
|
|
system: TestSystem,
|
|
vendored: VendoredFileSystem,
|
|
events: Arc<std::sync::Mutex<Vec<salsa::Event>>>,
|
|
}
|
|
|
|
impl TestDb {
|
|
pub(crate) fn new() -> Self {
|
|
Self {
|
|
storage: salsa::Storage::default(),
|
|
system: TestSystem::default(),
|
|
vendored: VendoredFileSystem::default(),
|
|
events: std::sync::Arc::default(),
|
|
files: Files::default(),
|
|
}
|
|
}
|
|
|
|
/// Empties the internal store of salsa events that have been emitted,
|
|
/// and returns them as a `Vec` (equivalent to [`std::mem::take`]).
|
|
///
|
|
/// ## Panics
|
|
/// If there are pending database snapshots.
|
|
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
|
let inner = Arc::get_mut(&mut self.events)
|
|
.expect("expected no pending salsa database snapshots.");
|
|
|
|
std::mem::take(inner.get_mut().unwrap())
|
|
}
|
|
|
|
/// Clears the emitted salsa events.
|
|
///
|
|
/// ## Panics
|
|
/// If there are pending database snapshots.
|
|
pub(crate) fn clear_salsa_events(&mut self) {
|
|
self.take_salsa_events();
|
|
}
|
|
|
|
pub(crate) fn with_vendored(&mut self, vendored_file_system: VendoredFileSystem) {
|
|
self.vendored = vendored_file_system;
|
|
}
|
|
}
|
|
|
|
#[salsa::db]
|
|
impl Db 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) -> ruff_python_ast::PythonVersion {
|
|
ruff_python_ast::PythonVersion::latest()
|
|
}
|
|
}
|
|
|
|
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 salsa::Database for TestDb {
|
|
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
|
let event = event();
|
|
tracing::trace!("event: {:?}", event);
|
|
let mut events = self.events.lock().unwrap();
|
|
events.push(event);
|
|
}
|
|
}
|
|
}
|