mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:44:56 +00:00
Avoid unnecessary-else violations in elif
branches (#2881)
Long-time source of confusion -- two reports over 1800 issues apart. Closes #1035. Closes #2879.
This commit is contained in:
parent
2bf7b35268
commit
c6c15d5cf9
3 changed files with 58 additions and 13 deletions
|
@ -136,3 +136,24 @@ def nested2(x, y, z):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
a = z
|
a = z
|
||||||
|
|
||||||
|
|
||||||
|
def elif1(x, y, w, z):
|
||||||
|
for i in x:
|
||||||
|
if i > y:
|
||||||
|
a = z
|
||||||
|
elif i > w:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
a = z
|
||||||
|
|
||||||
|
|
||||||
|
def elif2(x, y, w, z):
|
||||||
|
for i in x:
|
||||||
|
if i > y:
|
||||||
|
a = z
|
||||||
|
else:
|
||||||
|
if i > w:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
a = z
|
||||||
|
|
|
@ -423,13 +423,7 @@ fn superfluous_elif(checker: &mut Checker, stack: &Stack) -> bool {
|
||||||
|
|
||||||
/// RET505, RET506, RET507, RET508
|
/// RET505, RET506, RET507, RET508
|
||||||
fn superfluous_else(checker: &mut Checker, stack: &Stack) -> bool {
|
fn superfluous_else(checker: &mut Checker, stack: &Stack) -> bool {
|
||||||
for stmt in &stack.ifs {
|
for stmt in &stack.elses {
|
||||||
let StmtKind::If { orelse, .. } = &stmt.node else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
if orelse.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if superfluous_else_node(checker, stmt, Branch::Else) {
|
if superfluous_else_node(checker, stmt, Branch::Else) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::ast::visitor::Visitor;
|
||||||
pub struct Stack<'a> {
|
pub struct Stack<'a> {
|
||||||
pub returns: Vec<(&'a Stmt, Option<&'a Expr>)>,
|
pub returns: Vec<(&'a Stmt, Option<&'a Expr>)>,
|
||||||
pub yields: Vec<&'a Expr>,
|
pub yields: Vec<&'a Expr>,
|
||||||
pub ifs: Vec<&'a Stmt>,
|
pub elses: Vec<&'a Stmt>,
|
||||||
pub elifs: Vec<&'a Stmt>,
|
pub elifs: Vec<&'a Stmt>,
|
||||||
pub refs: FxHashMap<&'a str, Vec<Location>>,
|
pub refs: FxHashMap<&'a str, Vec<Location>>,
|
||||||
pub non_locals: FxHashSet<&'a str>,
|
pub non_locals: FxHashSet<&'a str>,
|
||||||
|
@ -20,6 +20,7 @@ pub struct Stack<'a> {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ReturnVisitor<'a> {
|
pub struct ReturnVisitor<'a> {
|
||||||
pub stack: Stack<'a>,
|
pub stack: Stack<'a>,
|
||||||
|
parents: Vec<&'a Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ReturnVisitor<'a> {
|
impl<'a> ReturnVisitor<'a> {
|
||||||
|
@ -72,16 +73,37 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||||
self.stack
|
self.stack
|
||||||
.returns
|
.returns
|
||||||
.push((stmt, value.as_ref().map(|expr| &**expr)));
|
.push((stmt, value.as_ref().map(|expr| &**expr)));
|
||||||
|
|
||||||
|
self.parents.push(stmt);
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
|
self.parents.pop();
|
||||||
}
|
}
|
||||||
StmtKind::If { orelse, .. } => {
|
StmtKind::If { orelse, .. } => {
|
||||||
if orelse.len() == 1 && matches!(orelse.first().unwrap().node, StmtKind::If { .. })
|
let is_elif_arm = self.parents.iter().any(|parent| {
|
||||||
{
|
if let StmtKind::If { orelse, .. } = &parent.node {
|
||||||
self.stack.elifs.push(stmt);
|
orelse.len() == 1 && &orelse[0] == stmt
|
||||||
} else {
|
} else {
|
||||||
self.stack.ifs.push(stmt);
|
false
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if !is_elif_arm {
|
||||||
|
let has_elif = orelse.len() == 1
|
||||||
|
&& matches!(orelse.first().unwrap().node, StmtKind::If { .. });
|
||||||
|
let has_else = !orelse.is_empty();
|
||||||
|
|
||||||
|
if has_elif {
|
||||||
|
// `stmt` is an `if` block followed by an `elif` clause.
|
||||||
|
self.stack.elifs.push(stmt);
|
||||||
|
} else if has_else {
|
||||||
|
// `stmt` is an `if` block followed by an `else` clause.
|
||||||
|
self.stack.elses.push(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parents.push(stmt);
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
|
self.parents.pop();
|
||||||
}
|
}
|
||||||
StmtKind::Assign { targets, value, .. } => {
|
StmtKind::Assign { targets, value, .. } => {
|
||||||
if let ExprKind::Name { id, .. } = &value.node {
|
if let ExprKind::Name { id, .. } = &value.node {
|
||||||
|
@ -109,16 +131,24 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||||
self.stack
|
self.stack
|
||||||
.loops
|
.loops
|
||||||
.push((stmt.location, stmt.end_location.unwrap()));
|
.push((stmt.location, stmt.end_location.unwrap()));
|
||||||
|
|
||||||
|
self.parents.push(stmt);
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
|
self.parents.pop();
|
||||||
}
|
}
|
||||||
StmtKind::Try { .. } => {
|
StmtKind::Try { .. } => {
|
||||||
self.stack
|
self.stack
|
||||||
.tries
|
.tries
|
||||||
.push((stmt.location, stmt.end_location.unwrap()));
|
.push((stmt.location, stmt.end_location.unwrap()));
|
||||||
|
|
||||||
|
self.parents.push(stmt);
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
|
self.parents.pop();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
self.parents.push(stmt);
|
||||||
visitor::walk_stmt(self, stmt);
|
visitor::walk_stmt(self, stmt);
|
||||||
|
self.parents.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue