about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Schubart <michael@schubart.net>2023-03-06 07:16:36 +0000
committerMichael Schubart <michael@schubart.net>2023-03-06 07:19:09 +0000
commit85ad8a6fdcd2b62b04219592966152196b0a98d7 (patch)
tree0b2f21edd12cc818c911fd3c7f39c7e274d65fe5
parentfbb7fd59c35095645fafc17ba573817cef68ffcf (diff)
downloadrust-85ad8a6fdcd2b62b04219592966152196b0a98d7.tar.gz
rust-85ad8a6fdcd2b62b04219592966152196b0a98d7.zip
Avoid false positives from extension traits
-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();
+}