return_and_then: only lint returning expressions

If an expression is not going to return from the current function of
closure, it should not get linted.

This also allows `return` expression to be linted, in addition to the
final expression. Those require blockification and proper indentation.
This commit is contained in:
Samuel Tardieu 2025-05-11 17:33:20 +02:00
parent 7f6d507bba
commit c040e9f6fc
No known key found for this signature in database
GPG key ID: BDDC3208C6FEAFA8
4 changed files with 165 additions and 9 deletions

View file

@ -67,8 +67,60 @@ fn main() {
.first() // creates temporary reference
.and_then(|x| test_opt_block(Some(*x)))
}
fn in_closure() -> bool {
let _ = || {
let x = Some("")?;
if x.len() > 2 { Some(3) } else { None }
//~^ return_and_then
};
true
}
fn with_return(shortcut: bool) -> Option<i32> {
if shortcut {
return {
let x = Some("")?;
if x.len() > 2 { Some(3) } else { None }
};
//~^ return_and_then
};
None
}
fn with_return_multiline(shortcut: bool) -> Option<i32> {
if shortcut {
return {
let mut x = Some("")?;
let x = format!("{x}.");
if x.len() > 2 { Some(3) } else { None }
};
//~^^^^ return_and_then
};
None
}
}
fn gen_option(n: i32) -> Option<i32> {
Some(n)
}
mod issue14781 {
fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> {
Ok((1, 1))
}
fn bug(_: Option<&str>) -> Result<(), ()> {
let year: Option<&str> = None;
let month: Option<&str> = None;
let day: Option<&str> = None;
let _day = if let (Some(year), Some(month)) = (year, month) {
day.and_then(|day| foo(day, (1, 31)).ok())
} else {
None
};
Ok(())
}
}

View file

@ -63,8 +63,55 @@ fn main() {
.first() // creates temporary reference
.and_then(|x| test_opt_block(Some(*x)))
}
fn in_closure() -> bool {
let _ = || {
Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
//~^ return_and_then
};
true
}
fn with_return(shortcut: bool) -> Option<i32> {
if shortcut {
return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None });
//~^ return_and_then
};
None
}
fn with_return_multiline(shortcut: bool) -> Option<i32> {
if shortcut {
return Some("").and_then(|mut x| {
let x = format!("{x}.");
if x.len() > 2 { Some(3) } else { None }
});
//~^^^^ return_and_then
};
None
}
}
fn gen_option(n: i32) -> Option<i32> {
Some(n)
}
mod issue14781 {
fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> {
Ok((1, 1))
}
fn bug(_: Option<&str>) -> Result<(), ()> {
let year: Option<&str> = None;
let month: Option<&str> = None;
let day: Option<&str> = None;
let _day = if let (Some(year), Some(month)) = (year, month) {
day.and_then(|day| foo(day, (1, 31)).ok())
} else {
None
};
Ok(())
}
}

View file

@ -101,5 +101,50 @@ LL + })?;
LL + if x.len() > 2 { Some(3) } else { None }
|
error: aborting due to 7 previous errors
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:69:13
|
LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
LL ~ let x = Some("")?;
LL + if x.len() > 2 { Some(3) } else { None }
|
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:77:20
|
LL | return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
LL ~ return {
LL + let x = Some("")?;
LL + if x.len() > 2 { Some(3) } else { None }
LL ~ };
|
error: use the `?` operator instead of an `and_then` call
--> tests/ui/return_and_then.rs:85:20
|
LL | return Some("").and_then(|mut x| {
| ____________________^
LL | | let x = format!("{x}.");
LL | | if x.len() > 2 { Some(3) } else { None }
LL | | });
| |______________^
|
help: try
|
LL ~ return {
LL + let mut x = Some("")?;
LL + let x = format!("{x}.");
LL + if x.len() > 2 { Some(3) } else { None }
LL ~ };
|
error: aborting due to 10 previous errors