@@ -1371,6 +1371,39 @@ declare_clippy_lint! {
1371
1371
"using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
1372
1372
}
1373
1373
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
+
1374
1407
declare_lint_pass ! ( Methods => [
1375
1408
UNWRAP_USED ,
1376
1409
EXPECT_USED ,
@@ -1421,6 +1454,7 @@ declare_lint_pass!(Methods => [
1421
1454
OPTION_AS_REF_DEREF ,
1422
1455
UNNECESSARY_LAZY_EVALUATIONS ,
1423
1456
MAP_COLLECT_RESULT_UNIT ,
1457
+ FROM_ITER_INSTEAD_OF_COLLECT ,
1424
1458
] ) ;
1425
1459
1426
1460
impl < ' tcx > LateLintPass < ' tcx > for Methods {
@@ -1507,6 +1541,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1507
1541
}
1508
1542
1509
1543
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
+ } ,
1510
1551
hir:: ExprKind :: MethodCall ( ref method_call, ref method_span, ref args, _) => {
1511
1552
lint_or_fun_call ( cx, expr, * method_span, & method_call. ident . as_str ( ) , args) ;
1512
1553
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
3856
3897
span_lint_and_help ( cx, FILETYPE_IS_FILE , span, & lint_msg, None , & help_msg) ;
3857
3898
}
3858
3899
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
+
3859
3922
fn fn_header_equals ( expected : hir:: FnHeader , actual : hir:: FnHeader ) -> bool {
3860
3923
expected. constness == actual. constness
3861
3924
&& expected. unsafety == actual. unsafety
0 commit comments