Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend unnecessary-pass (PIE790) to trigger on all unnecessary pass statements #7697

Merged
merged 3 commits into from Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/flake8_pie/PIE790.py
Expand Up @@ -123,3 +123,14 @@ class Error(Exception):

def foo() -> None:
pass


def foo():
print("foo")
pass


def foo():
"""A docstring."""
print("foo")
pass
4 changes: 2 additions & 2 deletions crates/ruff_linter/src/rules/flake8_pie/rules/mod.rs
@@ -1,17 +1,17 @@
pub(crate) use duplicate_class_field_definition::*;
pub(crate) use multiple_starts_ends_with::*;
pub(crate) use no_unnecessary_pass::*;
pub(crate) use non_unique_enums::*;
pub(crate) use reimplemented_list_builtin::*;
pub(crate) use unnecessary_dict_kwargs::*;
pub(crate) use unnecessary_pass::*;
pub(crate) use unnecessary_range_start::*;
pub(crate) use unnecessary_spread::*;

mod duplicate_class_field_definition;
mod multiple_starts_ends_with;
mod no_unnecessary_pass;
mod non_unique_enums;
mod reimplemented_list_builtin;
mod unnecessary_dict_kwargs;
mod unnecessary_pass;
mod unnecessary_range_start;
mod unnecessary_spread;

This file was deleted.

77 changes: 77 additions & 0 deletions crates/ruff_linter/src/rules/flake8_pie/rules/unnecessary_pass.rs
@@ -0,0 +1,77 @@
use ruff_python_ast::Stmt;

use ruff_diagnostics::AlwaysFixableViolation;
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::whitespace::trailing_comment_start_offset;
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
use crate::fix;
use crate::registry::AsRule;

/// ## What it does
/// Checks for unnecessary `pass` statements in functions, classes, and other
/// blocks.
///
/// ## Why is this bad?
/// In Python, the `pass` statement serves as a placeholder, allowing for
/// syntactically correct empty code blocks. The primary purpose of the `pass`
/// statement is to avoid syntax errors in situations where a statement is
/// syntactically required, but no code needs to be executed.
///
/// If a `pass` statement is present in a code block that includes at least
/// one other statement (even, e.g., a docstring), it is unnecessary and should
/// be removed.
///
/// ## Example
/// ```python
/// def func():
/// """Placeholder docstring."""
/// pass
/// ```
///
/// Use instead:
/// ```python
/// def func():
/// """Placeholder docstring."""
/// ```
///
/// ## References
/// - [Python documentation: The `pass` statement](https://docs.python.org/3/reference/simple_stmts.html#the-pass-statement)
#[violation]
pub struct UnnecessaryPass;

impl AlwaysFixableViolation for UnnecessaryPass {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unnecessary `pass` statement")
}

fn fix_title(&self) -> String {
"Remove unnecessary `pass`".to_string()
}
}

/// PIE790
pub(crate) fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
if body.len() < 2 {
return;
}

body.iter()
.filter(|stmt| stmt.is_pass_stmt())
.for_each(|stmt| {
let mut diagnostic = Diagnostic::new(UnnecessaryPass, stmt.range());
if checker.patch(diagnostic.kind.rule()) {
let edit =
if let Some(index) = trailing_comment_start_offset(stmt, checker.locator()) {
Edit::range_deletion(stmt.range().add_end(index))
} else {
fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer())
};
diagnostic.set_fix(Fix::automatic(edit));
}
checker.diagnostics.push(diagnostic);
});
}
Expand Up @@ -317,4 +317,37 @@ PIE790.py:101:5: PIE790 [*] Unnecessary `pass` statement
103 103 |
104 104 | class Foo:

PIE790.py:130:5: PIE790 [*] Unnecessary `pass` statement
|
128 | def foo():
129 | print("foo")
130 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`

ℹ Fix
127 127 |
128 128 | def foo():
129 129 | print("foo")
130 |- pass
131 130 |
132 131 |
133 132 | def foo():

PIE790.py:136:5: PIE790 [*] Unnecessary `pass` statement
|
134 | """A docstring."""
135 | print("foo")
136 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`

ℹ Fix
133 133 | def foo():
134 134 | """A docstring."""
135 135 | print("foo")
136 |- pass