From 5c1597de219e801ec81d6757c0aecf51dff1f03d Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 17 May 2023 10:45:32 -0400 Subject: [PATCH] Include precise tokens for extraneous-whitespace diagnostics --- .../logical_lines/extraneous_whitespace.rs | 119 +++++++++++------- ...ules__pycodestyle__tests__E201_E20.py.snap | 8 +- ...ules__pycodestyle__tests__E202_E20.py.snap | 8 +- ...ules__pycodestyle__tests__E203_E20.py.snap | 12 +- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs index 53fd590e5c9ed..cf8240ded7ad3 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/extraneous_whitespace.rs @@ -1,12 +1,14 @@ use ruff_text_size::TextRange; -use super::{LogicalLine, Whitespace}; -use crate::checkers::logical_lines::LogicalLinesContext; use ruff_diagnostics::DiagnosticKind; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::token_kind::TokenKind; +use crate::checkers::logical_lines::LogicalLinesContext; + +use super::{LogicalLine, Whitespace}; + /// ## What it does /// Checks for the use of extraneous whitespace after "(". /// @@ -30,12 +32,15 @@ use ruff_python_ast::token_kind::TokenKind; /// ## References /// - [PEP 8](https://peps.python.org/pep-0008/#pet-peeves) #[violation] -pub struct WhitespaceAfterOpenBracket; +pub struct WhitespaceAfterOpenBracket { + symbol: char, +} impl Violation for WhitespaceAfterOpenBracket { #[derive_message_formats] fn message(&self) -> String { - format!("Whitespace after '('") + let WhitespaceAfterOpenBracket { symbol } = self; + format!("Whitespace after '{symbol}'") } } @@ -62,12 +67,15 @@ impl Violation for WhitespaceAfterOpenBracket { /// ## References /// - [PEP 8](https://peps.python.org/pep-0008/#pet-peeves) #[violation] -pub struct WhitespaceBeforeCloseBracket; +pub struct WhitespaceBeforeCloseBracket { + symbol: char, +} impl Violation for WhitespaceBeforeCloseBracket { #[derive_message_formats] fn message(&self) -> String { - format!("Whitespace before ')'") + let WhitespaceBeforeCloseBracket { symbol } = self; + format!("Whitespace before '{symbol}'") } } @@ -92,61 +100,86 @@ impl Violation for WhitespaceBeforeCloseBracket { /// ## References /// - [PEP 8](https://peps.python.org/pep-0008/#pet-peeves) #[violation] -pub struct WhitespaceBeforePunctuation; +pub struct WhitespaceBeforePunctuation { + symbol: char, +} impl Violation for WhitespaceBeforePunctuation { #[derive_message_formats] fn message(&self) -> String { - format!("Whitespace before ',', ';', or ':'") + let WhitespaceBeforePunctuation { symbol } = self; + format!("Whitespace before '{symbol}'") } } /// E201, E202, E203 pub(crate) fn extraneous_whitespace(line: &LogicalLine, context: &mut LogicalLinesContext) { - let mut last_token = TokenKind::EndOfFile; + let mut prev_token = None; for token in line.tokens() { let kind = token.kind(); - match kind { - TokenKind::Lbrace | TokenKind::Lpar | TokenKind::Lsqb => { - let (trailing, trailing_len) = line.trailing_whitespace(token); - if !matches!(trailing, Whitespace::None) { - context.push( - WhitespaceAfterOpenBracket, - TextRange::at(token.end(), trailing_len), - ); - } - } - TokenKind::Rbrace - | TokenKind::Rpar - | TokenKind::Rsqb - | TokenKind::Comma - | TokenKind::Semi - | TokenKind::Colon => { - if !matches!(last_token, TokenKind::Comma | TokenKind::EndOfFile) { - if let (Whitespace::Single | Whitespace::Many | Whitespace::Tab, offset) = - line.leading_whitespace(token) - { - let diagnostic_kind = if matches!( - kind, - TokenKind::Comma | TokenKind::Semi | TokenKind::Colon - ) { - DiagnosticKind::from(WhitespaceBeforePunctuation) - } else { - DiagnosticKind::from(WhitespaceBeforeCloseBracket) - }; - + if let Some(symbol) = BracketOrPunctuation::from_kind(kind) { + match symbol { + BracketOrPunctuation::OpenBracket(symbol) => { + let (trailing, trailing_len) = line.trailing_whitespace(token); + if !matches!(trailing, Whitespace::None) { context.push( - diagnostic_kind, - TextRange::at(token.start() - offset, offset), + WhitespaceAfterOpenBracket { symbol }, + TextRange::at(token.end(), trailing_len), ); } } + BracketOrPunctuation::CloseBracket(symbol) => { + if !matches!(prev_token, Some(TokenKind::Comma)) { + if let (Whitespace::Single | Whitespace::Many | Whitespace::Tab, offset) = + line.leading_whitespace(token) + { + context.push( + DiagnosticKind::from(WhitespaceBeforeCloseBracket { symbol }), + TextRange::at(token.start() - offset, offset), + ); + } + } + } + BracketOrPunctuation::Punctuation(symbol) => { + if !matches!(prev_token, Some(TokenKind::Comma)) { + if let (Whitespace::Single | Whitespace::Many | Whitespace::Tab, offset) = + line.leading_whitespace(token) + { + context.push( + DiagnosticKind::from(WhitespaceBeforePunctuation { symbol }), + TextRange::at(token.start() - offset, offset), + ); + } + } + } } - - _ => {} } - last_token = kind; + prev_token = Some(kind); + } +} + +#[derive(Debug)] +enum BracketOrPunctuation { + OpenBracket(char), + CloseBracket(char), + Punctuation(char), +} + +impl BracketOrPunctuation { + fn from_kind(kind: TokenKind) -> Option { + match kind { + TokenKind::Lbrace => Some(BracketOrPunctuation::OpenBracket('{')), + TokenKind::Lpar => Some(BracketOrPunctuation::OpenBracket('(')), + TokenKind::Lsqb => Some(BracketOrPunctuation::OpenBracket('[')), + TokenKind::Rbrace => Some(BracketOrPunctuation::CloseBracket('}')), + TokenKind::Rpar => Some(BracketOrPunctuation::CloseBracket(')')), + TokenKind::Rsqb => Some(BracketOrPunctuation::CloseBracket(']')), + TokenKind::Comma => Some(BracketOrPunctuation::Punctuation(',')), + TokenKind::Colon => Some(BracketOrPunctuation::Punctuation(':')), + TokenKind::Semi => Some(BracketOrPunctuation::Punctuation(';')), + _ => None, + } } } diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E201_E20.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E201_E20.py.snap index 35e6582c5a561..5f52c0791d7a2 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E201_E20.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E201_E20.py.snap @@ -10,7 +10,7 @@ E20.py:2:6: E201 Whitespace after '(' 5 | spam(ham[ 1], {eggs: 2}) | -E20.py:4:10: E201 Whitespace after '(' +E20.py:4:10: E201 Whitespace after '[' | 4 | spam( ham[1], {eggs: 2}) 5 | #: E201:1:10 @@ -20,7 +20,7 @@ E20.py:4:10: E201 Whitespace after '(' 8 | spam(ham[1], { eggs: 2}) | -E20.py:6:15: E201 Whitespace after '(' +E20.py:6:15: E201 Whitespace after '{' | 6 | spam(ham[ 1], {eggs: 2}) 7 | #: E201:1:15 @@ -40,7 +40,7 @@ E20.py:8:6: E201 Whitespace after '(' 12 | spam(ham[ 1], {eggs: 2}) | -E20.py:10:10: E201 Whitespace after '(' +E20.py:10:10: E201 Whitespace after '[' | 10 | spam( ham[1], {eggs: 2}) 11 | #: E201:1:10 @@ -50,7 +50,7 @@ E20.py:10:10: E201 Whitespace after '(' 14 | spam(ham[1], { eggs: 2}) | -E20.py:12:15: E201 Whitespace after '(' +E20.py:12:15: E201 Whitespace after '{' | 12 | spam(ham[ 1], {eggs: 2}) 13 | #: E201:1:15 diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E202_E20.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E202_E20.py.snap index 67181268433ee..72cd783c5b806 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E202_E20.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E202_E20.py.snap @@ -10,7 +10,7 @@ E20.py:19:23: E202 Whitespace before ')' 22 | spam(ham[1], {eggs: 2 }) | -E20.py:21:22: E202 Whitespace before ')' +E20.py:21:22: E202 Whitespace before '}' | 21 | spam(ham[1], {eggs: 2} ) 22 | #: E202:1:22 @@ -20,7 +20,7 @@ E20.py:21:22: E202 Whitespace before ')' 25 | spam(ham[1 ], {eggs: 2}) | -E20.py:23:11: E202 Whitespace before ')' +E20.py:23:11: E202 Whitespace before ']' | 23 | spam(ham[1], {eggs: 2 }) 24 | #: E202:1:11 @@ -40,7 +40,7 @@ E20.py:25:23: E202 Whitespace before ')' 29 | spam(ham[1], {eggs: 2 }) | -E20.py:27:22: E202 Whitespace before ')' +E20.py:27:22: E202 Whitespace before '}' | 27 | spam(ham[1], {eggs: 2} ) 28 | #: E202:1:22 @@ -50,7 +50,7 @@ E20.py:27:22: E202 Whitespace before ')' 31 | spam(ham[1 ], {eggs: 2}) | -E20.py:29:11: E202 Whitespace before ')' +E20.py:29:11: E202 Whitespace before ']' | 29 | spam(ham[1], {eggs: 2 }) 30 | #: E202:1:11 diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E203_E20.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E203_E20.py.snap index c50b975ad4505..e5715034c84ef 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E203_E20.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E203_E20.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff/src/rules/pycodestyle/mod.rs --- -E20.py:51:10: E203 Whitespace before ',', ';', or ':' +E20.py:51:10: E203 Whitespace before ':' | 51 | #: E203:1:10 52 | if x == 4 : @@ -10,7 +10,7 @@ E20.py:51:10: E203 Whitespace before ',', ';', or ':' 54 | x, y = y, x | -E20.py:55:10: E203 Whitespace before ',', ';', or ':' +E20.py:55:10: E203 Whitespace before ':' | 55 | x, y = y, x 56 | #: E203:1:10 @@ -20,7 +20,7 @@ E20.py:55:10: E203 Whitespace before ',', ';', or ':' 59 | x, y = y, x | -E20.py:60:15: E203 Whitespace before ',', ';', or ':' +E20.py:60:15: E203 Whitespace before ';' | 60 | #: E203:2:15 E702:2:16 61 | if x == 4: @@ -30,7 +30,7 @@ E20.py:60:15: E203 Whitespace before ',', ';', or ':' 64 | if x == 4: | -E20.py:63:15: E203 Whitespace before ',', ';', or ':' +E20.py:63:15: E203 Whitespace before ';' | 63 | #: E203:2:15 E702:2:16 64 | if x == 4: @@ -40,7 +40,7 @@ E20.py:63:15: E203 Whitespace before ',', ';', or ':' 67 | if x == 4: | -E20.py:67:13: E203 Whitespace before ',', ';', or ':' +E20.py:67:13: E203 Whitespace before ',' | 67 | if x == 4: 68 | print x, y @@ -50,7 +50,7 @@ E20.py:67:13: E203 Whitespace before ',', ';', or ':' 71 | if x == 4: | -E20.py:71:13: E203 Whitespace before ',', ';', or ':' +E20.py:71:13: E203 Whitespace before ',' | 71 | if x == 4: 72 | print x, y