Skip to content

Commit c242ef2

Browse files
committed
Improve redundant_slicing lint
* Lint when slicing triggers auto-deref * Lint when slicing returns the same type as dereferencing
1 parent 3ea7784 commit c242ef2

8 files changed

+139
-37
lines changed

clippy_lints/src/redundant_slicing.rs

+49-19
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::get_parent_expr;
33
use clippy_utils::source::snippet_with_context;
4-
use clippy_utils::ty::is_type_lang_item;
4+
use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs};
55
use if_chain::if_chain;
66
use rustc_errors::Applicability;
77
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
88
use rustc_lint::{LateContext, LateLintPass};
9-
use rustc_middle::ty::TyS;
9+
use rustc_middle::ty::{subst::GenericArg, TyS};
1010
use rustc_session::{declare_lint_pass, declare_tool_lint};
1111

1212
declare_clippy_lint! {
@@ -54,34 +54,64 @@ impl LateLintPass<'_> for RedundantSlicing {
5454
if addressee.span.ctxt() == ctxt;
5555
if let ExprKind::Index(indexed, range) = addressee.kind;
5656
if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
57-
if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
5857
then {
58+
let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
59+
let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed));
5960
let mut app = Applicability::MachineApplicable;
60-
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
6161

62-
let (reborrow_str, help_str) = if mutability == Mutability::Mut {
63-
// The slice was used to reborrow the mutable reference.
64-
("&mut *", "reborrow the original value instead")
65-
} else if matches!(
66-
get_parent_expr(cx, expr),
67-
Some(Expr {
68-
kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
69-
..
70-
})
71-
) {
72-
// The slice was used to make a temporary reference.
73-
("&*", "reborrow the original value instead")
62+
let (help, sugg) = if TyS::same_type(expr_ty, indexed_ty) {
63+
if expr_ref_count > indexed_ref_count {
64+
return;
65+
}
66+
67+
let (reborrow_str, help_str) = if mutability == Mutability::Mut {
68+
// The slice was used to reborrow the mutable reference.
69+
("&mut *", "reborrow the original value instead")
70+
} else if matches!(
71+
get_parent_expr(cx, expr),
72+
Some(Expr {
73+
kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
74+
..
75+
})
76+
) {
77+
// The slice was used to make a temporary reference.
78+
("&*", "reborrow the original value instead")
79+
} else if expr_ref_count != indexed_ref_count {
80+
("", "dereference the original value instead")
81+
} else {
82+
("", "use the original value instead")
83+
};
84+
85+
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
86+
(help_str, format!("{}{}{}", reborrow_str, "*".repeat(indexed_ref_count - expr_ref_count), snip))
87+
} else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
88+
if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
89+
cx.param_env,
90+
cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())),
91+
) {
92+
if TyS::same_type(deref_ty, expr_ty) {
93+
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
94+
(
95+
"dereference the original value instead",
96+
format!("&{}{}*{}", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip),
97+
)
98+
} else {
99+
return;
100+
}
101+
} else {
102+
return;
103+
}
74104
} else {
75-
("", "use the original value instead")
105+
return;
76106
};
77107

78108
span_lint_and_sugg(
79109
cx,
80110
REDUNDANT_SLICING,
81111
expr.span,
82112
"redundant slicing of the whole range",
83-
help_str,
84-
format!("{}{}", reborrow_str, snip),
113+
help,
114+
sugg,
85115
app,
86116
);
87117
}

