mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:48 +00:00
Move violations for pycodestyle rules to rules files (#2138)
This commit is contained in:
parent
4190f1045e
commit
708295f4c9
17 changed files with 329 additions and 317 deletions
|
@ -211,6 +211,7 @@ mod tests {
|
|||
use crate::ast::types::Range;
|
||||
use crate::noqa::{add_noqa_inner, NOQA_LINE_REGEX};
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::rules::AmbiguousVariableName;
|
||||
use crate::settings::hashable::HashableHashSet;
|
||||
use crate::source_code::LineEnding;
|
||||
use crate::violations;
|
||||
|
@ -264,7 +265,7 @@ mod tests {
|
|||
|
||||
let diagnostics = vec![
|
||||
Diagnostic::new(
|
||||
violations::AmbiguousVariableName("x".to_string()),
|
||||
AmbiguousVariableName("x".to_string()),
|
||||
Range::new(Location::new(1, 0), Location::new(1, 0)),
|
||||
),
|
||||
Diagnostic::new(
|
||||
|
@ -287,7 +288,7 @@ mod tests {
|
|||
|
||||
let diagnostics = vec![
|
||||
Diagnostic::new(
|
||||
violations::AmbiguousVariableName("x".to_string()),
|
||||
AmbiguousVariableName("x".to_string()),
|
||||
Range::new(Location::new(1, 0), Location::new(1, 0)),
|
||||
),
|
||||
Diagnostic::new(
|
||||
|
|
|
@ -13,26 +13,26 @@ use crate::{rules, violations};
|
|||
|
||||
ruff_macros::define_rule_mapping!(
|
||||
// pycodestyle errors
|
||||
E101 => violations::MixedSpacesAndTabs,
|
||||
E101 => rules::pycodestyle::rules::MixedSpacesAndTabs,
|
||||
E401 => violations::MultipleImportsOnOneLine,
|
||||
E402 => violations::ModuleImportNotAtTopOfFile,
|
||||
E501 => violations::LineTooLong,
|
||||
E711 => violations::NoneComparison,
|
||||
E712 => violations::TrueFalseComparison,
|
||||
E713 => violations::NotInTest,
|
||||
E714 => violations::NotIsTest,
|
||||
E721 => violations::TypeComparison,
|
||||
E722 => violations::DoNotUseBareExcept,
|
||||
E731 => violations::DoNotAssignLambda,
|
||||
E741 => violations::AmbiguousVariableName,
|
||||
E742 => violations::AmbiguousClassName,
|
||||
E743 => violations::AmbiguousFunctionName,
|
||||
E501 => rules::pycodestyle::rules::LineTooLong,
|
||||
E711 => rules::pycodestyle::rules::NoneComparison,
|
||||
E712 => rules::pycodestyle::rules::TrueFalseComparison,
|
||||
E713 => rules::pycodestyle::rules::NotInTest,
|
||||
E714 => rules::pycodestyle::rules::NotIsTest,
|
||||
E721 => rules::pycodestyle::rules::TypeComparison,
|
||||
E722 => rules::pycodestyle::rules::DoNotUseBareExcept,
|
||||
E731 => rules::pycodestyle::rules::DoNotAssignLambda,
|
||||
E741 => rules::pycodestyle::rules::AmbiguousVariableName,
|
||||
E742 => rules::pycodestyle::rules::AmbiguousClassName,
|
||||
E743 => rules::pycodestyle::rules::AmbiguousFunctionName,
|
||||
E902 => violations::IOError,
|
||||
E999 => violations::SyntaxError,
|
||||
// pycodestyle warnings
|
||||
W292 => violations::NoNewLineAtEndOfFile,
|
||||
W505 => violations::DocLineTooLong,
|
||||
W605 => violations::InvalidEscapeSequence,
|
||||
W292 => rules::pycodestyle::rules::NoNewLineAtEndOfFile,
|
||||
W505 => rules::pycodestyle::rules::DocLineTooLong,
|
||||
W605 => rules::pycodestyle::rules::InvalidEscapeSequence,
|
||||
// pyflakes
|
||||
F401 => violations::UnusedImport,
|
||||
F402 => violations::ImportShadowedByLoopVar,
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::is_ambiguous_name;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousClassName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousClassName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousClassName(name) = self;
|
||||
format!("Ambiguous class name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E742
|
||||
pub fn ambiguous_class_name<F>(name: &str, locate: F) -> Option<Diagnostic>
|
||||
|
@ -10,7 +24,7 @@ where
|
|||
{
|
||||
if is_ambiguous_name(name) {
|
||||
Some(Diagnostic::new(
|
||||
violations::AmbiguousClassName(name.to_string()),
|
||||
AmbiguousClassName(name.to_string()),
|
||||
locate(),
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::is_ambiguous_name;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousFunctionName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousFunctionName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousFunctionName(name) = self;
|
||||
format!("Ambiguous function name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E743
|
||||
pub fn ambiguous_function_name<F>(name: &str, locate: F) -> Option<Diagnostic>
|
||||
|
@ -10,7 +24,7 @@ where
|
|||
{
|
||||
if is_ambiguous_name(name) {
|
||||
Some(Diagnostic::new(
|
||||
violations::AmbiguousFunctionName(name.to_string()),
|
||||
AmbiguousFunctionName(name.to_string()),
|
||||
locate(),
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::is_ambiguous_name;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousVariableName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousVariableName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousVariableName(name) = self;
|
||||
format!("Ambiguous variable name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E741
|
||||
pub fn ambiguous_variable_name(name: &str, range: Range) -> Option<Diagnostic> {
|
||||
if is_ambiguous_name(name) {
|
||||
Some(Diagnostic::new(
|
||||
violations::AmbiguousVariableName(name.to_string()),
|
||||
AmbiguousVariableName(name.to_string()),
|
||||
range,
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Arguments, Location, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
|
@ -5,19 +6,33 @@ use crate::ast::helpers::{match_leading_content, match_trailing_content, unparse
|
|||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Stylist;
|
||||
use crate::violations;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
define_violation!(
|
||||
pub struct DoNotAssignLambda(pub String);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for DoNotAssignLambda {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not assign a `lambda` expression, use a `def`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let DoNotAssignLambda(name) = self;
|
||||
format!("Rewrite `{name}` as a `def`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) {
|
||||
if let ExprKind::Name { id, .. } = &target.node {
|
||||
if let ExprKind::Lambda { args, body } = &value.node {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::DoNotAssignLambda(id.to_string()),
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(DoNotAssignLambda(id.to_string()), Range::from_located(stmt));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
if !match_leading_content(stmt, checker.locator)
|
||||
&& !match_trailing_content(stmt, checker.locator)
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Excepthandler, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use crate::ast::helpers::except_range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Locator;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct DoNotUseBareExcept;
|
||||
);
|
||||
impl Violation for DoNotUseBareExcept {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not use bare `except`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E722
|
||||
pub fn do_not_use_bare_except(
|
||||
|
@ -19,7 +31,7 @@ pub fn do_not_use_bare_except(
|
|||
.any(|stmt| matches!(stmt.node, StmtKind::Raise { exc: None, .. }))
|
||||
{
|
||||
Some(Diagnostic::new(
|
||||
violations::DoNotUseBareExcept,
|
||||
DoNotUseBareExcept,
|
||||
except_range(handler, locator),
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::is_overlong;
|
||||
use crate::settings::Settings;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct DocLineTooLong(pub usize, pub usize);
|
||||
);
|
||||
impl Violation for DocLineTooLong {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let DocLineTooLong(length, limit) = self;
|
||||
format!("Doc line too long ({length} > {limit} characters)")
|
||||
}
|
||||
}
|
||||
|
||||
/// W505
|
||||
pub fn doc_line_too_long(lineno: usize, line: &str, settings: &Settings) -> Option<Diagnostic> {
|
||||
|
@ -21,7 +34,7 @@ pub fn doc_line_too_long(lineno: usize, line: &str, settings: &Settings) -> Opti
|
|||
&settings.task_tags,
|
||||
) {
|
||||
Some(Diagnostic::new(
|
||||
violations::DocLineTooLong(line_length, limit),
|
||||
DocLineTooLong(line_length, limit),
|
||||
Range::new(
|
||||
Location::new(lineno + 1, limit),
|
||||
Location::new(lineno + 1, line_length),
|
||||
|
|
|
@ -1,10 +1,27 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Locator;
|
||||
use crate::violations;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
define_violation!(
|
||||
pub struct InvalidEscapeSequence(pub char);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for InvalidEscapeSequence {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let InvalidEscapeSequence(char) = self;
|
||||
format!("Invalid escape sequence: '\\{char}'")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add backslash to escape sequence".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
// See: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
|
||||
const VALID_ESCAPE_SEQUENCES: &[char; 23] = &[
|
||||
|
@ -75,7 +92,7 @@ pub fn invalid_escape_sequence(
|
|||
let location = Location::new(start.row() + row_offset, col);
|
||||
let end_location = Location::new(location.row(), location.column() + 2);
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::InvalidEscapeSequence(next_char),
|
||||
InvalidEscapeSequence(next_char),
|
||||
Range::new(location, end_location),
|
||||
);
|
||||
if autofix {
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::is_overlong;
|
||||
use crate::settings::Settings;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct LineTooLong(pub usize, pub usize);
|
||||
);
|
||||
impl Violation for LineTooLong {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let LineTooLong(length, limit) = self;
|
||||
format!("Line too long ({length} > {limit} characters)")
|
||||
}
|
||||
}
|
||||
|
||||
/// E501
|
||||
pub fn line_too_long(lineno: usize, line: &str, settings: &Settings) -> Option<Diagnostic> {
|
||||
|
@ -18,7 +31,7 @@ pub fn line_too_long(lineno: usize, line: &str, settings: &Settings) -> Option<D
|
|||
&settings.task_tags,
|
||||
) {
|
||||
Some(Diagnostic::new(
|
||||
violations::LineTooLong(line_length, limit),
|
||||
LineTooLong(line_length, limit),
|
||||
Range::new(
|
||||
Location::new(lineno + 1, limit),
|
||||
Location::new(lineno + 1, line_length),
|
||||
|
|
|
@ -1,15 +1,86 @@
|
|||
use itertools::izip;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_ast::Constant;
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::compare;
|
||||
use crate::violations;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum EqCmpop {
|
||||
Eq,
|
||||
NotEq,
|
||||
}
|
||||
|
||||
impl From<&Cmpop> for EqCmpop {
|
||||
fn from(cmpop: &Cmpop) -> Self {
|
||||
match cmpop {
|
||||
Cmpop::Eq => EqCmpop::Eq,
|
||||
Cmpop::NotEq => EqCmpop::NotEq,
|
||||
_ => unreachable!("Expected Cmpop::Eq | Cmpop::NotEq"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NoneComparison(pub EqCmpop);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NoneComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NoneComparison(op) = self;
|
||||
match op {
|
||||
EqCmpop::Eq => format!("Comparison to `None` should be `cond is None`"),
|
||||
EqCmpop::NotEq => format!("Comparison to `None` should be `cond is not None`"),
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let NoneComparison(op) = self;
|
||||
match op {
|
||||
EqCmpop::Eq => "Replace with `cond is None`".to_string(),
|
||||
EqCmpop::NotEq => "Replace with `cond is not None`".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct TrueFalseComparison(pub bool, pub EqCmpop);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for TrueFalseComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let TrueFalseComparison(value, op) = self;
|
||||
match (value, op) {
|
||||
(true, EqCmpop::Eq) => format!("Comparison to `True` should be `cond is True`"),
|
||||
(true, EqCmpop::NotEq) => {
|
||||
format!("Comparison to `True` should be `cond is not True`")
|
||||
}
|
||||
(false, EqCmpop::Eq) => format!("Comparison to `False` should be `cond is False`"),
|
||||
(false, EqCmpop::NotEq) => {
|
||||
format!("Comparison to `False` should be `cond is not False`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let TrueFalseComparison(value, op) = self;
|
||||
match (value, op) {
|
||||
(true, EqCmpop::Eq) => "Replace with `cond is True`".to_string(),
|
||||
(true, EqCmpop::NotEq) => "Replace with `cond is not True`".to_string(),
|
||||
(false, EqCmpop::Eq) => "Replace with `cond is False`".to_string(),
|
||||
(false, EqCmpop::NotEq) => "Replace with `cond is not False`".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// E711, E712
|
||||
pub fn literal_comparisons(
|
||||
|
@ -43,20 +114,16 @@ pub fn literal_comparisons(
|
|||
)
|
||||
{
|
||||
if matches!(op, Cmpop::Eq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::NoneComparison(op.into()),
|
||||
Range::from_located(comparator),
|
||||
);
|
||||
let diagnostic =
|
||||
Diagnostic::new(NoneComparison(op.into()), Range::from_located(comparator));
|
||||
if checker.patch(diagnostic.kind.rule()) && !helpers::is_constant_non_singleton(next) {
|
||||
bad_ops.insert(0, Cmpop::Is);
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
if matches!(op, Cmpop::NotEq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::NoneComparison(op.into()),
|
||||
Range::from_located(comparator),
|
||||
);
|
||||
let diagnostic =
|
||||
Diagnostic::new(NoneComparison(op.into()), Range::from_located(comparator));
|
||||
if checker.patch(diagnostic.kind.rule()) && !helpers::is_constant_non_singleton(next) {
|
||||
bad_ops.insert(0, Cmpop::IsNot);
|
||||
}
|
||||
|
@ -72,7 +139,7 @@ pub fn literal_comparisons(
|
|||
{
|
||||
if matches!(op, Cmpop::Eq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::TrueFalseComparison(value, op.into()),
|
||||
TrueFalseComparison(value, op.into()),
|
||||
Range::from_located(comparator),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
|
@ -84,7 +151,7 @@ pub fn literal_comparisons(
|
|||
}
|
||||
if matches!(op, Cmpop::NotEq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::TrueFalseComparison(value, op.into()),
|
||||
TrueFalseComparison(value, op.into()),
|
||||
Range::from_located(comparator),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
|
@ -109,10 +176,8 @@ pub fn literal_comparisons(
|
|||
)
|
||||
{
|
||||
if matches!(op, Cmpop::Eq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::NoneComparison(op.into()),
|
||||
Range::from_located(next),
|
||||
);
|
||||
let diagnostic =
|
||||
Diagnostic::new(NoneComparison(op.into()), Range::from_located(next));
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
&& !helpers::is_constant_non_singleton(comparator)
|
||||
{
|
||||
|
@ -121,10 +186,8 @@ pub fn literal_comparisons(
|
|||
diagnostics.push(diagnostic);
|
||||
}
|
||||
if matches!(op, Cmpop::NotEq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::NoneComparison(op.into()),
|
||||
Range::from_located(next),
|
||||
);
|
||||
let diagnostic =
|
||||
Diagnostic::new(NoneComparison(op.into()), Range::from_located(next));
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
&& !helpers::is_constant_non_singleton(comparator)
|
||||
{
|
||||
|
@ -142,7 +205,7 @@ pub fn literal_comparisons(
|
|||
{
|
||||
if matches!(op, Cmpop::Eq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::TrueFalseComparison(value, op.into()),
|
||||
TrueFalseComparison(value, op.into()),
|
||||
Range::from_located(next),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
|
@ -154,7 +217,7 @@ pub fn literal_comparisons(
|
|||
}
|
||||
if matches!(op, Cmpop::NotEq) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
violations::TrueFalseComparison(value, op.into()),
|
||||
TrueFalseComparison(value, op.into()),
|
||||
Range::from_located(next),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule())
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct MixedSpacesAndTabs;
|
||||
);
|
||||
impl Violation for MixedSpacesAndTabs {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Indentation contains mixed spaces and tabs")
|
||||
}
|
||||
}
|
||||
|
||||
/// E101
|
||||
pub fn mixed_spaces_and_tabs(lineno: usize, line: &str) -> Option<Diagnostic> {
|
||||
|
@ -11,7 +23,7 @@ pub fn mixed_spaces_and_tabs(lineno: usize, line: &str) -> Option<Diagnostic> {
|
|||
|
||||
if indent.contains(' ') && indent.contains('\t') {
|
||||
Some(Diagnostic::new(
|
||||
violations::MixedSpacesAndTabs,
|
||||
MixedSpacesAndTabs,
|
||||
Range::new(
|
||||
Location::new(lineno + 1, 0),
|
||||
Location::new(lineno + 1, indent.chars().count()),
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
pub use ambiguous_class_name::ambiguous_class_name;
|
||||
pub use ambiguous_function_name::ambiguous_function_name;
|
||||
pub use ambiguous_variable_name::ambiguous_variable_name;
|
||||
pub use do_not_assign_lambda::do_not_assign_lambda;
|
||||
pub use do_not_use_bare_except::do_not_use_bare_except;
|
||||
pub use doc_line_too_long::doc_line_too_long;
|
||||
pub use invalid_escape_sequence::invalid_escape_sequence;
|
||||
pub use line_too_long::line_too_long;
|
||||
pub use literal_comparisons::literal_comparisons;
|
||||
pub use mixed_spaces_and_tabs::mixed_spaces_and_tabs;
|
||||
pub use no_newline_at_end_of_file::no_newline_at_end_of_file;
|
||||
pub use not_tests::not_tests;
|
||||
pub use type_comparison::type_comparison;
|
||||
pub use ambiguous_class_name::{ambiguous_class_name, AmbiguousClassName};
|
||||
pub use ambiguous_function_name::{ambiguous_function_name, AmbiguousFunctionName};
|
||||
pub use ambiguous_variable_name::{ambiguous_variable_name, AmbiguousVariableName};
|
||||
pub use do_not_assign_lambda::{do_not_assign_lambda, DoNotAssignLambda};
|
||||
pub use do_not_use_bare_except::{do_not_use_bare_except, DoNotUseBareExcept};
|
||||
pub use doc_line_too_long::{doc_line_too_long, DocLineTooLong};
|
||||
pub use invalid_escape_sequence::{invalid_escape_sequence, InvalidEscapeSequence};
|
||||
pub use line_too_long::{line_too_long, LineTooLong};
|
||||
pub use literal_comparisons::{literal_comparisons, NoneComparison, TrueFalseComparison};
|
||||
pub use mixed_spaces_and_tabs::{mixed_spaces_and_tabs, MixedSpacesAndTabs};
|
||||
pub use no_newline_at_end_of_file::{no_newline_at_end_of_file, NoNewLineAtEndOfFile};
|
||||
pub use not_tests::{not_tests, NotInTest, NotIsTest};
|
||||
pub use type_comparison::{type_comparison, TypeComparison};
|
||||
|
||||
mod ambiguous_class_name;
|
||||
mod ambiguous_function_name;
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Stylist;
|
||||
use crate::violations;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
define_violation!(
|
||||
pub struct NoNewLineAtEndOfFile;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NoNewLineAtEndOfFile {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("No newline at end of file")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add trailing newline".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// W292
|
||||
pub fn no_newline_at_end_of_file(
|
||||
|
@ -18,10 +34,8 @@ pub fn no_newline_at_end_of_file(
|
|||
if let Some(line) = contents.lines().last() {
|
||||
// Both locations are at the end of the file (and thus the same).
|
||||
let location = Location::new(contents.lines().count(), line.len());
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::NoNewLineAtEndOfFile,
|
||||
Range::new(location, location),
|
||||
);
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(NoNewLineAtEndOfFile, Range::new(location, location));
|
||||
if autofix {
|
||||
diagnostic.amend(Fix::insertion(stylist.line_ending().to_string(), location));
|
||||
}
|
||||
|
|
|
@ -1,12 +1,42 @@
|
|||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Unaryop;
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::helpers::compare;
|
||||
use crate::violations;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
define_violation!(
|
||||
pub struct NotInTest;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NotInTest {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Test for membership should be `not in`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Convert to `not in`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NotIsTest;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NotIsTest {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Test for object identity should be `is not`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Convert to `is not`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// E713, E714
|
||||
pub fn not_tests(
|
||||
|
@ -30,10 +60,8 @@ pub fn not_tests(
|
|||
match op {
|
||||
Cmpop::In => {
|
||||
if check_not_in {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::NotInTest,
|
||||
Range::from_located(operand),
|
||||
);
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(NotInTest, Range::from_located(operand));
|
||||
if checker.patch(diagnostic.kind.rule()) && should_fix {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
compare(left, &[Cmpop::NotIn], comparators, checker.stylist),
|
||||
|
@ -46,10 +74,8 @@ pub fn not_tests(
|
|||
}
|
||||
Cmpop::Is => {
|
||||
if check_not_is {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::NotIsTest,
|
||||
Range::from_located(operand),
|
||||
);
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(NotIsTest, Range::from_located(operand));
|
||||
if checker.patch(diagnostic.kind.rule()) && should_fix {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
compare(left, &[Cmpop::IsNot], comparators, checker.stylist),
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
use itertools::izip;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::Constant;
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violations;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct TypeComparison;
|
||||
);
|
||||
impl Violation for TypeComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not compare types, use `isinstance()`")
|
||||
}
|
||||
}
|
||||
|
||||
/// E721
|
||||
pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) -> Vec<Diagnostic> {
|
||||
|
@ -29,8 +41,7 @@ pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) ->
|
|||
kind: None
|
||||
}
|
||||
) {
|
||||
diagnostics
|
||||
.push(Diagnostic::new(violations::TypeComparison, location));
|
||||
diagnostics.push(Diagnostic::new(TypeComparison, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +51,7 @@ pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) ->
|
|||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
// Ex) types.IntType
|
||||
if id == "types" {
|
||||
diagnostics.push(Diagnostic::new(violations::TypeComparison, location));
|
||||
diagnostics.push(Diagnostic::new(TypeComparison, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,191 +37,6 @@ impl Violation for ModuleImportNotAtTopOfFile {
|
|||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct LineTooLong(pub usize, pub usize);
|
||||
);
|
||||
impl Violation for LineTooLong {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let LineTooLong(length, limit) = self;
|
||||
format!("Line too long ({length} > {limit} characters)")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct MixedSpacesAndTabs;
|
||||
);
|
||||
impl Violation for MixedSpacesAndTabs {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Indentation contains mixed spaces and tabs")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum EqCmpop {
|
||||
Eq,
|
||||
NotEq,
|
||||
}
|
||||
|
||||
impl From<&Cmpop> for EqCmpop {
|
||||
fn from(cmpop: &Cmpop) -> Self {
|
||||
match cmpop {
|
||||
Cmpop::Eq => EqCmpop::Eq,
|
||||
Cmpop::NotEq => EqCmpop::NotEq,
|
||||
_ => unreachable!("Expected Cmpop::Eq | Cmpop::NotEq"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NoneComparison(pub EqCmpop);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NoneComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NoneComparison(op) = self;
|
||||
match op {
|
||||
EqCmpop::Eq => format!("Comparison to `None` should be `cond is None`"),
|
||||
EqCmpop::NotEq => format!("Comparison to `None` should be `cond is not None`"),
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let NoneComparison(op) = self;
|
||||
match op {
|
||||
EqCmpop::Eq => "Replace with `cond is None`".to_string(),
|
||||
EqCmpop::NotEq => "Replace with `cond is not None`".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct TrueFalseComparison(pub bool, pub EqCmpop);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for TrueFalseComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let TrueFalseComparison(value, op) = self;
|
||||
match (value, op) {
|
||||
(true, EqCmpop::Eq) => format!("Comparison to `True` should be `cond is True`"),
|
||||
(true, EqCmpop::NotEq) => {
|
||||
format!("Comparison to `True` should be `cond is not True`")
|
||||
}
|
||||
(false, EqCmpop::Eq) => format!("Comparison to `False` should be `cond is False`"),
|
||||
(false, EqCmpop::NotEq) => {
|
||||
format!("Comparison to `False` should be `cond is not False`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let TrueFalseComparison(value, op) = self;
|
||||
match (value, op) {
|
||||
(true, EqCmpop::Eq) => "Replace with `cond is True`".to_string(),
|
||||
(true, EqCmpop::NotEq) => "Replace with `cond is not True`".to_string(),
|
||||
(false, EqCmpop::Eq) => "Replace with `cond is False`".to_string(),
|
||||
(false, EqCmpop::NotEq) => "Replace with `cond is not False`".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NotInTest;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NotInTest {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Test for membership should be `not in`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Convert to `not in`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NotIsTest;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NotIsTest {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Test for object identity should be `is not`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Convert to `is not`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct TypeComparison;
|
||||
);
|
||||
impl Violation for TypeComparison {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not compare types, use `isinstance()`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct DoNotUseBareExcept;
|
||||
);
|
||||
impl Violation for DoNotUseBareExcept {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not use bare `except`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct DoNotAssignLambda(pub String);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for DoNotAssignLambda {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Do not assign a `lambda` expression, use a `def`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let DoNotAssignLambda(name) = self;
|
||||
format!("Rewrite `{name}` as a `def`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousVariableName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousVariableName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousVariableName(name) = self;
|
||||
format!("Ambiguous variable name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousClassName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousClassName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousClassName(name) = self;
|
||||
format!("Ambiguous class name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct AmbiguousFunctionName(pub String);
|
||||
);
|
||||
impl Violation for AmbiguousFunctionName {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let AmbiguousFunctionName(name) = self;
|
||||
format!("Ambiguous function name: `{name}`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct IOError(pub String);
|
||||
);
|
||||
|
@ -244,48 +59,6 @@ impl Violation for SyntaxError {
|
|||
}
|
||||
}
|
||||
|
||||
// pycodestyle warnings
|
||||
|
||||
define_violation!(
|
||||
pub struct NoNewLineAtEndOfFile;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for NoNewLineAtEndOfFile {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("No newline at end of file")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add trailing newline".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct InvalidEscapeSequence(pub char);
|
||||
);
|
||||
impl AlwaysAutofixableViolation for InvalidEscapeSequence {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let InvalidEscapeSequence(char) = self;
|
||||
format!("Invalid escape sequence: '\\{char}'")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Add backslash to escape sequence".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct DocLineTooLong(pub usize, pub usize);
|
||||
);
|
||||
impl Violation for DocLineTooLong {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let DocLineTooLong(length, limit) = self;
|
||||
format!("Doc line too long ({length} > {limit} characters)")
|
||||
}
|
||||
}
|
||||
|
||||
// pyflakes
|
||||
|
||||
define_violation!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue