about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-03 00:12:02 +0000
committerbors <bors@rust-lang.org>2019-01-03 00:12:02 +0000
commit84aa027888f95c9df3e09d9229424f525b3fcec1 (patch)
tree041f754424d205817572e7653a681bddabbfae76
parent0fc5857d0b2150e2427f4e76b155e00997d6250c (diff)
parentf38fb56baf2921ed006a36c54df3add3b7605593 (diff)
downloadrust-84aa027888f95c9df3e09d9229424f525b3fcec1.tar.gz
rust-84aa027888f95c9df3e09d9229424f525b3fcec1.zip
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.
-rw-r--r--clippy_lints/src/infinite_iter.rs20
-rw-r--r--tests/ui/infinite_iter.rs19
-rw-r--r--tests/ui/infinite_iter.stderr10
3 files changed, 46 insertions, 3 deletions
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 @@ static POSSIBLY_COMPLETING_METHODS: &[(&str, usize)] = &[
 /// their iterators
 static COMPLETING_METHODS: &[(&str, usize)] = &[
     ("count", 1),
-    ("collect", 1),
     ("fold", 3),
     ("for_each", 2),
     ("partition", 2),
@@ -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) => {
@@ -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<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();
+    }
+}
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<i32> = (0..).collect(); // Infinite iter
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: #[deny(clippy::infinite_iter)] on by default
+
+error: aborting due to 15 previous errors