about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--book/src/lint_configuration.md1
-rw-r--r--clippy_config/src/conf.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/manual_is_power_of_two.rs60
-rw-r--r--clippy_utils/src/msrvs.rs1
-rw-r--r--tests/ui/manual_is_power_of_two.fixed11
-rw-r--r--tests/ui/manual_is_power_of_two.rs11
-rw-r--r--tests/ui/manual_is_power_of_two.stderr8
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