@@ -1371,6 +1371,39 @@ declare_clippy_lint! {
13711371 "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
13721372}
13731373
1374+ declare_clippy_lint ! {
1375+ /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator`
1376+ /// trait.
1377+ ///
1378+ /// **Why is this bad?** It is recommended style to use collect. See
1379+ /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
1380+ ///
1381+ /// **Known problems:** None.
1382+ ///
1383+ /// **Example:**
1384+ ///
1385+ /// ```rust
1386+ /// use std::iter::FromIterator;
1387+ ///
1388+ /// let five_fives = std::iter::repeat(5).take(5);
1389+ ///
1390+ /// let v = Vec::from_iter(five_fives);
1391+ ///
1392+ /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1393+ /// ```
1394+ /// Use instead:
1395+ /// ```rust
1396+ /// let five_fives = std::iter::repeat(5).take(5);
1397+ ///
1398+ /// let v: Vec<i32> = five_fives.collect();
1399+ ///
1400+ /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1401+ /// ```
1402+ pub FROM_ITER_INSTEAD_OF_COLLECT ,
1403+ style,
1404+ "use `.collect()` instead of `::from_iter()`"
1405+ }
1406+
13741407declare_lint_pass ! ( Methods => [
13751408 UNWRAP_USED ,
13761409 EXPECT_USED ,
@@ -1421,6 +1454,7 @@ declare_lint_pass!(Methods => [
14211454 OPTION_AS_REF_DEREF ,
14221455 UNNECESSARY_LAZY_EVALUATIONS ,
14231456 MAP_COLLECT_RESULT_UNIT ,
1457+ FROM_ITER_INSTEAD_OF_COLLECT ,
14241458] ) ;
14251459
14261460impl < ' tcx > LateLintPass < ' tcx > for Methods {
@@ -1507,6 +1541,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15071541 }
15081542
15091543 match expr. kind {
1544+ hir:: ExprKind :: Call ( ref func, ref args) => {
1545+ if let hir:: ExprKind :: Path ( path) = & func. kind {
1546+ if match_qpath ( path, & [ "from_iter" ] ) {
1547+ lint_from_iter ( cx, expr, args) ;
1548+ }
1549+ }
1550+ } ,
15101551 hir:: ExprKind :: MethodCall ( ref method_call, ref method_span, ref args, _) => {
15111552 lint_or_fun_call ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
15121553 lint_expect_fun_call ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
@@ -3856,6 +3897,28 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir
38563897 span_lint_and_help ( cx, FILETYPE_IS_FILE , span, & lint_msg, None , & help_msg) ;
38573898}
38583899
3900+ fn lint_from_iter ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , args : & [ hir:: Expr < ' _ > ] ) {
3901+ let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
3902+ let arg_ty = cx. typeck_results ( ) . expr_ty ( & args[ 0 ] ) ;
3903+
3904+ let from_iter_id = get_trait_def_id ( cx, & paths:: FROM_ITERATOR ) . unwrap ( ) ;
3905+ let iter_id = get_trait_def_id ( cx, & paths:: ITERATOR ) . unwrap ( ) ;
3906+
3907+ if implements_trait ( cx, ty, from_iter_id, & [ ] ) && implements_trait ( cx, arg_ty, iter_id, & [ ] ) {
3908+ // `expr` implements `FromIterator` trait
3909+ let iter_expr = snippet ( cx, args[ 0 ] . span , ".." ) ;
3910+ span_lint_and_sugg (
3911+ cx,
3912+ FROM_ITER_INSTEAD_OF_COLLECT ,
3913+ expr. span ,
3914+ "usage of `FromIterator::from_iter`" ,
3915+ "use `.collect()` instead of `::from_iter()`" ,
3916+ format ! ( "{}.collect()" , iter_expr) ,
3917+ Applicability :: MaybeIncorrect ,
3918+ ) ;
3919+ }
3920+ }
3921+
38593922fn fn_header_equals ( expected : hir:: FnHeader , actual : hir:: FnHeader ) -> bool {
38603923 expected. constness == actual. constness
38613924 && expected. unsafety == actual. unsafety
0 commit comments