From 315bab0ea186d5324fba28ccd5db82ecc7996cc4 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 10 Sep 2020 20:14:23 +0200 Subject: [PATCH 01/13] Add `from_iter_instead_of_collect` lint implementation --- clippy_lints/src/methods/mod.rs | 59 +++++++++++++++++++++++++++++++++ clippy_lints/src/utils/paths.rs | 1 + 2 files changed, 60 insertions(+) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c3093e869c1..93b5d4e7efc9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1369,6 +1369,38 @@ declare_clippy_lint! { "using `.map(_).collect::()`, which can be replaced with `try_for_each`" } +declare_clippy_lint! { + /// **What it does:** Checks for `from_iter()` function calls that implements `FromIterator` + /// trait. + /// + /// **Why is this bad?** Makes code less readable especially in method chaining. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// use std::iter::FromIterator; + /// + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v = Vec::from_iter(five_fives); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + /// Use instead: + /// ```rust + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v: Vec = five_fives.collect(); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + pub FROM_ITER_INSTEAD_OF_COLLECT, + style, + "use `.collect()` instead of `::from_iter()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1419,6 +1451,7 @@ declare_lint_pass!(Methods => [ OPTION_AS_REF_DEREF, UNNECESSARY_LAZY_EVALUATIONS, MAP_COLLECT_RESULT_UNIT, + FROM_ITER_INSTEAD_OF_COLLECT, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1505,6 +1538,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } match expr.kind { + hir::ExprKind::Call(ref func, ref args) => { + if let hir::ExprKind::Path(path) = &func.kind { + let path_segment = last_path_segment(path); + if path_segment.ident.name.as_str() == "from_iter" { + lint_from_iter(cx, expr, args); + } + } + }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); @@ -3831,6 +3872,24 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } +fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let ty = cx.typeck_results().expr_ty(expr); + let id = get_trait_def_id(cx, &paths::FROM_ITERATOR_TRAIT).unwrap(); + + if implements_trait(cx, ty, id, &[]) { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_help( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "use `.collect()` instead of `::from_iter()`", + None, + &format!("consider using `{}.collect()`", iter_expr), + ); + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 736a531eda65..3aade8ca8a2f 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,6 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; +pub const FROM_ITERATOR_TRAIT: [&str; 3] = ["std", "iter", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; From 9d6eedf5f2fccfc94f36473012794b2c679d3ad3 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 10 Sep 2020 20:16:28 +0200 Subject: [PATCH 02/13] Run `cargo dev update_lints` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 +++ src/lintlist/mod.rs | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b63dbb7eff5..50f03126c7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1732,6 +1732,7 @@ Released 2018-09-13 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5c3af014ee12..fa4b6d116233 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -693,6 +693,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::FILTER_NEXT, &methods::FIND_MAP, &methods::FLAT_MAP_IDENTITY, + &methods::FROM_ITER_INSTEAD_OF_COLLECT, &methods::GET_UNWRAP, &methods::INEFFICIENT_TO_STRING, &methods::INTO_ITER_ON_REF, @@ -1422,6 +1423,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::EXPECT_FUN_CALL), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), + LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), @@ -1620,6 +1622,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), + LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NEXT_SLICE), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 016bda77ef5e..7a1ebc3d2dd9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -753,6 +753,13 @@ vec![ deprecation: None, module: "drop_forget_ref", }, + Lint { + name: "from_iter_instead_of_collect", + group: "style", + desc: "use `.collect()` instead of `::from_iter()`", + deprecation: None, + module: "methods", + }, Lint { name: "future_not_send", group: "nursery", From 1b117f46296b5c15848d02a4433912a604cc9873 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 10 Sep 2020 20:18:23 +0200 Subject: [PATCH 03/13] Add tests for `from_iter_instead_of_collect` --- tests/ui/from_iter_instead_of_collect.rs | 15 +++++++++++++++ tests/ui/from_iter_instead_of_collect.stderr | 19 +++++++++++++++++++ tests/ui/from_iter_instead_of_collect.stdout | 0 3 files changed, 34 insertions(+) create mode 100644 tests/ui/from_iter_instead_of_collect.rs create mode 100644 tests/ui/from_iter_instead_of_collect.stderr create mode 100644 tests/ui/from_iter_instead_of_collect.stdout diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs new file mode 100644 index 000000000000..7a1bc64f4bd8 --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -0,0 +1,15 @@ +#![warn(clippy::from_iter_instead_of_collect)] + +use std::collections::HashMap; +use std::iter::FromIterator; + +fn main() { + { + let iter_expr = std::iter::repeat(5).take(5); + + Vec::from_iter(iter_expr); + HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + //let v: Vec = iter_expr.collect(); + let a: Vec = Vec::new(); + } +} diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr new file mode 100644 index 000000000000..4fadfb658fe3 --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -0,0 +1,19 @@ +error: use `.collect()` instead of `::from_iter()` + --> $DIR/from_iter_instead_of_collect.rs:10:5 + | +LL | Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` + = help: consider using `iter_expr.collect()` + +error: use `.collect()` instead of `::from_iter()` + --> $DIR/from_iter_instead_of_collect.rs:11:5 + | +LL | HashMap::::from_iter(vec![5,5,5,5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `vec![5,5,5,5].iter().enumerate().collect()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/from_iter_instead_of_collect.stdout b/tests/ui/from_iter_instead_of_collect.stdout new file mode 100644 index 000000000000..e69de29bb2d1 From 8a5d78b71a71317314d7dccef7c73b523f0a44c2 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Fri, 11 Sep 2020 13:29:52 +0200 Subject: [PATCH 04/13] Fix `from_iter_instead_of_collect` lint crashing on exprs without path segment --- clippy_lints/src/methods/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 93b5d4e7efc9..c0c39dae8658 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1540,8 +1540,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(ref func, ref args) => { if let hir::ExprKind::Path(path) = &func.kind { - let path_segment = last_path_segment(path); - if path_segment.ident.name.as_str() == "from_iter" { + if match_qpath(path, &["from_iter"]) { lint_from_iter(cx, expr, args); } } From a85670652a37238db7328b5eaab7cb7794fa40c8 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 12:36:17 +0200 Subject: [PATCH 05/13] Update: stderr message format --- tests/ui/from_iter_instead_of_collect.stderr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 4fadfb658fe3..cfb92dfbbfd0 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,19 +1,19 @@ error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:10:5 + --> $DIR/from_iter_instead_of_collect.rs:10:9 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` = help: consider using `iter_expr.collect()` error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:11:5 + --> $DIR/from_iter_instead_of_collect.rs:11:9 | -LL | HashMap::::from_iter(vec![5,5,5,5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `vec![5,5,5,5].iter().enumerate().collect()` + = help: consider using `vec![5, 5, 5, 5].iter().enumerate().collect()` error: aborting due to 2 previous errors From 8906040445a6700be2aaf40ec09937b84dea5d6a Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:04:05 +0200 Subject: [PATCH 06/13] Improvements from PR feedback --- clippy_lints/src/methods/mod.rs | 14 ++++++++------ clippy_lints/src/utils/paths.rs | 2 +- tests/ui/from_iter_instead_of_collect.rs | 10 +++------- tests/ui/from_iter_instead_of_collect.stderr | 15 ++++++--------- tests/ui/from_iter_instead_of_collect.stdout | 0 5 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 tests/ui/from_iter_instead_of_collect.stdout diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c0c39dae8658..70be8909c439 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1370,10 +1370,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `from_iter()` function calls that implements `FromIterator` + /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator` /// trait. /// - /// **Why is this bad?** Makes code less readable especially in method chaining. + /// **Why is this bad?** It is recommended style to use collect. See + /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// /// **Known problems:** None. /// @@ -3873,18 +3874,19 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); - let id = get_trait_def_id(cx, &paths::FROM_ITERATOR_TRAIT).unwrap(); + let id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); if implements_trait(cx, ty, id, &[]) { // `expr` implements `FromIterator` trait let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_help( + span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, "use `.collect()` instead of `::from_iter()`", - None, - &format!("consider using `{}.collect()`", iter_expr), + "consider using", + format!("`{}.collect()`", iter_expr), + Applicability::MaybeIncorrect ); } } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 3aade8ca8a2f..8afbd8930b63 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,7 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; -pub const FROM_ITERATOR_TRAIT: [&str; 3] = ["std", "iter", "FromIterator"]; +pub const FROM_ITERATOR: [&str; 3] = ["std", "iter", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 7a1bc64f4bd8..9071be33c647 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -4,12 +4,8 @@ use std::collections::HashMap; use std::iter::FromIterator; fn main() { - { - let iter_expr = std::iter::repeat(5).take(5); + let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); - HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - //let v: Vec = iter_expr.collect(); - let a: Vec = Vec::new(); - } + Vec::from_iter(iter_expr); + HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index cfb92dfbbfd0..1bc787aa795a 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,19 +1,16 @@ error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:10:9 + --> $DIR/from_iter_instead_of_collect.rs:9:5 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``iter_expr.collect()`` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` - = help: consider using `iter_expr.collect()` error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:11:9 + --> $DIR/from_iter_instead_of_collect.rs:10:5 | -LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `vec![5, 5, 5, 5].iter().enumerate().collect()` +LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``vec![5, 5, 5, 5].iter().enumerate().collect()`` error: aborting due to 2 previous errors diff --git a/tests/ui/from_iter_instead_of_collect.stdout b/tests/ui/from_iter_instead_of_collect.stdout deleted file mode 100644 index e69de29bb2d1..000000000000 From 0ab96ba2c0196558dc49624f59e6fd9c717a02f6 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:17:50 +0200 Subject: [PATCH 07/13] Allow lint --- tests/ui/get_unwrap.fixed | 2 +- tests/ui/get_unwrap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 97e6b20f471f..924c02a4054d 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused_mut)] +#![allow(unused_mut, clippy::from_iter_instead_of_collect)] #![deny(clippy::get_unwrap)] use std::collections::BTreeMap; diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index 1c9a71c09699..c0c37bb72066 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused_mut)] +#![allow(unused_mut, clippy::from_iter_instead_of_collect)] #![deny(clippy::get_unwrap)] use std::collections::BTreeMap; From e320dd30428aeb85577b36afa594429a41bc07f6 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:34:36 +0200 Subject: [PATCH 08/13] Improve: error message --- clippy_lints/src/utils/paths.rs | 2 +- tests/ui/from_iter_instead_of_collect.rs | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 8afbd8930b63..95fe87334215 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,7 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; -pub const FROM_ITERATOR: [&str; 3] = ["std", "iter", "FromIterator"]; +pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 9071be33c647..25b87a0a903f 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -5,7 +5,7 @@ use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); + HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 1bc787aa795a..3263005d7eca 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,5 +1,5 @@ error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:9:5 + --> $DIR/from_iter_instead_of_collect.rs:8:5 | LL | Vec::from_iter(iter_expr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``iter_expr.collect()`` From 854f2cef06f60b37a3176b17b27c1104692f6255 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:36:49 +0200 Subject: [PATCH 09/13] Run `cargo dev fmt` --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 70be8909c439..013ed67b8e58 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3886,7 +3886,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< "use `.collect()` instead of `::from_iter()`", "consider using", format!("`{}.collect()`", iter_expr), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } From abdb7aeb55461f0355829be49a09ed86af066ae8 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:44:12 +0200 Subject: [PATCH 10/13] Remove backticks --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 013ed67b8e58..2119cb28fc3f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3885,7 +3885,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< expr.span, "use `.collect()` instead of `::from_iter()`", "consider using", - format!("`{}.collect()`", iter_expr), + format!("{}.collect()", iter_expr), Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 3263005d7eca..7f248beadbe7 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -2,7 +2,7 @@ error: use `.collect()` instead of `::from_iter()` --> $DIR/from_iter_instead_of_collect.rs:8:5 | LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``iter_expr.collect()`` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `iter_expr.collect()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use `.collect()` instead of `::from_iter()` --> $DIR/from_iter_instead_of_collect.rs:10:5 | LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``vec![5, 5, 5, 5].iter().enumerate().collect()`` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `vec![5, 5, 5, 5].iter().enumerate().collect()` error: aborting due to 2 previous errors From f359fb872b405fca196f40eadd341d1d06f1fb8b Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 19:04:19 +0200 Subject: [PATCH 11/13] Improve error message --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2119cb28fc3f..fde43f0055d4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3883,8 +3883,8 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, + "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", - "consider using", format!("{}.collect()", iter_expr), Applicability::MaybeIncorrect, ); diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 7f248beadbe7..46bdc2f4e199 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,16 +1,16 @@ -error: use `.collect()` instead of `::from_iter()` +error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:8:5 | LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `iter_expr.collect()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` -error: use `.collect()` instead of `::from_iter()` +error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:10:5 | LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `vec![5, 5, 5, 5].iter().enumerate().collect()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` error: aborting due to 2 previous errors From 52d1ea3c9ad8ea97350ba7a0ca0a8e172cfcae78 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Mon, 12 Oct 2020 17:27:50 +0200 Subject: [PATCH 12/13] Fix: Don't show lint for types that doesn't implement Iterator --- clippy_lints/src/methods/mod.rs | 7 +++++-- tests/ui/from_iter_instead_of_collect.rs | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fde43f0055d4..521b151f5e16 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3874,9 +3874,12 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); - let id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); - if implements_trait(cx, ty, id, &[]) { + let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); + let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { // `expr` implements `FromIterator` trait let iter_expr = snippet(cx, args[0].span, ".."); span_lint_and_sugg( diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 25b87a0a903f..045eb3133d3c 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -8,4 +8,6 @@ fn main() { Vec::from_iter(iter_expr); HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + + Vec::from_iter(vec![42u32]); } From ddf23d649ae02dde7aed22ec6699a736492b7184 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Sat, 24 Oct 2020 13:53:09 +0200 Subject: [PATCH 13/13] Fix: Use `.collect()` instead of `::fromIterator()` --- clippy_lints/src/lifetimes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index c8a5a9c94313..4d737b3f49b0 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -16,7 +16,6 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Symbol}; -use std::iter::FromIterator; declare_clippy_lint! { /// **What it does:** Checks for lifetime annotations which can be removed by @@ -214,14 +213,15 @@ fn could_use_elision<'tcx>( } if allowed_lts - .intersection(&FxHashSet::from_iter( - input_visitor + .intersection( + &input_visitor .nested_elision_site_lts .iter() .chain(output_visitor.nested_elision_site_lts.iter()) .cloned() - .filter(|v| matches!(v, RefLt::Named(_))), - )) + .filter(|v| matches!(v, RefLt::Named(_))) + .collect(), + ) .next() .is_some() {