mirror of https://github.com/astral-sh/ruff
Implement pylint's `else-if-used` rule (`PLR5501`) (#3231)
Attempt to implement else-if-used https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/else-if-used.html Issue #970
This commit is contained in:
parent
994e2e0903
commit
0b7d6b9097
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""
|
||||||
|
Test for else-if-used
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def ok0():
|
||||||
|
"""Should not trigger on elif"""
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
elif 2:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def ok1():
|
||||||
|
"""If the orelse has more than 1 item in it, shouldn't trigger"""
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def ok2():
|
||||||
|
"""If the orelse has more than 1 item in it, shouldn't trigger"""
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def not_ok0():
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if 2:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def not_ok1():
|
||||||
|
if 1:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if 2:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
@ -1633,6 +1633,13 @@ where
|
||||||
if self.settings.rules.enabled(&Rule::OutdatedVersionBlock) {
|
if self.settings.rules.enabled(&Rule::OutdatedVersionBlock) {
|
||||||
pyupgrade::rules::outdated_version_block(self, stmt, test, body, orelse);
|
pyupgrade::rules::outdated_version_block(self, stmt, test, body, orelse);
|
||||||
}
|
}
|
||||||
|
if self.settings.rules.enabled(&Rule::CollapsibleElseIf) {
|
||||||
|
if let Some(diagnostic) =
|
||||||
|
pylint::rules::collapsible_else_if(orelse, self.locator)
|
||||||
|
{
|
||||||
|
self.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Assert { test, msg } => {
|
StmtKind::Assert { test, msg } => {
|
||||||
if self.settings.rules.enabled(&Rule::AssertTuple) {
|
if self.settings.rules.enabled(&Rule::AssertTuple) {
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||||
|
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ ruff_macros::register_rules!(
|
||||||
rules::pylint::rules::BadStringFormatType,
|
rules::pylint::rules::BadStringFormatType,
|
||||||
rules::pylint::rules::BidirectionalUnicode,
|
rules::pylint::rules::BidirectionalUnicode,
|
||||||
rules::pylint::rules::BadStrStripCall,
|
rules::pylint::rules::BadStrStripCall,
|
||||||
|
rules::pylint::rules::CollapsibleElseIf,
|
||||||
rules::pylint::rules::UselessImportAlias,
|
rules::pylint::rules::UselessImportAlias,
|
||||||
rules::pylint::rules::UnnecessaryDirectLambdaCall,
|
rules::pylint::rules::UnnecessaryDirectLambdaCall,
|
||||||
rules::pylint::rules::NonlocalWithoutBinding,
|
rules::pylint::rules::NonlocalWithoutBinding,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ mod tests {
|
||||||
#[test_case(Rule::TooManyArguments, Path::new("too_many_arguments.py"); "PLR0913")]
|
#[test_case(Rule::TooManyArguments, Path::new("too_many_arguments.py"); "PLR0913")]
|
||||||
#[test_case(Rule::TooManyBranches, Path::new("too_many_branches.py"); "PLR0912")]
|
#[test_case(Rule::TooManyBranches, Path::new("too_many_branches.py"); "PLR0912")]
|
||||||
#[test_case(Rule::TooManyStatements, Path::new("too_many_statements.py"); "PLR0915")]
|
#[test_case(Rule::TooManyStatements, Path::new("too_many_statements.py"); "PLR0915")]
|
||||||
|
#[test_case(Rule::CollapsibleElseIf, Path::new("collapsible_else_if.py"); "PLR5501")]
|
||||||
#[test_case(Rule::BadStringFormatType, Path::new("bad_string_format_type.py"); "PLE1307")]
|
#[test_case(Rule::BadStringFormatType, Path::new("bad_string_format_type.py"); "PLE1307")]
|
||||||
#[test_case(Rule::BidirectionalUnicode, Path::new("bidirectional_unicode.py"); "PLE2502")]
|
#[test_case(Rule::BidirectionalUnicode, Path::new("bidirectional_unicode.py"); "PLE2502")]
|
||||||
#[test_case(Rule::BadStrStripCall, Path::new("bad_str_strip_call.py"); "PLE01310")]
|
#[test_case(Rule::BadStrStripCall, Path::new("bad_str_strip_call.py"); "PLE01310")]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
use rustpython_parser::ast::{Stmt, StmtKind};
|
||||||
|
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::registry::Diagnostic;
|
||||||
|
use crate::source_code::Locator;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
pub struct CollapsibleElseIf;
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Violation for CollapsibleElseIf {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Consider using `elif` instead of `else` then `if` to remove one indentation level")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// PLR5501
|
||||||
|
pub fn collapsible_else_if(orelse: &[Stmt], locator: &Locator) -> Option<Diagnostic> {
|
||||||
|
if orelse.len() == 1 {
|
||||||
|
let first = &orelse[0];
|
||||||
|
if matches!(first.node, StmtKind::If { .. }) {
|
||||||
|
// Determine whether this is an `elif`, or an `if` in an `else` block.
|
||||||
|
if locator
|
||||||
|
.slice(&Range {
|
||||||
|
location: first.location,
|
||||||
|
end_location: first.end_location.unwrap(),
|
||||||
|
})
|
||||||
|
.starts_with("if")
|
||||||
|
{
|
||||||
|
return Some(Diagnostic::new(
|
||||||
|
CollapsibleElseIf,
|
||||||
|
Range::from_located(first),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ pub use await_outside_async::{await_outside_async, AwaitOutsideAsync};
|
||||||
pub use bad_str_strip_call::{bad_str_strip_call, BadStrStripCall};
|
pub use bad_str_strip_call::{bad_str_strip_call, BadStrStripCall};
|
||||||
pub use bad_string_format_type::{bad_string_format_type, BadStringFormatType};
|
pub use bad_string_format_type::{bad_string_format_type, BadStringFormatType};
|
||||||
pub use bidirectional_unicode::{bidirectional_unicode, BidirectionalUnicode};
|
pub use bidirectional_unicode::{bidirectional_unicode, BidirectionalUnicode};
|
||||||
|
pub use collapsible_else_if::{collapsible_else_if, CollapsibleElseIf};
|
||||||
pub use comparison_of_constant::{comparison_of_constant, ComparisonOfConstant};
|
pub use comparison_of_constant::{comparison_of_constant, ComparisonOfConstant};
|
||||||
pub use consider_using_sys_exit::{consider_using_sys_exit, ConsiderUsingSysExit};
|
pub use consider_using_sys_exit::{consider_using_sys_exit, ConsiderUsingSysExit};
|
||||||
pub use global_variable_not_assigned::GlobalVariableNotAssigned;
|
pub use global_variable_not_assigned::GlobalVariableNotAssigned;
|
||||||
|
|
@ -33,6 +34,7 @@ mod await_outside_async;
|
||||||
mod bad_str_strip_call;
|
mod bad_str_strip_call;
|
||||||
mod bad_string_format_type;
|
mod bad_string_format_type;
|
||||||
mod bidirectional_unicode;
|
mod bidirectional_unicode;
|
||||||
|
mod collapsible_else_if;
|
||||||
mod comparison_of_constant;
|
mod comparison_of_constant;
|
||||||
mod consider_using_sys_exit;
|
mod consider_using_sys_exit;
|
||||||
mod global_variable_not_assigned;
|
mod global_variable_not_assigned;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pylint/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
CollapsibleElseIf: ~
|
||||||
|
location:
|
||||||
|
row: 38
|
||||||
|
column: 8
|
||||||
|
end_location:
|
||||||
|
row: 39
|
||||||
|
column: 16
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
CollapsibleElseIf: ~
|
||||||
|
location:
|
||||||
|
row: 46
|
||||||
|
column: 8
|
||||||
|
end_location:
|
||||||
|
row: 49
|
||||||
|
column: 16
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
||||||
|
|
@ -1847,6 +1847,10 @@
|
||||||
"PLR20",
|
"PLR20",
|
||||||
"PLR200",
|
"PLR200",
|
||||||
"PLR2004",
|
"PLR2004",
|
||||||
|
"PLR5",
|
||||||
|
"PLR55",
|
||||||
|
"PLR550",
|
||||||
|
"PLR5501",
|
||||||
"PLW",
|
"PLW",
|
||||||
"PLW0",
|
"PLW0",
|
||||||
"PLW01",
|
"PLW01",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue