Skip to content

Commit 98aa0db

Browse files
committed
Add a lint for slice.iter().cloned().collect()
If one uses `slice.iter().cloned().collect()` to create a new `Vec`, it should be `slice.to_owned()`. Fix #1292
1 parent 4b29f9a commit 98aa0db

File tree

4 files changed

+48
-3
lines changed

4 files changed

+48
-3
lines changed

clippy_lints/src/methods.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,13 +494,33 @@ declare_lint! {
494494
/// s.push_str(abc);
495495
/// s.push_str(&def));
496496
/// ```
497-
498497
declare_lint! {
499498
pub STRING_EXTEND_CHARS,
500499
Warn,
501500
"using `x.extend(s.chars())` where s is a `&str` or `String`"
502501
}
503502

503+
/// **What it does:** Checks for the use of `.cloned().collect()` on slice to create a Vec.
504+
///
505+
/// **Why is this bad?** `.to_owned()` is clearer
506+
///
507+
/// **Known problems:** None.
508+
///
509+
/// **Example:**
510+
/// ```rust
511+
/// let s = [1,2,3,4,5];
512+
/// let s2 : Vec<isize> = s.iter().cloned().collect();
513+
/// ```
514+
/// The correct use would be:
515+
/// ```rust
516+
/// let s = [1,2,3,4,5];
517+
/// let s2 : Vec<isize> = s.to_owned();
518+
/// ```
519+
declare_lint! {
520+
pub ITER_CLONED_COLLECT,
521+
Warn,
522+
"using `.cloned().collect()` on slice to create a `Vec`"
523+
}
504524

505525
impl LintPass for Pass {
506526
fn get_lints(&self) -> LintArray {
@@ -525,7 +545,8 @@ impl LintPass for Pass {
525545
ITER_NTH,
526546
ITER_SKIP_NEXT,
527547
GET_UNWRAP,
528-
STRING_EXTEND_CHARS)
548+
STRING_EXTEND_CHARS,
549+
ITER_CLONED_COLLECT)
529550
}
530551
}
531552

@@ -580,6 +601,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
580601
lint_iter_nth(cx, expr, arglists[0], true);
581602
} else if method_chain_args(expr, &["skip", "next"]).is_some() {
582603
lint_iter_skip_next(cx, expr);
604+
} else if let Some(arglists) = method_chain_args(expr, &["cloned", "collect"]) {
605+
lint_iter_cloned_collect(cx, expr, arglists[0]);
583606
}
584607

585608
lint_or_fun_call(cx, expr, &name.node.as_str(), args);
@@ -879,6 +902,16 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
879902
}}
880903
}
881904

905+
fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) {
906+
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) &&
907+
derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
908+
span_lint(cx,
909+
ITER_CLONED_COLLECT,
910+
expr.span,
911+
"called `cloned().collect()` on a slice to create a `Vec`. This is more succinctly expressed by calling `to_owned(x)`");
912+
}
913+
}
914+
882915
fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
883916
let mut_str = if is_mut { "_mut" } else { "" };
884917
let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {

src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// error-pattern:yummy
22
#![feature(box_syntax)]
33
#![feature(rustc_private)]
4-
#![feature(static_in_const)]
54

65
#![allow(unknown_lints, missing_docs_in_private_items)]
76

tests/ui/methods.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,8 @@ fn temporary_cstring() {
689689

690690

691691
}
692+
693+
fn iter_clone_collect() {
694+
let v = [1,2,3,4,5];
695+
let v2 : Vec<isize> = v.iter().cloned().collect();
696+
}

tests/ui/methods.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,5 +950,13 @@ help: assign the `CString` to a variable to extend its lifetime
950950
687 | CString::new("foo").unwrap().as_ptr();
951951
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
952952

953+
warning: called `cloned().collect()` on a slice to create a `Vec`. This is more succinctly expressed by calling `to_owned(x)`
954+
--> $DIR/methods.rs:695:27
955+
|
956+
695 | let v2 : Vec<isize> = v.iter().cloned().collect();
957+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
958+
|
959+
= note: #[warn(iter_cloned_collect)] on by default
960+
953961
error: aborting due to 88 previous errors
954962

0 commit comments

Comments
 (0)