diff --git a/crates/ruff/src/rules/flake8_pyi/rules/type_comment_in_stub.rs b/crates/ruff/src/rules/flake8_pyi/rules/type_comment_in_stub.rs index cde4262ef2..79a2721363 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/type_comment_in_stub.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/type_comment_in_stub.rs @@ -3,33 +3,33 @@ use regex::Regex; use rustpython_parser::lexer::LexResult; use rustpython_parser::Tok; -use ruff_macros::{define_violation, derive_message_formats}; +use ruff_macros::{derive_message_formats, violation}; use crate::registry::Diagnostic; use crate::violation::Violation; use crate::Range; -define_violation!( - /// ## What it does - /// Checks for the use of type comments (e.g., `x = 1 # type: int`) in stub - /// files. - /// - /// ## Why is this bad? - /// Stub (`.pyi`) files should use type annotations directly, rather - /// than type comments, even if they're intended to support Python 2, since - /// stub files are not executed at runtime. The one exception is `# type: ignore`. - /// - /// ## Example - /// ```python - /// x = 1 # type: int - /// ``` - /// - /// Use instead: - /// ```python - /// x: int = 1 - /// ``` - pub struct TypeCommentInStub; -); +/// ## What it does +/// Checks for the use of type comments (e.g., `x = 1 # type: int`) in stub +/// files. +/// +/// ## Why is this bad? +/// Stub (`.pyi`) files should use type annotations directly, rather +/// than type comments, even if they're intended to support Python 2, since +/// stub files are not executed at runtime. The one exception is `# type: ignore`. +/// +/// ## Example +/// ```python +/// x = 1 # type: int +/// ``` +/// +/// Use instead: +/// ```python +/// x: int = 1 +/// ``` +#[violation] +pub struct TypeCommentInStub; + impl Violation for TypeCommentInStub { #[derive_message_formats] fn message(&self) -> String { diff --git a/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace.rs b/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace.rs index 048c8896cd..9d478d86f4 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::Location; use rustpython_parser::Tok; -use ruff_macros::{define_violation, derive_message_formats}; +use ruff_macros::{derive_message_formats, violation}; use crate::ast::types::Range; use crate::fix::Fix; @@ -13,11 +13,11 @@ use crate::rules::pycodestyle::helpers::{is_keyword_token, is_singleton_token}; use crate::violation::AlwaysAutofixableViolation; use crate::violation::Violation; -define_violation!( - pub struct MissingWhitespace { - pub token: String, - } -); +#[violation] +pub struct MissingWhitespace { + pub token: String, +} + impl AlwaysAutofixableViolation for MissingWhitespace { #[derive_message_formats] fn message(&self) -> String { diff --git a/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace_around_operator.rs b/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace_around_operator.rs index 25f34b39fb..8b8e7623f0 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace_around_operator.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/missing_whitespace_around_operator.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::Location; use rustpython_parser::Tok; -use ruff_macros::{define_violation, derive_message_formats}; +use ruff_macros::{derive_message_formats, violation}; use crate::registry::DiagnosticKind; use crate::rules::pycodestyle::helpers::{ @@ -13,9 +13,9 @@ use crate::rules::pycodestyle::helpers::{ use crate::violation::Violation; // E225 -define_violation!( - pub struct MissingWhitespaceAroundOperator; -); +#[violation] +pub struct MissingWhitespaceAroundOperator; + impl Violation for MissingWhitespaceAroundOperator { #[derive_message_formats] fn message(&self) -> String { @@ -24,9 +24,9 @@ impl Violation for MissingWhitespaceAroundOperator { } // E226 -define_violation!( - pub struct MissingWhitespaceAroundArithmeticOperator; -); +#[violation] +pub struct MissingWhitespaceAroundArithmeticOperator; + impl Violation for MissingWhitespaceAroundArithmeticOperator { #[derive_message_formats] fn message(&self) -> String { @@ -35,9 +35,9 @@ impl Violation for MissingWhitespaceAroundArithmeticOperator { } // E227 -define_violation!( - pub struct MissingWhitespaceAroundBitwiseOrShiftOperator; -); +#[violation] +pub struct MissingWhitespaceAroundBitwiseOrShiftOperator; + impl Violation for MissingWhitespaceAroundBitwiseOrShiftOperator { #[derive_message_formats] fn message(&self) -> String { @@ -46,9 +46,9 @@ impl Violation for MissingWhitespaceAroundBitwiseOrShiftOperator { } // E228 -define_violation!( - pub struct MissingWhitespaceAroundModuloOperator; -); +#[violation] +pub struct MissingWhitespaceAroundModuloOperator; + impl Violation for MissingWhitespaceAroundModuloOperator { #[derive_message_formats] fn message(&self) -> String { diff --git a/crates/ruff/src/rules/pycodestyle/rules/whitespace_before_parameters.rs b/crates/ruff/src/rules/pycodestyle/rules/whitespace_before_parameters.rs index ecc139dec0..999930c5ff 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/whitespace_before_parameters.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/whitespace_before_parameters.rs @@ -3,7 +3,7 @@ use rustpython_parser::ast::Location; use rustpython_parser::Tok; -use ruff_macros::{define_violation, derive_message_formats}; +use ruff_macros::{derive_message_formats, violation}; use crate::ast::types::Range; use crate::fix::Fix; @@ -11,11 +11,10 @@ use crate::registry::Diagnostic; use crate::rules::pycodestyle::helpers::{is_keyword_token, is_op_token, is_soft_keyword_token}; use crate::violation::AlwaysAutofixableViolation; -define_violation!( - pub struct WhitespaceBeforeParameters { - pub bracket: String, - } -); +#[violation] +pub struct WhitespaceBeforeParameters { + pub bracket: String, +} impl AlwaysAutofixableViolation for WhitespaceBeforeParameters { #[derive_message_formats] diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs index cc95808b2a..266b44f89a 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep604_isinstance.rs @@ -1,7 +1,9 @@ -use ruff_macros::{define_violation, derive_message_formats}; +use std::fmt; + use rustpython_parser::ast::{Expr, ExprKind, Location, Operator}; use serde::{Deserialize, Serialize}; -use std::fmt; + +use ruff_macros::{derive_message_formats, violation}; use crate::ast::helpers::unparse_expr; use crate::ast::types::Range; @@ -35,12 +37,12 @@ impl CallKind { } } -define_violation!( - // TODO: document referencing [PEP 604]: https://peps.python.org/pep-0604/ - pub struct IsinstanceWithTuple { - pub kind: CallKind, - } -); +// TODO: document referencing [PEP 604]: https://peps.python.org/pep-0604/ +#[violation] +pub struct IsinstanceWithTuple { + pub kind: CallKind, +} + impl AlwaysAutofixableViolation for IsinstanceWithTuple { #[derive_message_formats] fn message(&self) -> String { diff --git a/crates/ruff_macros/src/lib.rs b/crates/ruff_macros/src/lib.rs index 3d63e6eaae..8234653419 100644 --- a/crates/ruff_macros/src/lib.rs +++ b/crates/ruff_macros/src/lib.rs @@ -6,12 +6,12 @@ use syn::{parse_macro_input, DeriveInput, ItemFn, ItemStruct}; mod cache_key; mod config; -mod define_violation; mod derive_message_formats; mod map_codes; mod register_rules; mod rule_code_prefix; mod rule_namespace; +mod violation; #[proc_macro_derive(ConfigurationOptions, attributes(option, doc, option_group))] pub fn derive_config(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -38,19 +38,12 @@ pub fn register_rules(item: proc_macro::TokenStream) -> proc_macro::TokenStream register_rules::register_rules(&mapping).into() } -#[proc_macro] -pub fn define_violation(item: proc_macro::TokenStream) -> proc_macro::TokenStream { - let cloned = item.clone(); - let meta = parse_macro_input!(cloned as define_violation::LintMeta); - define_violation::define_violation(&item.into(), meta).into() -} - /// Adds an `explanation()` method from the doc comment and /// `#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]` #[proc_macro_attribute] pub fn violation(_attr: TokenStream, item: TokenStream) -> TokenStream { let violation = parse_macro_input!(item as ItemStruct); - define_violation::violation(&violation) + violation::violation(&violation) .unwrap_or_else(syn::Error::into_compile_error) .into() } diff --git a/crates/ruff_macros/src/define_violation.rs b/crates/ruff_macros/src/violation.rs similarity index 53% rename from crates/ruff_macros/src/define_violation.rs rename to crates/ruff_macros/src/violation.rs index 16eb7a3e4f..39b6602584 100644 --- a/crates/ruff_macros/src/define_violation.rs +++ b/crates/ruff_macros/src/violation.rs @@ -1,7 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Error, Ident, ItemStruct, Lit, LitStr, Meta, Result, Token}; +use syn::{Attribute, Error, ItemStruct, Lit, LitStr, Meta, Result}; fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { if let Meta::NameValue(name_value) = attr.parse_meta().ok()? { @@ -21,59 +20,6 @@ fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> None } -pub struct LintMeta { - explanation: String, - name: Ident, -} - -impl Parse for LintMeta { - fn parse(input: ParseStream) -> Result { - let attrs = input.call(Attribute::parse_outer)?; - - let mut explanation = String::new(); - for attr in &attrs { - if let Some(lit) = parse_attr(["doc"], attr) { - let value = lit.value(); - let line = value.strip_prefix(' ').unwrap_or(&value); - explanation.push_str(line); - explanation.push('\n'); - } else { - return Err(Error::new_spanned(attr, "unexpected attribute")); - } - } - - input.parse::()?; - input.parse::()?; - let name = input.parse()?; - - // Ignore the rest of the input. - input.parse::()?; - - Ok(Self { explanation, name }) - } -} - -pub fn define_violation(input: &TokenStream, meta: LintMeta) -> TokenStream { - let LintMeta { explanation, name } = meta; - if explanation.is_empty() { - quote! { - #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - #input - } - } else { - quote! { - #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] - #input - - impl #name { - pub fn explanation() -> Option<&'static str> { - Some(#explanation) - } - } - } - } -} - /// Collect all doc comment attributes into a string fn get_docs(attrs: &[Attribute]) -> Result { let mut explanation = String::new();