]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/manual_bits.rs
Update lint description of `clippy::manual_bits` to include the `as usize` cast
[rust.git] / clippy_lints / src / manual_bits.rs
index dcf44303cf449f2a0b83322414643fdd7243e6db..ac3d9447b6bd3d35fc2472e35ca7dd00ad84eb9e 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
@@ -24,7 +24,7 @@
     /// ```
     /// Use instead:
     /// ```rust
-    /// usize::BITS;
+    /// usize::BITS as usize;
     /// ```
     #[clippy::version = "1.60.0"]
     pub MANUAL_BITS,
@@ -59,16 +59,19 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
             if let ExprKind::Lit(lit) = &other_expr.kind;
             if let LitKind::Int(8, _) = lit.node;
-
             then {
+                let mut app = Applicability::MachineApplicable;
+                let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app);
+                let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
+
                 span_lint_and_sugg(
                     cx,
                     MANUAL_BITS,
                     expr.span,
                     "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
                     "consider using",
-                    format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()),
-                    Applicability::MachineApplicable,
+                    sugg,
+                    app,
                 );
             }
         }
@@ -108,3 +111,36 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         }
     }
 }
+
+fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> String {
+    if let Some(parent_expr) = get_parent_expr(cx, expr) {
+        if is_ty_conversion(parent_expr) {
+            return base_sugg;
+        }
+
+        // These expressions have precedence over casts, the suggestion therefore
+        // needs to be wrapped into parentheses
+        match parent_expr.kind {
+            ExprKind::Unary(..) | ExprKind::AddrOf(..) | ExprKind::MethodCall(..) => {
+                return format!("({base_sugg} as usize)");
+            },
+            _ => {},
+        }
+    }
+
+    format!("{base_sugg} as usize")
+}
+
+fn is_ty_conversion(expr: &Expr<'_>) -> bool {
+    if let ExprKind::Cast(..) = expr.kind {
+        true
+    } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+        && path.ident.name == rustc_span::sym::try_into
+    {
+        // This is only called for `usize` which implements `TryInto`. Therefore,
+        // we don't have to check here if `self` implements the `TryInto` trait.
+        true
+    } else {
+        false
+    }
+}