tests/ui/bytecount.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ fn main() {
44

55
let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
66

7-
let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
7+
let _ = (&*x).iter().filter(|&a| *a == 0).count(); // naive byte count
88

99
let _ = x.iter().filter(|a| **a > 0).count(); // not an equality count, OK.
1010

tests/ui/bytecount.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ LL | #[deny(clippy::naive_bytecount)]
1313
error: you appear to be counting bytes the naive way
1414
--> $DIR/bytecount.rs:7:13
1515
|
16-
LL | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
16+
LL | let _ = (&*x).iter().filter(|&a| *a == 0).count(); // naive byte count
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&*x), 0)`
1818

1919
error: you appear to be counting bytes the naive way
2020
--> $DIR/bytecount.rs:19:13

tests/ui/indexing_slicing_slice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// We also check the out_of_bounds_indexing lint here, because it lints similar things and
33
// we want to avoid false positives.
44
#![warn(clippy::out_of_bounds_indexing)]
5-
#![allow(clippy::no_effect, clippy::unnecessary_operation)]
5+
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::redundant_slicing)]
66

77
fn main() {
88
let x = [1, 2, 3, 4];

tests/ui/redundant_slicing.fixed

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
#![warn(clippy::redundant_slicing)]
5+
6+
fn main() {
7+
let slice: &[u32] = &[0];
8+
let _ = slice; // Redundant slice
9+
10+
let v = vec![0];
11+
let _ = &*v; // Deref instead of slice
12+
let _ = (&*v); // Outer borrow is redundant
13+
14+
static S: &[u8] = &[0, 1, 2];
15+
let err = &mut &*S; // Should reborrow instead of slice
16+
17+
let mut vec = vec![0];
18+
let mut_slice = &mut *vec; // Deref instead of slice
19+
let _ = &mut *mut_slice; // Should reborrow instead of slice
20+
21+
let ref_vec = &vec;
22+
let _ = &**ref_vec; // Deref instead of slice
23+
24+
macro_rules! m {
25+
($e:expr) => {
26+
$e
27+
};
28+
}
29+
let _ = slice;
30+
31+
macro_rules! m2 {
32+
($e:expr) => {
33+
&$e[..]
34+
};
35+
}
36+
let _ = m2!(slice); // Don't lint in a macro
37+
38+
let slice_ref = &slice;
39+
let _ = *slice_ref; // Deref instead of slice
40+
}

tests/ui/redundant_slicing.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1+
// run-rustfix
2+
13
#![allow(unused)]
24
#![warn(clippy::redundant_slicing)]
35

46
fn main() {
57
let slice: &[u32] = &[0];
6-
let _ = &slice[..];
8+
let _ = &slice[..]; // Redundant slice
79

810
let v = vec![0];
9-
let _ = &v[..]; // Changes the type
10-
let _ = &(&v[..])[..]; // Outer borrow is redundant
11+
let _ = &v[..]; // Deref instead of slice
12+
let _ = &(&*v)[..]; // Outer borrow is redundant
1113

1214
static S: &[u8] = &[0, 1, 2];
1315
let err = &mut &S[..]; // Should reborrow instead of slice
1416

1517
let mut vec = vec![0];
16-
let mut_slice = &mut *vec;
18+
let mut_slice = &mut vec[..]; // Deref instead of slice
1719
let _ = &mut mut_slice[..]; // Should reborrow instead of slice
1820

21+
let ref_vec = &vec;
22+
let _ = &ref_vec[..]; // Deref instead of slice
23+
1924
macro_rules! m {
2025
($e:expr) => {
2126
$e
@@ -29,4 +34,7 @@ fn main() {
2934
};
3035
}
3136
let _ = m2!(slice); // Don't lint in a macro
37+
38+
let slice_ref = &slice;
39+
let _ = &slice_ref[..]; // Deref instead of slice
3240
}

tests/ui/redundant_slicing.stderr

+33-9
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,58 @@
11
error: redundant slicing of the whole range
2-
--> $DIR/redundant_slicing.rs:6:13
2+
--> $DIR/redundant_slicing.rs:8:13
33
|
4-
LL | let _ = &slice[..];
4+
LL | let _ = &slice[..]; // Redundant slice
55
| ^^^^^^^^^^ help: use the original value instead: `slice`
66
|
77
= note: `-D clippy::redundant-slicing` implied by `-D warnings`
88

99
error: redundant slicing of the whole range
10-
--> $DIR/redundant_slicing.rs:10:13
10+
--> $DIR/redundant_slicing.rs:11:13
1111
|
12-
LL | let _ = &(&v[..])[..]; // Outer borrow is redundant
13-
| ^^^^^^^^^^^^^ help: use the original value instead: `(&v[..])`
12+
LL | let _ = &v[..]; // Deref instead of slice
13+
| ^^^^^^ help: dereference the original value instead: `&*v`
1414

1515
error: redundant slicing of the whole range
16-
--> $DIR/redundant_slicing.rs:13:20
16+
--> $DIR/redundant_slicing.rs:12:13
17+
|
18+
LL | let _ = &(&*v)[..]; // Outer borrow is redundant
19+
| ^^^^^^^^^^ help: use the original value instead: `(&*v)`
20+
21+
error: redundant slicing of the whole range
22+
--> $DIR/redundant_slicing.rs:15:20
1723
|
1824
LL | let err = &mut &S[..]; // Should reborrow instead of slice
1925
| ^^^^^^ help: reborrow the original value instead: `&*S`
2026

2127
error: redundant slicing of the whole range
22-
--> $DIR/redundant_slicing.rs:17:13
28+
--> $DIR/redundant_slicing.rs:18:21
29+
|
30+
LL | let mut_slice = &mut vec[..]; // Deref instead of slice
31+
| ^^^^^^^^^^^^ help: dereference the original value instead: `&mut *vec`
32+
33+
error: redundant slicing of the whole range
34+
--> $DIR/redundant_slicing.rs:19:13
2335
|
2436
LL | let _ = &mut mut_slice[..]; // Should reborrow instead of slice
2537
| ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice`
2638

2739
error: redundant slicing of the whole range
28-
--> $DIR/redundant_slicing.rs:24:13
40+
--> $DIR/redundant_slicing.rs:22:13
41+
|
42+
LL | let _ = &ref_vec[..]; // Deref instead of slice
43+
| ^^^^^^^^^^^^ help: dereference the original value instead: `&**ref_vec`
44+
45+
error: redundant slicing of the whole range
46+
--> $DIR/redundant_slicing.rs:29:13
2947
|
3048
LL | let _ = &m!(slice)[..];
3149
| ^^^^^^^^^^^^^^ help: use the original value instead: `slice`
3250

33-
error: aborting due to 5 previous errors
51+
error: redundant slicing of the whole range
52+
--> $DIR/redundant_slicing.rs:39:13
53+
|
54+
LL | let _ = &slice_ref[..]; // Deref instead of slice
55+
| ^^^^^^^^^^^^^^ help: dereference the original value instead: `*slice_ref`
56+
57+
error: aborting due to 9 previous errors
3458

tests/ui/str_to_string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
fn main() {
44
let hello = "hello world".to_string();
5-
let msg = &hello[..];
5+
let msg = &*hello;
66
msg.to_string();
77
}

0 commit comments

Comments
 (0)