about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-13 23:46:27 +0000
committerbors <bors@rust-lang.org>2023-09-13 23:46:27 +0000
commit2009b58df27aab2463eaaba8b870aee09caabf1e (patch)
treeeb75397b57b38c42e545f968876d6bf78202e0fa
parentb788addfcc955368b9771b77d312c248fab60253 (diff)
parent26c0f97579763363310bc32cf6d8ef4cd6f5588f (diff)
downloadrust-2009b58df27aab2463eaaba8b870aee09caabf1e.tar.gz
rust-2009b58df27aab2463eaaba8b870aee09caabf1e.zip
Auto merge of #11452 - y21:issue11165, r=Centri3
[`len_without_is_empty`]: follow type alias to find inherent `is_empty` method

Fixes #11165

When we see an `impl B` and `B` is a type alias to some type `A`, then we need to follow the type alias to look for an `is_empty` method on the aliased type `A`. Before this PR, it'd get the inherent impls of `B`, which there aren't any and so it would warn that there isn't an `is_empty` method even if there was one.
Passing the type alias `DefId` to `TyCtxt::type_of` gives us the aliased `DefId` (or simply return the type itself if it wasn't a type alias) so we can just use that

changelog: [`len_without_is_empty`]: follow type alias to find inherent `is_empty` method
-rw-r--r--clippy_lints/src/len_zero.rs8
-rw-r--r--tests/ui/len_without_is_empty.rs23
-rw-r--r--tests/ui/len_without_is_empty.stderr8
3 files changed, 38 insertions, 1 deletions
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index deba232bdd2..c06b35ca0da 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -424,6 +424,14 @@ fn check_for_is_empty(
     item_name: Symbol,
     item_kind: &str,
 ) {
+    // Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to
+    // find the correct inherent impls.
+    let impl_ty = if let Some(adt) = cx.tcx.type_of(impl_ty).skip_binder().ty_adt_def() {
+        adt.did()
+    } else {
+        return;
+    };
+
     let is_empty = Symbol::intern("is_empty");
     let is_empty = cx
         .tcx
diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs
index ac6c3e06365..d623601110e 100644
--- a/tests/ui/len_without_is_empty.rs
+++ b/tests/ui/len_without_is_empty.rs
@@ -436,4 +436,27 @@ impl DifferingErrors {
     }
 }
 
+// Issue #11165
+pub struct Aliased1;
+pub type Alias1 = Aliased1;
+
+impl Alias1 {
+    pub fn len(&self) -> usize {
+        todo!()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        todo!()
+    }
+}
+
+pub struct Aliased2;
+pub type Alias2 = Aliased2;
+impl Alias2 {
+    pub fn len(&self) -> usize {
+        //~^ ERROR: type `Alias2` has a public `len` method, but no `is_empty` method
+        todo!()
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/len_without_is_empty.stderr b/tests/ui/len_without_is_empty.stderr
index 4815ce6a04b..8e51c28b330 100644
--- a/tests/ui/len_without_is_empty.stderr
+++ b/tests/ui/len_without_is_empty.stderr
@@ -141,5 +141,11 @@ error: struct `AsyncResultLenWithoutIsEmpty` has a public `len` method, but no `
 LL |     pub async fn len(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 15 previous errors
+error: type `Alias2` has a public `len` method, but no `is_empty` method
+  --> $DIR/len_without_is_empty.rs:456:5
+   |
+LL |     pub fn len(&self) -> usize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors