-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Needless return #5903
Needless return #5903
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @matthiaskrgr (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
@bors delegate=ebroto |
✌️ @ebroto can now approve this pull request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good on a general note, thanks!
I left some comments. Also, instead of adding a new module, can we reuse the let_and_return
one?. This way we don't have to repeat the code to check if the last statement borrows. I would suggest to change the name of the current returns.rs
to unused_unit.rs
because it's the last lint remaining there, and rename let_and_return.rs
to returns.rs
.
clippy_lints/src/needless_return.rs
Outdated
} | ||
} | ||
|
||
fn check_final_expr(cx: &LateContext<'_>, expr: &Expr<'_>, span: Option<Span>, replacement: RetReplacement) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn check_final_expr(cx: &LateContext<'_>, expr: &Expr<'_>, span: Option<Span>, replacement: RetReplacement) { | |
fn check_final_expr<'tcx>( | |
cx: &LateContext<'tcx>, | |
expr: &'tcx Expr<'tcx>, | |
span: Option<Span>, | |
replacement: RetReplacement, | |
) { | |
if last_statement_borrows(cx, expr) { | |
return; | |
} | |
This way we could get rid of the rest of calls to last_statement_borrows
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, I just realized the placement of the call to last_statement_borrows
is wrong. This would lead to false negatives in cases like the following
fn read_line2(value: bool) -> String {
if value {
use std::io::BufRead;
let stdin = ::std::io::stdin();
let _a = stdin.lock().lines().next().unwrap().unwrap();
return String::from("test");
} else {
return String::new();
}
}
because the visitor would walk recursively and see the borrow in the if block. The check should be done in the ExprKind::Ret(..)
part, I'm adding a further comment.
We could add this snippet as an extra test too.
clippy_lints/src/needless_return.rs
Outdated
attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) | ||
} | ||
|
||
fn check_block_return(cx: &LateContext<'_>, block: &Block<'_>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn check_block_return(cx: &LateContext<'_>, block: &Block<'_>) { | |
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { |
We need explicit lifetimes here to apply my previous suggestion.
clippy_lints/src/needless_return.rs
Outdated
FnKind::Closure(_) => { | ||
if !last_statement_borrows(cx, &body.value) { | ||
check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty) | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FnKind::Closure(_) => { | |
if !last_statement_borrows(cx, &body.value) { | |
check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty) | |
} | |
}, | |
FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty), |
We can get rid of the if here after moving the call to last_statement_borrows
clippy_lints/src/needless_return.rs
Outdated
if let Some(expr) = block.expr { | ||
if !last_statement_borrows(cx, expr) { | ||
check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty); | ||
} | ||
} else if let Some(stmt) = block.stmts.iter().last() { | ||
match stmt.kind { | ||
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { | ||
if !last_statement_borrows(cx, expr) { | ||
check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); | ||
} | ||
}, | ||
_ => (), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if let Some(expr) = block.expr { | |
if !last_statement_borrows(cx, expr) { | |
check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty); | |
} | |
} else if let Some(stmt) = block.stmts.iter().last() { | |
match stmt.kind { | |
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { | |
if !last_statement_borrows(cx, expr) { | |
check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); | |
} | |
}, | |
_ => (), | |
} | |
} | |
check_block_return(cx, block); |
We can simplify here now too
clippy_lints/src/needless_return.rs
Outdated
ExprKind::Ret(ref inner) => { | ||
// allow `#[cfg(a)] return a; #[cfg(b)] return b;` | ||
if !expr.attrs.iter().any(attr_is_cfg) { | ||
emit_return_lint( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before emitting, we could add something like:
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows {
Thanks! I will publish the changes according to the latest review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there, just some small changes!
Also, could you:
- Change the "changelog:" line to show the lint between backticks like this: [
needless_return
]? This way the link in theCHANGELOG.md
will work. - Please rebase to get rid of the merge commits.
clippy_lints/src/returns.rs
Outdated
if last_statement_borrows(cx, expr) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if last_statement_borrows(cx, expr) { | |
return; | |
} |
Sorry if I was not clear, this early return should be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, I misunderstood the change
tests/ui/needless_return.fixed
Outdated
return stdin.lock().lines().next().unwrap().unwrap(); | ||
} | ||
|
||
fn read_line2(value: bool) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check that this is linted because the borrow does not happen in the last statement of the block. Removing the early return I mentioned in my previous comment will fix this.
We could maybe change the name to make the intent more clear, what about borrows_but_not_last
?
tests/ui/needless_return.fixed
Outdated
mod no_lint_if_stmt_borrows { | ||
mod issue_5858 { | ||
fn read_line() -> String { | ||
use std::io::BufRead; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's factor out this import at the module level, removing this one and the one in the other function.
clippy_lints/src/unused_unit.rs
Outdated
/// **Known problems:** The lint currently misses unit return types in types, | ||
/// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// **Known problems:** The lint currently misses unit return types in types, | |
/// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`. | |
/// **Known problems:** None. |
Now that we're at it, could you make this change, please? I should have done it in a previous PR of mine 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure :)
Thanks for the review again! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! There seems to be a problem with the rebase though, the merge commits are still there and there's now additional commits from other PRs.
The process for doing the rebase should be something like the following. There are other ways, this is how I would do it (well, how my editor does it 😄):
# If you already have the remote added as "upstream", skip this first step
git remote add -f upstream https\://github.com/rust-lang/rust-clippy.git
# This will update our local master
git fetch --all
git checkout master
git reset --hard upstream/master
# This will be the actual rebase
git checkout needless_return
git rebase --interactive master
# When the editor window appears, keep just your commits. Since we have master pointing
# to the latests upstream/master, maybe git will see that and only show your commits,
# in that case you're already good to go
git push --force
After that only your commits should be on your branch.
If you have any problem with the process, we can make it work for you, but we will have to ping an actual collaborator since I don't have permissions to write to your fork (don't worry, I have to ping them anyway for a last review 😄).
hi @ebroto |
LGTM, thanks! The CI errors are unrelated to your PR and have been fixed by this other PR, another rebase should do the job. FYI this happens once in a while, when rustc breaks clippy the fixes need to be synced. cc @flip1995 this should be ready to merge when CI passes. |
📌 Commit baa4cb1 has been approved by |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Fixes #5858
changelog: fix false positive [
needless_return
]