diff options
| -rw-r--r-- | book/src/lint_configuration.md | 1 | ||||
| -rw-r--r-- | clippy_config/src/conf.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/manual_is_power_of_two.rs | 60 | ||||
| -rw-r--r-- | clippy_utils/src/msrvs.rs | 1 | ||||
| -rw-r--r-- | tests/ui/manual_is_power_of_two.fixed | 11 | ||||
| -rw-r--r-- | tests/ui/manual_is_power_of_two.rs | 11 | ||||
| -rw-r--r-- | tests/ui/manual_is_power_of_two.stderr | 8 |
8 files changed, 71 insertions, 24 deletions
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a677745379c..77de05d2d34 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -804,6 +804,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten) * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [`manual_is_power_of_two`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 34c62318aad..60477fa328a 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -721,6 +721,7 @@ define_Conf! { manual_flatten, manual_hash_one, manual_is_ascii_check, + manual_is_power_of_two, manual_let_else, manual_midpoint, manual_non_exhaustive, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ba80e122448..5561a7add3e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -969,7 +969,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); - store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); + store.register_late_pass(move |_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo::new(conf))); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); store.register_late_pass(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg)); store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index 067354ae5b2..b9866ff9ffb 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -1,11 +1,13 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{SpanlessEq, is_integer_literal}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does @@ -31,7 +33,36 @@ declare_clippy_lint! { "manually reimplementing `is_power_of_two`" } -declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); +pub struct ManualIsPowerOfTwo { + msrv: Msrv, +} + +impl_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); + +impl ManualIsPowerOfTwo { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } + + fn build_sugg(&self, cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + if is_in_const_context(cx) && !self.msrv.meets(cx, msrvs::CONST_IS_POWER_OF_TWO) { + return; + } + + let mut applicability = Applicability::MachineApplicable; + let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability); + + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + format!("{}.is_power_of_two()", snippet.maybe_paren()), + applicability, + ); + } +} impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { @@ -41,39 +72,24 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo { if let Some(a) = count_ones_receiver(cx, lhs) && is_integer_literal(rhs, 1) { - build_sugg(cx, expr, a); + self.build_sugg(cx, expr, a); } else if let Some(a) = count_ones_receiver(cx, rhs) && is_integer_literal(lhs, 1) { - build_sugg(cx, expr, a); + self.build_sugg(cx, expr, a); } else if is_integer_literal(rhs, 0) && let Some(a) = is_and_minus_one(cx, lhs) { - build_sugg(cx, expr, a); + self.build_sugg(cx, expr, a); } else if is_integer_literal(lhs, 0) && let Some(a) = is_and_minus_one(cx, rhs) { - build_sugg(cx, expr, a); + self.build_sugg(cx, expr, a); } } } } -fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability); - - span_lint_and_sugg( - cx, - MANUAL_IS_POWER_OF_TWO, - expr.span, - "manually reimplementing `is_power_of_two`", - "consider using `.is_power_of_two()`", - format!("{}.is_power_of_two()", snippet.maybe_paren()), - applicability, - ); -} - /// Return the unsigned integer receiver of `.count_ones()` fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index ab60fefddb4..10cb4f7f136 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -63,6 +63,7 @@ msrv_aliases! { 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,33,0 { UNDERSCORE_IMPORTS } + 1,32,0 { CONST_IS_POWER_OF_TWO } 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } diff --git a/tests/ui/manual_is_power_of_two.fixed b/tests/ui/manual_is_power_of_two.fixed index 2f18f566c58..216db87a09b 100644 --- a/tests/ui/manual_is_power_of_two.fixed +++ b/tests/ui/manual_is_power_of_two.fixed @@ -45,3 +45,14 @@ fn main() { let _ = binop!(a, and, a - 1) == 0; let _ = a & binop!(a, minus, 1) == 0; } + +#[clippy::msrv = "1.31"] +const fn low_msrv(a: u32) -> bool { + a & (a - 1) == 0 +} + +#[clippy::msrv = "1.32"] +const fn high_msrv(a: u32) -> bool { + a.is_power_of_two() + //~^ manual_is_power_of_two +} diff --git a/tests/ui/manual_is_power_of_two.rs b/tests/ui/manual_is_power_of_two.rs index ef219e92412..2ff29c37f3e 100644 --- a/tests/ui/manual_is_power_of_two.rs +++ b/tests/ui/manual_is_power_of_two.rs @@ -45,3 +45,14 @@ fn main() { let _ = binop!(a, and, a - 1) == 0; let _ = a & binop!(a, minus, 1) == 0; } + +#[clippy::msrv = "1.31"] +const fn low_msrv(a: u32) -> bool { + a & (a - 1) == 0 +} + +#[clippy::msrv = "1.32"] +const fn high_msrv(a: u32) -> bool { + a & (a - 1) == 0 + //~^ manual_is_power_of_two +} diff --git a/tests/ui/manual_is_power_of_two.stderr b/tests/ui/manual_is_power_of_two.stderr index 73b4b282c8b..043991f8ae8 100644 --- a/tests/ui/manual_is_power_of_two.stderr +++ b/tests/ui/manual_is_power_of_two.stderr @@ -43,5 +43,11 @@ error: manually reimplementing `is_power_of_two` LL | let _ = i as u32 & (i as u32 - 1) == 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()` -error: aborting due to 7 previous errors +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:56:5 + | +LL | a & (a - 1) == 0 + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 8 previous errors |
