mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-20 04:29:47 +00:00
Introduce a ruff_diagnostics crate (#3409)
## Summary This PR moves `Diagnostic`, `DiagnosticKind`, and `Fix` into their own crate, which will enable us to further split up Ruff, since sub-linter crates (which need to implement functions that return `Diagnostic`) can now depend on `ruff_diagnostics` rather than Ruff.
This commit is contained in:
parent
08ec11a31e
commit
024caca233
349 changed files with 758 additions and 1003 deletions
52
crates/ruff_diagnostics/src/diagnostic.rs
Normal file
52
crates/ruff_diagnostics/src/diagnostic.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use rustpython_parser::ast::Location;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::fix::Fix;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct DiagnosticKind {
|
||||
/// The identifier of the diagnostic, used to align the diagnostic with a rule.
|
||||
pub name: String,
|
||||
/// The message body to display to the user, to explain the diagnostic.
|
||||
pub body: String,
|
||||
/// The message to display to the user, to explain the suggested fix.
|
||||
pub suggestion: Option<String>,
|
||||
/// Whether the diagnostic is automatically fixable.
|
||||
pub fixable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Diagnostic {
|
||||
pub kind: DiagnosticKind,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
pub fix: Option<Fix>,
|
||||
pub parent: Option<Location>,
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn new<K: Into<DiagnosticKind>>(kind: K, range: Range) -> Self {
|
||||
Self {
|
||||
kind: kind.into(),
|
||||
location: range.location,
|
||||
end_location: range.end_location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn amend(&mut self, fix: Fix) -> &mut Self {
|
||||
self.fix = Some(fix);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parent(&mut self, parent: Location) -> &mut Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
}
|
||||
41
crates/ruff_diagnostics/src/fix.rs
Normal file
41
crates/ruff_diagnostics/src/fix.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
use rustpython_parser::ast::Location;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Fix {
|
||||
pub content: String,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
}
|
||||
|
||||
impl Fix {
|
||||
pub const fn deletion(start: Location, end: Location) -> Self {
|
||||
Self {
|
||||
content: String::new(),
|
||||
location: start,
|
||||
end_location: end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replacement(content: String, start: Location, end: Location) -> Self {
|
||||
debug_assert!(!content.is_empty(), "Prefer `Fix::deletion`");
|
||||
|
||||
Self {
|
||||
content,
|
||||
location: start,
|
||||
end_location: end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insertion(content: String, at: Location) -> Self {
|
||||
debug_assert!(!content.is_empty(), "Insert content is empty");
|
||||
|
||||
Self {
|
||||
content,
|
||||
location: at,
|
||||
end_location: at,
|
||||
}
|
||||
}
|
||||
}
|
||||
7
crates/ruff_diagnostics/src/lib.rs
Normal file
7
crates/ruff_diagnostics/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
pub use diagnostic::{Diagnostic, DiagnosticKind};
|
||||
pub use fix::Fix;
|
||||
pub use violation::{AlwaysAutofixableViolation, AutofixKind, Availability, Violation};
|
||||
|
||||
mod diagnostic;
|
||||
mod fix;
|
||||
mod violation;
|
||||
80
crates/ruff_diagnostics/src/violation.rs
Normal file
80
crates/ruff_diagnostics/src/violation.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub enum Availability {
|
||||
Sometimes,
|
||||
Always,
|
||||
}
|
||||
|
||||
pub struct AutofixKind {
|
||||
pub available: Availability,
|
||||
}
|
||||
|
||||
impl AutofixKind {
|
||||
pub const fn new(available: Availability) -> Self {
|
||||
Self { available }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Violation: Debug + PartialEq + Eq {
|
||||
/// `None` in the case an autofix is never available or otherwise Some
|
||||
/// [`AutofixKind`] describing the available autofix.
|
||||
const AUTOFIX: Option<AutofixKind> = None;
|
||||
|
||||
/// The message used to describe the violation.
|
||||
fn message(&self) -> String;
|
||||
|
||||
/// The explanation used in documentation and elsewhere.
|
||||
fn explanation() -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// If autofix is (potentially) available for this violation returns another
|
||||
/// function that in turn can be used to obtain a string describing the
|
||||
/// autofix.
|
||||
fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the format strings used by [`message`](Violation::message).
|
||||
fn message_formats() -> &'static [&'static str];
|
||||
}
|
||||
|
||||
/// This trait exists just to make implementing the [`Violation`] trait more
|
||||
/// convenient for violations that can always be autofixed.
|
||||
pub trait AlwaysAutofixableViolation: Debug + PartialEq + Eq {
|
||||
/// The message used to describe the violation.
|
||||
fn message(&self) -> String;
|
||||
|
||||
/// The explanation used in documentation and elsewhere.
|
||||
fn explanation() -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// The title displayed for the available autofix.
|
||||
fn autofix_title(&self) -> String;
|
||||
|
||||
/// Returns the format strings used by
|
||||
/// [`message`](AlwaysAutofixableViolation::message).
|
||||
fn message_formats() -> &'static [&'static str];
|
||||
}
|
||||
|
||||
/// A blanket implementation.
|
||||
impl<VA: AlwaysAutofixableViolation> Violation for VA {
|
||||
const AUTOFIX: Option<AutofixKind> = Some(AutofixKind::new(Availability::Always));
|
||||
|
||||
fn message(&self) -> String {
|
||||
<Self as AlwaysAutofixableViolation>::message(self)
|
||||
}
|
||||
|
||||
fn explanation() -> Option<&'static str> {
|
||||
<Self as AlwaysAutofixableViolation>::explanation()
|
||||
}
|
||||
|
||||
fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {
|
||||
Some(Self::autofix_title)
|
||||
}
|
||||
|
||||
fn message_formats() -> &'static [&'static str] {
|
||||
<Self as AlwaysAutofixableViolation>::message_formats()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue