about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Macleod <alex@macleod.io>2022-09-11 12:17:51 +0000
committerAlex Macleod <alex@macleod.io>2022-09-11 12:40:52 +0000
commit86d18b50ed64fa5dd6313d595ad4c53d6eb610a2 (patch)
tree5ced1edf727cbfe4d36b4a36c19d0f6497c83ec6
parentc8c2a234b3a04dc41626ab2e06c43f66b26042a9 (diff)
downloadrust-86d18b50ed64fa5dd6313d595ad4c53d6eb610a2.tar.gz
rust-86d18b50ed64fa5dd6313d595ad4c53d6eb610a2.zip
Fix `unused_peekable` closure and `f(&mut peekable)` false positives
-rw-r--r--clippy_lints/src/unused_peekable.rs36
-rw-r--r--tests/ui/unused_peekable.rs33
2 files changed, 50 insertions, 19 deletions
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
index cfc181e435b..13b08df16a5 100644
--- a/clippy_lints/src/unused_peekable.rs
+++ b/clippy_lints/src/unused_peekable.rs
@@ -6,6 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
@@ -109,8 +110,14 @@ impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
     }
 }
 
-impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
-    fn visit_expr(&mut self, ex: &'_ Expr<'_>) {
+impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if self.found_peek_call {
             return;
         }
@@ -136,12 +143,11 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
                                     return;
                                 }
 
-                                if args.iter().any(|arg| {
-                                    matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg)
-                                }) {
+                                if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) {
                                     self.found_peek_call = true;
-                                    return;
                                 }
+
+                                return;
                             },
                             // Catch anything taking a Peekable mutably
                             ExprKind::MethodCall(
@@ -190,21 +196,21 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
                     Node::Local(Local { init: Some(init), .. }) => {
                         if arg_is_mut_peekable(self.cx, init) {
                             self.found_peek_call = true;
-                            return;
                         }
 
-                        break;
+                        return;
                     },
-                    Node::Stmt(stmt) => match stmt.kind {
-                        StmtKind::Expr(_) | StmtKind::Semi(_) => {},
-                        _ => {
-                            self.found_peek_call = true;
-                            return;
-                        },
+                    Node::Stmt(stmt) => {
+                        match stmt.kind {
+                            StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true,
+                            StmtKind::Expr(_) | StmtKind::Semi(_) => {},
+                        }
+
+                        return;
                     },
                     Node::Block(_) | Node::ExprField(_) => {},
                     _ => {
-                        break;
+                        return;
                     },
                 }
             }
diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs
index 153457e3671..7374dfdf92e 100644
--- a/tests/ui/unused_peekable.rs
+++ b/tests/ui/unused_peekable.rs
@@ -57,12 +57,22 @@ fn valid() {
     impl PeekableConsumer {
         fn consume(&self, _: Peekable<Empty<u32>>) {}
         fn consume_mut_ref(&self, _: &mut Peekable<Empty<u32>>) {}
+        fn consume_assoc(_: Peekable<Empty<u32>>) {}
+        fn consume_assoc_mut_ref(_: &mut Peekable<Empty<u32>>) {}
     }
-
     let peekable_consumer = PeekableConsumer;
-    let mut passed_along_to_method = std::iter::empty::<u32>().peekable();
-    peekable_consumer.consume_mut_ref(&mut passed_along_to_method);
-    peekable_consumer.consume(passed_along_to_method);
+
+    let peekable = std::iter::empty::<u32>().peekable();
+    peekable_consumer.consume(peekable);
+
+    let mut peekable = std::iter::empty::<u32>().peekable();
+    peekable_consumer.consume_mut_ref(&mut peekable);
+
+    let peekable = std::iter::empty::<u32>().peekable();
+    PeekableConsumer::consume_assoc(peekable);
+
+    let mut peekable = std::iter::empty::<u32>().peekable();
+    PeekableConsumer::consume_assoc_mut_ref(&mut peekable);
 
     // `peek` called in another block
     let mut peekable_in_block = std::iter::empty::<u32>().peekable();
@@ -141,4 +151,19 @@ fn valid() {
     {
         peekable_last_expr.peek();
     }
+
+    let mut peek_in_closure = std::iter::empty::<u32>().peekable();
+    let _ = || {
+        let _ = peek_in_closure.peek();
+    };
+
+    trait PeekTrait {}
+    impl<I> PeekTrait for Peekable<I> where I: Iterator {}
+
+    let mut peekable = std::iter::empty::<u32>().peekable();
+    let _dyn = &mut peekable as &mut dyn PeekTrait;
+
+    fn takes_dyn(_: &mut dyn PeekTrait) {}
+    let mut peekable = std::iter::empty::<u32>().peekable();
+    takes_dyn(&mut peekable);
 }