Skip to content

Commit d5d8d7b

Browse files
committed
Auto merge of #3779 - mikerite:fix-3704, r=phansch
Improve `iter_cloned_collect` suggestions Fixes #3704
2 parents 075c212 + bef7c76 commit d5d8d7b

File tree

3 files changed

+60
-23
lines changed

3 files changed

+60
-23
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,17 +1477,22 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, new: &hir::Ex
14771477
}
14781478
}
14791479

1480-
fn lint_iter_cloned_collect(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr]) {
1481-
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC)
1482-
&& derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
1483-
{
1484-
span_lint(
1485-
cx,
1486-
ITER_CLONED_COLLECT,
1487-
expr.span,
1488-
"called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
1489-
more readable",
1490-
);
1480+
fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr]) {
1481+
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) {
1482+
if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])) {
1483+
if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) {
1484+
span_lint_and_sugg(
1485+
cx,
1486+
ITER_CLONED_COLLECT,
1487+
to_replace,
1488+
"called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
1489+
more readable",
1490+
"try",
1491+
".to_vec()".to_string(),
1492+
Applicability::MachineApplicable,
1493+
);
1494+
}
1495+
}
14911496
}
14921497
}
14931498

@@ -1573,7 +1578,7 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
15731578
};
15741579
}
15751580

1576-
fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
1581+
fn lint_iter_nth<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr], is_mut: bool) {
15771582
let mut_str = if is_mut { "_mut" } else { "" };
15781583
let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
15791584
"slice"
@@ -1596,7 +1601,7 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E
15961601
);
15971602
}
15981603

1599-
fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) {
1604+
fn lint_get_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, get_args: &'tcx [hir::Expr], is_mut: bool) {
16001605
// Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
16011606
// because they do not implement `IndexMut`
16021607
let mut applicability = Applicability::MachineApplicable;
@@ -1681,7 +1686,11 @@ fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
16811686
}
16821687
}
16831688

1684-
fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Option<sugg::Sugg<'static>> {
1689+
fn derefs_to_slice<'a, 'tcx>(
1690+
cx: &LateContext<'a, 'tcx>,
1691+
expr: &'tcx hir::Expr,
1692+
ty: Ty<'tcx>,
1693+
) -> Option<&'tcx hir::Expr> {
16851694
fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
16861695
match ty.sty {
16871696
ty::Slice(_) => true,
@@ -1695,17 +1704,17 @@ fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Op
16951704

16961705
if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
16971706
if path.ident.name == "iter" && may_slice(cx, cx.tables.expr_ty(&args[0])) {
1698-
sugg::Sugg::hir_opt(cx, &args[0]).map(sugg::Sugg::addr)
1707+
Some(&args[0])
16991708
} else {
17001709
None
17011710
}
17021711
} else {
17031712
match ty.sty {
1704-
ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr),
1705-
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
1713+
ty::Slice(_) => Some(expr),
1714+
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
17061715
ty::Ref(_, inner, _) => {
17071716
if may_slice(cx, inner) {
1708-
sugg::Sugg::hir_opt(cx, expr)
1717+
Some(expr)
17091718
} else {
17101719
None
17111720
}

tests/ui/unnecessary_clone.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ fn iter_clone_collect() {
6666
let v2: Vec<isize> = v.iter().cloned().collect();
6767
let v3: HashSet<isize> = v.iter().cloned().collect();
6868
let v4: VecDeque<isize> = v.iter().cloned().collect();
69+
70+
// Handle macro expansion in suggestion
71+
let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
72+
73+
// Issue #3704
74+
unsafe {
75+
let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
76+
.to_bytes()
77+
.iter()
78+
.cloned()
79+
.collect();
80+
}
6981
}
7082

7183
mod many_derefs {

tests/ui/unnecessary_clone.stderr

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,35 @@ help: or try being explicit about what type to clone
7878
LL | let z: &Vec<_> = &std::vec::Vec<i32>::clone(y);
7979
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8080

81-
error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
82-
--> $DIR/unnecessary_clone.rs:66:26
81+
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
82+
--> $DIR/unnecessary_clone.rs:66:27
8383
|
8484
LL | let v2: Vec<isize> = v.iter().cloned().collect();
85-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
85+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
8686
|
8787
= note: `-D clippy::iter-cloned-collect` implied by `-D warnings`
8888

89+
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
90+
--> $DIR/unnecessary_clone.rs:71:38
91+
|
92+
LL | let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
94+
95+
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
96+
--> $DIR/unnecessary_clone.rs:76:24
97+
|
98+
LL | .to_bytes()
99+
| ________________________^
100+
LL | | .iter()
101+
LL | | .cloned()
102+
LL | | .collect();
103+
| |______________________^ help: try: `.to_vec()`
104+
89105
error: using `clone` on a `Copy` type
90-
--> $DIR/unnecessary_clone.rs:102:20
106+
--> $DIR/unnecessary_clone.rs:114:20
91107
|
92108
LL | let _: E = a.clone();
93109
| ^^^^^^^^^ help: try dereferencing it: `*****a`
94110

95-
error: aborting due to 13 previous errors
111+
error: aborting due to 15 previous errors
96112

0 commit comments

Comments
 (0)