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