diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 2f7c5895af8..e2da8461f41 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -7,7 +7,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint}; +use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; @@ -200,7 +200,6 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { /// their iterators static COMPLETING_METHODS: &[(&str, usize)] = &[ ("count", 1), - ("collect", 1), ("fold", 3), ("for_each", 2), ("partition", 2), @@ -214,6 +213,18 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { ("product", 1), ]; +/// the paths of types that are known to be infinitely allocating +static INFINITE_COLLECTORS: &[&[&str]] = &[ + &paths::BINARY_HEAP, + &paths::BTREEMAP, + &paths::BTREESET, + &paths::HASHMAP, + &paths::HASHSET, + &paths::LINKED_LIST, + &paths::VEC, + &paths::VEC_DEQUE, +]; + fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { match expr.node { ExprKind::MethodCall(ref method, _, ref args) => { @@ -233,6 +244,11 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { if not_double_ended { return is_infinite(cx, &args[0]); } + } else if method.ident.name == "collect" { + let ty = cx.tables.expr_ty(expr); + if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) { + return is_infinite(cx, &args[0]); + } } }, ExprKind::Binary(op, ref l, ref r) => { diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index 8f41e3ae98d..bd266368dc4 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -58,3 +58,22 @@ fn main() { infinite_iters(); potential_infinite_iters(); } + +mod finite_collect { + use std::collections::HashSet; + use std::iter::FromIterator; + + struct C; + impl FromIterator for C { + fn from_iter>(iter: I) -> Self { + C + } + } + + fn check_collect() { + let _: HashSet = (0..).collect(); // Infinite iter + + // Some data structures don't collect infinitely, such as `ArrayVec` + let _: C = (0..).collect(); + } +} diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index c64b3918db4..288285d9aae 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -105,5 +105,13 @@ error: possible infinite iteration detected LL | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: infinite iteration detected + --> $DIR/infinite_iter.rs:74:31 + | +LL | let _: HashSet = (0..).collect(); // Infinite iter + | ^^^^^^^^^^^^^^^ + | + = note: #[deny(clippy::infinite_iter)] on by default + +error: aborting due to 15 previous errors