manual_pop_if: lint when the popped value is discarded - #17630
Conversation
`if vec.last().is_some_and(|x| *x > 5) { vec.pop(); }` is exactly
`vec.pop_if(|x| *x > 5);`, but the lint only fired when the popped value
was unwrapped. Accept a pop whose value is thrown away as well, both as a
plain `collection.pop();` statement and as `let _ = collection.pop();`.
A discarded pop is only recognised in statement position. Unlike
`.unwrap()`, a `collection.pop()` in value position carries no assertion
that the collection is non-empty, so walking every expression for one
would be a large false-positive surface for no benefit.
An annotated `let _: Option<i32> = collection.pop();` is left alone too:
the suggestion replaces the whole statement, and the annotation may be
the only thing pinning down the element type of the collection.
|
Thanks for the pull request, and welcome! You should hear from one of our reviewers after this PR gets at least 2 reviews from the community. Please see the contribution instructions for more information. |
| // A statement that pops and throws the value away: `collection.pop();` or | ||
| // `let _ = collection.pop();`. Unlike a bare `collection.pop()` in value position, | ||
| // this is exactly what `pop_if` does, so it is worth linting on its own. | ||
| // | ||
| // An annotated `let _: Option<i32> = collection.pop();` is left alone: the whole | ||
| // statement is replaced by the suggestion, and the annotation may be what pins down | ||
| // the element type of the collection. |
There was a problem hiding this comment.
please write comments a bit more human.
no weird semicolons, one sentence per line, short sentnces.
this goes for all the code comments you added.
There was a problem hiding this comment.
let me know if this is succint enough, I can rework if not.
| // Returns the pop call of a statement, along with the position the replaced code | ||
| // starts at (which is the start of the statement itself, as e.g. the `let _ =` of a | ||
| // discarded pop is replaced as well). | ||
| let as_pop_stmt = |stmt: &Stmt<'tcx>| -> Option<(&'tcx Expr<'tcx>, Span, BytePos)> { |
There was a problem hiding this comment.
only used once, please inline where you got the code from.
you can extract code, but this does not seem intentional.
There was a problem hiding this comment.
yeah, that was leftover from an earlier iteration, not intentional.
inlined it back into the single statement check.
Inline `as_pop_stmt` into its single call site. Reword the added comments into short sentences, one per line.
Let sentences wrap across lines instead of forcing one per line, in line with the surrounding comment style.
changelog: [
manual_pop_if]: also lint when the popped value is discarded, e.g.vec.pop();if vec.last().is_some_and(|x| *x > 5) { vec.pop(); }is exactlyvec.pop_if(|x| *x > 5);, but the lint only fired when the popped value was unwrapped. Accept a pop whose value is thrown away as well, both as a plaincollection.pop();statement and aslet _ = collection.pop();.A discarded pop is only recognised in statement position. Unlike
.unwrap(), acollection.pop()in value position carries no assertion that the collection is non-empty, so walking every expression for one would be a large false-positive surface for no benefit.An annotated
let _: Option<i32> = collection.pop();is left alone too: the suggestion replaces the whole statement, and the annotation may be the only thing pinning down the element type of the collection.