Skip to content

Commit 84aa027

Browse files
committed
Auto merge of #3607 - detrumi:limit_infinite_iter_to_known_types, r=phansch
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.
2 parents 0fc5857 + f38fb56 commit 84aa027

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

clippy_lints/src/infinite_iter.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// option. This file may not be copied, modified, or distributed
88
// except according to those terms.
99

10-
use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint};
10+
use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint};
1111
use rustc::hir::*;
1212
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
1313
use rustc::{declare_tool_lint, lint_array};
@@ -200,7 +200,6 @@ static POSSIBLY_COMPLETING_METHODS: &[(&str, usize)] = &[
200200
/// their iterators
201201
static COMPLETING_METHODS: &[(&str, usize)] = &[
202202
("count", 1),
203-
("collect", 1),
204203
("fold", 3),
205204
("for_each", 2),
206205
("partition", 2),
@@ -214,6 +213,18 @@ static COMPLETING_METHODS: &[(&str, usize)] = &[
214213
("product", 1),
215214
];
216215

216+
/// the paths of types that are known to be infinitely allocating
217+
static INFINITE_COLLECTORS: &[&[&str]] = &[
218+
&paths::BINARY_HEAP,
219+
&paths::BTREEMAP,
220+
&paths::BTREESET,
221+
&paths::HASHMAP,
222+
&paths::HASHSET,
223+
&paths::LINKED_LIST,
224+
&paths::VEC,
225+
&paths::VEC_DEQUE,
226+
];
227+
217228
fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
218229
match expr.node {
219230
ExprKind::MethodCall(ref method, _, ref args) => {
@@ -233,6 +244,11 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
233244
if not_double_ended {
234245
return is_infinite(cx, &args[0]);
235246
}
247+
} else if method.ident.name == "collect" {
248+
let ty = cx.tables.expr_ty(expr);
249+
if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
250+
return is_infinite(cx, &args[0]);
251+
}
236252
}
237253
},
238254
ExprKind::Binary(op, ref l, ref r) => {

tests/ui/infinite_iter.rs

+19
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,22 @@ fn main() {
5858
infinite_iters();
5959
potential_infinite_iters();
6060
}
61+
62+
mod finite_collect {
63+
use std::collections::HashSet;
64+
use std::iter::FromIterator;
65+
66+
struct C;
67+
impl FromIterator<i32> for C {
68+
fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
69+
C
70+
}
71+
}
72+
73+
fn check_collect() {
74+
let _: HashSet<i32> = (0..).collect(); // Infinite iter
75+
76+
// Some data structures don't collect infinitely, such as `ArrayVec`
77+
let _: C = (0..).collect();
78+
}
79+
}

tests/ui/infinite_iter.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,13 @@ error: possible infinite iteration detected
105105
LL | (0..).all(|x| x == 24); // maybe infinite iter
106106
| ^^^^^^^^^^^^^^^^^^^^^^
107107

108-
error: aborting due to 14 previous errors
108+
error: infinite iteration detected
109+
--> $DIR/infinite_iter.rs:74:31
110+
|
111+
LL | let _: HashSet<i32> = (0..).collect(); // Infinite iter
112+
| ^^^^^^^^^^^^^^^
113+
|
114+
= note: #[deny(clippy::infinite_iter)] on by default
115+
116+
error: aborting due to 15 previous errors
109117

0 commit comments

Comments
 (0)