Skip to content

Commit 644a367

Browse files
committed
Check MSRV before suggesting fix in const context
1 parent 29eec68 commit 644a367

File tree

8 files changed

+96
-37
lines changed

8 files changed

+96
-37
lines changed

book/src/lint_configuration.md

+1
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
804804
* [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten)
805805
* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
806806
* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
807+
* [`manual_is_power_of_two`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two)
807808
* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
808809
* [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint)
809810
* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)

clippy_config/src/conf.rs

+1
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ define_Conf! {
646646
manual_flatten,
647647
manual_hash_one,
648648
manual_is_ascii_check,
649+
manual_is_power_of_two,
649650
manual_let_else,
650651
manual_midpoint,
651652
manual_non_exhaustive,

clippy_lints/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
971971
store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses));
972972
store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock));
973973
store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf)));
974-
store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo));
974+
store.register_late_pass(move |_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo::new(conf)));
975975
store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions));
976976
store.register_late_pass(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg));
977977
store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));

clippy_lints/src/manual_is_power_of_two.rs

+38-22
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use clippy_config::Conf;
12
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use clippy_utils::msrvs::{self, Msrv};
24
use clippy_utils::sugg::Sugg;
3-
use clippy_utils::{SpanlessEq, is_integer_literal};
5+
use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
46
use rustc_errors::Applicability;
57
use rustc_hir::{BinOpKind, Expr, ExprKind};
68
use rustc_lint::{LateContext, LateLintPass};
79
use rustc_middle::ty;
8-
use rustc_session::declare_lint_pass;
10+
use rustc_session::impl_lint_pass;
911

1012
declare_clippy_lint! {
1113
/// ### What it does
@@ -31,7 +33,36 @@ declare_clippy_lint! {
3133
"manually reimplementing `is_power_of_two`"
3234
}
3335

34-
declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
36+
pub struct ManualIsPowerOfTwo {
37+
msrv: Msrv,
38+
}
39+
40+
impl_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
41+
42+
impl ManualIsPowerOfTwo {
43+
pub fn new(conf: &'static Conf) -> Self {
44+
Self { msrv: conf.msrv }
45+
}
46+
47+
fn build_sugg(&self, cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
48+
if is_in_const_context(cx) && !self.msrv.meets(cx, msrvs::CONST_IS_POWER_OF_TWO) {
49+
return;
50+
}
51+
52+
let mut applicability = Applicability::MachineApplicable;
53+
let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability);
54+
55+
span_lint_and_sugg(
56+
cx,
57+
MANUAL_IS_POWER_OF_TWO,
58+
expr.span,
59+
"manually reimplementing `is_power_of_two`",
60+
"consider using `.is_power_of_two()`",
61+
format!("{}.is_power_of_two()", snippet.maybe_par()),
62+
applicability,
63+
);
64+
}
65+
}
3566

3667
impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
3768
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
@@ -44,39 +75,24 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
4475
if let Some(a) = count_ones_receiver(cx, lhs)
4576
&& is_integer_literal(rhs, 1)
4677
{
47-
build_sugg(cx, expr, a);
78+
self.build_sugg(cx, expr, a);
4879
} else if let Some(a) = count_ones_receiver(cx, rhs)
4980
&& is_integer_literal(lhs, 1)
5081
{
51-
build_sugg(cx, expr, a);
82+
self.build_sugg(cx, expr, a);
5283
} else if is_integer_literal(rhs, 0)
5384
&& let Some(a) = is_and_minus_one(cx, lhs)
5485
{
55-
build_sugg(cx, expr, a);
86+
self.build_sugg(cx, expr, a);
5687
} else if is_integer_literal(lhs, 0)
5788
&& let Some(a) = is_and_minus_one(cx, rhs)
5889
{
59-
build_sugg(cx, expr, a);
90+
self.build_sugg(cx, expr, a);
6091
}
6192
}
6293
}
6394
}
6495

