From ba15cdd3c159b5feda929b7af0d929e17a6f5c6d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 10 Apr 2022 19:03:16 +0200 Subject: [PATCH] Add `usize` cast to `clippy::manual_bits` suggestion --- clippy_lints/src/manual_bits.rs | 46 ++++++++++-- tests/ui/manual_bits.fixed | 69 +++++++++-------- tests/ui/manual_bits.rs | 13 +++- tests/ui/manual_bits.stderr | 126 +++++++++++++++++++------------- 4 files changed, 168 insertions(+), 86 deletions(-) diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index dcf44303cf4..44ff151ea52 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -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}; @@ -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::()` 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 + } +} diff --git a/tests/ui/manual_bits.fixed b/tests/ui/manual_bits.fixed index 4f1b19b75b8..386360dbdcd 100644 --- a/tests/ui/manual_bits.fixed +++ b/tests/ui/manual_bits.fixed @@ -1,38 +1,44 @@ // run-rustfix #![warn(clippy::manual_bits)] -#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)] +#![allow( + clippy::no_effect, + clippy::useless_conversion, + path_statements, + unused_must_use, + clippy::unnecessary_operation +)] use std::mem::{size_of, size_of_val}; fn main() { - i8::BITS; - i16::BITS; - i32::BITS; - i64::BITS; - i128::BITS; - isize::BITS; - - u8::BITS; - u16::BITS; - u32::BITS; - u64::BITS; - u128::BITS; - usize::BITS; - - i8::BITS; - i16::BITS; - i32::BITS; - i64::BITS; - i128::BITS; - isize::BITS; - - u8::BITS; - u16::BITS; - u32::BITS; - u64::BITS; - u128::BITS; - usize::BITS; + i8::BITS as usize; + i16::BITS as usize; + i32::BITS as usize; + i64::BITS as usize; + i128::BITS as usize; + isize::BITS as usize; + + u8::BITS as usize; + u16::BITS as usize; + u32::BITS as usize; + u64::BITS as usize; + u128::BITS as usize; + usize::BITS as usize; + + i8::BITS as usize; + i16::BITS as usize; + i32::BITS as usize; + i64::BITS as usize; + i128::BITS as usize; + isize::BITS as usize; + + u8::BITS as usize; + u16::BITS as usize; + u32::BITS as usize; + u64::BITS as usize; + u128::BITS as usize; + usize::BITS as usize; size_of::() * 4; 4 * size_of::(); @@ -42,7 +48,12 @@ fn main() { size_of_val(&0u32) * 8; type Word = u32; - Word::BITS; + Word::BITS as usize; type Bool = bool; size_of::() * 8; + + let _: u32 = u128::BITS as u32; + let _: u32 = u128::BITS.try_into().unwrap(); + let _ = (u128::BITS as usize).pow(5); + let _ = &(u128::BITS as usize); } diff --git a/tests/ui/manual_bits.rs b/tests/ui/manual_bits.rs index f8a01313e6a..62638f047eb 100644 --- a/tests/ui/manual_bits.rs +++ b/tests/ui/manual_bits.rs @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::manual_bits)] -#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)] +#![allow( + clippy::no_effect, + clippy::useless_conversion, + path_statements, + unused_must_use, + clippy::unnecessary_operation +)] use std::mem::{size_of, size_of_val}; @@ -45,4 +51,9 @@ fn main() { size_of::() * 8; type Bool = bool; size_of::() * 8; + + let _: u32 = (size_of::() * 8) as u32; + let _: u32 = (size_of::() * 8).try_into().unwrap(); + let _ = (size_of::() * 8).pow(5); + let _ = &(size_of::() * 8); } diff --git a/tests/ui/manual_bits.stderr b/tests/ui/manual_bits.stderr index c4f5af2dcb0..69c591a203d 100644 --- a/tests/ui/manual_bits.stderr +++ b/tests/ui/manual_bits.stderr @@ -1,154 +1,178 @@ error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:9:5 + --> $DIR/manual_bits.rs:15:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` | = note: `-D clippy::manual-bits` implied by `-D warnings` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:10:5 + --> $DIR/manual_bits.rs:16:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:11:5 + --> $DIR/manual_bits.rs:17:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:12:5 + --> $DIR/manual_bits.rs:18:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:13:5 + --> $DIR/manual_bits.rs:19:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:14:5 + --> $DIR/manual_bits.rs:20:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:16:5 + --> $DIR/manual_bits.rs:22:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:17:5 + --> $DIR/manual_bits.rs:23:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:18:5 + --> $DIR/manual_bits.rs:24:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:19:5 + --> $DIR/manual_bits.rs:25:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:20:5 + --> $DIR/manual_bits.rs:26:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:21:5 + --> $DIR/manual_bits.rs:27:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:23:5 + --> $DIR/manual_bits.rs:29:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:24:5 + --> $DIR/manual_bits.rs:30:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:25:5 + --> $DIR/manual_bits.rs:31:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:26:5 + --> $DIR/manual_bits.rs:32:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:27:5 + --> $DIR/manual_bits.rs:33:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:28:5 + --> $DIR/manual_bits.rs:34:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:30:5 + --> $DIR/manual_bits.rs:36:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS` + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:31:5 + --> $DIR/manual_bits.rs:37:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:32:5 + --> $DIR/manual_bits.rs:38:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:33:5 + --> $DIR/manual_bits.rs:39:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:34:5 + --> $DIR/manual_bits.rs:40:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:35:5 + --> $DIR/manual_bits.rs:41:5 | LL | 8 * size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> $DIR/manual_bits.rs:45:5 + --> $DIR/manual_bits.rs:51:5 | LL | size_of::() * 8; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS as usize` + +error: usage of `mem::size_of::()` to obtain the size of `T` in bits + --> $DIR/manual_bits.rs:55:18 + | +LL | let _: u32 = (size_of::() * 8) as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` + +error: usage of `mem::size_of::()` to obtain the size of `T` in bits + --> $DIR/manual_bits.rs:56:18 + | +LL | let _: u32 = (size_of::() * 8).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` + +error: usage of `mem::size_of::()` to obtain the size of `T` in bits + --> $DIR/manual_bits.rs:57:13 + | +LL | let _ = (size_of::() * 8).pow(5); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` + +error: usage of `mem::size_of::()` to obtain the size of `T` in bits + --> $DIR/manual_bits.rs:58:14 + | +LL | let _ = &(size_of::() * 8); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` -error: aborting due to 25 previous errors +error: aborting due to 29 previous errors -- 2.44.0