Skip to content

Commit faeeef3

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

File tree

4 files changed

+134
-31
lines changed

4 files changed

+134
-31
lines changed

clippy_lints/src/redundant_slicing.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +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::subst::GenericArg;
910
use rustc_session::{declare_lint_pass, declare_tool_lint};
1011

1112
declare_clippy_lint! {
@@ -53,34 +54,64 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
5354
if addressee.span.ctxt() == ctxt;
5455
if let ExprKind::Index(indexed, range) = addressee.kind;
5556
if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
56-
if cx.typeck_results().expr_ty(expr) == cx.typeck_results().expr_ty(indexed);
5757
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));
5860
let mut app = Applicability::MachineApplicable;
59-
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
6061

61-
let (reborrow_str, help_str) = if mutability == Mutability::Mut {
62-
// The slice was used to reborrow the mutable reference.
63-
("&mut *", "reborrow the original value instead")
64-
} else if matches!(
65-
get_parent_expr(cx, expr),
66-
Some(Expr {
67-
kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
68-
..
69-
})
70-
) {
71-
// The slice was used to make a temporary reference.
72-
("&*", "reborrow the original value instead")
62+
let (help, sugg) = if 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 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+
}
73104
} else {
74-
("", "use the original value instead")
105+
return;
75106
};
76107

77108
span_lint_and_sugg(
78109
cx,
79110
REDUNDANT_SLICING,
80111
expr.span,
81112
"redundant slicing of the whole range",
82-
help_str,
83-
format!("{}{}", reborrow_str, snip),
113+
help,
114+
sugg,
84115
app,
85116
);
86117
}

tests/ui/redundant_slicing.fixed

Lines changed: 40 additions & 0 deletions
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

Lines changed: 12 additions & 4 deletions
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

Lines changed: 33 additions & 9 deletions
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

0 commit comments

Comments
 (0)