about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2024-09-21 19:13:37 +0200
committerSamuel Tardieu <sam@rfc1149.net>2024-09-22 21:29:32 +0200
commitacff51187115444038662ff4e9e23403a96d085d (patch)
treef17512708c38fa2b40c7650a7e1cc9d45adbb227
parent43e338458168db91b8459735ba6ac0f230d78d92 (diff)
downloadrust-acff51187115444038662ff4e9e23403a96d085d.tar.gz
rust-acff51187115444038662ff4e9e23403a96d085d.zip
Lint comparison to empty slice using `PartialEq` methods
-rw-r--r--clippy_lints/src/len_zero.rs15
-rw-r--r--tests/ui/comparison_to_empty.fixed8
-rw-r--r--tests/ui/comparison_to_empty.rs8
-rw-r--r--tests/ui/comparison_to_empty.stderr26
4 files changed, 55 insertions, 2 deletions
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index c1ba66de57e..3cd5f76e6b6 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
-use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
+use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -185,6 +185,19 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             );
         }
 
+        if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind
+            && is_trait_method(cx, expr, sym::PartialEq)
+            && !expr.span.from_expansion()
+        {
+            check_empty_expr(
+                cx,
+                expr.span,
+                lhs_expr,
+                peel_ref_operators(cx, rhs_expr),
+                (method.ident.name == sym::ne).then_some("!").unwrap_or_default(),
+            );
+        }
+
         if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind
             && !expr.span.from_expansion()
         {
diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed
index e102b13a761..a2a3dd9086d 100644
--- a/tests/ui/comparison_to_empty.fixed
+++ b/tests/ui/comparison_to_empty.fixed
@@ -33,4 +33,12 @@ fn main() {
     if let [0] = &*s
         && s == [0]
     {}
+
+    // Also lint the `PartialEq` methods
+    let s = String::new();
+    let _ = s.is_empty();
+    let _ = !s.is_empty();
+    let v = vec![0];
+    let _ = v.is_empty();
+    let _ = !v.is_empty();
 }
diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs
index 69a6c967d38..7c5689a4bbe 100644
--- a/tests/ui/comparison_to_empty.rs
+++ b/tests/ui/comparison_to_empty.rs
@@ -33,4 +33,12 @@ fn main() {
     if let [0] = &*s
         && s == [0]
     {}
+
+    // Also lint the `PartialEq` methods
+    let s = String::new();
+    let _ = s.eq("");
+    let _ = s.ne("");
+    let v = vec![0];
+    let _ = v.eq(&[]);
+    let _ = v.ne(&[]);
 }
diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr
index 6b027459ed3..2ee0efc7dbb 100644
--- a/tests/ui/comparison_to_empty.stderr
+++ b/tests/ui/comparison_to_empty.stderr
@@ -55,5 +55,29 @@ error: comparison to empty slice
 LL |         && s == []
    |            ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
-error: aborting due to 9 previous errors
+error: comparison to empty slice
+  --> tests/ui/comparison_to_empty.rs:39:13
+   |
+LL |     let _ = s.eq("");
+   |             ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice
+  --> tests/ui/comparison_to_empty.rs:40:13
+   |
+LL |     let _ = s.ne("");
+   |             ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
+
+error: comparison to empty slice
+  --> tests/ui/comparison_to_empty.rs:42:13
+   |
+LL |     let _ = v.eq(&[]);
+   |             ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
+
+error: comparison to empty slice
+  --> tests/ui/comparison_to_empty.rs:43:13
+   |
+LL |     let _ = v.ne(&[]);
+   |             ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
+
+error: aborting due to 13 previous errors