Do not lint result from macro expansion
If parts of the expression comes from macro expansion, it may match an expression equivalent to `is_power_of_two()` by chance only.
This commit is contained in:
parent
89385c135d
commit
1cab0b412e
4 changed files with 56 additions and 14 deletions
|
|
@ -35,8 +35,8 @@ declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if let ExprKind::Binary(bin_op, lhs, rhs) = expr.kind
|
||||
&& bin_op.node == BinOpKind::Eq
|
||||
if !expr.span.from_expansion()
|
||||
&& let Some((lhs, rhs)) = unexpanded_binop_operands(expr, BinOpKind::Eq)
|
||||
{
|
||||
if let Some(a) = count_ones_receiver(cx, lhs)
|
||||
&& is_integer_literal(rhs, 1)
|
||||
|
|
@ -92,8 +92,7 @@ fn is_one_less<'tcx>(
|
|||
greater: &'tcx Expr<'tcx>,
|
||||
smaller: &Expr<'tcx>,
|
||||
) -> Option<&'tcx Expr<'tcx>> {
|
||||
if let ExprKind::Binary(op, lhs, rhs) = smaller.kind
|
||||
&& op.node == BinOpKind::Sub
|
||||
if let Some((lhs, rhs)) = unexpanded_binop_operands(smaller, BinOpKind::Sub)
|
||||
&& SpanlessEq::new(cx).eq_expr(greater, lhs)
|
||||
&& is_integer_literal(rhs, 1)
|
||||
&& matches!(cx.typeck_results().expr_ty_adjusted(greater).kind(), ty::Uint(_))
|
||||
|
|
@ -106,10 +105,19 @@ fn is_one_less<'tcx>(
|
|||
|
||||
/// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v`
|
||||
fn is_and_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if let ExprKind::Binary(op, lhs, rhs) = expr.kind
|
||||
&& op.node == BinOpKind::BitAnd
|
||||
let (lhs, rhs) = unexpanded_binop_operands(expr, BinOpKind::BitAnd)?;
|
||||
is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs))
|
||||
}
|
||||
|
||||
/// Return the operands of the `expr` binary operation if the operator is `op` and none of the
|
||||
/// operands come from expansion.
|
||||
fn unexpanded_binop_operands<'hir>(expr: &Expr<'hir>, op: BinOpKind) -> Option<(&'hir Expr<'hir>, &'hir Expr<'hir>)> {
|
||||
if let ExprKind::Binary(binop, lhs, rhs) = expr.kind
|
||||
&& binop.node == op
|
||||
&& !lhs.span.from_expansion()
|
||||
&& !rhs.span.from_expansion()
|
||||
{
|
||||
is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs))
|
||||
Some((lhs, rhs))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,17 @@
|
|||
#![warn(clippy::manual_is_power_of_two)]
|
||||
#![allow(clippy::precedence)]
|
||||
|
||||
macro_rules! binop {
|
||||
($a: expr, equal, $b: expr) => {
|
||||
$a == $b
|
||||
};
|
||||
($a: expr, and, $b: expr) => {
|
||||
$a & $b
|
||||
};
|
||||
($a: expr, minus, $b: expr) => {
|
||||
$a - $b
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = 16_u64;
|
||||
|
|
@ -27,4 +40,8 @@ fn main() {
|
|||
let i: i32 = 3;
|
||||
let _ = (i as u32).is_power_of_two();
|
||||
//~^ manual_is_power_of_two
|
||||
|
||||
let _ = binop!(a.count_ones(), equal, 1);
|
||||
let _ = binop!(a, and, a - 1) == 0;
|
||||
let _ = a & binop!(a, minus, 1) == 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,17 @@
|
|||
#![warn(clippy::manual_is_power_of_two)]
|
||||
#![allow(clippy::precedence)]
|
||||
|
||||
macro_rules! binop {
|
||||
($a: expr, equal, $b: expr) => {
|
||||
$a == $b
|
||||
};
|
||||
($a: expr, and, $b: expr) => {
|
||||
$a & $b
|
||||
};
|
||||
($a: expr, minus, $b: expr) => {
|
||||
$a - $b
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = 16_u64;
|
||||
|
|
@ -27,4 +40,8 @@ fn main() {
|
|||
let i: i32 = 3;
|
||||
let _ = i as u32 & (i as u32 - 1) == 0;
|
||||
//~^ manual_is_power_of_two
|
||||
|
||||
let _ = binop!(a.count_ones(), equal, 1);
|
||||
let _ = binop!(a, and, a - 1) == 0;
|
||||
let _ = a & binop!(a, minus, 1) == 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:6:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:19:13
|
||||
|
|
||||
LL | let _ = a.count_ones() == 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
|
@ -8,37 +8,37 @@ LL | let _ = a.count_ones() == 1;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:8:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:21:13
|
||||
|
|
||||
LL | let _ = a & (a - 1) == 0;
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:12:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:25:13
|
||||
|
|
||||
LL | let _ = 1 == a.count_ones();
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:14:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:27:13
|
||||
|
|
||||
LL | let _ = (a - 1) & a == 0;
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:16:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:29:13
|
||||
|
|
||||
LL | let _ = 0 == a & (a - 1);
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:18:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:31:13
|
||||
|
|
||||
LL | let _ = 0 == (a - 1) & a;
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
|
||||
|
||||
error: manually reimplementing `is_power_of_two`
|
||||
--> tests/ui/manual_is_power_of_two.rs:28:13
|
||||
--> tests/ui/manual_is_power_of_two.rs:41:13
|
||||
|
|
||||
LL | let _ = i as u32 & (i as u32 - 1) == 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue