about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/collection_is_never_read.rs6
-rw-r--r--tests/ui/collection_is_never_read.rs20
2 files changed, 26 insertions, 0 deletions
diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs
index c0c231bb2c7..10f2bef268a 100644
--- a/clippy_lints/src/collection_is_never_read.rs
+++ b/clippy_lints/src/collection_is_never_read.rs
@@ -98,10 +98,16 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc
         // Method call on `id` in a statement ignores any return value, so it's not a read access:
         //
         // id.foo(...); // Not reading `id`.
+        //
+        // Only assuming this for "official" methods defined on the type. For methods defined in extension
+        // traits (identified as local, based on the orphan rule), pessimistically assume that they might
+        // have side effects, so consider them a read.
         if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id)
             && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind
             && path_to_local_id(receiver, id)
             && let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id)
+            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
+            && !method_def_id.is_local()
         {
             return ControlFlow::Continue(());
         }
diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs
index 8f5ceb06b89..49c72e7eefe 100644
--- a/tests/ui/collection_is_never_read.rs
+++ b/tests/ui/collection_is_never_read.rs
@@ -133,3 +133,23 @@ fn not_read_if_return_value_not_used() {
     let x = vec![1, 2, 3]; // WARNING
     x.is_empty();
 }
+
+fn extension_traits() {
+    trait VecExt<T> {
+        fn method_with_side_effect(&self);
+        fn method_without_side_effect(&self);
+    }
+
+    impl<T> VecExt<T> for Vec<T> {
+        fn method_with_side_effect(&self) {
+            println!("my length: {}", self.len());
+        }
+        fn method_without_side_effect(&self) {}
+    }
+
+    let x = vec![1, 2, 3]; // Ok
+    x.method_with_side_effect();
+
+    let y = vec![1, 2, 3]; // Ok (false negative)
+    y.method_without_side_effect();
+}