about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-22 18:20:12 +0000
committerbors <bors@rust-lang.org>2024-01-22 18:20:12 +0000
commita8017ae131cf500b2fc005d01a062cecb121cba9 (patch)
tree13bf84a640357e7ecce1bc20f248f9e37b1cfc3d
parent99423e8b30a5837adec3b987beb2099b432af007 (diff)
parentfd6e752f4e4fef715144b360fb7e29b4f3d10df9 (diff)
downloadrust-a8017ae131cf500b2fc005d01a062cecb121cba9.tar.gz
rust-a8017ae131cf500b2fc005d01a062cecb121cba9.zip
Auto merge of #12153 - GuillaumeGomez:non-exhaustive, r=llogiq
Don't emit `derive_partial_eq_without_eq` lint if the type has the `non_exhaustive` attribute

Part of https://github.com/rust-lang/rust-clippy/issues/9063.

If a type has a field/variant with the `#[non_exhaustive]` attribute or the type itself has it, then do no emit the `derive_partial_eq_without_eq` lint.

changelog: Don't emit `derive_partial_eq_without_eq` lint if the type has the `non_exhaustive` attribute
-rw-r--r--clippy_lints/src/derive.rs3
-rw-r--r--clippy_utils/src/attrs.rs12
-rw-r--r--tests/ui/derive_partial_eq_without_eq.fixed32
-rw-r--r--tests/ui/derive_partial_eq_without_eq.rs32
4 files changed, 78 insertions, 1 deletions
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index d8abe411030..081cbcb770f 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
-use clippy_utils::{is_lint_allowed, match_def_path, paths};
+use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
@@ -449,6 +449,7 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
         && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
         && let Some(def_id) = trait_ref.trait_def_id()
         && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
+        && !has_non_exhaustive_attr(cx.tcx, *adt)
         && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
         && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(),&[])
         // If all of our fields implement `Eq`, we can implement `Eq` too
diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs
index ad8619f0d3d..2d0c2cf1253 100644
--- a/clippy_utils/src/attrs.rs
+++ b/clippy_utils/src/attrs.rs
@@ -1,5 +1,6 @@
 use rustc_ast::{ast, attr};
 use rustc_errors::Applicability;
+use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
 use rustc_span::sym;
 use std::str::FromStr;
@@ -159,3 +160,14 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
         .filter_map(ast::Attribute::meta_item_list)
         .any(|l| attr::list_contains_name(&l, sym::hidden))
 }
+
+pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
+    adt.is_variant_list_non_exhaustive()
+        || tcx.has_attr(adt.did(), sym::non_exhaustive)
+        || adt.variants().iter().any(|variant_def| {
+            variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive)
+        })
+        || adt
+            .all_fields()
+            .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive))
+}
diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed
index a7f5d3ec7cd..aa7a95405e0 100644
--- a/tests/ui/derive_partial_eq_without_eq.fixed
+++ b/tests/ui/derive_partial_eq_without_eq.fixed
@@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn {
 #[derive(PartialEq)]
 struct InternalTy;
 
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub struct MissingEqNonExhaustive {
+    foo: u32,
+    bar: String,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+pub struct MissingEqNonExhaustive1 {
+    foo: u32,
+    #[non_exhaustive]
+    bar: String,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub enum MissingEqNonExhaustive2 {
+    Foo,
+    Bar,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+pub enum MissingEqNonExhaustive3 {
+    Foo,
+    #[non_exhaustive]
+    Bar,
+}
+
 fn main() {}
diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs
index 476d2aee23a..90ac7a7989e 100644
--- a/tests/ui/derive_partial_eq_without_eq.rs
+++ b/tests/ui/derive_partial_eq_without_eq.rs
@@ -121,4 +121,36 @@ pub fn _from_mod() -> _hidden::InPubFn {
 #[derive(PartialEq)]
 struct InternalTy;
 
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub struct MissingEqNonExhaustive {
+    foo: u32,
+    bar: String,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+pub struct MissingEqNonExhaustive1 {
+    foo: u32,
+    #[non_exhaustive]
+    bar: String,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub enum MissingEqNonExhaustive2 {
+    Foo,
+    Bar,
+}
+
+// This is a `non_exhaustive` type so should not warn.
+#[derive(Debug, PartialEq)]
+pub enum MissingEqNonExhaustive3 {
+    Foo,
+    #[non_exhaustive]
+    Bar,
+}
+
 fn main() {}