Add new lint: manual_highest_one - #17472
Conversation
|
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. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
|
Sorry, I confused with |
|
I added some test cases and found that |
| /// ``` | ||
| #[clippy::version = "1.99.0"] | ||
| pub MANUAL_HIGHEST_ONE, | ||
| nursery, |
There was a problem hiding this comment.
It's best to choose a category other than nursery.
There was a problem hiding this comment.
Its best to change it here.
There was a problem hiding this comment.
Fixed.
manual_highest_one and manual_ilog2 share some patterns. For now, I simply allow them, but is there a better choice?
ea630fa to
d8ed010
Compare
This comment has been minimized.
This comment has been minimized.
| let _ = identity!(31) - u.leading_zeros(); //~ manual_highest_one | ||
| let _ = 31 - identity!(u).leading_zeros(); //~ manual_highest_one | ||
| let _ = 31 - double!(u).leading_zeros(); //~ manual_highest_one | ||
| let _ = thirty_one!() - u.leading_zeros(); |
There was a problem hiding this comment.
We should be more conservative about macro expanded subexpressions, especially if the lint is aiming to be MachineApplicable. So we should also skip receivers or const operands coming from expansion too.
There was a problem hiding this comment.
I finally understand which kinds of macro usages are allowed. For example, macro!().bit_widrh() - 1 should be linted because macro can be modified without side effect as long as the bit_width call remains valid.
There was a problem hiding this comment.
To my understanding, Span carries no information about identity! macro because the macro does nothing and span is not updated during expansion. This is a corner case. IMO, we have two options:
- Introduce
EarlyLintPassand tackle the AST. - Ignore the case because it is unlikely to matter in practice. Appliciability can be also lowered.
There was a problem hiding this comment.
Changing this lint to an early pass would be an unecessary complexity for an edge case, it's better to just not deal with macros.
There was a problem hiding this comment.
Early passes also run after macro expansion so it wouldn't help anyway. There's currently no way to detect an identity macro ($e:expr => $e).
There was a problem hiding this comment.
I will ignore identity! macro and leave it a false positive, lowering applicaibility to MaybeIncorrect.
| /// ``` | ||
| #[clippy::version = "1.99.0"] | ||
| pub MANUAL_HIGHEST_ONE, | ||
| nursery, |
There was a problem hiding this comment.
Its best to change it here.
| // False positive: Currently, `integer_const` does not support `NonZero` | ||
| // and related aliases. It is better to enhance `integer_const`. | ||
| let _ = NonZeroU32::BITS - 1 - nz.leading_zeros(); |
There was a problem hiding this comment.
This should be handled, Instead of relying only on integer_const, maybe we can have a small helper that first tries integer_const, and if that fails, recognizes T::BITS directly and gets the bit width from the type:
fn integer_const_or_bits(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> Option<u128> {
integer_const(cx, expr, ctxt).or_else(|| {
if let ExprKind::Path(QPath::TypeRelative(hir_ty, segment)) = expr.kind
&& segment.ident.name == sym::BITS
{
bit_width(cx, cx.typeck_results().node_type(hir_ty.hir_id))
} else {
None
}
})
}Then we can use it in the bit_width checks.
9d05837 to
a822976
Compare
This comment has been minimized.
This comment has been minimized.
f95a04b to
1017af2
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1017af2 to
6f14e7b
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
☔ The latest upstream changes (possibly #17552) made this pull request unmergeable. Please resolve the merge conflicts. |
View all comments
implementation of #16985 (comment)
checklist
.stderrfile)cargo testpasses locally (except forcargo test --test dogfoodbecausetikv_jemalloc_sysis not resolved)cargo dev update_lintscargo dev fmtchangelog: [
manual_highest_one]: add new lint to check manual implementation ofhighest_one()