Skip to content

Commit ecb3c3f

Browse files
committed
Auto merge of #8677 - xFrednet:8213-manual-bits-suggestion, r=giraffate
Add `usize` cast to `clippy::manual_bits` suggestion A fix for the suggestion from #8213 changelog: [`manual_bits`]: The suggestion now includes a cast for proper type conversion
2 parents 38ba055 + 3bd0ac7 commit ecb3c3f

File tree

4 files changed

+169
-87
lines changed

4 files changed

+169
-87
lines changed

clippy_lints/src/manual_bits.rs

+42-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet_opt;
3-
use clippy_utils::{meets_msrv, msrvs};
2+
use clippy_utils::source::snippet_with_applicability;
3+
use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
44
use rustc_ast::ast::LitKind;
55
use rustc_errors::Applicability;
66
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
@@ -24,7 +24,7 @@ declare_clippy_lint! {
2424
/// ```
2525
/// Use instead:
2626
/// ```rust
27-
/// usize::BITS;
27+
/// usize::BITS as usize;
2828
/// ```
2929
#[clippy::version = "1.60.0"]
3030
pub MANUAL_BITS,
@@ -59,16 +59,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
5959
if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
6060
if let ExprKind::Lit(lit) = &other_expr.kind;
6161
if let LitKind::Int(8, _) = lit.node;
62-
6362
then {
63+
let mut app = Applicability::MachineApplicable;
64+
let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app);
65+
let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
66+
6467
span_lint_and_sugg(
6568
cx,
6669
MANUAL_BITS,
6770
expr.span,
6871
"usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
6972
"consider using",
70-
format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()),
71-
Applicability::MachineApplicable,
73+
sugg,
74+
app,
7275
);
7376
}
7477
}
@@ -108,3 +111,36 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
108111
}
109112
}
110113
}
114+
115+
fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> String {
116+
if let Some(parent_expr) = get_parent_expr(cx, expr) {
117+
if is_ty_conversion(parent_expr) {
118+
return base_sugg;
119+
}
120+
121+
// These expressions have precedence over casts, the suggestion therefore
122+
// needs to be wrapped into parentheses
123+
match parent_expr.kind {
124+
ExprKind::Unary(..) | ExprKind::AddrOf(..) | ExprKind::MethodCall(..) => {
125+
return format!("({base_sugg} as usize)");
126+
},
127+
_ => {},
128+
}
129+
}
130+
131+
format!("{base_sugg} as usize")
132+
}
133+
134+
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
135+
if let ExprKind::Cast(..) = expr.kind {
136+
true
137+
} else if let ExprKind::MethodCall(path, [_], _) = expr.kind
138+
&& path.ident.name == rustc_span::sym::try_into
139+
{
140+
// This is only called for `usize` which implements `TryInto`. Therefore,
141+
// we don't have to check here if `self` implements the `TryInto` trait.
142+
true
143+
} else {
144+
false
145+
}
146+
}

tests/ui/manual_bits.fixed

+40-29
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,44 @@
11
// run-rustfix
22

33
#![warn(clippy::manual_bits)]
4-
#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)]
4+
#![allow(
5+
clippy::no_effect,
6+
clippy::useless_conversion,
7+
path_statements,
8+
unused_must_use,
9+
clippy::unnecessary_operation
10+
)]
511

612
use std::mem::{size_of, size_of_val};
713

814
fn main() {
9-
i8::BITS;
10-
i16::BITS;
11-
i32::BITS;
12-
i64::BITS;
13-
i128::BITS;
14-
isize::BITS;
15-
16-
u8::BITS;
17-
u16::BITS;
18-
u32::BITS;
19-
u64::BITS;
20-
u128::BITS;
21-
usize::BITS;
22-
23-
i8::BITS;
24-
i16::BITS;
25-
i32::BITS;
26-
i64::BITS;
27-
i128::BITS;
28-
isize::BITS;
29-
30-
u8::BITS;
31-
u16::BITS;
32-
u32::BITS;
33-
u64::BITS;
34-
u128::BITS;
35-
usize::BITS;
15+
i8::BITS as usize;
16+
i16::BITS as usize;
17+
i32::BITS as usize;
18+
i64::BITS as usize;
19+
i128::BITS as usize;
20+
isize::BITS as usize;
21+
22+
u8::BITS as usize;
23+
u16::BITS as usize;
24+
u32::BITS as usize;
25+
u64::BITS as usize;
26+
u128::BITS as usize;
27+
usize::BITS as usize;
28+
29+
i8::BITS as usize;
30+
i16::BITS as usize;
31+
i32::BITS as usize;
32+
i64::BITS as usize;
33+
i128::BITS as usize;
34+
isize::BITS as usize;
35+
36+
u8::BITS as usize;
37+
u16::BITS as usize;
38+
u32::BITS as usize;
39+
u64::BITS as usize;
40+
u128::BITS as usize;
41+
usize::BITS as usize;
3642

3743
size_of::<usize>() * 4;
3844
4 * size_of::<usize>();
@@ -42,7 +48,12 @@ fn main() {
4248
size_of_val(&0u32) * 8;
4349

4450
type Word = u32;
45-
Word::BITS;
51+
Word::BITS as usize;
4652
type Bool = bool;
4753
size_of::<Bool>() * 8;
54+
55+
let _: u32 = u128::BITS as u32;
56+
let _: u32 = u128::BITS.try_into().unwrap();
57+
let _ = (u128::BITS as usize).pow(5);
58+
let _ = &(u128::BITS as usize);
4859
}

tests/ui/manual_bits.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// run-rustfix
22

33
#![warn(clippy::manual_bits)]
4-
#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)]
4+
#![allow(
5+
clippy::no_effect,
6+
clippy::useless_conversion,
7+
path_statements,
8+
unused_must_use,
9+
clippy::unnecessary_operation
10+
)]
511

612
use std::mem::{size_of, size_of_val};
713

@@ -45,4 +51,9 @@ fn main() {
4551
size_of::<Word>() * 8;
4652
type Bool = bool;
4753
size_of::<Bool>() * 8;
54+
55+
let _: u32 = (size_of::<u128>() * 8) as u32;
56+
let _: u32 = (size_of::<u128>() * 8).try_into().unwrap();
57+
let _ = (size_of::<u128>() * 8).pow(5);
58+
let _ = &(size_of::<u128>() * 8);
4859
}

0 commit comments

Comments
 (0)