2 get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP,
4 use clippy_utils::diagnostics::span_lint_and_sugg;
5 use clippy_utils::source::snippet_with_applicability;
6 use clippy_utils::{get_enclosing_block, is_integer_const};
7 use if_chain::if_chain;
8 use rustc_errors::Applicability;
9 use rustc_hir::intravisit::{walk_block, walk_expr};
10 use rustc_hir::{Expr, Pat};
11 use rustc_lint::LateContext;
13 // To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
14 // incremented exactly once in the loop body, and initialized to zero
15 // at the start of the loop.
16 pub(super) fn check<'tcx>(
17 cx: &LateContext<'tcx>,
23 // Look for variables that are incremented once per loop iteration.
24 let mut increment_visitor = IncrementVisitor::new(cx);
25 walk_expr(&mut increment_visitor, body);
27 // For each candidate, check the parent block to see if
28 // it's initialized to zero at the start of the loop.
29 if let Some(block) = get_enclosing_block(cx, expr.hir_id) {
30 for id in increment_visitor.into_results() {
31 let mut initialize_visitor = InitializeVisitor::new(cx, expr, id);
32 walk_block(&mut initialize_visitor, block);
35 if let Some((name, initializer)) = initialize_visitor.get_result();
36 if is_integer_const(cx, initializer, 0);
38 let mut applicability = Applicability::MachineApplicable;
40 let for_span = get_span_of_entire_for_loop(expr);
44 EXPLICIT_COUNTER_LOOP,
45 for_span.with_hi(arg.span.hi()),
46 &format!("the variable `{}` is used as a loop counter", name),
49 "for ({}, {}) in {}.enumerate()",
51 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
52 make_iterator_snippet(cx, arg, &mut applicability),