65-
fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
66-
let mut applicability = Applicability::MachineApplicable;
67-
let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability);
68-
69-
span_lint_and_sugg(
70-
cx,
71-
MANUAL_IS_POWER_OF_TWO,
72-
expr.span,
73-
"manually reimplementing `is_power_of_two`",
74-
"consider using `.is_power_of_two()`",
75-
format!("{}.is_power_of_two()", snippet.maybe_par()),
76-
applicability,
77-
);
78-
}
79-
8096
/// Return the unsigned integer receiver of `.count_ones()`
8197
fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
8298
if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind

clippy_utils/src/msrvs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ msrv_aliases! {
6363
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
6464
1,34,0 { TRY_FROM }
6565
1,33,0 { UNDERSCORE_IMPORTS }
66+
1,32,0 { CONST_IS_POWER_OF_TWO }
6667
1,31,0 { OPTION_REPLACE }
6768
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
6869
1,29,0 { ITER_FLATTEN }

tests/ui/manual_is_power_of_two.fixed

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
#![allow(clippy::precedence)]
33

44
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 };
5+
($a: expr, equal, $b: expr) => {
6+
$a == $b
7+
};
8+
($a: expr, and, $b: expr) => {
9+
$a & $b
10+
};
11+
($a: expr, minus, $b: expr) => {
12+
$a - $b
13+
};
814
}
915

1016
fn main() {
@@ -39,3 +45,14 @@ fn main() {
3945
let _ = binop!(a, and, a - 1) == 0;
4046
let _ = a & binop!(a, minus, 1) == 0;
4147
}
48+
49+
#[clippy::msrv = "1.31"]
50+
const fn low_msrv(a: u32) -> bool {
51+
a & (a - 1) == 0
52+
}
53+
54+
#[clippy::msrv = "1.32"]
55+
const fn high_msrv(a: u32) -> bool {
56+
a.is_power_of_two()
57+
//~^ manual_is_power_of_two
58+
}

tests/ui/manual_is_power_of_two.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
#![allow(clippy::precedence)]
33

44
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 };
5+
($a: expr, equal, $b: expr) => {
6+
$a == $b
7+
};
8+
($a: expr, and, $b: expr) => {
9+
$a & $b
10+
};
11+
($a: expr, minus, $b: expr) => {
12+
$a - $b
13+
};
814
}
915

1016
fn main() {
@@ -39,3 +45,14 @@ fn main() {
3945
let _ = binop!(a, and, a - 1) == 0;
4046
let _ = a & binop!(a, minus, 1) == 0;
4147
}
48+
49+
#[clippy::msrv = "1.31"]
50+
const fn low_msrv(a: u32) -> bool {
51+
a & (a - 1) == 0
52+
}
53+
54+
#[clippy::msrv = "1.32"]
55+
const fn high_msrv(a: u32) -> bool {
56+
a & (a - 1) == 0
57+
//~^ manual_is_power_of_two
58+
}
+14-8
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:13:13
2+
--> tests/ui/manual_is_power_of_two.rs:19:13
33
|
44
LL | let _ = a.count_ones() == 1;
55
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
@@ -8,40 +8,46 @@ 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:15:13
11+
--> tests/ui/manual_is_power_of_two.rs:21: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:19:13
17+
--> tests/ui/manual_is_power_of_two.rs:25: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:21:13
23+
--> tests/ui/manual_is_power_of_two.rs:27: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:23:13
29+
--> tests/ui/manual_is_power_of_two.rs:29: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:25:13
35+
--> tests/ui/manual_is_power_of_two.rs:31: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:35:13
41+
--> tests/ui/manual_is_power_of_two.rs:41: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()`
4545

46-
error: aborting due to 7 previous errors
46+
error: manually reimplementing `is_power_of_two`
47+
--> tests/ui/manual_is_power_of_two.rs:56:5
48+
|
49+
LL | a & (a - 1) == 0
50+
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
51+
52+
error: aborting due to 8 previous errors
4753

0 commit comments

Comments
 (0)