]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/loops/mod.rs
Merge commit '0cb0f7636851f9fcc57085cf80197a2ef6db098f' into clippyup
[rust.git] / src / tools / clippy / clippy_lints / src / loops / mod.rs
1 mod empty_loop;
2 mod explicit_counter_loop;
3 mod explicit_into_iter_loop;
4 mod explicit_iter_loop;
5 mod for_kv_map;
6 mod for_loops_over_fallibles;
7 mod iter_next_loop;
8 mod manual_find;
9 mod manual_flatten;
10 mod manual_memcpy;
11 mod missing_spin_loop;
12 mod mut_range_bound;
13 mod needless_collect;
14 mod needless_range_loop;
15 mod never_loop;
16 mod same_item_push;
17 mod single_element_loop;
18 mod utils;
19 mod while_immutable_condition;
20 mod while_let_loop;
21 mod while_let_on_iterator;
22
23 use clippy_utils::higher;
24 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
25 use rustc_lint::{LateContext, LateLintPass};
26 use rustc_session::{declare_lint_pass, declare_tool_lint};
27 use rustc_span::source_map::Span;
28 use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor};
29
30 declare_clippy_lint! {
31     /// ### What it does
32     /// Checks for for-loops that manually copy items between
33     /// slices that could be optimized by having a memcpy.
34     ///
35     /// ### Why is this bad?
36     /// It is not as fast as a memcpy.
37     ///
38     /// ### Example
39     /// ```rust
40     /// # let src = vec![1];
41     /// # let mut dst = vec![0; 65];
42     /// for i in 0..src.len() {
43     ///     dst[i + 64] = src[i];
44     /// }
45     /// ```
46     ///
47     /// Use instead:
48     /// ```rust
49     /// # let src = vec![1];
50     /// # let mut dst = vec![0; 65];
51     /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
52     /// ```
53     #[clippy::version = "pre 1.29.0"]
54     pub MANUAL_MEMCPY,
55     perf,
56     "manually copying items between slices"
57 }
58
59 declare_clippy_lint! {
60     /// ### What it does
61     /// Checks for looping over the range of `0..len` of some
62     /// collection just to get the values by index.
63     ///
64     /// ### Why is this bad?
65     /// Just iterating the collection itself makes the intent
66     /// more clear and is probably faster.
67     ///
68     /// ### Example
69     /// ```rust
70     /// let vec = vec!['a', 'b', 'c'];
71     /// for i in 0..vec.len() {
72     ///     println!("{}", vec[i]);
73     /// }
74     /// ```
75     ///
76     /// Use instead:
77     /// ```rust
78     /// let vec = vec!['a', 'b', 'c'];
79     /// for i in vec {
80     ///     println!("{}", i);
81     /// }
82     /// ```
83     #[clippy::version = "pre 1.29.0"]
84     pub NEEDLESS_RANGE_LOOP,
85     style,
86     "for-looping over a range of indices where an iterator over items would do"
87 }
88
89 declare_clippy_lint! {
90     /// ### What it does
91     /// Checks for loops on `x.iter()` where `&x` will do, and
92     /// suggests the latter.
93     ///
94     /// ### Why is this bad?
95     /// Readability.
96     ///
97     /// ### Known problems
98     /// False negatives. We currently only warn on some known
99     /// types.
100     ///
101     /// ### Example
102     /// ```rust
103     /// // with `y` a `Vec` or slice:
104     /// # let y = vec![1];
105     /// for x in y.iter() {
106     ///     // ..
107     /// }
108     /// ```
109     ///
110     /// Use instead:
111     /// ```rust
112     /// # let y = vec![1];
113     /// for x in &y {
114     ///     // ..
115     /// }
116     /// ```
117     #[clippy::version = "pre 1.29.0"]
118     pub EXPLICIT_ITER_LOOP,
119     pedantic,
120     "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do"
121 }
122
123 declare_clippy_lint! {
124     /// ### What it does
125     /// Checks for loops on `y.into_iter()` where `y` will do, and
126     /// suggests the latter.
127     ///
128     /// ### Why is this bad?
129     /// Readability.
130     ///
131     /// ### Example
132     /// ```rust
133     /// # let y = vec![1];
134     /// // with `y` a `Vec` or slice:
135     /// for x in y.into_iter() {
136     ///     // ..
137     /// }
138     /// ```
139     /// can be rewritten to
140     /// ```rust
141     /// # let y = vec![1];
142     /// for x in y {
143     ///     // ..
144     /// }
145     /// ```
146     #[clippy::version = "pre 1.29.0"]
147     pub EXPLICIT_INTO_ITER_LOOP,
148     pedantic,
149     "for-looping over `_.into_iter()` when `_` would do"
150 }
151
152 declare_clippy_lint! {
153     /// ### What it does
154     /// Checks for loops on `x.next()`.
155     ///
156     /// ### Why is this bad?
157     /// `next()` returns either `Some(value)` if there was a
158     /// value, or `None` otherwise. The insidious thing is that `Option<_>`
159     /// implements `IntoIterator`, so that possibly one value will be iterated,
160     /// leading to some hard to find bugs. No one will want to write such code
161     /// [except to win an Underhanded Rust
162     /// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
163     ///
164     /// ### Example
165     /// ```ignore
166     /// for x in y.next() {
167     ///     ..
168     /// }
169     /// ```
170     #[clippy::version = "pre 1.29.0"]
171     pub ITER_NEXT_LOOP,
172     correctness,
173     "for-looping over `_.next()` which is probably not intended"
174 }
175
176 declare_clippy_lint! {
177     /// ### What it does
178     /// Checks for `for` loops over `Option` or `Result` values.
179     ///
180     /// ### Why is this bad?
181     /// Readability. This is more clearly expressed as an `if
182     /// let`.
183     ///
184     /// ### Example
185     /// ```rust
186     /// # let opt = Some(1);
187     /// # let res: Result<i32, std::io::Error> = Ok(1);
188     /// for x in opt {
189     ///     // ..
190     /// }
191     ///
192     /// for x in &res {
193     ///     // ..
194     /// }
195     ///
196     /// for x in res.iter() {
197     ///     // ..
198     /// }
199     /// ```
200     ///
201     /// Use instead:
202     /// ```rust
203     /// # let opt = Some(1);
204     /// # let res: Result<i32, std::io::Error> = Ok(1);
205     /// if let Some(x) = opt {
206     ///     // ..
207     /// }
208     ///
209     /// if let Ok(x) = res {
210     ///     // ..
211     /// }
212     /// ```
213     #[clippy::version = "1.45.0"]
214     pub FOR_LOOPS_OVER_FALLIBLES,
215     suspicious,
216     "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
217 }
218
219 declare_clippy_lint! {
220     /// ### What it does
221     /// Detects `loop + match` combinations that are easier
222     /// written as a `while let` loop.
223     ///
224     /// ### Why is this bad?
225     /// The `while let` loop is usually shorter and more
226     /// readable.
227     ///
228     /// ### Known problems
229     /// Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)).
230     ///
231     /// ### Example
232     /// ```rust,no_run
233     /// # let y = Some(1);
234     /// loop {
235     ///     let x = match y {
236     ///         Some(x) => x,
237     ///         None => break,
238     ///     };
239     ///     // .. do something with x
240     /// }
241     /// // is easier written as
242     /// while let Some(x) = y {
243     ///     // .. do something with x
244     /// };
245     /// ```
246     #[clippy::version = "pre 1.29.0"]
247     pub WHILE_LET_LOOP,
248     complexity,
249     "`loop { if let { ... } else break }`, which can be written as a `while let` loop"
250 }
251
252 declare_clippy_lint! {
253     /// ### What it does
254     /// Checks for functions collecting an iterator when collect
255     /// is not needed.
256     ///
257     /// ### Why is this bad?
258     /// `collect` causes the allocation of a new data structure,
259     /// when this allocation may not be needed.
260     ///
261     /// ### Example
262     /// ```rust
263     /// # let iterator = vec![1].into_iter();
264     /// let len = iterator.clone().collect::<Vec<_>>().len();
265     /// // should be
266     /// let len = iterator.count();
267     /// ```
268     #[clippy::version = "1.30.0"]
269     pub NEEDLESS_COLLECT,
270     perf,
271     "collecting an iterator when collect is not needed"
272 }
273
274 declare_clippy_lint! {
275     /// ### What it does
276     /// Checks `for` loops over slices with an explicit counter
277     /// and suggests the use of `.enumerate()`.
278     ///
279     /// ### Why is this bad?
280     /// Using `.enumerate()` makes the intent more clear,
281     /// declutters the code and may be faster in some instances.
282     ///
283     /// ### Example
284     /// ```rust
285     /// # let v = vec![1];
286     /// # fn bar(bar: usize, baz: usize) {}
287     /// let mut i = 0;
288     /// for item in &v {
289     ///     bar(i, *item);
290     ///     i += 1;
291     /// }
292     /// ```
293     ///
294     /// Use instead:
295     /// ```rust
296     /// # let v = vec![1];
297     /// # fn bar(bar: usize, baz: usize) {}
298     /// for (i, item) in v.iter().enumerate() { bar(i, *item); }
299     /// ```
300     #[clippy::version = "pre 1.29.0"]
301     pub EXPLICIT_COUNTER_LOOP,
302     complexity,
303     "for-looping with an explicit counter when `_.enumerate()` would do"
304 }
305
306 declare_clippy_lint! {
307     /// ### What it does
308     /// Checks for empty `loop` expressions.
309     ///
310     /// ### Why is this bad?
311     /// These busy loops burn CPU cycles without doing
312     /// anything. It is _almost always_ a better idea to `panic!` than to have
313     /// a busy loop.
314     ///
315     /// If panicking isn't possible, think of the environment and either:
316     ///   - block on something
317     ///   - sleep the thread for some microseconds
318     ///   - yield or pause the thread
319     ///
320     /// For `std` targets, this can be done with
321     /// [`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
322     /// or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
323     ///
324     /// For `no_std` targets, doing this is more complicated, especially because
325     /// `#[panic_handler]`s can't panic. To stop/pause the thread, you will
326     /// probably need to invoke some target-specific intrinsic. Examples include:
327     ///   - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html)
328     ///   - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html)
329     ///
330     /// ### Example
331     /// ```no_run
332     /// loop {}
333     /// ```
334     #[clippy::version = "pre 1.29.0"]
335     pub EMPTY_LOOP,
336     suspicious,
337     "empty `loop {}`, which should block or sleep"
338 }
339
340 declare_clippy_lint! {
341     /// ### What it does
342     /// Checks for `while let` expressions on iterators.
343     ///
344     /// ### Why is this bad?
345     /// Readability. A simple `for` loop is shorter and conveys
346     /// the intent better.
347     ///
348     /// ### Example
349     /// ```ignore
350     /// while let Some(val) = iter.next() {
351     ///     ..
352     /// }
353     /// ```
354     ///
355     /// Use instead:
356     /// ```ignore
357     /// for val in &mut iter {
358     ///     ..
359     /// }
360     /// ```
361     #[clippy::version = "pre 1.29.0"]
362     pub WHILE_LET_ON_ITERATOR,
363     style,
364     "using a `while let` loop instead of a for loop on an iterator"
365 }
366
367 declare_clippy_lint! {
368     /// ### What it does
369     /// Checks for iterating a map (`HashMap` or `BTreeMap`) and
370     /// ignoring either the keys or values.
371     ///
372     /// ### Why is this bad?
373     /// Readability. There are `keys` and `values` methods that
374     /// can be used to express that don't need the values or keys.
375     ///
376     /// ### Example
377     /// ```ignore
378     /// for (k, _) in &map {
379     ///     ..
380     /// }
381     /// ```
382     ///
383     /// could be replaced by
384     ///
385     /// ```ignore
386     /// for k in map.keys() {
387     ///     ..
388     /// }
389     /// ```
390     #[clippy::version = "pre 1.29.0"]
391     pub FOR_KV_MAP,
392     style,
393     "looping on a map using `iter` when `keys` or `values` would do"
394 }
395
396 declare_clippy_lint! {
397     /// ### What it does
398     /// Checks for loops that will always `break`, `return` or
399     /// `continue` an outer loop.
400     ///
401     /// ### Why is this bad?
402     /// This loop never loops, all it does is obfuscating the
403     /// code.
404     ///
405     /// ### Example
406     /// ```rust
407     /// loop {
408     ///     ..;
409     ///     break;
410     /// }
411     /// ```
412     #[clippy::version = "pre 1.29.0"]
413     pub NEVER_LOOP,
414     correctness,
415     "any loop that will always `break` or `return`"
416 }
417
418 declare_clippy_lint! {
419     /// ### What it does
420     /// Checks for loops which have a range bound that is a mutable variable
421     ///
422     /// ### Why is this bad?
423     /// One might think that modifying the mutable variable changes the loop bounds
424     ///
425     /// ### Known problems
426     /// False positive when mutation is followed by a `break`, but the `break` is not immediately
427     /// after the mutation:
428     ///
429     /// ```rust
430     /// let mut x = 5;
431     /// for _ in 0..x {
432     ///     x += 1; // x is a range bound that is mutated
433     ///     ..; // some other expression
434     ///     break; // leaves the loop, so mutation is not an issue
435     /// }
436     /// ```
437     ///
438     /// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072))
439     ///
440     /// ### Example
441     /// ```rust
442     /// let mut foo = 42;
443     /// for i in 0..foo {
444     ///     foo -= 1;
445     ///     println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
446     /// }
447     /// ```
448     #[clippy::version = "pre 1.29.0"]
449     pub MUT_RANGE_BOUND,
450     suspicious,
451     "for loop over a range where one of the bounds is a mutable variable"
452 }
453
454 declare_clippy_lint! {
455     /// ### What it does
456     /// Checks whether variables used within while loop condition
457     /// can be (and are) mutated in the body.
458     ///
459     /// ### Why is this bad?
460     /// If the condition is unchanged, entering the body of the loop
461     /// will lead to an infinite loop.
462     ///
463     /// ### Known problems
464     /// If the `while`-loop is in a closure, the check for mutation of the
465     /// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
466     /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
467     ///
468     /// ### Example
469     /// ```rust
470     /// let i = 0;
471     /// while i > 10 {
472     ///     println!("let me loop forever!");
473     /// }
474     /// ```
475     #[clippy::version = "pre 1.29.0"]
476     pub WHILE_IMMUTABLE_CONDITION,
477     correctness,
478     "variables used within while expression are not mutated in the body"
479 }
480
481 declare_clippy_lint! {
482     /// ### What it does
483     /// Checks whether a for loop is being used to push a constant
484     /// value into a Vec.
485     ///
486     /// ### Why is this bad?
487     /// This kind of operation can be expressed more succinctly with
488     /// `vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
489     /// have better performance.
490     ///
491     /// ### Example
492     /// ```rust
493     /// let item1 = 2;
494     /// let item2 = 3;
495     /// let mut vec: Vec<u8> = Vec::new();
496     /// for _ in 0..20 {
497     ///    vec.push(item1);
498     /// }
499     /// for _ in 0..30 {
500     ///     vec.push(item2);
501     /// }
502     /// ```
503     ///
504     /// Use instead:
505     /// ```rust
506     /// let item1 = 2;
507     /// let item2 = 3;
508     /// let mut vec: Vec<u8> = vec![item1; 20];
509     /// vec.resize(20 + 30, item2);
510     /// ```
511     #[clippy::version = "1.47.0"]
512     pub SAME_ITEM_PUSH,
513     style,
514     "the same item is pushed inside of a for loop"
515 }
516
517 declare_clippy_lint! {
518     /// ### What it does
519     /// Checks whether a for loop has a single element.
520     ///
521     /// ### Why is this bad?
522     /// There is no reason to have a loop of a
523     /// single element.
524     ///
525     /// ### Example
526     /// ```rust
527     /// let item1 = 2;
528     /// for item in &[item1] {
529     ///     println!("{}", item);
530     /// }
531     /// ```
532     ///
533     /// Use instead:
534     /// ```rust
535     /// let item1 = 2;
536     /// let item = &item1;
537     /// println!("{}", item);
538     /// ```
539     #[clippy::version = "1.49.0"]
540     pub SINGLE_ELEMENT_LOOP,
541     complexity,
542     "there is no reason to have a single element loop"
543 }
544
545 declare_clippy_lint! {
546     /// ### What it does
547     /// Check for unnecessary `if let` usage in a for loop
548     /// where only the `Some` or `Ok` variant of the iterator element is used.
549     ///
550     /// ### Why is this bad?
551     /// It is verbose and can be simplified
552     /// by first calling the `flatten` method on the `Iterator`.
553     ///
554     /// ### Example
555     ///
556     /// ```rust
557     /// let x = vec![Some(1), Some(2), Some(3)];
558     /// for n in x {
559     ///     if let Some(n) = n {
560     ///         println!("{}", n);
561     ///     }
562     /// }
563     /// ```
564     /// Use instead:
565     /// ```rust
566     /// let x = vec![Some(1), Some(2), Some(3)];
567     /// for n in x.into_iter().flatten() {
568     ///     println!("{}", n);
569     /// }
570     /// ```
571     #[clippy::version = "1.52.0"]
572     pub MANUAL_FLATTEN,
573     complexity,
574     "for loops over `Option`s or `Result`s with a single expression can be simplified"
575 }
576
577 declare_clippy_lint! {
578     /// ### What it does
579     /// Check for empty spin loops
580     ///
581     /// ### Why is this bad?
582     /// The loop body should have something like `thread::park()` or at least
583     /// `std::hint::spin_loop()` to avoid needlessly burning cycles and conserve
584     /// energy. Perhaps even better use an actual lock, if possible.
585     ///
586     /// ### Known problems
587     /// This lint doesn't currently trigger on `while let` or
588     /// `loop { match .. { .. } }` loops, which would be considered idiomatic in
589     /// combination with e.g. `AtomicBool::compare_exchange_weak`.
590     ///
591     /// ### Example
592     ///
593     /// ```ignore
594     /// use core::sync::atomic::{AtomicBool, Ordering};
595     /// let b = AtomicBool::new(true);
596     /// // give a ref to `b` to another thread,wait for it to become false
597     /// while b.load(Ordering::Acquire) {};
598     /// ```
599     /// Use instead:
600     /// ```rust,no_run
601     ///# use core::sync::atomic::{AtomicBool, Ordering};
602     ///# let b = AtomicBool::new(true);
603     /// while b.load(Ordering::Acquire) {
604     ///     std::hint::spin_loop()
605     /// }
606     /// ```
607     #[clippy::version = "1.61.0"]
608     pub MISSING_SPIN_LOOP,
609     perf,
610     "An empty busy waiting loop"
611 }
612
613 declare_clippy_lint! {
614     /// ### What it does
615     /// Check for manual implementations of Iterator::find
616     ///
617     /// ### Why is this bad?
618     /// It doesn't affect performance, but using `find` is shorter and easier to read.
619     ///
620     /// ### Example
621     ///
622     /// ```rust
623     /// fn example(arr: Vec<i32>) -> Option<i32> {
624     ///     for el in arr {
625     ///         if el == 1 {
626     ///             return Some(el);
627     ///         }
628     ///     }
629     ///     None
630     /// }
631     /// ```
632     /// Use instead:
633     /// ```rust
634     /// fn example(arr: Vec<i32>) -> Option<i32> {
635     ///     arr.into_iter().find(|&el| el == 1)
636     /// }
637     /// ```
638     #[clippy::version = "1.61.0"]
639     pub MANUAL_FIND,
640     complexity,
641     "manual implementation of `Iterator::find`"
642 }
643
644 declare_lint_pass!(Loops => [
645     MANUAL_MEMCPY,
646     MANUAL_FLATTEN,
647     NEEDLESS_RANGE_LOOP,
648     EXPLICIT_ITER_LOOP,
649     EXPLICIT_INTO_ITER_LOOP,
650     ITER_NEXT_LOOP,
651     FOR_LOOPS_OVER_FALLIBLES,
652     WHILE_LET_LOOP,
653     NEEDLESS_COLLECT,
654     EXPLICIT_COUNTER_LOOP,
655     EMPTY_LOOP,
656     WHILE_LET_ON_ITERATOR,
657     FOR_KV_MAP,
658     NEVER_LOOP,
659     MUT_RANGE_BOUND,
660     WHILE_IMMUTABLE_CONDITION,
661     SAME_ITEM_PUSH,
662     SINGLE_ELEMENT_LOOP,
663     MISSING_SPIN_LOOP,
664     MANUAL_FIND,
665 ]);
666
667 impl<'tcx> LateLintPass<'tcx> for Loops {
668     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
669         let for_loop = higher::ForLoop::hir(expr);
670         if let Some(higher::ForLoop {
671             pat,
672             arg,
673             body,
674             loop_id,
675             span,
676         }) = for_loop
677         {
678             // we don't want to check expanded macros
679             // this check is not at the top of the function
680             // since higher::for_loop expressions are marked as expansions
681             if body.span.from_expansion() {
682                 return;
683             }
684             check_for_loop(cx, pat, arg, body, expr, span);
685             if let ExprKind::Block(block, _) = body.kind {
686                 never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
687             }
688         }
689
690         // we don't want to check expanded macros
691         if expr.span.from_expansion() {
692             return;
693         }
694
695         // check for never_loop
696         if let ExprKind::Loop(block, ..) = expr.kind {
697             never_loop::check(cx, block, expr.hir_id, expr.span, None);
698         }
699
700         // check for `loop { if let {} else break }` that could be `while let`
701         // (also matches an explicit "match" instead of "if let")
702         // (even if the "match" or "if let" is used for declaration)
703         if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind {
704             // also check for empty `loop {}` statements, skipping those in #[panic_handler]
705             empty_loop::check(cx, expr, block);
706             while_let_loop::check(cx, expr, block);
707         }
708
709         while_let_on_iterator::check(cx, expr);
710
711         if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
712             while_immutable_condition::check(cx, condition, body);
713             missing_spin_loop::check(cx, condition, body);
714         }
715
716         needless_collect::check(expr, cx);
717     }
718 }
719
720 fn check_for_loop<'tcx>(
721     cx: &LateContext<'tcx>,
722     pat: &'tcx Pat<'_>,
723     arg: &'tcx Expr<'_>,
724     body: &'tcx Expr<'_>,
725     expr: &'tcx Expr<'_>,
726     span: Span,
727 ) {
728     let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
729     if !is_manual_memcpy_triggered {
730         needless_range_loop::check(cx, pat, arg, body, expr);
731         explicit_counter_loop::check(cx, pat, arg, body, expr);
732     }
733     check_for_loop_arg(cx, pat, arg);
734     for_kv_map::check(cx, pat, arg, body);
735     mut_range_bound::check(cx, arg, body);
736     single_element_loop::check(cx, pat, arg, body, expr);
737     same_item_push::check(cx, pat, arg, body, expr);
738     manual_flatten::check(cx, pat, arg, body, span);
739     manual_find::check(cx, pat, arg, body, span, expr);
740 }
741
742 fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
743     let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
744
745     if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
746         let method_name = method.ident.as_str();
747         // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
748         match method_name {
749             "iter" | "iter_mut" => {
750                 explicit_iter_loop::check(cx, self_arg, arg, method_name);
751                 for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
752             },
753             "into_iter" => {
754                 explicit_iter_loop::check(cx, self_arg, arg, method_name);
755                 explicit_into_iter_loop::check(cx, self_arg, arg);
756                 for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
757             },
758             "next" => {
759                 next_loop_linted = iter_next_loop::check(cx, arg);
760             },
761             _ => {},
762         }
763     }
764
765     if !next_loop_linted {
766         for_loops_over_fallibles::check(cx, pat, arg, None);
767     }
768 }