Skip to content

Commit

Permalink
Auto merge of #3607 - detrumi:limit_infinite_iter_to_known_types, r=p…
Browse files Browse the repository at this point in the history
…hansch

Only trigger `infinite_iter` lint for infinitely allocating `collect()` calls

Fixes  #3538

~Oh, I guess this should actually check other methods like `count` as well, not only `collect()`.~
Never mind, `collect` is the only of these functions that allocates a data structure.
  • Loading branch information
bors committed Jan 3, 2019
2 parents 0fc5857 + f38fb56 commit 84aa027
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
20 changes: 18 additions & 2 deletions clippy_lints/src/infinite_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -200,7 +200,6 @@ static POSSIBLY_COMPLETING_METHODS: &[(&str, usize)] = &[
/// their iterators
static COMPLETING_METHODS: &[(&str, usize)] = &[
("count", 1),
("collect", 1),
("fold", 3),
("for_each", 2),
("partition", 2),
Expand All @@ -214,6 +213,18 @@ static COMPLETING_METHODS: &[(&str, usize)] = &[
("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) => {
Expand All @@ -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) => {
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/infinite_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32> for C {
fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
C
}
}

fn check_collect() {
let _: HashSet<i32> = (0..).collect(); // Infinite iter

// Some data structures don't collect infinitely, such as `ArrayVec`
let _: C = (0..).collect();
}
}
10 changes: 9 additions & 1 deletion tests/ui/infinite_iter.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32> = (0..).collect(); // Infinite iter
| ^^^^^^^^^^^^^^^
|
= note: #[deny(clippy::infinite_iter)] on by default

error: aborting due to 15 previous errors

0 comments on commit 84aa027

Please sign in to comment.