Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c43c87d

Browse files
committed
Recognize <uint>::count_ones(x) as x.count_ones()
1 parent 4d343d5 commit c43c87d

File tree

4 files changed

+29
-15
lines changed

4 files changed

+29
-15
lines changed

clippy_lints/src/manual_is_power_of_two.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::msrvs::{self, Msrv};
44
use clippy_utils::sugg::Sugg;
5+
use clippy_utils::ty::ty_from_hir_ty;
56
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
67
use rustc_errors::Applicability;
7-
use rustc_hir::{BinOpKind, Expr, ExprKind};
8+
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
89
use rustc_lint::{LateContext, LateLintPass};
910
use rustc_middle::ty;
1011
use rustc_session::impl_lint_pass;
@@ -90,16 +91,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
9091
}
9192
}
9293

93-
/// Return the unsigned integer receiver of `.count_ones()`
94+
/// Return the unsigned integer receiver of `.count_ones()` or the argument of
95+
/// `<int-type>::count_ones(…)`.
9496
fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
95-
if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind
96-
&& method_name.ident.as_str() == "count_ones"
97-
&& matches!(cx.typeck_results().expr_ty_adjusted(receiver).kind(), ty::Uint(_))
97+
let (method, ty, receiver) = if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind {
98+
(method_name, cx.typeck_results().expr_ty_adjusted(receiver), receiver)
99+
} else if let ExprKind::Call(func, [arg]) = expr.kind
100+
&& let ExprKind::Path(QPath::TypeRelative(ty, func_name)) = func.kind
98101
{
99-
Some(receiver)
102+
(func_name, ty_from_hir_ty(cx, ty), arg)
100103
} else {
101-
None
102-
}
104+
return None;
105+
};
106+
(method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
103107
}
104108

105109
/// Return `greater` if `smaller == greater - 1`

tests/ui/manual_is_power_of_two.fixed

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ fn main() {
2020
//~^ manual_is_power_of_two
2121
let _ = a.is_power_of_two();
2222
//~^ manual_is_power_of_two
23+
let _ = a.is_power_of_two();
24+
//~^ manual_is_power_of_two
2325

2426
// Test different orders of expression
2527
let _ = a.is_power_of_two();

tests/ui/manual_is_power_of_two.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ fn main() {
1818

1919
let _ = a.count_ones() == 1;
2020
//~^ manual_is_power_of_two
21+
let _ = u64::count_ones(a) == 1;
22+
//~^ manual_is_power_of_two
2123
let _ = a & (a - 1) == 0;
2224
//~^ manual_is_power_of_two
2325

tests/ui/manual_is_power_of_two.stderr

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,50 @@ LL | let _ = a.count_ones() == 1;
1010
error: manually reimplementing `is_power_of_two`
1111
--> tests/ui/manual_is_power_of_two.rs:21:13
1212
|
13+
LL | let _ = u64::count_ones(a) == 1;
14+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
15+
16+
error: manually reimplementing `is_power_of_two`
17+
--> tests/ui/manual_is_power_of_two.rs:23:13
18+
|
1319
LL | let _ = a & (a - 1) == 0;
1420
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
1521

1622
error: manually reimplementing `is_power_of_two`
17-
--> tests/ui/manual_is_power_of_two.rs:25:13
23+
--> tests/ui/manual_is_power_of_two.rs:27:13
1824
|
1925
LL | let _ = 1 == a.count_ones();
2026
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
2127

2228
error: manually reimplementing `is_power_of_two`
23-
--> tests/ui/manual_is_power_of_two.rs:27:13
29+
--> tests/ui/manual_is_power_of_two.rs:29:13
2430
|
2531
LL | let _ = (a - 1) & a == 0;
2632
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
2733

2834
error: manually reimplementing `is_power_of_two`
29-
--> tests/ui/manual_is_power_of_two.rs:29:13
35+
--> tests/ui/manual_is_power_of_two.rs:31:13
3036
|
3137
LL | let _ = 0 == a & (a - 1);
3238
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
3339

3440
error: manually reimplementing `is_power_of_two`
35-
--> tests/ui/manual_is_power_of_two.rs:31:13
41+
--> tests/ui/manual_is_power_of_two.rs:33:13
3642
|
3743
LL | let _ = 0 == (a - 1) & a;
3844
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
3945

4046
error: manually reimplementing `is_power_of_two`
41-
--> tests/ui/manual_is_power_of_two.rs:41:13
47+
--> tests/ui/manual_is_power_of_two.rs:43:13
4248
|
4349
LL | let _ = i as u32 & (i as u32 - 1) == 0;
4450
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()`
4551

4652
error: manually reimplementing `is_power_of_two`
47-
--> tests/ui/manual_is_power_of_two.rs:56:5
53+
--> tests/ui/manual_is_power_of_two.rs:58:5
4854
|
4955
LL | a & (a - 1) == 0
5056
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
5157

52-
error: aborting due to 8 previous errors
58+
error: aborting due to 9 previous errors
5359

0 commit comments

Comments
 (0)