feat(E275): add Missing whitespace after keyword (#3225)

This commit is contained in:
Carlos Gonçalves 2023-02-26 21:36:05 +00:00 committed by GitHub
parent 1c75071136
commit 484ce7b8fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 179 additions and 2 deletions

View file

@ -7,8 +7,8 @@ use crate::ast::types::Range;
use crate::registry::Diagnostic;
use crate::rules::pycodestyle::logical_lines::{iter_logical_lines, TokenFlags};
use crate::rules::pycodestyle::rules::{
extraneous_whitespace, indentation, space_around_operator, whitespace_around_keywords,
whitespace_before_comment,
extraneous_whitespace, indentation, missing_whitespace_after_keyword, space_around_operator,
whitespace_around_keywords, whitespace_before_comment,
};
use crate::settings::Settings;
use crate::source_code::{Locator, Stylist};
@ -106,6 +106,18 @@ pub fn check_logical_lines(
});
}
}
for (location, kind) in missing_whitespace_after_keyword(&line.tokens) {
if settings.rules.enabled(kind.rule()) {
diagnostics.push(Diagnostic {
kind,
location,
end_location: location,
fix: None,
parent: None,
});
}
}
}
if line.flags.contains(TokenFlags::COMMENT) {
for (range, kind) in whitespace_before_comment(&line.tokens, locator) {

View file

@ -52,6 +52,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
(Pycodestyle, "E273") => Rule::TabAfterKeyword,
#[cfg(feature = "logical_lines")]
(Pycodestyle, "E274") => Rule::TabBeforeKeyword,
#[cfg(feature = "logical_lines")]
(Pycodestyle, "E275") => Rule::MissingWhitespaceAfterKeyword,
(Pycodestyle, "E401") => Rule::MultipleImportsOnOneLine,
(Pycodestyle, "E402") => Rule::ModuleImportNotAtTopOfFile,
(Pycodestyle, "E501") => Rule::LineTooLong,

View file

@ -53,6 +53,8 @@ ruff_macros::register_rules!(
#[cfg(feature = "logical_lines")]
rules::pycodestyle::rules::MultipleSpacesAfterKeyword,
#[cfg(feature = "logical_lines")]
rules::pycodestyle::rules::MissingWhitespaceAfterKeyword,
#[cfg(feature = "logical_lines")]
rules::pycodestyle::rules::MultipleSpacesBeforeKeyword,
#[cfg(feature = "logical_lines")]
rules::pycodestyle::rules::TabAfterKeyword,
@ -824,6 +826,7 @@ impl Rule {
| Rule::MultipleSpacesAfterOperator
| Rule::MultipleSpacesBeforeKeyword
| Rule::MultipleSpacesBeforeOperator
| Rule::MissingWhitespaceAfterKeyword
| Rule::NoIndentedBlock
| Rule::NoIndentedBlockComment
| Rule::NoSpaceAfterBlockComment

View file

@ -1,6 +1,7 @@
use once_cell::sync::Lazy;
use regex::Regex;
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
use rustpython_parser::Tok;
use crate::ast::helpers::{create_expr, unparse_expr};
use crate::source_code::Stylist;
@ -56,3 +57,50 @@ pub fn is_overlong(
true
}
pub fn is_keyword_token(token: &Tok) -> bool {
matches!(
token,
Tok::False { .. }
| Tok::True { .. }
| Tok::None { .. }
| Tok::And { .. }
| Tok::As { .. }
| Tok::Assert { .. }
| Tok::Await { .. }
| Tok::Break { .. }
| Tok::Class { .. }
| Tok::Continue { .. }
| Tok::Def { .. }
| Tok::Del { .. }
| Tok::Elif { .. }
| Tok::Else { .. }
| Tok::Except { .. }
| Tok::Finally { .. }
| Tok::For { .. }
| Tok::From { .. }
| Tok::Global { .. }
| Tok::If { .. }
| Tok::Import { .. }
| Tok::In { .. }
| Tok::Is { .. }
| Tok::Lambda { .. }
| Tok::Nonlocal { .. }
| Tok::Not { .. }
| Tok::Or { .. }
| Tok::Pass { .. }
| Tok::Raise { .. }
| Tok::Return { .. }
| Tok::Try { .. }
| Tok::While { .. }
| Tok::With { .. }
| Tok::Yield { .. }
)
}
pub fn is_singleton_token(token: &Tok) -> bool {
matches!(
token,
Tok::False { .. } | Tok::True { .. } | Tok::None { .. },
)
}

View file

@ -83,6 +83,7 @@ mod tests {
#[test_case(Rule::MultipleSpacesAfterKeyword, Path::new("E27.py"))]
#[test_case(Rule::MultipleSpacesAfterOperator, Path::new("E22.py"))]
#[test_case(Rule::MultipleSpacesBeforeKeyword, Path::new("E27.py"))]
#[test_case(Rule::MissingWhitespaceAfterKeyword, Path::new("E27.py"))]
#[test_case(Rule::MultipleSpacesBeforeOperator, Path::new("E22.py"))]
#[test_case(Rule::NoIndentedBlock, Path::new("E11.py"))]
#[test_case(Rule::NoIndentedBlockComment, Path::new("E11.py"))]

View file

@ -0,0 +1,52 @@
#![allow(dead_code)]
use ruff_macros::{define_violation, derive_message_formats};
use crate::registry::DiagnosticKind;
use crate::violation::Violation;
use crate::rules::pycodestyle::helpers::{is_keyword_token, is_singleton_token};
use rustpython_parser::ast::Location;
use rustpython_parser::Tok;
define_violation!(
pub struct MissingWhitespaceAfterKeyword;
);
impl Violation for MissingWhitespaceAfterKeyword {
#[derive_message_formats]
fn message(&self) -> String {
format!("Missing whitespace after keyword")
}
}
/// E275
#[cfg(feature = "logical_lines")]
pub fn missing_whitespace_after_keyword(
tokens: &[(Location, &Tok, Location)],
) -> Vec<(Location, DiagnosticKind)> {
let mut diagnostics = vec![];
for (tok0, tok1) in tokens.iter().zip(&tokens[1..]) {
if tok0.2 == tok1.0
&& is_keyword_token(tok0.1)
&& !is_singleton_token(tok0.1)
&& *tok0.1 != Tok::Async
&& *tok0.1 != Tok::Await
&& !(*tok0.1 == Tok::Except && *tok1.1 == Tok::Star)
&& !(*tok0.1 == Tok::Yield && *tok1.1 == Tok::Rpar)
&& *tok1.1 != Tok::Colon
&& *tok1.1 != Tok::Newline
{
diagnostics.push((tok0.2, MissingWhitespaceAfterKeyword.into()));
}
}
diagnostics
}
#[cfg(not(feature = "logical_lines"))]
pub fn missing_whitespace_after_keyword(
_tokens: &[(Location, &Tok, Location)],
) -> Vec<(Location, DiagnosticKind)> {
vec![]
}

View file

@ -25,6 +25,9 @@ pub use invalid_escape_sequence::{invalid_escape_sequence, InvalidEscapeSequence
pub use lambda_assignment::{lambda_assignment, LambdaAssignment};
pub use line_too_long::{line_too_long, LineTooLong};
pub use literal_comparisons::{literal_comparisons, NoneComparison, TrueFalseComparison};
pub use missing_whitespace_after_keyword::{
missing_whitespace_after_keyword, MissingWhitespaceAfterKeyword,
};
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};
@ -59,6 +62,7 @@ mod invalid_escape_sequence;
mod lambda_assignment;
mod line_too_long;
mod literal_comparisons;
mod missing_whitespace_after_keyword;
mod mixed_spaces_and_tabs;
mod no_newline_at_end_of_file;
mod not_tests;

View file

@ -0,0 +1,55 @@
---
source: crates/ruff/src/rules/pycodestyle/mod.rs
expression: diagnostics
---
- kind:
MissingWhitespaceAfterKeyword: ~
location:
row: 37
column: 13
end_location:
row: 37
column: 13
fix: ~
parent: ~
- kind:
MissingWhitespaceAfterKeyword: ~
location:
row: 39
column: 29
end_location:
row: 39
column: 29
fix: ~
parent: ~
- kind:
MissingWhitespaceAfterKeyword: ~
location:
row: 42
column: 33
end_location:
row: 42
column: 33
fix: ~
parent: ~
- kind:
MissingWhitespaceAfterKeyword: ~
location:
row: 46
column: 2
end_location:
row: 46
column: 2
fix: ~
parent: ~
- kind:
MissingWhitespaceAfterKeyword: ~
location:
row: 54
column: 10
end_location:
row: 54
column: 10
fix: ~
parent: ~