]>
Commit | Line | Data |
---|---|---|
1 | use super::{ | |
2 | get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, | |
3 | }; | |
4 | use crate::utils::{get_enclosing_block, is_integer_const, snippet_with_applicability, span_lint_and_sugg}; | |
5 | use if_chain::if_chain; | |
6 | use rustc_errors::Applicability; | |
7 | use rustc_hir::intravisit::{walk_block, walk_expr}; | |
8 | use rustc_hir::{Expr, Pat}; | |
9 | use 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. | |
14 | pub(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 | } |