]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/infinite_iter.rs
Merge commit '4911ab124c481430672a3833b37075e6435ec34d' into clippyup
[rust.git] / clippy_lints / src / infinite_iter.rs
index 689cd8fd3b05eefd2783af72428cc6523b392e02..129abd7d89749342e89da0f41d695ed2732fecbf 100644 (file)
@@ -1,6 +1,6 @@
-use rustc::hir::*;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_tool_lint, lint_array};
+use rustc_hir::{BorrowKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint};
 
     ///
     /// **Example:**
     /// ```rust
-    /// [0..].iter().zip(infinite_iter.take_while(|x| x > 5))
+    /// let infinite_iter = 0..;
+    /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
     /// ```
     pub MAYBE_INFINITE_ITER,
     pedantic,
     "possible infinite iteration"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INFINITE_ITER, MAYBE_INFINITE_ITER)
-    }
-
-    fn name(&self) -> &'static str {
-        "InfiniteIter"
-    }
-}
+declare_lint_pass!(InfiniteIter => [INFINITE_ITER, MAYBE_INFINITE_ITER]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (lint, msg) = match complete_infinite_iter(cx, expr) {
             Infinite => (INFINITE_ITER, "infinite iteration detected"),
             MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
@@ -77,6 +67,7 @@ enum Finiteness {
 use self::Finiteness::{Finite, Infinite, MaybeInfinite};
 
 impl Finiteness {
+    #[must_use]
     fn and(self, b: Self) -> Self {
         match (self, b) {
             (Finite, _) | (_, Finite) => Finite,
@@ -85,6 +76,7 @@ fn and(self, b: Self) -> Self {
         }
     }
 
+    #[must_use]
     fn or(self, b: Self) -> Self {
         match (self, b) {
             (Infinite, _) | (_, Infinite) => Infinite,
@@ -95,6 +87,7 @@ fn or(self, b: Self) -> Self {
 }
 
 impl From<bool> for Finiteness {
+    #[must_use]
     fn from(b: bool) -> Self {
         if b {
             Infinite
@@ -125,7 +118,7 @@ enum Heuristic {
 /// returns an infinite or possibly infinite iterator. The finiteness
 /// is an upper bound, e.g., some methods can return a possibly
 /// infinite iterator at worst, e.g., `take_while`.
-static HEURISTICS: &[(&str, usize, Heuristic, Finiteness)] = &[
+const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
     ("zip", 2, All, Infinite),
     ("chain", 2, Any, Infinite),
     ("cycle", 1, Always, Infinite),
@@ -147,11 +140,11 @@ enum Heuristic {
     ("scan", 3, First, MaybeInfinite),
 ];
 
-fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
-    match expr.node {
-        ExprKind::MethodCall(ref method, _, ref args) => {
-            for &(name, len, heuristic, cap) in HEURISTICS.iter() {
-                if method.ident.name == name && args.len() == len {
+fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
+    match expr.kind {
+        ExprKind::MethodCall(ref method, _, ref args, _) => {
+            for &(name, len, heuristic, cap) in &HEURISTICS {
+                if method.ident.name.as_str() == name && args.len() == len {
                     return (match heuristic {
                         Always => Infinite,
                         First => is_infinite(cx, &args[0]),
@@ -161,8 +154,8 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
                     .and(cap);
                 }
             }
-            if method.ident.name == "flat_map" && args.len() == 2 {
-                if let ExprKind::Closure(_, _, body_id, _, _) = args[1].node {
+            if method.ident.name == sym!(flat_map) && args.len() == 2 {
+                if let ExprKind::Closure(_, _, body_id, _, _) = args[1].kind {
                     let body = cx.tcx.hir().body(body_id);
                     return is_infinite(cx, &body.value);
                 }
@@ -170,22 +163,22 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
             Finite
         },
         ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
-        ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e),
+        ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) => is_infinite(cx, e),
         ExprKind::Call(ref path, _) => {
-            if let ExprKind::Path(ref qpath) = path.node {
+            if let ExprKind::Path(ref qpath) = path.kind {
                 match_qpath(qpath, &paths::REPEAT).into()
             } else {
                 Finite
             }
         },
-        ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
+        ExprKind::Struct(..) => higher::range(expr).map_or(false, |r| r.end.is_none()).into(),
         _ => Finite,
     }
 }
 
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
-static POSSIBLY_COMPLETING_METHODS: &[(&str, usize)] = &[
+const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
     ("find", 2),
     ("rfind", 2),
     ("position", 2),
@@ -196,7 +189,7 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
-static COMPLETING_METHODS: &[(&str, usize)] = &[
+const COMPLETING_METHODS: [(&str, usize); 12] = [
     ("count", 1),
     ("fold", 3),
     ("for_each", 2),
@@ -212,7 +205,7 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
 ];
 
 /// the paths of types that are known to be infinitely allocating
-static INFINITE_COLLECTORS: &[&[&str]] = &[
+const INFINITE_COLLECTORS: [&[&str]; 8] = [
     &paths::BINARY_HEAP,
     &paths::BTREEMAP,
     &paths::BTREESET,
@@ -223,27 +216,28 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
     &paths::VEC_DEQUE,
 ];
 
-fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
-    match expr.node {
-        ExprKind::MethodCall(ref method, _, ref args) => {
-            for &(name, len) in COMPLETING_METHODS.iter() {
-                if method.ident.name == name && args.len() == len {
+fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
+    match expr.kind {
+        ExprKind::MethodCall(ref method, _, ref args, _) => {
+            for &(name, len) in &COMPLETING_METHODS {
+                if method.ident.name.as_str() == name && args.len() == len {
                     return is_infinite(cx, &args[0]);
                 }
             }
-            for &(name, len) in POSSIBLY_COMPLETING_METHODS.iter() {
-                if method.ident.name == name && args.len() == len {
+            for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
+                if method.ident.name.as_str() == name && args.len() == len {
                     return MaybeInfinite.and(is_infinite(cx, &args[0]));
                 }
             }
-            if method.ident.name == "last" && args.len() == 1 {
-                let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR)
-                    .map_or(false, |id| !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[]));
+            if method.ident.name == sym!(last) && args.len() == 1 {
+                let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| {
+                    !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
+                });
                 if not_double_ended {
                     return is_infinite(cx, &args[0]);
                 }
-            } else if method.ident.name == "collect" {
-                let ty = cx.tables.expr_ty(expr);
+            } else if method.ident.name == sym!(collect) {
+                let ty = cx.typeck_results().expr_ty(expr);
                 if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
                     return is_infinite(cx, &args[0]);
                 }