|  | 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::ty::ty_from_hir_ty; | 
|  | use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; | 
|  | use rustc_errors::Applicability; | 
|  | use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; | 
|  | use rustc_lint::{LateContext, LateLintPass}; | 
|  | use rustc_middle::ty; | 
|  | use rustc_session::impl_lint_pass; | 
|  |  | 
|  | declare_clippy_lint! { | 
|  | /// ### What it does | 
|  | /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, with x and unsigned integer, which may be manual | 
|  | /// reimplementations of `x.is_power_of_two()`. | 
|  | /// | 
|  | /// ### Why is this bad? | 
|  | /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. | 
|  | /// | 
|  | /// ### Example | 
|  | /// ```no_run | 
|  | /// let a: u32 = 4; | 
|  | /// let result = a.count_ones() == 1; | 
|  | /// ``` | 
|  | /// Use instead: | 
|  | /// ```no_run | 
|  | /// let a: u32 = 4; | 
|  | /// let result = a.is_power_of_two(); | 
|  | /// ``` | 
|  | #[clippy::version = "1.83.0"] | 
|  | pub MANUAL_IS_POWER_OF_TWO, | 
|  | pedantic, | 
|  | "manually reimplementing `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>) { | 
|  | if !expr.span.from_expansion() | 
|  | && let Some((lhs, rhs)) = unexpanded_binop_operands(expr, BinOpKind::Eq) | 
|  | { | 
|  | if let Some(a) = count_ones_receiver(cx, lhs) | 
|  | && is_integer_literal(rhs, 1) | 
|  | { | 
|  | self.build_sugg(cx, expr, a); | 
|  | } else if let Some(a) = count_ones_receiver(cx, rhs) | 
|  | && is_integer_literal(lhs, 1) | 
|  | { | 
|  | self.build_sugg(cx, expr, a); | 
|  | } else if is_integer_literal(rhs, 0) | 
|  | && let Some(a) = is_and_minus_one(cx, lhs) | 
|  | { | 
|  | self.build_sugg(cx, expr, a); | 
|  | } else if is_integer_literal(lhs, 0) | 
|  | && let Some(a) = is_and_minus_one(cx, rhs) | 
|  | { | 
|  | self.build_sugg(cx, expr, a); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return the unsigned integer receiver of `.count_ones()` or the argument of | 
|  | /// `<int-type>::count_ones(…)`. | 
|  | fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { | 
|  | let (method, ty, receiver) = if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind { | 
|  | (method_name, cx.typeck_results().expr_ty_adjusted(receiver), receiver) | 
|  | } else if let ExprKind::Call(func, [arg]) = expr.kind | 
|  | && let ExprKind::Path(QPath::TypeRelative(ty, func_name)) = func.kind | 
|  | { | 
|  | (func_name, ty_from_hir_ty(cx, ty), arg) | 
|  | } else { | 
|  | return None; | 
|  | }; | 
|  | (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver) | 
|  | } | 
|  |  | 
|  | /// Return `greater` if `smaller == greater - 1` | 
|  | fn is_one_less<'tcx>( | 
|  | cx: &LateContext<'tcx>, | 
|  | greater: &'tcx Expr<'tcx>, | 
|  | smaller: &Expr<'tcx>, | 
|  | ) -> Option<&'tcx Expr<'tcx>> { | 
|  | if let Some((lhs, rhs)) = unexpanded_binop_operands(smaller, BinOpKind::Sub) | 
|  | && SpanlessEq::new(cx).eq_expr(greater, lhs) | 
|  | && is_integer_literal(rhs, 1) | 
|  | && matches!(cx.typeck_results().expr_ty_adjusted(greater).kind(), ty::Uint(_)) | 
|  | { | 
|  | Some(greater) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v` | 
|  | fn is_and_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { | 
|  | let (lhs, rhs) = unexpanded_binop_operands(expr, BinOpKind::BitAnd)?; | 
|  | is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs)) | 
|  | } | 
|  |  | 
|  | /// Return the operands of the `expr` binary operation if the operator is `op` and none of the | 
|  | /// operands come from expansion. | 
|  | fn unexpanded_binop_operands<'hir>(expr: &Expr<'hir>, op: BinOpKind) -> Option<(&'hir Expr<'hir>, &'hir Expr<'hir>)> { | 
|  | if let ExprKind::Binary(binop, lhs, rhs) = expr.kind | 
|  | && binop.node == op | 
|  | && !lhs.span.from_expansion() | 
|  | && !rhs.span.from_expansion() | 
|  | { | 
|  | Some((lhs, rhs)) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } |