Skip to content

Commit

Permalink
Include precise tokens for extraneous-whitespace diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed May 17, 2023
1 parent 39fb2cc commit 5c1597d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -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 "(".
///
Expand All @@ -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}'")
}
}

Expand All @@ -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}'")
}
}

Expand All @@ -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<BracketOrPunctuation> {
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,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 :
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 5c1597d

Please sign in to comment.