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