Skip to content

Commit 29eec68

Browse files
committed
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.
1 parent 0d5e898 commit 29eec68

File tree

4 files changed

+37
-8
lines changed

4 files changed

+37
-8
lines changed

clippy_lints/src/manual_is_power_of_two.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
3535

3636
impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
3737
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
38-
if let ExprKind::Binary(bin_op, lhs, rhs) = expr.kind
38+
if !expr.span.from_expansion()
39+
&& let ExprKind::Binary(bin_op, lhs, rhs) = expr.kind
40+
&& !lhs.span.from_expansion()
41+
&& !rhs.span.from_expansion()
3942
&& bin_op.node == BinOpKind::Eq
4043
{
4144
if let Some(a) = count_ones_receiver(cx, lhs)
@@ -93,6 +96,8 @@ fn is_one_less<'tcx>(
9396
smaller: &Expr<'tcx>,
9497
) -> Option<&'tcx Expr<'tcx>> {
9598
if let ExprKind::Binary(op, lhs, rhs) = smaller.kind
99+
&& !lhs.span.from_expansion()
100+
&& !rhs.span.from_expansion()
96101
&& op.node == BinOpKind::Sub
97102
&& SpanlessEq::new(cx).eq_expr(greater, lhs)
98103
&& is_integer_literal(rhs, 1)
@@ -107,6 +112,8 @@ fn is_one_less<'tcx>(
107112
/// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v`
108113
fn is_and_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
109114
if let ExprKind::Binary(op, lhs, rhs) = expr.kind
115+
&& !lhs.span.from_expansion()
116+
&& !rhs.span.from_expansion()
110117
&& op.node == BinOpKind::BitAnd
111118
{
112119
is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs))

tests/ui/manual_is_power_of_two.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
#![warn(clippy::manual_is_power_of_two)]
2+
#![allow(clippy::precedence)]
3+
4+
macro_rules! binop {
5+
($a: expr, equal, $b: expr) => { $a == $b };
6+
($a: expr, and, $b: expr) => { $a & $b };
7+
($a: expr, minus, $b: expr) => { $a - $b };
8+
}
29

310
fn main() {
411
let a = 16_u64;
@@ -27,4 +34,8 @@ fn main() {
2734
let i: i32 = 3;
2835
let _ = (i as u32).is_power_of_two();
2936
//~^ manual_is_power_of_two
37+
38+
let _ = binop!(a.count_ones(), equal, 1);
39+
let _ = binop!(a, and, a - 1) == 0;
40+
let _ = a & binop!(a, minus, 1) == 0;
3041
}

tests/ui/manual_is_power_of_two.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
#![warn(clippy::manual_is_power_of_two)]
2+
#![allow(clippy::precedence)]
3+
4+
macro_rules! binop {
5+
($a: expr, equal, $b: expr) => { $a == $b };
6+
($a: expr, and, $b: expr) => { $a & $b };
7+
($a: expr, minus, $b: expr) => { $a - $b };
8+
}
29

310
fn main() {
411
let a = 16_u64;
@@ -27,4 +34,8 @@ fn main() {
2734
let i: i32 = 3;
2835
let _ = i as u32 & (i as u32 - 1) == 0;
2936
//~^ manual_is_power_of_two
37+
38+
let _ = binop!(a.count_ones(), equal, 1);
39+
let _ = binop!(a, and, a - 1) == 0;
40+
let _ = a & binop!(a, minus, 1) == 0;
3041
}

tests/ui/manual_is_power_of_two.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: manually reimplementing `is_power_of_two`
2-
--> tests/ui/manual_is_power_of_two.rs:6:13
2+
--> tests/ui/manual_is_power_of_two.rs:13:13
33
|
44
LL | let _ = a.count_ones() == 1;
55
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
@@ -8,37 +8,37 @@ LL | let _ = a.count_ones() == 1;
88
= help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]`
99

1010
error: manually reimplementing `is_power_of_two`
11-
--> tests/ui/manual_is_power_of_two.rs:8:13
11+
--> tests/ui/manual_is_power_of_two.rs:15:13
1212
|
1313
LL | let _ = a & (a - 1) == 0;
1414
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
1515

1616
error: manually reimplementing `is_power_of_two`
17-
--> tests/ui/manual_is_power_of_two.rs:12:13
17+
--> tests/ui/manual_is_power_of_two.rs:19:13
1818
|
1919
LL | let _ = 1 == a.count_ones();
2020
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
2121

2222
error: manually reimplementing `is_power_of_two`
23-
--> tests/ui/manual_is_power_of_two.rs:14:13
23+
--> tests/ui/manual_is_power_of_two.rs:21:13
2424
|
2525
LL | let _ = (a - 1) & a == 0;
2626
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
2727

2828
error: manually reimplementing `is_power_of_two`
29-
--> tests/ui/manual_is_power_of_two.rs:16:13
29+
--> tests/ui/manual_is_power_of_two.rs:23:13
3030
|
3131
LL | let _ = 0 == a & (a - 1);
3232
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
3333

3434
error: manually reimplementing `is_power_of_two`
35-
--> tests/ui/manual_is_power_of_two.rs:18:13
35+
--> tests/ui/manual_is_power_of_two.rs:25:13
3636
|
3737
LL | let _ = 0 == (a - 1) & a;
3838
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
3939

4040
error: manually reimplementing `is_power_of_two`
41-
--> tests/ui/manual_is_power_of_two.rs:28:13
41+
--> tests/ui/manual_is_power_of_two.rs:35:13
4242
|
4343
LL | let _ = i as u32 & (i as u32 - 1) == 0;
4444
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()`

0 commit comments

Comments
 (0)