Skip to content

Commit 6a281e9

Browse files
committed
Auto merge of #13487 - Coekjan:fix-slice-size-calc-on-ref-ref, r=dswij
Fix lint `manual_slice_size_calculation` when a slice is ref more than once When a slice is ref more than once, current suggestion given by `manual_slice_size_calculation` is wrong. For example: ```rs let s: &[i32] = &[1, 2][..]; let ss: &&[i32] = &s; // <----- let _ = size_of::<i32>() * ss.len(); ``` clippy now suggests: ```patch - let _ = size_of::<i32>() * ss.len(); + let _ = size_of_val(ss); ``` However, this can result in calculating the size of `&[i32]`, instead of `[i32]` (this wrong suggestion also leads to `size_of_ref` warning: https://rust-lang.github.io/rust-clippy/master/index.html#/size_of_ref ) Now I am sending this PR to fix this bug, so that clippy will suggest (some deref added): ```patch - let _ = size_of::<i32>() * ss.len(); + let _ = size_of_val(*ss); ``` As I am not familiar with current clippy code-base, please correct me if I am not doing well or I can do it better :) changelog: [`manual_slice_size_calculation`]: fix a bug when a slice is ref more than once.
2 parents f883e28 + 2080634 commit 6a281e9

4 files changed

+35
-13
lines changed

clippy_lints/src/manual_slice_size_calculation.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
4545
&& !expr.span.from_expansion()
4646
// Does not apply inside const because size_of_val is not cost in stable.
4747
&& !is_in_const_context(cx)
48-
&& let Some(receiver) = simplify(cx, left, right)
48+
&& let Some((receiver, refs_count)) = simplify(cx, left, right)
4949
{
5050
let ctxt = expr.span.ctxt();
5151
let mut app = Applicability::MachineApplicable;
52+
let deref = "*".repeat(refs_count - 1);
5253
let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0;
5354
let Some(sugg) = std_or_core(cx) else { return };
5455

@@ -58,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
5859
expr.span,
5960
"manual slice size calculation",
6061
"try",
61-
format!("{sugg}::mem::size_of_val({val_name})"),
62+
format!("{sugg}::mem::size_of_val({deref}{val_name})"),
6263
app,
6364
);
6465
}
@@ -69,7 +70,7 @@ fn simplify<'tcx>(
6970
cx: &LateContext<'tcx>,
7071
expr1: &'tcx Expr<'tcx>,
7172
expr2: &'tcx Expr<'tcx>,
72-
) -> Option<&'tcx Expr<'tcx>> {
73+
) -> Option<(&'tcx Expr<'tcx>, usize)> {
7374
let expr1 = expr_or_init(cx, expr1);
7475
let expr2 = expr_or_init(cx, expr2);
7576

@@ -80,13 +81,14 @@ fn simplify_half<'tcx>(
8081
cx: &LateContext<'tcx>,
8182
expr1: &'tcx Expr<'tcx>,
8283
expr2: &'tcx Expr<'tcx>,
83-
) -> Option<&'tcx Expr<'tcx>> {
84+
) -> Option<(&'tcx Expr<'tcx>, usize)> {
8485
if !expr1.span.from_expansion()
8586
// expr1 is `[T1].len()`?
8687
&& let ExprKind::MethodCall(method_path, receiver, [], _) = expr1.kind
8788
&& method_path.ident.name == sym::len
8889
&& let receiver_ty = cx.typeck_results().expr_ty(receiver)
89-
&& let ty::Slice(ty1) = receiver_ty.peel_refs().kind()
90+
&& let (receiver_ty, refs_count) = clippy_utils::ty::walk_ptrs_ty_depth(receiver_ty)
91+
&& let ty::Slice(ty1) = receiver_ty.kind()
9092
// expr2 is `size_of::<T2>()`?
9193
&& let ExprKind::Call(func, []) = expr2.kind
9294
&& let ExprKind::Path(ref func_qpath) = func.kind
@@ -96,7 +98,7 @@ fn simplify_half<'tcx>(
9698
// T1 == T2?
9799
&& *ty1 == ty2
98100
{
99-
Some(receiver)
101+
Some((receiver, refs_count))
100102
} else {
101103
None
102104
}

tests/ui/manual_slice_size_calculation.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ use proc_macros::external;
1010
fn main() {
1111
let v_i32 = Vec::<i32>::new();
1212
let s_i32 = v_i32.as_slice();
13+
let s_i32_ref = &s_i32;
14+
let s_i32_ref_ref = &s_i32_ref;
1315

1416
// True positives:
1517
let _ = std::mem::size_of_val(s_i32); // WARNING
1618
let _ = std::mem::size_of_val(s_i32); // WARNING
1719
let _ = std::mem::size_of_val(s_i32) * 5; // WARNING
20+
let _ = std::mem::size_of_val(*s_i32_ref); // WARNING
21+
let _ = std::mem::size_of_val(**s_i32_ref_ref); // WARNING
1822

1923
let len = s_i32.len();
2024
let size = size_of::<i32>();

tests/ui/manual_slice_size_calculation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ use proc_macros::external;
1010
fn main() {
1111
let v_i32 = Vec::<i32>::new();
1212
let s_i32 = v_i32.as_slice();
13+
let s_i32_ref = &s_i32;
14+
let s_i32_ref_ref = &s_i32_ref;
1315

1416
// True positives:
1517
let _ = s_i32.len() * size_of::<i32>(); // WARNING
1618
let _ = size_of::<i32>() * s_i32.len(); // WARNING
1719
let _ = size_of::<i32>() * s_i32.len() * 5; // WARNING
20+
let _ = size_of::<i32>() * s_i32_ref.len(); // WARNING
21+
let _ = size_of::<i32>() * s_i32_ref_ref.len(); // WARNING
1822

1923
let len = s_i32.len();
2024
let size = size_of::<i32>();
Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: manual slice size calculation
2-
--> tests/ui/manual_slice_size_calculation.rs:15:13
2+
--> tests/ui/manual_slice_size_calculation.rs:17:13
33
|
44
LL | let _ = s_i32.len() * size_of::<i32>(); // WARNING
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
@@ -8,40 +8,52 @@ LL | let _ = s_i32.len() * size_of::<i32>(); // WARNING
88
= help: to override `-D warnings` add `#[allow(clippy::manual_slice_size_calculation)]`
99

1010
error: manual slice size calculation
11-
--> tests/ui/manual_slice_size_calculation.rs:16:13
11+
--> tests/ui/manual_slice_size_calculation.rs:18:13
1212
|
1313
LL | let _ = size_of::<i32>() * s_i32.len(); // WARNING
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
1515

1616
error: manual slice size calculation
17-
--> tests/ui/manual_slice_size_calculation.rs:17:13
17+
--> tests/ui/manual_slice_size_calculation.rs:19:13
1818
|
1919
LL | let _ = size_of::<i32>() * s_i32.len() * 5; // WARNING
2020
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
2121

22+
error: manual slice size calculation
23+
--> tests/ui/manual_slice_size_calculation.rs:20:13
24+
|
25+
LL | let _ = size_of::<i32>() * s_i32_ref.len(); // WARNING
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(*s_i32_ref)`
27+
2228
error: manual slice size calculation
2329
--> tests/ui/manual_slice_size_calculation.rs:21:13
2430
|
31+
LL | let _ = size_of::<i32>() * s_i32_ref_ref.len(); // WARNING
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(**s_i32_ref_ref)`
33+
34+
error: manual slice size calculation
35+
--> tests/ui/manual_slice_size_calculation.rs:25:13
36+
|
2537
LL | let _ = len * size_of::<i32>(); // WARNING
2638
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
2739

2840
error: manual slice size calculation
29-
--> tests/ui/manual_slice_size_calculation.rs:22:13
41+
--> tests/ui/manual_slice_size_calculation.rs:26:13
3042
|
3143
LL | let _ = s_i32.len() * size; // WARNING
3244
| ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
3345

3446
error: manual slice size calculation
35-
--> tests/ui/manual_slice_size_calculation.rs:23:13
47+
--> tests/ui/manual_slice_size_calculation.rs:27:13
3648
|
3749
LL | let _ = len * size; // WARNING
3850
| ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
3951

4052
error: manual slice size calculation
41-
--> tests/ui/manual_slice_size_calculation.rs:25:13
53+
--> tests/ui/manual_slice_size_calculation.rs:29:13
4254
|
4355
LL | let _ = external!(&[1u64][..]).len() * size_of::<u64>();
4456
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))`
4557

46-
error: aborting due to 7 previous errors
58+
error: aborting due to 9 previous errors
4759

0 commit comments

Comments
 (0)