]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / loops / explicit_counter_loop.rs
CommitLineData
f20569fa
XL
1use super::{
2 get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP,
3};
4use crate::utils::{get_enclosing_block, is_integer_const, snippet_with_applicability, span_lint_and_sugg};
5use if_chain::if_chain;
6use rustc_errors::Applicability;
7use rustc_hir::intravisit::{walk_block, walk_expr};
8use rustc_hir::{Expr, Pat};
9use rustc_lint::LateContext;
10
11// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
12// incremented exactly once in the loop body, and initialized to zero
13// at the start of the loop.
14pub(super) fn check<'tcx>(
15 cx: &LateContext<'tcx>,
16 pat: &'tcx Pat<'_>,
17 arg: &'tcx Expr<'_>,
18 body: &'tcx Expr<'_>,
19 expr: &'tcx Expr<'_>,
20) {
21 // Look for variables that are incremented once per loop iteration.
22 let mut increment_visitor = IncrementVisitor::new(cx);
23 walk_expr(&mut increment_visitor, body);
24
25 // For each candidate, check the parent block to see if
26 // it's initialized to zero at the start of the loop.
27 if let Some(block) = get_enclosing_block(&cx, expr.hir_id) {
28 for id in increment_visitor.into_results() {
29 let mut initialize_visitor = InitializeVisitor::new(cx, expr, id);
30 walk_block(&mut initialize_visitor, block);
31
32 if_chain! {
33 if let Some((name, initializer)) = initialize_visitor.get_result();
34 if is_integer_const(cx, initializer, 0);
35 then {
36 let mut applicability = Applicability::MachineApplicable;
37
38 let for_span = get_span_of_entire_for_loop(expr);
39
40 span_lint_and_sugg(
41 cx,
42 EXPLICIT_COUNTER_LOOP,
43 for_span.with_hi(arg.span.hi()),
44 &format!("the variable `{}` is used as a loop counter", name),
45 "consider using",
46 format!(
47 "for ({}, {}) in {}.enumerate()",
48 name,
49 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
50 make_iterator_snippet(cx, arg, &mut applicability),
51 ),
52 applicability,
53 );
54 }
55 }
56 }
57 }
58}