diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/E26.py b/crates/ruff/resources/test/fixtures/pycodestyle/E26.py index 2cdd4cf5425b0..9d35553dc521a 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/E26.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/E26.py @@ -64,3 +64,11 @@ def oof(): #: E262:2:9 # (Two spaces) Ok for block comment a = 42 # (Two spaces) + +#: E265:5:1 +### Means test is not done yet +# E Means test is giving error (E) +# F Means test is failing (F) +# EF Means test is giving error and Failing +#! Means test is segfaulting +# 8 Means test runs forever diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/shebang.py b/crates/ruff/resources/test/fixtures/pycodestyle/shebang.py new file mode 100644 index 0000000000000..2d5d0e2441c52 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pycodestyle/shebang.py @@ -0,0 +1,4 @@ +#!/usr/bin/python +# +#! +#: diff --git a/crates/ruff/src/checkers/logical_lines.rs b/crates/ruff/src/checkers/logical_lines.rs index 8d9ba1dd5d3f3..e839d3625aa2b 100644 --- a/crates/ruff/src/checkers/logical_lines.rs +++ b/crates/ruff/src/checkers/logical_lines.rs @@ -67,7 +67,7 @@ pub(crate) fn check_logical_lines( } if line.flags().contains(TokenFlags::COMMENT) { - whitespace_before_comment(&line, locator, prev_line.is_none(), &mut context); + whitespace_before_comment(&line, locator, &mut context); } if line.flags().contains(TokenFlags::BRACKET) { diff --git a/crates/ruff/src/rules/pycodestyle/mod.rs b/crates/ruff/src/rules/pycodestyle/mod.rs index 50cb780ad92cb..7b7f492426335 100644 --- a/crates/ruff/src/rules/pycodestyle/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/mod.rs @@ -128,6 +128,21 @@ mod tests { Ok(()) } + #[test] + fn shebang() -> Result<()> { + let diagnostics = test_path( + Path::new("pycodestyle/shebang.py"), + &settings::Settings::for_rules(vec![ + Rule::TooFewSpacesBeforeInlineComment, + Rule::NoSpaceAfterInlineComment, + Rule::NoSpaceAfterBlockComment, + Rule::MultipleLeadingHashesForBlockComment, + ]), + )?; + assert_messages!(diagnostics); + Ok(()) + } + #[test_case(false)] #[test_case(true)] fn task_tags(ignore_overlong_task_comments: bool) -> Result<()> { diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs index f8f153132c6e5..2923a9cefc81d 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/mod.rs @@ -151,6 +151,11 @@ pub(crate) struct LogicalLine<'a> { } impl<'a> LogicalLine<'a> { + /// Returns `true` if this line is positioned at the start of the file. + pub(crate) const fn is_start_of_file(&self) -> bool { + self.line.tokens_start == 0 + } + /// Returns `true` if this is a comment only line pub(crate) fn is_comment_only(&self) -> bool { self.flags() == TokenFlags::COMMENT diff --git a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs index 5ba261116ec51..30cf2a149c601 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/logical_lines/whitespace_before_comment.rs @@ -139,7 +139,6 @@ impl Violation for MultipleLeadingHashesForBlockComment { pub(crate) fn whitespace_before_comment( line: &LogicalLine, locator: &Locator, - is_first_row: bool, context: &mut LogicalLinesContext, ) { let mut prev_end = TextSize::default(); @@ -149,13 +148,13 @@ pub(crate) fn whitespace_before_comment( if let TokenKind::Comment = kind { let range = token.range(); - let line = locator.slice(TextRange::new( + let line_text = locator.slice(TextRange::new( locator.line_start(range.start()), range.start(), )); - let text = locator.slice(range); + let token_text = locator.slice(range); - let is_inline_comment = !line.trim().is_empty(); + let is_inline_comment = !line_text.trim().is_empty(); if is_inline_comment { if range.start() - prev_end < " ".text_len() { context.push( @@ -166,7 +165,7 @@ pub(crate) fn whitespace_before_comment( } // Split into the portion before and after the first space. - let mut parts = text.splitn(2, ' '); + let mut parts = token_text.splitn(2, ' '); let symbol = parts.next().unwrap_or(""); let comment = parts.next().unwrap_or(""); @@ -182,7 +181,7 @@ pub(crate) fn whitespace_before_comment( context.push(NoSpaceAfterInlineComment, range); } } else if let Some(bad_prefix) = bad_prefix { - if bad_prefix != '!' || !is_first_row { + if bad_prefix != '!' || !line.is_start_of_file() { if bad_prefix != '#' { context.push(NoSpaceAfterBlockComment, range); } else if !comment.is_empty() { diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E262_E26.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E262_E26.py.snap index 36c1bd5be8cb0..9f55ff13ab77d 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E262_E26.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E262_E26.py.snap @@ -47,6 +47,8 @@ E26.py:66:9: E262 Inline comment should start with `# ` 67 | # (Two spaces) Ok for block comment 68 | a = 42 # (Two spaces) | ^^^^^^^^^^^^^^^ E262 +69 | +70 | #: E265:5:1 | diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E265_E26.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E265_E26.py.snap index 72764afcb3c7f..d5246061018a5 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E265_E26.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E265_E26.py.snap @@ -40,4 +40,13 @@ E26.py:32:1: E265 Block comment should start with `# ` 35 | pass # an inline comment | +E26.py:73:1: E265 Block comment should start with `# ` + | +73 | # F Means test is failing (F) +74 | # EF Means test is giving error and Failing +75 | #! Means test is segfaulting + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E265 +76 | # 8 Means test runs forever + | + diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E266_E26.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E266_E26.py.snap index 4ecd7f71f792a..172a3352b8dbc 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E266_E26.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E266_E26.py.snap @@ -30,4 +30,13 @@ E26.py:26:1: E266 Too many leading `#` before block comment 30 | ######################################### | +E26.py:69:1: E266 Too many leading `#` before block comment + | +69 | #: E265:5:1 +70 | ### Means test is not done yet + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E266 +71 | # E Means test is giving error (E) +72 | # F Means test is failing (F) + | + diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__shebang.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__shebang.snap new file mode 100644 index 0000000000000..b3ef62b1e2b58 --- /dev/null +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__shebang.snap @@ -0,0 +1,13 @@ +--- +source: crates/ruff/src/rules/pycodestyle/mod.rs +--- +shebang.py:3:1: E265 Block comment should start with `# ` + | +3 | #!/usr/bin/python +4 | # +5 | #! + | ^^ E265 +6 | #: + | + +