Skip to content

Commit

Permalink
Add fix for comment-related whitespace rules (#9075)
Browse files Browse the repository at this point in the history
Closes #9067.

Closes #9068.

Closes #8119.
  • Loading branch information
charliermarsh authored Dec 9, 2023
1 parent b7b137a commit cb8a2f5
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 22 deletions.
12 changes: 12 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/pycodestyle/E26.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,15 @@ def oof():
# EF Means test is giving error and Failing
#! Means test is segfaulting
# 8 Means test runs forever

#: Colon prefix is okay

###This is a variable ###

# We should strip the space, but preserve the hashes.
#: E266:1:3
## Foo

a = 1 ## Foo

a = 1 #:Foo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_parser::TokenKind;
use ruff_python_trivia::PythonWhitespace;
Expand Down Expand Up @@ -66,11 +66,15 @@ impl AlwaysFixableViolation for TooFewSpacesBeforeInlineComment {
#[violation]
pub struct NoSpaceAfterInlineComment;

impl Violation for NoSpaceAfterInlineComment {
impl AlwaysFixableViolation for NoSpaceAfterInlineComment {
#[derive_message_formats]
fn message(&self) -> String {
format!("Inline comment should start with `# `")
}

fn fix_title(&self) -> String {
format!("Format space")
}
}

/// ## What it does
Expand Down Expand Up @@ -98,11 +102,15 @@ impl Violation for NoSpaceAfterInlineComment {
#[violation]
pub struct NoSpaceAfterBlockComment;

impl Violation for NoSpaceAfterBlockComment {
impl AlwaysFixableViolation for NoSpaceAfterBlockComment {
#[derive_message_formats]
fn message(&self) -> String {
format!("Block comment should start with `# `")
}

fn fix_title(&self) -> String {
format!("Format space")
}
}

/// ## What it does
Expand Down Expand Up @@ -130,11 +138,15 @@ impl Violation for NoSpaceAfterBlockComment {
#[violation]
pub struct MultipleLeadingHashesForBlockComment;

impl Violation for MultipleLeadingHashesForBlockComment {
impl AlwaysFixableViolation for MultipleLeadingHashesForBlockComment {
#[derive_message_formats]
fn message(&self) -> String {
format!("Too many leading `#` before block comment")
}

fn fix_title(&self) -> String {
format!("Remove leading `#`")
}
}

/// E261, E262, E265, E266
Expand Down Expand Up @@ -184,14 +196,30 @@ pub(crate) fn whitespace_before_comment(

if is_inline_comment {
if bad_prefix.is_some() || comment.chars().next().is_some_and(char::is_whitespace) {
context.push(NoSpaceAfterInlineComment, range);
let mut diagnostic = Diagnostic::new(NoSpaceAfterInlineComment, range);
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format_leading_space(token_text),
range,
)));
context.push_diagnostic(diagnostic);
}
} else if let Some(bad_prefix) = bad_prefix {
if bad_prefix != '!' || !line.is_start_of_file() {
if bad_prefix != '#' {
context.push(NoSpaceAfterBlockComment, range);
let mut diagnostic = Diagnostic::new(NoSpaceAfterBlockComment, range);
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format_leading_space(token_text),
range,
)));
context.push_diagnostic(diagnostic);
} else if !comment.is_empty() {
context.push(MultipleLeadingHashesForBlockComment, range);
let mut diagnostic =
Diagnostic::new(MultipleLeadingHashesForBlockComment, range);
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format_leading_hashes(token_text),
range,
)));
context.push_diagnostic(diagnostic);
}
}
}
Expand All @@ -200,3 +228,17 @@ pub(crate) fn whitespace_before_comment(
}
}
}

/// Format a comment to have a single space after the `#`.
fn format_leading_space(comment: &str) -> String {
if let Some(rest) = comment.strip_prefix("#:") {
format!("#: {}", rest.trim_start())
} else {
format!("# {}", comment.trim_start_matches('#').trim_start())
}
}

