From 39e45aa06f0a1ff24e3cf381afde3156c77720a0 Mon Sep 17 00:00:00 2001 From: Weijie Guo Date: Tue, 24 Oct 2023 00:31:08 +0800 Subject: [PATCH] add auto-fix for E273,274 (#8144) ## Summary Introduce auto fix for `E273` and `E274`. This partially address #8120. ## Test Plan Already covered. --- .../whitespace_around_keywords.rs | 32 +++++++-- ...ules__pycodestyle__tests__E273_E27.py.snap | 65 +++++++++++++++++-- ...ules__pycodestyle__tests__E274_E27.py.snap | 26 +++++++- 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs index 650f92797d..cc3e86cf8b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_keywords.rs @@ -1,4 +1,4 @@ -use ruff_diagnostics::Violation; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_text_size::{Ranged, TextRange}; @@ -74,11 +74,15 @@ impl Violation for MultipleSpacesBeforeKeyword { #[violation] pub struct TabAfterKeyword; -impl Violation for TabAfterKeyword { +impl AlwaysFixableViolation for TabAfterKeyword { #[derive_message_formats] fn message(&self) -> String { format!("Tab after keyword") } + + fn fix_title(&self) -> String { + format!("Replace with single space") + } } /// ## What it does @@ -99,11 +103,15 @@ impl Violation for TabAfterKeyword { #[violation] pub struct TabBeforeKeyword; -impl Violation for TabBeforeKeyword { +impl AlwaysFixableViolation for TabBeforeKeyword { #[derive_message_formats] fn message(&self) -> String { format!("Tab before keyword") } + + fn fix_title(&self) -> String { + format!("Replace with single space") + } } /// E271, E272, E273, E274 @@ -117,7 +125,15 @@ pub(crate) fn whitespace_around_keywords(line: &LogicalLine, context: &mut Logic match line.leading_whitespace(token) { (Whitespace::Tab, offset) => { let start = token.start(); - context.push(TabBeforeKeyword, TextRange::at(start - offset, offset)); + let mut diagnostic = Diagnostic::new( + TabBeforeKeyword, + TextRange::at(start - offset, offset), + ); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + " ".to_string(), + TextRange::at(start - offset, offset), + ))); + context.push_diagnostic(diagnostic); } (Whitespace::Many, offset) => { let start = token.start(); @@ -132,7 +148,13 @@ pub(crate) fn whitespace_around_keywords(line: &LogicalLine, context: &mut Logic match line.trailing_whitespace(token) { (Whitespace::Tab, len) => { - context.push(TabAfterKeyword, TextRange::at(token.end(), len)); + let mut diagnostic = + Diagnostic::new(TabAfterKeyword, TextRange::at(token.end(), len)); + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + " ".to_string(), + TextRange::at(token.end(), len), + ))); + context.push_diagnostic(diagnostic); } (Whitespace::Many, len) => { context.push(MultipleSpacesAfterKeyword, TextRange::at(token.end(), len)); diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E273_E27.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E273_E27.py.snap index 122c091a1e..672945a191 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E273_E27.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E273_E27.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E27.py:10:9: E273 Tab after keyword +E27.py:10:9: E273 [*] Tab after keyword | 8 | if 1: 9 | #: E273 @@ -10,8 +10,19 @@ E27.py:10:9: E273 Tab after keyword 11 | #: E273 E274 12 | True and False | + = help: Replace with single space -E27.py:12:5: E273 Tab after keyword +ℹ Fix +7 7 | #: E271 +8 8 | if 1: +9 9 | #: E273 +10 |-True and False + 10 |+True and False +11 11 | #: E273 E274 +12 12 | True and False +13 13 | #: E271 + +E27.py:12:5: E273 [*] Tab after keyword | 10 | True and False 11 | #: E273 E274 @@ -20,8 +31,19 @@ E27.py:12:5: E273 Tab after keyword 13 | #: E271 14 | a and b | + = help: Replace with single space -E27.py:12:10: E273 Tab after keyword +ℹ Fix +9 9 | #: E273 +10 10 | True and False +11 11 | #: E273 E274 +12 |-True and False + 12 |+True and False +13 13 | #: E271 +14 14 | a and b +15 15 | #: E271 + +E27.py:12:10: E273 [*] Tab after keyword | 10 | True and False 11 | #: E273 E274 @@ -30,8 +52,19 @@ E27.py:12:10: E273 Tab after keyword 13 | #: E271 14 | a and b | + = help: Replace with single space -E27.py:26:6: E273 Tab after keyword +ℹ Fix +9 9 | #: E273 +10 10 | True and False +11 11 | #: E273 E274 +12 |-True and False + 12 |+True and False +13 13 | #: E271 +14 14 | a and b +15 15 | #: E271 + +E27.py:26:6: E273 [*] Tab after keyword | 24 | this and False 25 | #: E273 @@ -40,8 +73,19 @@ E27.py:26:6: E273 Tab after keyword 27 | #: E274 28 | a and b | + = help: Replace with single space -E27.py:30:10: E273 Tab after keyword +ℹ Fix +23 23 | #: E272 +24 24 | this and False +25 25 | #: E273 +26 |-a and b + 26 |+a and b +27 27 | #: E274 +28 28 | a and b +29 29 | #: E273 E274 + +E27.py:30:10: E273 [*] Tab after keyword | 28 | a and b 29 | #: E273 E274 @@ -50,5 +94,16 @@ E27.py:30:10: E273 Tab after keyword 31 | #: Okay 32 | from u import (a, b) | + = help: Replace with single space + +ℹ Fix +27 27 | #: E274 +28 28 | a and b +29 29 | #: E273 E274 +30 |-this and False + 30 |+this and False +31 31 | #: Okay +32 32 | from u import (a, b) +33 33 | from v import c, d diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E274_E27.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E274_E27.py.snap index 3230f60fe8..811e4fe703 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E274_E27.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E274_E27.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E27.py:28:2: E274 Tab before keyword +E27.py:28:2: E274 [*] Tab before keyword | 26 | a and b 27 | #: E274 @@ -10,8 +10,19 @@ E27.py:28:2: E274 Tab before keyword 29 | #: E273 E274 30 | this and False | + = help: Replace with single space -E27.py:30:5: E274 Tab before keyword +ℹ Fix +25 25 | #: E273 +26 26 | a and b +27 27 | #: E274 +28 |-a and b + 28 |+a and b +29 29 | #: E273 E274 +30 30 | this and False +31 31 | #: Okay + +E27.py:30:5: E274 [*] Tab before keyword | 28 | a and b 29 | #: E273 E274 @@ -20,5 +31,16 @@ E27.py:30:5: E274 Tab before keyword 31 | #: Okay 32 | from u import (a, b) | + = help: Replace with single space + +ℹ Fix +27 27 | #: E274 +28 28 | a and b +29 29 | #: E273 E274 +30 |-this and False + 30 |+this and False +31 31 | #: Okay +32 32 | from u import (a, b) +33 33 | from v import c, d