Skip to content

Commit 315bab0

Browse files
pitiK3Uflip1995
authored andcommitted
Add from_iter_instead_of_collect lint implementation
1 parent c45255b commit 315bab0

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,38 @@ declare_clippy_lint! {
13691369
"using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
13701370
}
13711371

1372+
declare_clippy_lint! {
1373+
/// **What it does:** Checks for `from_iter()` function calls that implements `FromIterator`
1374+
/// trait.
1375+
///
1376+
/// **Why is this bad?** Makes code less readable especially in method chaining.
1377+
///
1378+
/// **Known problems:** None.
1379+
///
1380+
/// **Example:**
1381+
///
1382+
/// ```rust
1383+
/// use std::iter::FromIterator;
1384+
///
1385+
/// let five_fives = std::iter::repeat(5).take(5);
1386+
///
1387+
/// let v = Vec::from_iter(five_fives);
1388+
///
1389+
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1390+
/// ```
1391+
/// Use instead:
1392+
/// ```rust
1393+
/// let five_fives = std::iter::repeat(5).take(5);
1394+
///
1395+
/// let v: Vec<i32> = five_fives.collect();
1396+
///
1397+
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1398+
/// ```
1399+
pub FROM_ITER_INSTEAD_OF_COLLECT,
1400+
style,
1401+
"use `.collect()` instead of `::from_iter()`"
1402+
}
1403+
13721404
declare_lint_pass!(Methods => [
13731405
UNWRAP_USED,
13741406
EXPECT_USED,
@@ -1419,6 +1451,7 @@ declare_lint_pass!(Methods => [
14191451
OPTION_AS_REF_DEREF,
14201452
UNNECESSARY_LAZY_EVALUATIONS,
14211453
MAP_COLLECT_RESULT_UNIT,
1454+
FROM_ITER_INSTEAD_OF_COLLECT,
14221455
]);
14231456

14241457
impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -1505,6 +1538,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15051538
}
15061539

15071540
match expr.kind {
1541+
hir::ExprKind::Call(ref func, ref args) => {
1542+
if let hir::ExprKind::Path(path) = &func.kind {
1543+
let path_segment = last_path_segment(path);
1544+
if path_segment.ident.name.as_str() == "from_iter" {
1545+
lint_from_iter(cx, expr, args);
1546+
}
1547+
}
1548+
},
15081549
hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
15091550
lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
15101551
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
38313872
span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
38323873
}
38333874

3875+
fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3876+
let ty = cx.typeck_results().expr_ty(expr);
3877+
let id = get_trait_def_id(cx, &paths::FROM_ITERATOR_TRAIT).unwrap();
3878+
3879+
if implements_trait(cx, ty, id, &[]) {
3880+
// `expr` implements `FromIterator` trait
3881+
let iter_expr = snippet(cx, args[0].span, "..");
3882+
span_lint_and_help(
3883+
cx,
3884+
FROM_ITER_INSTEAD_OF_COLLECT,
3885+
expr.span,
3886+
"use `.collect()` instead of `::from_iter()`",
3887+
None,
3888+
&format!("consider using `{}.collect()`", iter_expr),
3889+
);
3890+
}
3891+
}
3892+
38343893
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
38353894
expected.constness == actual.constness
38363895
&& expected.unsafety == actual.unsafety

clippy_lints/src/utils/paths.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"];
4444
pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
4545
pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
4646
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
47+
pub const FROM_ITERATOR_TRAIT: [&str; 3] = ["std", "iter", "FromIterator"];
4748
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
4849
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
4950
pub const HASH: [&str; 3] = ["core", "hash", "Hash"];

0 commit comments

Comments
 (0)