/// Format a comment to strip multiple leading `#` characters.
fn format_leading_hashes(comment: &str) -> String {
format!("# {}", comment.trim_start_matches('#').trim_start())
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E26.py:4:12: E262 Inline comment should start with `# `
E26.py:4:12: E262 [*] Inline comment should start with `# `
|
2 | pass # an inline comment
3 | #: E262:1:12
Expand All @@ -10,8 +10,19 @@ E26.py:4:12: E262 Inline comment should start with `# `
5 | #: E262:1:12
6 | x = x + 1 # Increment x
|
= help: Format space

E26.py:6:12: E262 Inline comment should start with `# `
Safe fix
1 1 | #: E261:1:5
2 2 | pass # an inline comment
3 3 | #: E262:1:12
4 |-x = x + 1 #Increment x
4 |+x = x + 1 # Increment x
5 5 | #: E262:1:12
6 6 | x = x + 1 # Increment x
7 7 | #: E262:1:12

E26.py:6:12: E262 [*] Inline comment should start with `# `
|
4 | x = x + 1 #Increment x
5 | #: E262:1:12
Expand All @@ -20,8 +31,19 @@ E26.py:6:12: E262 Inline comment should start with `# `
7 | #: E262:1:12
8 | x = y + 1 #: Increment x
|
= help: Format space

Safe fix
3 3 | #: E262:1:12
4 4 | x = x + 1 #Increment x
5 5 | #: E262:1:12
6 |-x = x + 1 # Increment x
6 |+x = x + 1 # Increment x
7 7 | #: E262:1:12
8 8 | x = y + 1 #: Increment x
9 9 | #: E265:1:1

E26.py:8:12: E262 Inline comment should start with `# `
E26.py:8:12: E262 [*] Inline comment should start with `# `
|
6 | x = x + 1 # Increment x
7 | #: E262:1:12
Expand All @@ -30,8 +52,19 @@ E26.py:8:12: E262 Inline comment should start with `# `
9 | #: E265:1:1
10 | #Block comment
|
= help: Format space

E26.py:63:9: E262 Inline comment should start with `# `
Safe fix
5 5 | #: E262:1:12
6 6 | x = x + 1 # Increment x
7 7 | #: E262:1:12
8 |-x = y + 1 #: Increment x
8 |+x = y + 1 #: Increment x
9 9 | #: E265:1:1
10 10 | #Block comment
11 11 | a = 1

E26.py:63:9: E262 [*] Inline comment should start with `# `
|
61 | # -*- coding: utf8 -*-
62 | #  (One space one NBSP) Ok for block comment
Expand All @@ -40,8 +73,19 @@ E26.py:63:9: E262 Inline comment should start with `# `
64 | #: E262:2:9
65 | # (Two spaces) Ok for block comment
|
= help: Format space

Safe fix
60 60 | #: E262:3:9
61 61 | # -*- coding: utf8 -*-
62 62 | #  (One space one NBSP) Ok for block comment
63 |-a = 42 #  (One space one NBSP)
63 |+a = 42 # (One space one NBSP)
64 64 | #: E262:2:9
65 65 | # (Two spaces) Ok for block comment
66 66 | a = 42 # (Two spaces)

E26.py:66:9: E262 Inline comment should start with `# `
E26.py:66:9: E262 [*] Inline comment should start with `# `
|
64 | #: E262:2:9
65 | # (Two spaces) Ok for block comment
Expand All @@ -50,5 +94,52 @@ E26.py:66:9: E262 Inline comment should start with `# `
67 |
68 | #: E265:5:1
|
= help: Format space

Safe fix
63 63 | a = 42 #  (One space one NBSP)
64 64 | #: E262:2:9
65 65 | # (Two spaces) Ok for block comment
66 |-a = 42 # (Two spaces)
66 |+a = 42 # (Two spaces)
67 67 |
68 68 | #: E265:5:1
69 69 | ### Means test is not done yet

E26.py:84:8: E262 [*] Inline comment should start with `# `
|
82 | ## Foo
83 |
84 | a = 1 ## Foo
| ^^^^^^ E262
85 |
86 | a = 1 #:Foo
|
= help: Format space

Safe fix
81 81 | #: E266:1:3
82 82 | ## Foo
83 83 |
84 |-a = 1 ## Foo
84 |+a = 1 # Foo
85 85 |
86 86 | a = 1 #:Foo

E26.py:86:8: E262 [*] Inline comment should start with `# `
|
84 | a = 1 ## Foo
85 |
86 | a = 1 #:Foo
| ^^^^^ E262
|
= help: Format space

Safe fix
83 83 |
84 84 | a = 1 ## Foo
85 85 |
86 |-a = 1 #:Foo
86 |+a = 1 #: Foo


Loading

0 comments on commit cb8a2f5

Please sign in to comment.