-use rustc::hir::*;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint_pass, declare_tool_lint};
-
-use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{higher, match_def_path, path_def_id, paths};
+use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::{sym, Symbol};
declare_clippy_lint! {
- /// **What it does:** Checks for iteration that is guaranteed to be infinite.
+ /// ### What it does
+ /// Checks for iteration that is guaranteed to be infinite.
///
- /// **Why is this bad?** While there may be places where this is acceptable
+ /// ### Why is this bad?
+ /// While there may be places where this is acceptable
/// (e.g., in event streams), in most cases this is simply an error.
///
- /// **Known problems:** None.
- ///
- /// **Example:**
+ /// ### Example
/// ```no_run
/// use std::iter;
///
/// iter::repeat(1_u8).collect::<Vec<_>>();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INFINITE_ITER,
correctness,
"infinite iteration"
}
declare_clippy_lint! {
- /// **What it does:** Checks for iteration that may be infinite.
+ /// ### What it does
+ /// Checks for iteration that may be infinite.
///
- /// **Why is this bad?** While there may be places where this is acceptable
+ /// ### Why is this bad?
+ /// While there may be places where this is acceptable
/// (e.g., in event streams), in most cases this is simply an error.
///
- /// **Known problems:** The code may have a condition to stop iteration, but
+ /// ### Known problems
+ /// The code may have a condition to stop iteration, but
/// this lint is not clever enough to analyze it.
///
- /// **Example:**
+ /// ### Example
/// ```rust
/// let infinite_iter = 0..;
+ /// # #[allow(unused)]
/// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MAYBE_INFINITE_ITER,
pedantic,
"possible infinite iteration"
declare_lint_pass!(InfiniteIter => [INFINITE_ITER, MAYBE_INFINITE_ITER]);
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InfiniteIter {
- 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"),
return;
},
};
- span_lint(cx, lint, expr.span, msg)
+ span_lint(cx, lint, expr.span, msg);
}
}
impl From<bool> for Finiteness {
#[must_use]
fn from(b: bool) -> Self {
- if b {
- Infinite
- } else {
- Finite
- }
+ if b { Infinite } else { Finite }
}
}
("scan", 3, First, MaybeInfinite),
];
-fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
+fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(ref method, _, ref args) => {
+ ExprKind::MethodCall(method, args, _) => {
for &(name, len, heuristic, cap) in &HEURISTICS {
if method.ident.name.as_str() == name && args.len() == len {
return (match heuristic {
}
}
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);
+ if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
+ let body = cx.tcx.hir().body(body);
return is_infinite(cx, &body.value);
}
}
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::Call(ref path, _) => {
- 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::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
+ ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
+ ExprKind::Call(path, _) => path_def_id(cx, path)
+ .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
+ .into(),
+ ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
_ => Finite,
}
}
];
/// the paths of types that are known to be infinitely allocating
-const INFINITE_COLLECTORS: [&[&str]; 8] = [
- &paths::BINARY_HEAP,
- &paths::BTREEMAP,
- &paths::BTREESET,
- &paths::HASHMAP,
- &paths::HASHSET,
- &paths::LINKED_LIST,
- &paths::VEC,
- &paths::VEC_DEQUE,
+const INFINITE_COLLECTORS: &[Symbol] = &[
+ sym::BinaryHeap,
+ sym::BTreeMap,
+ sym::BTreeSet,
+ sym::HashMap,
+ sym::HashSet,
+ sym::LinkedList,
+ sym::Vec,
+ sym::VecDeque,
];
-fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
+fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(ref method, _, ref args) => {
+ ExprKind::MethodCall(method, args, _) => {
for &(name, len) in &COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
return is_infinite(cx, &args[0]);
}
}
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.tables.expr_ty(&args[0]), id, &[]));
+ let not_double_ended = cx
+ .tcx
+ .get_diagnostic_item(sym::DoubleEndedIterator)
+ .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 == sym!(collect) {
- let ty = cx.tables.expr_ty(expr);
- if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
+ let ty = cx.typeck_results().expr_ty(expr);
+ if INFINITE_COLLECTORS
+ .iter()
+ .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
+ {
return is_infinite(cx, &args[0]);
}
}
},
- ExprKind::Binary(op, ref l, ref r) => {
+ ExprKind::Binary(op, l, r) => {
if op.node.is_comparison() {
return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
}